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