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