]> git.proxmox.com Git - mirror_lxcfs.git/blob - src/lxcfs.c
Merge pull request #473 from brauner/2021-08-31.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 #include "config.h"
8
9 #ifdef HAVE_FUSE3
10 #ifndef FUSE_USE_VERSION
11 #define FUSE_USE_VERSION 30
12 #endif
13 #else
14 #ifndef FUSE_USE_VERSION
15 #define FUSE_USE_VERSION 26
16 #endif
17 #endif
18
19 #define _FILE_OFFSET_BITS 64
20
21 #include <alloca.h>
22 #include <dirent.h>
23 #include <dlfcn.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <fuse.h>
27 #include <getopt.h>
28 #include <libgen.h>
29 #include <pthread.h>
30 #include <sched.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <wait.h>
38 #include <linux/sched.h>
39 #include <sys/epoll.h>
40 #include <sys/mount.h>
41 #include <sys/socket.h>
42 #include <linux/limits.h>
43
44 #include "bindings.h"
45 #include "lxcfs_fuse_compat.h"
46 #include "macro.h"
47 #include "memory_utils.h"
48
49 void *dlopen_handle;
50
51 /* Functions to keep track of number of threads using the library */
52
53 static int users_count;
54 static pthread_mutex_t user_count_mutex = PTHREAD_MUTEX_INITIALIZER;
55 static void lock_mutex(pthread_mutex_t *l)
56 {
57 int ret;
58
59 ret = pthread_mutex_lock(l);
60 if (ret)
61 log_exit("%s - returned: %d\n", strerror(ret), ret);
62 }
63
64 static void unlock_mutex(pthread_mutex_t *l)
65 {
66 int ret;
67
68 ret = pthread_mutex_unlock(l);
69 if (ret)
70 log_exit("%s - returned: %d\n", strerror(ret), ret);
71 }
72
73 static inline void users_lock(void)
74 {
75 lock_mutex(&user_count_mutex);
76 }
77
78 static inline void users_unlock(void)
79 {
80 unlock_mutex(&user_count_mutex);
81 }
82
83 static pthread_t loadavg_pid = 0;
84
85 /* Returns zero on success */
86 static int start_loadavg(void)
87 {
88 char *error;
89 pthread_t (*__load_daemon)(int);
90
91 dlerror();
92 __load_daemon = (pthread_t(*)(int))dlsym(dlopen_handle, "load_daemon");
93 error = dlerror();
94 if (error)
95 return log_error(-1, "%s - Failed to start loadavg daemon", error);
96
97 loadavg_pid = __load_daemon(1);
98 if (!loadavg_pid)
99 return -1;
100
101 return 0;
102 }
103
104 /* Returns zero on success */
105 static int stop_loadavg(void)
106 {
107 char *error;
108 int (*__stop_load_daemon)(pthread_t);
109
110 __stop_load_daemon = (int (*)(pthread_t))dlsym(dlopen_handle, "stop_load_daemon");
111 error = dlerror();
112 if (error)
113 return log_error(-1, "%s - Failed to stop loadavg daemon", error);
114
115 if (__stop_load_daemon(loadavg_pid))
116 return -1;
117
118 return 0;
119 }
120
121 static volatile sig_atomic_t need_reload;
122
123 /* do_reload - reload the dynamic library. Done under
124 * lock and when we know the user_count was 0 */
125 static void do_reload(void)
126 {
127 int ret;
128 char lxcfs_lib_path[PATH_MAX];
129
130 if (loadavg_pid > 0)
131 stop_loadavg();
132
133 if (dlopen_handle) {
134 lxcfs_info("Closed liblxcfs.so");
135 dlclose(dlopen_handle);
136 }
137
138 /* First try loading using ld.so */
139 #ifdef RESOLVE_NOW
140 dlopen_handle = dlopen("liblxcfs.so", RTLD_NOW);
141 #else
142 dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY);
143 #endif
144 if (dlopen_handle) {
145 lxcfs_debug("Opened liblxcfs.so");
146 goto good;
147 }
148
149 #ifdef LIBDIR
150 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
151 ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "%s/lxcfs/liblxcfs.so", LIBDIR);
152 #else
153 ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "/usr/local/lib/lxcfs/liblxcfs.so");
154 #endif
155 if (ret < 0 || ret >= sizeof(lxcfs_lib_path))
156 log_exit("Failed to create path to open liblxcfs");
157
158 dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY);
159 if (!dlopen_handle)
160 log_exit("%s - Failed to open liblxcfs.so", dlerror());
161 else
162 lxcfs_debug("Opened %s", lxcfs_lib_path);
163
164 good:
165 if (loadavg_pid > 0)
166 start_loadavg();
167
168 if (need_reload)
169 lxcfs_info("Reloaded LXCFS");
170 need_reload = 0;
171 }
172
173 static void up_users(void)
174 {
175 users_lock();
176 if (users_count == 0 && need_reload)
177 do_reload();
178 users_count++;
179 users_unlock();
180 }
181
182 static void down_users(void)
183 {
184 users_lock();
185 users_count--;
186 users_unlock();
187 }
188
189 static void sigusr1_reload(int signo, siginfo_t *info, void *extra)
190 {
191 need_reload = 1;
192 }
193
194 /* Functions to run the library methods */
195 static int do_cg_getattr(const char *path, struct stat *sb)
196 {
197 char *error;
198 int (*__cg_getattr)(const char *path, struct stat *sb);
199
200 dlerror();
201 __cg_getattr = (int (*)(const char *, struct stat *))dlsym(dlopen_handle, "cg_getattr");
202 error = dlerror();
203 if (error)
204 return log_error(-1, "%s - Failed to find cg_getattr()", error);
205
206 return __cg_getattr(path, sb);
207 }
208
209 static int do_proc_getattr(const char *path, struct stat *sb)
210 {
211 char *error;
212 int (*__proc_getattr)(const char *path, struct stat *sb);
213
214 dlerror();
215 __proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
216 error = dlerror();
217 if (error)
218 return log_error(-1, "%s - Failed to find proc_getattr()", error);
219
220 return __proc_getattr(path, sb);
221 }
222
223 static int do_sys_getattr(const char *path, struct stat *sb)
224 {
225 char *error;
226 int (*__sys_getattr)(const char *path, struct stat *sb);
227
228 dlerror();
229 __sys_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "sys_getattr");
230 error = dlerror();
231 if (error)
232 return log_error(-1, "%s - Failed to find sys_getattr()", error);
233
234 return __sys_getattr(path, sb);
235 }
236
237 static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
238 struct fuse_file_info *fi)
239 {
240 char *error;
241 int (*__cg_read)(const char *path, char *buf, size_t size, off_t offset,
242 struct fuse_file_info *fi);
243
244 dlerror();
245 __cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_read");
246 error = dlerror();
247 if (error)
248 return log_error(-1, "%s - Failed to find cg_read()", error);
249
250 return __cg_read(path, buf, size, offset, fi);
251 }
252
253 static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
254 struct fuse_file_info *fi)
255 {
256 char *error;
257 int (*__proc_read)(const char *path, char *buf, size_t size,
258 off_t offset, struct fuse_file_info *fi);
259
260 dlerror();
261 __proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "proc_read");
262 error = dlerror();
263 if (error)
264 return log_error(-1, "%s - Failed to find proc_read()", error);
265
266 return __proc_read(path, buf, size, offset, fi);
267 }
268
269 static int do_sys_read(const char *path, char *buf, size_t size, off_t offset,
270 struct fuse_file_info *fi)
271 {
272 char *error;
273 int (*__sys_read)(const char *path, char *buf, size_t size,
274 off_t offset, struct fuse_file_info *fi);
275
276 dlerror();
277 __sys_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_read");
278 error = dlerror();
279 if (error)
280 return log_error(-1, "%s - Failed to find sys_read()", error);
281
282 return __sys_read(path, buf, size, offset, fi);
283 }
284
285 static int do_cg_write(const char *path, const char *buf, size_t size,
286 off_t offset, struct fuse_file_info *fi)
287 {
288 char *error;
289 int (*__cg_write)(const char *path, const char *buf, size_t size,
290 off_t offset, struct fuse_file_info *fi);
291
292 dlerror();
293 __cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_write");
294 error = dlerror();
295 if (error)
296 return log_error(-1, "%s - Failed to find cg_write()", error);
297
298 return __cg_write(path, buf, size, offset, fi);
299 }
300
301 static int do_sys_write(const char *path, const char *buf, size_t size,
302 off_t offset, struct fuse_file_info *fi)
303 {
304 char *error;
305 int (*__sys_write)(const char *path, const char *buf, size_t size,
306 off_t offset, struct fuse_file_info *fi);
307
308 dlerror();
309 __sys_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_write");
310 error = dlerror();
311 if (error)
312 return log_error(-1, "%s - Failed to find sys_write()", error);
313
314 return __sys_write(path, buf, size, offset, fi);
315 }
316
317 static int do_cg_mkdir(const char *path, mode_t mode)
318 {
319 char *error;
320 int (*__cg_mkdir)(const char *path, mode_t mode);
321
322 dlerror();
323 __cg_mkdir = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_mkdir");
324 error = dlerror();
325 if (error)
326 return log_error(-1, "%s - Failed to find cg_mkdir()", error);
327
328 return __cg_mkdir(path, mode);
329 }
330
331 static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
332 {
333 char *error;
334 int (*__cg_chown)(const char *path, uid_t uid, gid_t gid);
335
336 dlerror();
337 __cg_chown = (int (*)(const char *, uid_t, gid_t))dlsym(dlopen_handle, "cg_chown");
338 error = dlerror();
339 if (error)
340 return log_error(-1, "%s - Failed to find cg_chown()", error);
341
342 return __cg_chown(path, uid, gid);
343 }
344
345 static int do_cg_rmdir(const char *path)
346 {
347 char *error;
348 int (*__cg_rmdir)(const char *path);
349
350 dlerror();
351 __cg_rmdir = (int (*)(const char *path))dlsym(dlopen_handle, "cg_rmdir");
352 error = dlerror();
353 if (error)
354 return log_error(-1, "%s - Failed to find cg_rmdir()", error);
355
356 return __cg_rmdir(path);
357 }
358
359 static int do_cg_chmod(const char *path, mode_t mode)
360 {
361 char *error;
362 int (*__cg_chmod)(const char *path, mode_t mode);
363
364 dlerror();
365 __cg_chmod = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_chmod");
366 error = dlerror();
367 if (error)
368 return log_error(-1, "%s - Failed to find cg_chmod()", error);
369
370 return __cg_chmod(path, mode);
371 }
372
373 static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
374 off_t offset, struct fuse_file_info *fi)
375 {
376 char *error;
377 int (*__cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
378 off_t offset, struct fuse_file_info *fi);
379
380 dlerror();
381 __cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_readdir");
382 error = dlerror();
383 if (error)
384 return log_error(-1, "%s - Failed to find cg_readdir()", error);
385
386 return __cg_readdir(path, buf, filler, offset, fi);
387 }
388
389 static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
390 off_t offset, struct fuse_file_info *fi)
391 {
392 char *error;
393 int (*__proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
394 off_t offset, struct fuse_file_info *fi);
395
396 dlerror();
397 __proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "proc_readdir");
398 error = dlerror();
399 if (error)
400 return log_error(-1, "%s - Failed to find proc_readdir()", error);
401
402 return __proc_readdir(path, buf, filler, offset, fi);
403 }
404
405 static int do_sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
406 off_t offset, struct fuse_file_info *fi)
407 {
408 char *error;
409 int (*__sys_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
410 off_t offset, struct fuse_file_info *fi);
411
412 dlerror();
413 __sys_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_readdir");
414 error = dlerror();
415 if (error)
416 return log_error(-1, "%s - Failed to find sys_readdir()", error);
417
418 return __sys_readdir(path, buf, filler, offset, fi);
419 }
420
421 static int do_sys_readlink(const char *path, char *buf, size_t size)
422 {
423 char *error;
424 int (*__sys_readlink)(const char *path, char *buf, size_t size);
425
426 dlerror();
427 __sys_readlink = (int (*)(const char *, char *, size_t))dlsym(dlopen_handle, "sys_readlink");
428 error = dlerror();
429 if (error)
430 return log_error(-1, "%s - Failed to find sys_readlink()", error);
431
432 return __sys_readlink(path, buf, size);
433 }
434
435 static int do_cg_open(const char *path, struct fuse_file_info *fi)
436 {
437 char *error;
438 int (*__cg_open)(const char *path, struct fuse_file_info *fi);
439
440 dlerror();
441 __cg_open = (int (*)(const char *, struct fuse_file_info *))dlsym(dlopen_handle, "cg_open");
442 error = dlerror();
443 if (error)
444 return log_error(-1, "%s - Failed to find cg_open()", error);
445
446 return __cg_open(path, fi);
447 }
448
449 static int do_cg_access(const char *path, int mode)
450 {
451 char *error;
452 int (*__cg_access)(const char *path, int mode);
453
454 dlerror();
455 __cg_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "cg_access");
456 error = dlerror();
457 if (error)
458 return log_error(-1, "%s - Failed to find cg_access()", error);
459
460 return __cg_access(path, mode);
461 }
462
463 static int do_proc_open(const char *path, struct fuse_file_info *fi)
464 {
465 char *error;
466 int (*__proc_open)(const char *path, struct fuse_file_info *fi);
467
468 dlerror();
469 __proc_open = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "proc_open");
470 error = dlerror();
471 if (error)
472 return log_error(-1, "%s - Failed to find proc_open()", error);
473
474 return __proc_open(path, fi);
475 }
476
477 static int do_proc_access(const char *path, int mode)
478 {
479 char *error;
480 int (*__proc_access)(const char *path, int mode);
481
482 dlerror();
483 __proc_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "proc_access");
484 error = dlerror();
485 if (error)
486 return log_error(-1, "%s - Failed to find proc_access()", error);
487
488 return __proc_access(path, mode);
489 }
490
491 static int do_sys_open(const char *path, struct fuse_file_info *fi)
492 {
493 char *error;
494 int (*__sys_open)(const char *path, struct fuse_file_info *fi);
495
496 dlerror();
497 __sys_open = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_open");
498 error = dlerror();
499 if (error)
500 return log_error(-1, "%s - Failed to find sys_open()", error);
501
502 return __sys_open(path, fi);
503 }
504
505 static int do_sys_opendir(const char *path, struct fuse_file_info *fi)
506 {
507 char *error;
508 int (*__sys_opendir)(const char *path, struct fuse_file_info *fi);
509
510 dlerror();
511 __sys_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_opendir");
512 error = dlerror();
513 if (error)
514 return log_error(-1, "%s - Failed to find sys_opendir()", error);
515
516 return __sys_opendir(path, fi);
517 }
518
519 static int do_sys_access(const char *path, int mode)
520 {
521 char *error;
522 int (*__sys_access)(const char *path, int mode);
523
524 dlerror();
525 __sys_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "sys_access");
526 error = dlerror();
527 if (error)
528 return log_error(-1, "%s - Failed to find sys_access()", error);
529
530 return __sys_access(path, mode);
531 }
532
533 static int do_cg_release(const char *path, struct fuse_file_info *fi)
534 {
535 char *error;
536 int (*__cg_release)(const char *path, struct fuse_file_info *fi);
537
538 dlerror();
539 __cg_release = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "cg_release");
540 error = dlerror();
541 if (error)
542 return log_error(-1, "%s - Failed to find cg_release()", error);
543
544 return __cg_release(path, fi);
545 }
546
547 static int do_proc_release(const char *path, struct fuse_file_info *fi)
548 {
549 char *error;
550 int (*__proc_release)(const char *path, struct fuse_file_info *fi);
551
552 dlerror();
553 __proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
554 error = dlerror();
555 if (error)
556 return log_error(-1, "%s - Failed to find proc_release()", error);
557
558 return __proc_release(path, fi);
559 }
560
561 static int do_sys_release(const char *path, struct fuse_file_info *fi)
562 {
563 char *error;
564 int (*__sys_release)(const char *path, struct fuse_file_info *fi);
565
566 dlerror();
567 __sys_release = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_release");
568 error = dlerror();
569 if (error)
570 return log_error(-1, "%s - Failed to find sys_release()", error);
571
572 return __sys_release(path, fi);
573 }
574
575 static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
576 {
577 char *error;
578 int (*__cg_opendir)(const char *path, struct fuse_file_info *fi);
579
580 dlerror();
581 __cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "cg_opendir");
582 error = dlerror();
583 if (error)
584 return log_error(-1, "%s - Failed to find cg_opendir()", error);
585
586 return __cg_opendir(path, fi);
587 }
588
589 static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
590 {
591 char *error;
592 int (*__cg_releasedir)(const char *path, struct fuse_file_info *fi);
593
594 dlerror();
595 __cg_releasedir = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "cg_releasedir");
596 error = dlerror();
597 if (error)
598 return log_error(-1, "%s - Failed to find cg_releasedir()", error);
599
600 return __cg_releasedir(path, fi);
601 }
602
603 static int do_sys_releasedir(const char *path, struct fuse_file_info *fi)
604 {
605 char *error;
606 int (*__sys_releasedir)(const char *path, struct fuse_file_info *fi);
607
608 dlerror();
609 __sys_releasedir = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_releasedir");
610 error = dlerror();
611 if (error)
612 return log_error(-1, "%s - Failed to find sys_releasedir()", error);
613
614 return __sys_releasedir(path, fi);
615 }
616
617 #ifdef HAVE_FUSE3
618 static int lxcfs_getattr(const char *path, struct stat *sb, struct fuse_file_info *fi)
619 #else
620 static int lxcfs_getattr(const char *path, struct stat *sb)
621 #endif
622 {
623 int ret;
624 struct timespec now;
625
626 if (strcmp(path, "/") == 0) {
627 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
628 return -EINVAL;
629 sb->st_uid = sb->st_gid = 0;
630 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
631 sb->st_size = 0;
632 sb->st_mode = S_IFDIR | 00755;
633 sb->st_nlink = 2;
634 return 0;
635 }
636
637 if (strncmp(path, "/cgroup", 7) == 0) {
638 up_users();
639 ret = do_cg_getattr(path, sb);
640 down_users();
641 return ret;
642 }
643
644 if (strncmp(path, "/proc", 5) == 0) {
645 up_users();
646 ret = do_proc_getattr(path, sb);
647 down_users();
648 return ret;
649 }
650
651 if (strncmp(path, "/sys", 4) == 0) {
652 up_users();
653 ret = do_sys_getattr(path, sb);
654 down_users();
655 return ret;
656 }
657
658 return -ENOENT;
659 }
660
661 static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
662 {
663 int ret;
664
665 if (strcmp(path, "/") == 0)
666 return 0;
667
668 if (strncmp(path, "/cgroup", 7) == 0) {
669 up_users();
670 ret = do_cg_opendir(path, fi);
671 down_users();
672 return ret;
673 }
674
675 if (strcmp(path, "/proc") == 0)
676 return 0;
677
678 if (strncmp(path, "/sys", 4) == 0) {
679 up_users();
680 ret = do_sys_opendir(path, fi);
681 down_users();
682 return ret;
683 }
684
685 return -ENOENT;
686 }
687
688 #ifdef HAVE_FUSE3
689 static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
690 off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
691 #else
692 static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
693 off_t offset, struct fuse_file_info *fi)
694 #endif
695 {
696 int ret;
697
698 if (strcmp(path, "/") == 0) {
699 if (DIR_FILLER(filler, buf, ".", NULL, 0) != 0 ||
700 DIR_FILLER(filler, buf, "..", NULL, 0) != 0 ||
701 DIR_FILLER(filler, buf, "proc", NULL, 0) != 0 ||
702 DIR_FILLER(filler, buf, "sys", NULL, 0) != 0 ||
703 DIR_FILLER(filler, buf, "cgroup", NULL, 0) != 0)
704 return -ENOMEM;
705
706 return 0;
707 }
708
709 if (strncmp(path, "/cgroup", 7) == 0) {
710 up_users();
711 ret = do_cg_readdir(path, buf, filler, offset, fi);
712 down_users();
713 return ret;
714 }
715
716 if (strcmp(path, "/proc") == 0) {
717 up_users();
718 ret = do_proc_readdir(path, buf, filler, offset, fi);
719 down_users();
720 return ret;
721 }
722
723 if (strncmp(path, "/sys", 4) == 0) {
724 up_users();
725 ret = do_sys_readdir(path, buf, filler, offset, fi);
726 down_users();
727 return ret;
728 }
729
730 return -ENOENT;
731 }
732
733 static int lxcfs_access(const char *path, int mode)
734 {
735 int ret;
736
737 if (strcmp(path, "/") == 0 && (mode & W_OK) == 0)
738 return 0;
739
740 if (strncmp(path, "/cgroup", 7) == 0) {
741 up_users();
742 ret = do_cg_access(path, mode);
743 down_users();
744 return ret;
745 }
746
747 if (strncmp(path, "/proc", 5) == 0) {
748 up_users();
749 ret = do_proc_access(path, mode);
750 down_users();
751 return ret;
752 }
753
754 if (strncmp(path, "/sys", 4) == 0) {
755 up_users();
756 ret = do_sys_access(path, mode);
757 down_users();
758 return ret;
759 }
760
761 return -EACCES;
762 }
763
764 static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
765 {
766 int ret;
767
768 if (strcmp(path, "/") == 0)
769 return 0;
770
771 if (strncmp(path, "/cgroup", 7) == 0) {
772 up_users();
773 ret = do_cg_releasedir(path, fi);
774 down_users();
775 return ret;
776 }
777
778 if (strcmp(path, "/proc") == 0)
779 return 0;
780
781 if (strncmp(path, "/sys", 4) == 0) {
782 up_users();
783 ret = do_sys_releasedir(path, fi);
784 down_users();
785 return ret;
786 }
787
788 return -EINVAL;
789 }
790
791 static int lxcfs_open(const char *path, struct fuse_file_info *fi)
792 {
793 int ret;
794
795 if (strncmp(path, "/cgroup", 7) == 0) {
796 up_users();
797 ret = do_cg_open(path, fi);
798 down_users();
799 return ret;
800 }
801
802 if (strncmp(path, "/proc", 5) == 0) {
803 up_users();
804 ret = do_proc_open(path, fi);
805 down_users();
806 return ret;
807 }
808
809 if (strncmp(path, "/sys", 4) == 0) {
810 up_users();
811 ret = do_sys_open(path, fi);
812 down_users();
813 return ret;
814 }
815
816 return -EACCES;
817 }
818
819 static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
820 struct fuse_file_info *fi)
821 {
822 int ret;
823
824 if (strncmp(path, "/cgroup", 7) == 0) {
825 up_users();
826 ret = do_cg_read(path, buf, size, offset, fi);
827 down_users();
828 return ret;
829 }
830
831 if (strncmp(path, "/proc", 5) == 0) {
832 up_users();
833 ret = do_proc_read(path, buf, size, offset, fi);
834 down_users();
835 return ret;
836 }
837
838 if (strncmp(path, "/sys", 4) == 0) {
839 up_users();
840 ret = do_sys_read(path, buf, size, offset, fi);
841 down_users();
842 return ret;
843 }
844
845 return -EINVAL;
846 }
847
848 int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
849 struct fuse_file_info *fi)
850 {
851 int ret;
852
853 if (strncmp(path, "/cgroup", 7) == 0) {
854 up_users();
855 ret = do_cg_write(path, buf, size, offset, fi);
856 down_users();
857 return ret;
858 }
859
860 if (strncmp(path, "/sys", 4) == 0) {
861 up_users();
862 ret = do_sys_write(path, buf, size, offset, fi);
863 down_users();
864 return ret;
865 }
866
867 return -EINVAL;
868 }
869
870 int lxcfs_readlink(const char *path, char *buf, size_t size)
871 {
872 int ret;
873
874 if (strncmp(path, "/sys", 4) == 0) {
875 up_users();
876 ret = do_sys_readlink(path, buf, size);
877 down_users();
878 return ret;
879 }
880
881 return -EINVAL;
882 }
883
884 static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
885 {
886 return 0;
887 }
888
889 static int lxcfs_release(const char *path, struct fuse_file_info *fi)
890 {
891 int ret;
892
893 if (strncmp(path, "/cgroup", 7) == 0) {
894 up_users();
895 ret = do_cg_release(path, fi);
896 down_users();
897 return ret;
898 }
899
900 if (strncmp(path, "/proc", 5) == 0) {
901 up_users();
902 ret = do_proc_release(path, fi);
903 down_users();
904 return ret;
905 }
906
907 if (strncmp(path, "/sys", 4) == 0) {
908 up_users();
909 ret = do_sys_release(path, fi);
910 down_users();
911 return ret;
912 }
913
914 return -EINVAL;
915 }
916
917 static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
918 {
919 return 0;
920 }
921
922 int lxcfs_mkdir(const char *path, mode_t mode)
923 {
924 int ret;
925
926 if (strncmp(path, "/cgroup", 7) == 0) {
927 up_users();
928 ret = do_cg_mkdir(path, mode);
929 down_users();
930 return ret;
931 }
932
933 return -EPERM;
934 }
935
936 #ifdef HAVE_FUSE3
937 int lxcfs_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi)
938 #else
939 int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
940 #endif
941 {
942 int ret;
943
944 if (strncmp(path, "/cgroup", 7) == 0) {
945 up_users();
946 ret = do_cg_chown(path, uid, gid);
947 down_users();
948 return ret;
949 }
950
951 if (strncmp(path, "/proc", 5) == 0)
952 return -EPERM;
953
954 if (strncmp(path, "/sys", 4) == 0)
955 return -EPERM;
956
957 return -ENOENT;
958 }
959
960 /*
961 * cat first does a truncate before doing ops->write. This doesn't
962 * really make sense for cgroups. So just return 0 always but do
963 * nothing.
964 */
965 #ifdef HAVE_FUSE3
966 int lxcfs_truncate(const char *path, off_t newsize, struct fuse_file_info *fi)
967 #else
968 int lxcfs_truncate(const char *path, off_t newsize)
969 #endif
970 {
971 if (strncmp(path, "/cgroup", 7) == 0)
972 return 0;
973
974 if (strncmp(path, "/sys", 4) == 0)
975 return 0;
976
977 return -EPERM;
978 }
979
980 int lxcfs_rmdir(const char *path)
981 {
982 int ret;
983
984 if (strncmp(path, "/cgroup", 7) == 0) {
985 up_users();
986 ret = do_cg_rmdir(path);
987 down_users();
988 return ret;
989 }
990
991 return -EPERM;
992 }
993
994 #ifdef HAVE_FUSE3
995 int lxcfs_chmod(const char *path, mode_t mode, struct fuse_file_info *fi)
996 #else
997 int lxcfs_chmod(const char *path, mode_t mode)
998 #endif
999 {
1000 int ret;
1001
1002 if (strncmp(path, "/cgroup", 7) == 0) {
1003 up_users();
1004 ret = do_cg_chmod(path, mode);
1005 down_users();
1006 return ret;
1007 }
1008
1009 if (strncmp(path, "/proc", 5) == 0)
1010 return -EPERM;
1011
1012 if (strncmp(path, "/sys", 4) == 0)
1013 return -EPERM;
1014
1015 return -ENOENT;
1016 }
1017
1018 #ifdef HAVE_FUSE3
1019 static void *lxcfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
1020 #else
1021 static void *lxcfs_init(struct fuse_conn_info *conn)
1022 #endif
1023 {
1024 char *error;
1025 void *(*__lxcfs_fuse_init)(struct fuse_conn_info * conn, void * cfg);
1026
1027 dlerror();
1028 __lxcfs_fuse_init = (void *(*)(struct fuse_conn_info * conn, void * cfg))dlsym(dlopen_handle, "lxcfs_fuse_init");
1029 error = dlerror();
1030 if (error)
1031 return log_error(NULL, "%s - Failed to find lxcfs_fuse_init()", error);
1032
1033 return __lxcfs_fuse_init(conn, NULL);
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 #ifndef HAVE_FUSE3
1059 .fgetattr = NULL,
1060 #endif
1061 .fsyncdir = NULL,
1062 #ifndef 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 #ifndef HAVE_FUSE3
1077 .utime = NULL,
1078 #endif
1079 };
1080
1081 static void usage()
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 || 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 #ifndef 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 default:
1255 usage();
1256 }
1257 }
1258
1259 if (foreground && debug)
1260 log_exit("Both --debug and --forgreound specified");
1261
1262 new_argv = &argv[optind];
1263 new_argc = argc - optind;
1264 if (new_argc != 1) {
1265 lxcfs_error("Missing mountpoint");
1266 goto out;
1267 }
1268
1269 fuse_argv[fuse_argc++] = argv[0];
1270 if (debug)
1271 fuse_argv[fuse_argc++] = "-d";
1272 else
1273 fuse_argv[fuse_argc++] = "-f";
1274 fuse_argv[fuse_argc++] = "-o";
1275
1276 /* Parse additional fuse options. */
1277 if (fuse_opts) {
1278 char *dup;
1279
1280 dup = strdup(fuse_opts);
1281 if (!dup) {
1282 lxcfs_error("Failed to copy fuse options");
1283 goto out;
1284 }
1285
1286 lxc_iterate_parts(token, dup, ",") {
1287 /* default */
1288 if (strcmp(token, "allow_other") == 0)
1289 continue;
1290
1291 /* default for LXCFS */
1292 if (strcmp(token, "direct_io") == 0)
1293 continue;
1294
1295 /* default for LXCFS */
1296 if (strncmp(token, "entry_timeout", STRLITERALLEN("entry_timeout")) == 0)
1297 continue;
1298
1299 /* default for LXCFS */
1300 if (strncmp(token, "attr_timeout", STRLITERALLEN("entry_timeout")) == 0)
1301 continue;
1302
1303 /* default for LXCFS */
1304 if (strncmp(token, "allow_other", STRLITERALLEN("allow_other")) == 0)
1305 continue;
1306
1307 /* default with fuse3 */
1308 if (strcmp(token, "nonempty") == 0) {
1309 #ifndef HAVE_FUSE3
1310 nonempty = true;
1311 #endif
1312 continue;
1313 }
1314
1315 if (append_comma_separate(&new_fuse_opts, token)) {
1316 lxcfs_error("Failed to copy fuse argument \"%s\"", token);
1317 free(dup);
1318 goto out;
1319 }
1320 }
1321 free(dup);
1322 }
1323
1324 if (append_comma_separate(&new_fuse_opts, "allow_other,entry_timeout=0.5,attr_timeout=0.5")) {
1325 lxcfs_error("Failed to copy fuse argument \"allow_other,entry_timeout=0.5,attr_timeout=0.5\"");
1326 goto out;
1327 }
1328
1329 #ifndef HAVE_FUSE3
1330 if (nonempty) {
1331 if (append_comma_separate(&new_fuse_opts, "nonempty")) {
1332 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1333 goto out;
1334 }
1335 }
1336
1337 if (append_comma_separate(&new_fuse_opts, "direct_io")) {
1338 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1339 goto out;
1340 }
1341 #endif
1342
1343 /*
1344 * We can't use default_permissions since we still support systems that
1345 * don't have kernels with cgroup namespace support. On such kernels
1346 * lxcfs will provide a namespaced cgroup view and needs explicit
1347 * access helpers to make that work.
1348 * Another reason that came to me is that we can't or at least
1349 * shouldn't guarantee that we don't need more complicated access
1350 * helpers for proc and sys virtualization in the future.
1351 */
1352
1353 fuse_argv[fuse_argc++] = new_fuse_opts;
1354 fuse_argv[fuse_argc++] = new_argv[0];
1355 fuse_argv[fuse_argc] = NULL;
1356
1357 do_reload();
1358 if (install_signal_handler(SIGUSR1, sigusr1_reload)) {
1359 lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno));
1360 goto out;
1361 }
1362
1363 if (!pidfile) {
1364 snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH);
1365 pidfile = pidfile_buf;
1366 }
1367
1368 pidfile_fd = set_pidfile(pidfile);
1369 if (pidfile_fd < 0)
1370 goto out;
1371
1372 if (load_use && start_loadavg() != 0)
1373 goto out;
1374
1375 if (!fuse_main(fuse_argc, fuse_argv, &lxcfs_ops, opts))
1376 ret = EXIT_SUCCESS;
1377
1378 if (load_use)
1379 stop_loadavg();
1380
1381 out:
1382 if (dlopen_handle)
1383 dlclose(dlopen_handle);
1384 if (pidfile)
1385 unlink(pidfile);
1386 free(new_fuse_opts);
1387 free(opts);
1388 close_prot_errno_disarm(pidfile_fd);
1389 exit(ret);
1390 }