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