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