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