]> git.proxmox.com Git - mirror_lxcfs.git/blob - src/lxcfs.c
tree-wide: fix HAVE_FUSE3 checks
[mirror_lxcfs.git] / src / lxcfs.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #endif
6
7 #include "config.h"
8
9 #include <alloca.h>
10 #include <dirent.h>
11 #include <dlfcn.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <getopt.h>
15 #include <libgen.h>
16 #include <pthread.h>
17 #include <sched.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <wait.h>
25 #include <linux/sched.h>
26 #include <sys/epoll.h>
27 #include <sys/mount.h>
28 #include <sys/socket.h>
29 #include <linux/limits.h>
30
31 #if HAVE_FUSE3
32 #include <fuse3/fuse.h>
33 #else
34 #include <fuse.h>
35 #endif
36
37 #include "bindings.h"
38 #include "lxcfs_fuse_compat.h"
39 #include "macro.h"
40 #include "memory_utils.h"
41
42 void *dlopen_handle;
43
44 /* Functions to keep track of number of threads using the library */
45
46 static int users_count;
47 static pthread_mutex_t user_count_mutex = PTHREAD_MUTEX_INITIALIZER;
48 static void lock_mutex(pthread_mutex_t *l)
49 {
50 int ret;
51
52 ret = pthread_mutex_lock(l);
53 if (ret)
54 log_exit("%s - returned: %d\n", strerror(ret), ret);
55 }
56
57 static void unlock_mutex(pthread_mutex_t *l)
58 {
59 int ret;
60
61 ret = pthread_mutex_unlock(l);
62 if (ret)
63 log_exit("%s - returned: %d\n", strerror(ret), ret);
64 }
65
66 static inline void users_lock(void)
67 {
68 lock_mutex(&user_count_mutex);
69 }
70
71 static inline void users_unlock(void)
72 {
73 unlock_mutex(&user_count_mutex);
74 }
75
76 static pthread_t loadavg_pid = 0;
77
78 /* Returns zero on success */
79 static int start_loadavg(void)
80 {
81 char *error;
82 pthread_t (*__load_daemon)(int);
83
84 dlerror();
85 __load_daemon = (pthread_t(*)(int))dlsym(dlopen_handle, "load_daemon");
86 error = dlerror();
87 if (error)
88 return log_error(-1, "%s - Failed to start loadavg daemon", error);
89
90 loadavg_pid = __load_daemon(1);
91 if (!loadavg_pid)
92 return -1;
93
94 return 0;
95 }
96
97 /* Returns zero on success */
98 static int stop_loadavg(void)
99 {
100 char *error;
101 int (*__stop_load_daemon)(pthread_t);
102
103 __stop_load_daemon = (int (*)(pthread_t))dlsym(dlopen_handle, "stop_load_daemon");
104 error = dlerror();
105 if (error)
106 return log_error(-1, "%s - Failed to stop loadavg daemon", error);
107
108 if (__stop_load_daemon(loadavg_pid))
109 return -1;
110
111 return 0;
112 }
113
114 static volatile sig_atomic_t need_reload;
115
116 /* do_reload - reload the dynamic library. Done under
117 * lock and when we know the user_count was 0 */
118 static void do_reload(void)
119 {
120 int ret;
121 char lxcfs_lib_path[PATH_MAX];
122
123 if (loadavg_pid > 0)
124 stop_loadavg();
125
126 if (dlopen_handle) {
127 lxcfs_info("Closed liblxcfs.so");
128 dlclose(dlopen_handle);
129 }
130
131 /* First try loading using ld.so */
132 #ifdef RESOLVE_NOW
133 dlopen_handle = dlopen("liblxcfs.so", RTLD_NOW);
134 #else
135 dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY);
136 #endif
137 if (dlopen_handle) {
138 lxcfs_debug("Opened liblxcfs.so");
139 goto good;
140 }
141
142 #ifdef LIBDIR
143 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
144 ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "%s/lxcfs/liblxcfs.so", LIBDIR);
145 #else
146 ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "/usr/local/lib/lxcfs/liblxcfs.so");
147 #endif
148 if (ret < 0 || (size_t)ret >= sizeof(lxcfs_lib_path))
149 log_exit("Failed to create path to open liblxcfs");
150
151 dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY);
152 if (!dlopen_handle)
153 log_exit("%s - Failed to open liblxcfs.so", dlerror());
154 else
155 lxcfs_debug("Opened %s", lxcfs_lib_path);
156
157 good:
158 if (loadavg_pid > 0)
159 start_loadavg();
160
161 if (need_reload)
162 lxcfs_info("Reloaded LXCFS");
163 need_reload = 0;
164 }
165
166 static void up_users(void)
167 {
168 users_lock();
169 if (users_count == 0 && need_reload)
170 do_reload();
171 users_count++;
172 users_unlock();
173 }
174
175 static void down_users(void)
176 {
177 users_lock();
178 users_count--;
179 users_unlock();
180 }
181
182 static void sigusr1_reload(int signo, siginfo_t *info, void *extra)
183 {
184 need_reload = 1;
185 }
186
187 /* Functions to run the library methods */
188 static int do_cg_getattr(const char *path, struct stat *sb)
189 {
190 char *error;
191 int (*__cg_getattr)(const char *path, struct stat *sb);
192
193 dlerror();
194 __cg_getattr = (int (*)(const char *, struct stat *))dlsym(dlopen_handle, "cg_getattr");
195 error = dlerror();
196 if (error)
197 return log_error(-1, "%s - Failed to find cg_getattr()", error);
198
199 return __cg_getattr(path, sb);
200 }
201
202 static int do_proc_getattr(const char *path, struct stat *sb)
203 {
204 char *error;
205 int (*__proc_getattr)(const char *path, struct stat *sb);
206
207 dlerror();
208 __proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
209 error = dlerror();
210 if (error)
211 return log_error(-1, "%s - Failed to find proc_getattr()", error);
212
213 return __proc_getattr(path, sb);
214 }
215
216 static int do_sys_getattr(const char *path, struct stat *sb)
217 {
218 char *error;
219 int (*__sys_getattr)(const char *path, struct stat *sb);
220
221 dlerror();
222 __sys_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "sys_getattr");
223 error = dlerror();
224 if (error)
225 return log_error(-1, "%s - Failed to find sys_getattr()", error);
226
227 return __sys_getattr(path, sb);
228 }
229
230 static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
231 struct fuse_file_info *fi)
232 {
233 char *error;
234 int (*__cg_read)(const char *path, char *buf, size_t size, off_t offset,
235 struct fuse_file_info *fi);
236
237 dlerror();
238 __cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_read");
239 error = dlerror();
240 if (error)
241 return log_error(-1, "%s - Failed to find cg_read()", error);
242
243 return __cg_read(path, buf, size, offset, fi);
244 }
245
246 static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
247 struct fuse_file_info *fi)
248 {
249 char *error;
250 int (*__proc_read)(const char *path, char *buf, size_t size,
251 off_t offset, struct fuse_file_info *fi);
252
253 dlerror();
254 __proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "proc_read");
255 error = dlerror();
256 if (error)
257 return log_error(-1, "%s - Failed to find proc_read()", error);
258
259 return __proc_read(path, buf, size, offset, fi);
260 }
261
262 static int do_sys_read(const char *path, char *buf, size_t size, off_t offset,
263 struct fuse_file_info *fi)
264 {
265 char *error;
266 int (*__sys_read)(const char *path, char *buf, size_t size,
267 off_t offset, struct fuse_file_info *fi);
268
269 dlerror();
270 __sys_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_read");
271 error = dlerror();
272 if (error)
273 return log_error(-1, "%s - Failed to find sys_read()", error);
274
275 return __sys_read(path, buf, size, offset, fi);
276 }
277
278 static int do_cg_write(const char *path, const char *buf, size_t size,
279 off_t offset, struct fuse_file_info *fi)
280 {
281 char *error;
282 int (*__cg_write)(const char *path, const char *buf, size_t size,
283 off_t offset, struct fuse_file_info *fi);
284
285 dlerror();
286 __cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_write");
287 error = dlerror();
288 if (error)
289 return log_error(-1, "%s - Failed to find cg_write()", error);
290
291 return __cg_write(path, buf, size, offset, fi);
292 }
293
294 static int do_sys_write(const char *path, const char *buf, size_t size,
295 off_t offset, struct fuse_file_info *fi)
296 {
297 char *error;
298 int (*__sys_write)(const char *path, const char *buf, size_t size,
299 off_t offset, struct fuse_file_info *fi);
300
301 dlerror();
302 __sys_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_write");
303 error = dlerror();
304 if (error)
305 return log_error(-1, "%s - Failed to find sys_write()", error);
306
307 return __sys_write(path, buf, size, offset, fi);
308 }
309
310 static int do_cg_mkdir(const char *path, mode_t mode)
311 {
312 char *error;
313 int (*__cg_mkdir)(const char *path, mode_t mode);
314
315 dlerror();
316 __cg_mkdir = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_mkdir");
317 error = dlerror();
318 if (error)
319 return log_error(-1, "%s - Failed to find cg_mkdir()", error);
320
321 return __cg_mkdir(path, mode);
322 }
323
324 static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
325 {
326 char *error;
327 int (*__cg_chown)(const char *path, uid_t uid, gid_t gid);
328
329 dlerror();
330 __cg_chown = (int (*)(const char *, uid_t, gid_t))dlsym(dlopen_handle, "cg_chown");
331 error = dlerror();
332 if (error)
333 return log_error(-1, "%s - Failed to find cg_chown()", error);
334
335 return __cg_chown(path, uid, gid);
336 }
337
338 static int do_cg_rmdir(const char *path)
339 {
340 char *error;
341 int (*__cg_rmdir)(const char *path);
342
343 dlerror();
344 __cg_rmdir = (int (*)(const char *path))dlsym(dlopen_handle, "cg_rmdir");
345 error = dlerror();
346 if (error)
347 return log_error(-1, "%s - Failed to find cg_rmdir()", error);
348
349 return __cg_rmdir(path);
350 }
351
352 static int do_cg_chmod(const char *path, mode_t mode)
353 {
354 char *error;
355 int (*__cg_chmod)(const char *path, mode_t mode);
356
357 dlerror();
358 __cg_chmod = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_chmod");
359 error = dlerror();
360 if (error)
361 return log_error(-1, "%s - Failed to find cg_chmod()", error);
362
363 return __cg_chmod(path, mode);
364 }
365
366 static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
367 off_t offset, struct fuse_file_info *fi)
368 {
369 char *error;
370 int (*__cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
371 off_t offset, struct fuse_file_info *fi);
372
373 dlerror();
374 __cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_readdir");
375 error = dlerror();
376 if (error)
377 return log_error(-1, "%s - Failed to find cg_readdir()", error);
378
379 return __cg_readdir(path, buf, filler, offset, fi);
380 }
381
382 static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
383 off_t offset, struct fuse_file_info *fi)
384 {
385 char *error;
386 int (*__proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
387 off_t offset, struct fuse_file_info *fi);
388
389 dlerror();
390 __proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "proc_readdir");
391 error = dlerror();
392 if (error)
393 return log_error(-1, "%s - Failed to find proc_readdir()", error);
394
395 return __proc_readdir(path, buf, filler, offset, fi);
396 }
397
398 static int do_sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
399 off_t offset, struct fuse_file_info *fi)
400 {
401 char *error;
402 int (*__sys_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
403 off_t offset, struct fuse_file_info *fi);
404
405 dlerror();
406 __sys_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_readdir");
407 error = dlerror();
408 if (error)
409 return log_error(-1, "%s - Failed to find sys_readdir()", error);
410
411 return __sys_readdir(path, buf, filler, offset, fi);
412 }
413
414 static int do_sys_readlink(const char *path, char *buf, size_t size)
415 {
416 char *error;
417 int (*__sys_readlink)(const char *path, char *buf, size_t size);
418
419 dlerror();
420 __sys_readlink = (int (*)(const char *, char *, size_t))dlsym(dlopen_handle, "sys_readlink");
421 error = dlerror();
422 if (error)
423 return log_error(-1, "%s - Failed to find sys_readlink()", error);
424
425 return __sys_readlink(path, buf, size);
426 }
427
428 static int do_cg_open(const char *path, struct fuse_file_info *fi)
429 {
430 char *error;
431 int (*__cg_open)(const char *path, struct fuse_file_info *fi);
432
433 dlerror();
434 __cg_open = (int (*)(const char *, struct fuse_file_info *))dlsym(dlopen_handle, "cg_open");
435 error = dlerror();
436 if (error)
437 return log_error(-1, "%s - Failed to find cg_open()", error);
438
439 return __cg_open(path, fi);
440 }
441
442 static int do_cg_access(const char *path, int mode)
443 {
444 char *error;
445 int (*__cg_access)(const char *path, int mode);
446
447 dlerror();
448 __cg_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "cg_access");
449 error = dlerror();
450 if (error)
451 return log_error(-1, "%s - Failed to find cg_access()", error);
452
453 return __cg_access(path, mode);
454 }
455
456 static int do_proc_open(const char *path, struct fuse_file_info *fi)
457 {
458 char *error;
459 int (*__proc_open)(const char *path, struct fuse_file_info *fi);
460
461 dlerror();
462 __proc_open = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "proc_open");
463 error = dlerror();
464 if (error)
465 return log_error(-1, "%s - Failed to find proc_open()", error);
466
467 return __proc_open(path, fi);
468 }
469
470 static int do_proc_access(const char *path, int mode)
471 {
472 char *error;
473 int (*__proc_access)(const char *path, int mode);
474
475 dlerror();
476 __proc_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "proc_access");
477 error = dlerror();
478 if (error)
479 return log_error(-1, "%s - Failed to find proc_access()", error);
480
481 return __proc_access(path, mode);
482 }
483
484 static int do_sys_open(const char *path, struct fuse_file_info *fi)
485 {
486 char *error;
487 int (*__sys_open)(const char *path, struct fuse_file_info *fi);
488
489 dlerror();
490 __sys_open = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_open");
491 error = dlerror();
492 if (error)
493 return log_error(-1, "%s - Failed to find sys_open()", error);
494
495 return __sys_open(path, fi);
496 }
497
498 static int do_sys_opendir(const char *path, struct fuse_file_info *fi)
499 {
500 char *error;
501 int (*__sys_opendir)(const char *path, struct fuse_file_info *fi);
502
503 dlerror();
504 __sys_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_opendir");
505 error = dlerror();
506 if (error)
507 return log_error(-1, "%s - Failed to find sys_opendir()", error);
508
509 return __sys_opendir(path, fi);
510 }
511
512 static int do_sys_access(const char *path, int mode)
513 {
514 char *error;
515 int (*__sys_access)(const char *path, int mode);
516
517 dlerror();
518 __sys_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "sys_access");
519 error = dlerror();
520 if (error)
521 return log_error(-1, "%s - Failed to find sys_access()", error);
522
523 return __sys_access(path, mode);
524 }
525
526 static int do_cg_release(const char *path, struct fuse_file_info *fi)
527 {
528 char *error;
529 int (*__cg_release)(const char *path, struct fuse_file_info *fi);
530
531 dlerror();
532 __cg_release = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "cg_release");
533 error = dlerror();
534 if (error)
535 return log_error(-1, "%s - Failed to find cg_release()", error);
536
537 return __cg_release(path, fi);
538 }
539
540 static int do_proc_release(const char *path, struct fuse_file_info *fi)
541 {
542 char *error;
543 int (*__proc_release)(const char *path, struct fuse_file_info *fi);
544
545 dlerror();
546 __proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
547 error = dlerror();
548 if (error)
549 return log_error(-1, "%s - Failed to find proc_release()", error);
550
551 return __proc_release(path, fi);
552 }
553
554 static int do_sys_release(const char *path, struct fuse_file_info *fi)
555 {
556 char *error;
557 int (*__sys_release)(const char *path, struct fuse_file_info *fi);
558
559 dlerror();
560 __sys_release = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_release");
561 error = dlerror();
562 if (error)
563 return log_error(-1, "%s - Failed to find sys_release()", error);
564
565 return __sys_release(path, fi);
566 }
567
568 static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
569 {
570 char *error;
571 int (*__cg_opendir)(const char *path, struct fuse_file_info *fi);
572
573 dlerror();
574 __cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "cg_opendir");
575 error = dlerror();
576 if (error)
577 return log_error(-1, "%s - Failed to find cg_opendir()", error);
578
579 return __cg_opendir(path, fi);
580 }
581
582 static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
583 {
584 char *error;
585 int (*__cg_releasedir)(const char *path, struct fuse_file_info *fi);
586
587 dlerror();
588 __cg_releasedir = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "cg_releasedir");
589 error = dlerror();
590 if (error)
591 return log_error(-1, "%s - Failed to find cg_releasedir()", error);
592
593 return __cg_releasedir(path, fi);
594 }
595
596 static int do_sys_releasedir(const char *path, struct fuse_file_info *fi)
597 {
598 char *error;
599 int (*__sys_releasedir)(const char *path, struct fuse_file_info *fi);
600
601 dlerror();
602 __sys_releasedir = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_releasedir");
603 error = dlerror();
604 if (error)
605 return log_error(-1, "%s - Failed to find sys_releasedir()", error);
606
607 return __sys_releasedir(path, fi);
608 }
609
610 #if HAVE_FUSE3
611 static int lxcfs_getattr(const char *path, struct stat *sb, struct fuse_file_info *fi)
612 #else
613 static int lxcfs_getattr(const char *path, struct stat *sb)
614 #endif
615 {
616 int ret;
617 struct timespec now;
618
619 if (strcmp(path, "/") == 0) {
620 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
621 return -EINVAL;
622 sb->st_uid = sb->st_gid = 0;
623 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
624 sb->st_size = 0;
625 sb->st_mode = S_IFDIR | 00755;
626 sb->st_nlink = 2;
627 return 0;
628 }
629
630 if (strncmp(path, "/cgroup", 7) == 0) {
631 up_users();
632 ret = do_cg_getattr(path, sb);
633 down_users();
634 return ret;
635 }
636
637 if (strncmp(path, "/proc", 5) == 0) {
638 up_users();
639 ret = do_proc_getattr(path, sb);
640 down_users();
641 return ret;
642 }
643
644 if (strncmp(path, "/sys", 4) == 0) {
645 up_users();
646 ret = do_sys_getattr(path, sb);
647 down_users();
648 return ret;
649 }
650
651 return -ENOENT;
652 }
653
654 static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
655 {
656 int ret;
657
658 if (strcmp(path, "/") == 0)
659 return 0;
660
661 if (strncmp(path, "/cgroup", 7) == 0) {
662 up_users();
663 ret = do_cg_opendir(path, fi);
664 down_users();
665 return ret;
666 }
667
668 if (strcmp(path, "/proc") == 0)
669 return 0;
670
671 if (strncmp(path, "/sys", 4) == 0) {
672 up_users();
673 ret = do_sys_opendir(path, fi);
674 down_users();
675 return ret;
676 }
677
678 return -ENOENT;
679 }
680
681 #if HAVE_FUSE3
682 static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
683 off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
684 #else
685 static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
686 off_t offset, struct fuse_file_info *fi)
687 #endif
688 {
689 int ret;
690
691 if (strcmp(path, "/") == 0) {
692 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
693 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
694 DIR_FILLER(filler, buf, "proc", NULL, 0) != 0 ||
695 DIR_FILLER(filler, buf, "sys", NULL, 0) != 0 ||
696 DIR_FILLER(filler, buf, "cgroup", NULL, 0) != 0)
697 return -ENOMEM;
698
699 return 0;
700 }
701
702 if (strncmp(path, "/cgroup", 7) == 0) {
703 up_users();
704 ret = do_cg_readdir(path, buf, filler, offset, fi);
705 down_users();
706 return ret;
707 }
708
709 if (strcmp(path, "/proc") == 0) {
710 up_users();
711 ret = do_proc_readdir(path, buf, filler, offset, fi);
712 down_users();
713 return ret;
714 }
715
716 if (strncmp(path, "/sys", 4) == 0) {
717 up_users();
718 ret = do_sys_readdir(path, buf, filler, offset, fi);
719 down_users();
720 return ret;
721 }
722
723 return -ENOENT;
724 }
725
726 static int lxcfs_access(const char *path, int mode)
727 {
728 int ret;
729
730 if (strcmp(path, "/") == 0 && (mode & W_OK) == 0)
731 return 0;
732
733 if (strncmp(path, "/cgroup", 7) == 0) {
734 up_users();
735 ret = do_cg_access(path, mode);
736 down_users();
737 return ret;
738 }
739
740 if (strncmp(path, "/proc", 5) == 0) {
741 up_users();
742 ret = do_proc_access(path, mode);
743 down_users();
744 return ret;
745 }
746
747 if (strncmp(path, "/sys", 4) == 0) {
748 up_users();
749 ret = do_sys_access(path, mode);
750 down_users();
751 return ret;
752 }
753
754 return -EACCES;
755 }
756
757 static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
758 {
759 int ret;
760
761 if (strcmp(path, "/") == 0)
762 return 0;
763
764 if (strncmp(path, "/cgroup", 7) == 0) {
765 up_users();
766 ret = do_cg_releasedir(path, fi);
767 down_users();
768 return ret;
769 }
770
771 if (strcmp(path, "/proc") == 0)
772 return 0;
773
774 if (strncmp(path, "/sys", 4) == 0) {
775 up_users();
776 ret = do_sys_releasedir(path, fi);
777 down_users();
778 return ret;
779 }
780
781 return -EINVAL;
782 }
783
784 static int lxcfs_open(const char *path, struct fuse_file_info *fi)
785 {
786 int ret;
787
788 if (strncmp(path, "/cgroup", 7) == 0) {
789 up_users();
790 ret = do_cg_open(path, fi);
791 down_users();
792 return ret;
793 }
794
795 if (strncmp(path, "/proc", 5) == 0) {
796 up_users();
797 ret = do_proc_open(path, fi);
798 down_users();
799 return ret;
800 }
801
802 if (strncmp(path, "/sys", 4) == 0) {
803 up_users();
804 ret = do_sys_open(path, fi);
805 down_users();
806 return ret;
807 }
808
809 return -EACCES;
810 }
811
812 static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
813 struct fuse_file_info *fi)
814 {
815 int ret;
816
817 if (strncmp(path, "/cgroup", 7) == 0) {
818 up_users();
819 ret = do_cg_read(path, buf, size, offset, fi);
820 down_users();
821 return ret;
822 }
823
824 if (strncmp(path, "/proc", 5) == 0) {
825 up_users();
826 ret = do_proc_read(path, buf, size, offset, fi);
827 down_users();
828 return ret;
829 }
830
831 if (strncmp(path, "/sys", 4) == 0) {
832 up_users();
833 ret = do_sys_read(path, buf, size, offset, fi);
834 down_users();
835 return ret;
836 }
837
838 return -EINVAL;
839 }
840
841 int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
842 struct fuse_file_info *fi)
843 {
844 int ret;
845
846 if (strncmp(path, "/cgroup", 7) == 0) {
847 up_users();
848 ret = do_cg_write(path, buf, size, offset, fi);
849 down_users();
850 return ret;
851 }
852
853 if (strncmp(path, "/sys", 4) == 0) {
854 up_users();
855 ret = do_sys_write(path, buf, size, offset, fi);
856 down_users();
857 return ret;
858 }
859
860 return -EINVAL;
861 }
862
863 int lxcfs_readlink(const char *path, char *buf, size_t size)
864 {
865 int ret;
866
867 if (strncmp(path, "/sys", 4) == 0) {
868 up_users();
869 ret = do_sys_readlink(path, buf, size);
870 down_users();
871 return ret;
872 }
873
874 return -EINVAL;
875 }
876
877 static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
878 {
879 return 0;
880 }
881
882 static int lxcfs_release(const char *path, struct fuse_file_info *fi)
883 {
884 int ret;
885
886 if (strncmp(path, "/cgroup", 7) == 0) {
887 up_users();
888 ret = do_cg_release(path, fi);
889 down_users();
890 return ret;
891 }
892
893 if (strncmp(path, "/proc", 5) == 0) {
894 up_users();
895 ret = do_proc_release(path, fi);
896 down_users();
897 return ret;
898 }
899
900 if (strncmp(path, "/sys", 4) == 0) {
901 up_users();
902 ret = do_sys_release(path, fi);
903 down_users();
904 return ret;
905 }
906
907 return -EINVAL;
908 }
909
910 static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
911 {
912 return 0;
913 }
914
915 int lxcfs_mkdir(const char *path, mode_t mode)
916 {
917 int ret;
918
919 if (strncmp(path, "/cgroup", 7) == 0) {
920 up_users();
921 ret = do_cg_mkdir(path, mode);
922 down_users();
923 return ret;
924 }
925
926 return -EPERM;
927 }
928
929 #if HAVE_FUSE3
930 int lxcfs_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi)
931 #else
932 int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
933 #endif
934 {
935 int ret;
936
937 if (strncmp(path, "/cgroup", 7) == 0) {
938 up_users();
939 ret = do_cg_chown(path, uid, gid);
940 down_users();
941 return ret;
942 }
943
944 if (strncmp(path, "/proc", 5) == 0)
945 return -EPERM;
946
947 if (strncmp(path, "/sys", 4) == 0)
948 return -EPERM;
949
950 return -ENOENT;
951 }
952
953 /*
954 * cat first does a truncate before doing ops->write. This doesn't
955 * really make sense for cgroups. So just return 0 always but do
956 * nothing.
957 */
958 #if HAVE_FUSE3
959 int lxcfs_truncate(const char *path, off_t newsize, struct fuse_file_info *fi)
960 #else
961 int lxcfs_truncate(const char *path, off_t newsize)
962 #endif
963 {
964 if (strncmp(path, "/cgroup", 7) == 0)
965 return 0;
966
967 if (strncmp(path, "/sys", 4) == 0)
968 return 0;
969
970 return -EPERM;
971 }
972
973 int lxcfs_rmdir(const char *path)
974 {
975 int ret;
976
977 if (strncmp(path, "/cgroup", 7) == 0) {
978 up_users();
979 ret = do_cg_rmdir(path);
980 down_users();
981 return ret;
982 }
983
984 return -EPERM;
985 }
986
987 #if HAVE_FUSE3
988 int lxcfs_chmod(const char *path, mode_t mode, struct fuse_file_info *fi)
989 #else
990 int lxcfs_chmod(const char *path, mode_t mode)
991 #endif
992 {
993 int ret;
994
995 if (strncmp(path, "/cgroup", 7) == 0) {
996 up_users();
997 ret = do_cg_chmod(path, mode);
998 down_users();
999 return ret;
1000 }
1001
1002 if (strncmp(path, "/proc", 5) == 0)
1003 return -EPERM;
1004
1005 if (strncmp(path, "/sys", 4) == 0)
1006 return -EPERM;
1007
1008 return -ENOENT;
1009 }
1010
1011 #if HAVE_FUSE3
1012 static void *lxcfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
1013 #else
1014 static void *lxcfs_init(struct fuse_conn_info *conn)
1015 #endif
1016 {
1017 char *error;
1018 void *(*__lxcfs_fuse_init)(struct fuse_conn_info * conn, void * cfg);
1019
1020 dlerror();
1021 __lxcfs_fuse_init = (void *(*)(struct fuse_conn_info * conn, void * cfg))dlsym(dlopen_handle, "lxcfs_fuse_init");
1022 error = dlerror();
1023 if (error)
1024 return log_error(NULL, "%s - Failed to find lxcfs_fuse_init()", error);
1025
1026 return __lxcfs_fuse_init(conn, NULL);
1027 }
1028
1029 const struct fuse_operations lxcfs_ops = {
1030 .access = lxcfs_access,
1031 .chmod = lxcfs_chmod,
1032 .chown = lxcfs_chown,
1033 .flush = lxcfs_flush,
1034 .fsync = lxcfs_fsync,
1035 .getattr = lxcfs_getattr,
1036 .init = lxcfs_init,
1037 .mkdir = lxcfs_mkdir,
1038 .open = lxcfs_open,
1039 .opendir = lxcfs_opendir,
1040 .read = lxcfs_read,
1041 .readdir = lxcfs_readdir,
1042 .release = lxcfs_release,
1043 .releasedir = lxcfs_releasedir,
1044 .rmdir = lxcfs_rmdir,
1045 .truncate = lxcfs_truncate,
1046 .write = lxcfs_write,
1047 .readlink = lxcfs_readlink,
1048
1049 .create = NULL,
1050 .destroy = NULL,
1051 #if !HAVE_FUSE3
1052 .fgetattr = NULL,
1053 #endif
1054 .fsyncdir = NULL,
1055 #if !HAVE_FUSE3
1056 .ftruncate = NULL,
1057 .getdir = NULL,
1058 #endif
1059 .getxattr = NULL,
1060 .link = NULL,
1061 .listxattr = NULL,
1062 .mknod = NULL,
1063 .rename = NULL,
1064 .removexattr = NULL,
1065 .setxattr = NULL,
1066 .statfs = NULL,
1067 .symlink = NULL,
1068 .unlink = NULL,
1069 #if !HAVE_FUSE3
1070 .utime = NULL,
1071 #endif
1072 };
1073
1074 static void usage(void)
1075 {
1076 lxcfs_info("Usage: lxcfs <directory>\n");
1077 lxcfs_info("lxcfs is a FUSE-based proc, sys and cgroup virtualizing filesystem\n");
1078 lxcfs_info("Options :");
1079 lxcfs_info(" -d, --debug Run lxcfs with debugging enabled");
1080 lxcfs_info(" -f, --foreground Run lxcfs in the foreground");
1081 lxcfs_info(" -n, --help Print help");
1082 lxcfs_info(" -l, --enable-loadavg Enable loadavg virtualization");
1083 lxcfs_info(" -o Options to pass directly through fuse");
1084 lxcfs_info(" -p, --pidfile=FILE Path to use for storing lxcfs pid");
1085 lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH);
1086 lxcfs_info(" -u, --disable-swap Disable swap virtualization");
1087 lxcfs_info(" -v, --version Print lxcfs version");
1088 lxcfs_info(" --enable-cfs Enable CPU virtualization via CPU shares");
1089 lxcfs_info(" --enable-pidfd Use pidfd for process tracking");
1090 exit(EXIT_FAILURE);
1091 }
1092
1093 static int set_pidfile(char *pidfile)
1094 {
1095 __do_close int fd = -EBADF;
1096 char buf[INTTYPE_TO_STRLEN(long)];
1097 int ret;
1098 struct flock fl = {
1099 .l_type = F_WRLCK,
1100 .l_whence = SEEK_SET,
1101 .l_start = 0,
1102 .l_len = 0,
1103 };
1104
1105 fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | O_CLOEXEC);
1106 if (fd < 0)
1107 return log_error(-1, "Could not open pidfile %s: %m", pidfile);
1108
1109 if (fcntl(fd, F_SETLK, &fl) < 0) {
1110 if (errno == EAGAIN || errno == EACCES)
1111 return log_error(-1, "PID file '%s' is already locked", pidfile);
1112 lxcfs_error("Warning; unable to lock PID file, proceeding");
1113 }
1114
1115 if (ftruncate(fd, 0))
1116 return log_error(-1, "Error truncating PID file '%s': %m", pidfile);
1117
1118 ret = snprintf(buf, sizeof(buf), "%ld\n", (long)getpid());
1119 if (ret < 0 || (size_t)ret >= sizeof(buf))
1120 return log_error(-1, "Failed to convert pid to string %m");
1121
1122 if (write(fd, buf, ret) != ret)
1123 return log_error(-1, "Error writing to PID file '%s': %m", pidfile);
1124
1125 return move_fd(fd);
1126 }
1127
1128 static const struct option long_options[] = {
1129 {"debug", no_argument, 0, 'd' },
1130 {"disable-swap", no_argument, 0, 'u' },
1131 {"enable-loadavg", no_argument, 0, 'l' },
1132 {"foreground", no_argument, 0, 'f' },
1133 {"help", no_argument, 0, 'h' },
1134 {"version", no_argument, 0, 'v' },
1135
1136 {"enable-cfs", no_argument, 0, 0 },
1137 {"enable-pidfd", no_argument, 0, 0 },
1138
1139 {"pidfile", required_argument, 0, 'p' },
1140 { },
1141 };
1142
1143 static int append_comma_separate(char **s, const char *append)
1144 {
1145 int ret;
1146 char *news;
1147 size_t append_len, len;
1148
1149 if (!append)
1150 return 0;
1151
1152 append_len = strlen(append);
1153 if (!append_len)
1154 return 0;
1155
1156 if (*s) {
1157 len = strlen(*s);
1158 news = realloc(*s, len + append_len + 2);
1159 } else {
1160 len = 0;
1161 news = realloc(NULL, append_len + 1);
1162 }
1163 if (!news)
1164 return -ENOMEM;
1165
1166 if (*s)
1167 ret = snprintf(news + len, append_len + 2, ",%s", append);
1168 else
1169 ret = snprintf(news, append_len + 1, "%s", append);
1170 if (ret < 0)
1171 return -EIO;
1172
1173 *s = news;
1174 return 0;
1175 }
1176
1177 int main(int argc, char *argv[])
1178 {
1179 int pidfile_fd = -EBADF;
1180 int ret = EXIT_FAILURE;
1181 char *pidfile = NULL, *token = NULL;
1182 char pidfile_buf[STRLITERALLEN(RUNTIME_PATH) + STRLITERALLEN("/lxcfs.pid") + 1] = {};
1183 bool debug = false, foreground = false;
1184 #if !HAVE_FUSE3
1185 bool nonempty = false;
1186 #endif
1187 bool load_use = false;
1188 /*
1189 * what we pass to fuse_main is:
1190 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
1191 */
1192 int fuse_argc = 0;
1193 int c, idx, new_argc;
1194 char *fuse_argv[7];
1195 const char *fuse_opts = NULL;
1196 char *new_fuse_opts = NULL;
1197 char *const *new_argv;
1198 struct lxcfs_opts *opts;
1199
1200 opts = malloc(sizeof(struct lxcfs_opts));
1201 if (opts == NULL) {
1202 lxcfs_error("Error allocating memory for options");
1203 goto out;
1204 }
1205
1206 opts->swap_off = false;
1207 opts->use_pidfd = false;
1208 opts->use_cfs = false;
1209 opts->version = 1;
1210
1211 while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) {
1212 switch (c) {
1213 case 0:
1214 if (strcmp(long_options[idx].name, "enable-pidfd") == 0)
1215 opts->use_pidfd = true;
1216 else if (strcmp(long_options[idx].name, "enable-cfs") == 0)
1217 opts->use_cfs = true;
1218 else
1219 usage();
1220 break;
1221 case 'd':
1222 debug = true;
1223 break;
1224 case 'f':
1225 foreground = true;
1226 break;
1227 case 'l':
1228 load_use = true;
1229 break;
1230 case 'o':
1231 if (fuse_opts) {
1232 lxcfs_error("Specifying -o multiple times is unsupported");
1233 usage();
1234 }
1235
1236 fuse_opts = optarg;
1237 break;
1238 case 'p':
1239 pidfile = optarg;
1240 break;
1241 case 's':
1242 /* legacy argument: ignore */
1243 break;
1244 case 'u':
1245 opts->swap_off = true;
1246 break;
1247 case 'v':
1248 lxcfs_info("%s", STRINGIFY(PROJECT_VERSION));
1249 exit(EXIT_SUCCESS);
1250 default:
1251 usage();
1252 }
1253 }
1254
1255 if (foreground && debug)
1256 log_exit("Both --debug and --forgreound specified");
1257
1258 new_argv = &argv[optind];
1259 new_argc = argc - optind;
1260
1261 /* Older LXCFS versions printed help when used without any argument. */
1262 if (new_argc == 0)
1263 usage();
1264
1265 if (new_argc != 1) {
1266 lxcfs_error("Missing mountpoint");
1267 goto out;
1268 }
1269
1270 fuse_argv[fuse_argc++] = argv[0];
1271 if (debug)
1272 fuse_argv[fuse_argc++] = "-d";
1273 else
1274 fuse_argv[fuse_argc++] = "-f";
1275 fuse_argv[fuse_argc++] = "-o";
1276
1277 /* Parse additional fuse options. */
1278 if (fuse_opts) {
1279 char *dup;
1280
1281 dup = strdup(fuse_opts);
1282 if (!dup) {
1283 lxcfs_error("Failed to copy fuse options");
1284 goto out;
1285 }
1286
1287 lxc_iterate_parts(token, dup, ",") {
1288 /* default */
1289 if (strcmp(token, "allow_other") == 0)
1290 continue;
1291
1292 /* default for LXCFS */
1293 if (strcmp(token, "direct_io") == 0)
1294 continue;
1295
1296 /* default for LXCFS */
1297 if (strncmp(token, "entry_timeout", STRLITERALLEN("entry_timeout")) == 0)
1298 continue;
1299
1300 /* default for LXCFS */
1301 if (strncmp(token, "attr_timeout", STRLITERALLEN("entry_timeout")) == 0)
1302 continue;
1303
1304 /* default for LXCFS */
1305 if (strncmp(token, "allow_other", STRLITERALLEN("allow_other")) == 0)
1306 continue;
1307
1308 /* default with fuse3 */
1309 if (strcmp(token, "nonempty") == 0) {
1310 #if !HAVE_FUSE3
1311 nonempty = true;
1312 #endif
1313 continue;
1314 }
1315
1316 if (append_comma_separate(&new_fuse_opts, token)) {
1317 lxcfs_error("Failed to copy fuse argument \"%s\"", token);
1318 free(dup);
1319 goto out;
1320 }
1321 }
1322 free(dup);
1323 }
1324
1325 if (append_comma_separate(&new_fuse_opts, "allow_other,entry_timeout=0.5,attr_timeout=0.5")) {
1326 lxcfs_error("Failed to copy fuse argument \"allow_other,entry_timeout=0.5,attr_timeout=0.5\"");
1327 goto out;
1328 }
1329
1330 #if !HAVE_FUSE3
1331 if (nonempty) {
1332 if (append_comma_separate(&new_fuse_opts, "nonempty")) {
1333 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1334 goto out;
1335 }
1336 }
1337
1338 if (append_comma_separate(&new_fuse_opts, "direct_io")) {
1339 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1340 goto out;
1341 }
1342 #endif
1343
1344 /*
1345 * We can't use default_permissions since we still support systems that
1346 * don't have kernels with cgroup namespace support. On such kernels
1347 * lxcfs will provide a namespaced cgroup view and needs explicit
1348 * access helpers to make that work.
1349 * Another reason that came to me is that we can't or at least
1350 * shouldn't guarantee that we don't need more complicated access
1351 * helpers for proc and sys virtualization in the future.
1352 */
1353
1354 fuse_argv[fuse_argc++] = new_fuse_opts;
1355 fuse_argv[fuse_argc++] = new_argv[0];
1356 fuse_argv[fuse_argc] = NULL;
1357
1358 do_reload();
1359 if (install_signal_handler(SIGUSR1, sigusr1_reload)) {
1360 lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno));
1361 goto out;
1362 }
1363
1364 if (!pidfile) {
1365 snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH);
1366 pidfile = pidfile_buf;
1367 }
1368
1369 pidfile_fd = set_pidfile(pidfile);
1370 if (pidfile_fd < 0)
1371 goto out;
1372
1373 if (load_use && start_loadavg() != 0)
1374 goto out;
1375
1376 if (!fuse_main(fuse_argc, fuse_argv, &lxcfs_ops, opts))
1377 ret = EXIT_SUCCESS;
1378
1379 if (load_use)
1380 stop_loadavg();
1381
1382 out:
1383 if (dlopen_handle)
1384 dlclose(dlopen_handle);
1385 if (pidfile)
1386 unlink(pidfile);
1387 free(new_fuse_opts);
1388 free(opts);
1389 close_prot_errno_disarm(pidfile_fd);
1390 exit(ret);
1391 }