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