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