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