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