]> git.proxmox.com Git - mirror_lxcfs.git/blob - lxcfs.c
Look for liblxcfs under LIBDIR/lxcfs
[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 #define FUSE_USE_VERSION 26
10
11 #include <stdio.h>
12 #include <dirent.h>
13 #include <fcntl.h>
14 #include <fuse.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <stdbool.h>
18 #include <time.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <libgen.h>
22 #include <sched.h>
23 #include <pthread.h>
24 #include <dlfcn.h>
25 #include <linux/sched.h>
26 #include <sys/socket.h>
27 #include <sys/mount.h>
28 #include <sys/epoll.h>
29 #include <wait.h>
30
31 #include "config.h" // for VERSION
32 #include "bindings.h"
33
34 void *dlopen_handle;
35
36 /* Functions to keep track of number of threads using the library */
37
38 static int users_count;
39 static pthread_mutex_t user_count_mutex = PTHREAD_MUTEX_INITIALIZER;
40 static void lock_mutex(pthread_mutex_t *l)
41 {
42 int ret;
43
44 if ((ret = pthread_mutex_lock(l)) != 0) {
45 fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
46 exit(1);
47 }
48 }
49
50 static void unlock_mutex(pthread_mutex_t *l)
51 {
52 int ret;
53
54 if ((ret = pthread_mutex_unlock(l)) != 0) {
55 fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
56 exit(1);
57 }
58 }
59
60 static void users_lock(void)
61 {
62 lock_mutex(&user_count_mutex);
63 }
64
65 static void users_unlock(void)
66 {
67 unlock_mutex(&user_count_mutex);
68 }
69
70 static int need_reload;
71
72 /* do_reload - reload the dynamic library. Done under
73 * lock and when we know the user_count was 0 */
74 static void do_reload(void)
75 {
76 if (dlopen_handle)
77 dlclose(dlopen_handle);
78
79 /* First try loading using ld.so */
80 dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY);
81 if (dlopen_handle)
82 goto good;
83
84 /* Fall back to loading from /usr/lib/lxcfs/liblxcfs.so */
85 dlopen_handle = dlopen(LIBDIR "lxcfs/liblxcfs.so", RTLD_LAZY);
86 if (!dlopen_handle) {
87 fprintf(stderr, "Failed to open liblxcfs\n");
88 _exit(1);
89 }
90
91 good:
92 if (need_reload)
93 fprintf(stderr, "lxcfs: reloaded\n");
94 need_reload = 0;
95 }
96
97 static void up_users(void)
98 {
99 users_lock();
100 if (users_count == 0 && need_reload)
101 do_reload();
102 users_count++;
103 users_unlock();
104 }
105
106 static void down_users(void)
107 {
108 users_lock();
109 users_count--;
110 users_unlock();
111 }
112
113 static void reload_handler(int sig)
114 {
115 fprintf(stderr, "lxcfs: caught a SIGUSR1. Reloading\n");
116 users_lock();
117 need_reload = 1;
118 users_unlock();
119 }
120
121 /* Functions to run the library methods */
122 static int do_cg_getattr(const char *path, struct stat *sb)
123 {
124 int (*cg_getattr)(const char *path, struct stat *sb);
125 char *error;
126 dlerror(); /* Clear any existing error */
127 cg_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "cg_getattr");
128 error = dlerror();
129 if (error != NULL) {
130 fprintf(stderr, "cg_getattr: %s\n", error);
131 return -1;
132 }
133
134 return cg_getattr(path, sb);
135 }
136
137 static int do_proc_getattr(const char *path, struct stat *sb)
138 {
139 int (*proc_getattr)(const char *path, struct stat *sb);
140 char *error;
141 dlerror(); /* Clear any existing error */
142 proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
143 error = dlerror();
144 if (error != NULL) {
145 fprintf(stderr, "proc_getattr: %s\n", error);
146 return -1;
147 }
148
149 return proc_getattr(path, sb);
150 }
151
152 static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
153 struct fuse_file_info *fi)
154 {
155 int (*cg_read)(const char *path, char *buf, size_t size, off_t offset,
156 struct fuse_file_info *fi);
157 char *error;
158
159 dlerror(); /* Clear any existing error */
160 cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_read");
161 error = dlerror();
162 if (error != NULL) {
163 fprintf(stderr, "cg_read: %s\n", error);
164 return -1;
165 }
166
167 return cg_read(path, buf, size, offset, fi);
168 }
169
170 static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
171 struct fuse_file_info *fi)
172 {
173 int (*proc_read)(const char *path, char *buf, size_t size, off_t offset,
174 struct fuse_file_info *fi);
175 char *error;
176
177 dlerror(); /* Clear any existing error */
178 proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_read");
179 error = dlerror();
180 if (error != NULL) {
181 fprintf(stderr, "proc_read: %s\n", error);
182 return -1;
183 }
184
185 return proc_read(path, buf, size, offset, fi);
186 }
187
188 static int do_cg_write(const char *path, const char *buf, size_t size, off_t offset,
189 struct fuse_file_info *fi)
190 {
191 int (*cg_write)(const char *path, const char *buf, size_t size, off_t offset,
192 struct fuse_file_info *fi);
193 char *error;
194 dlerror(); /* Clear any existing error */
195 cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_write");
196 error = dlerror();
197 if (error != NULL) {
198 fprintf(stderr, "cg_write: %s\n", error);
199 return -1;
200 }
201
202 return cg_write(path, buf, size, offset, fi);
203 }
204
205 static int do_cg_mkdir(const char *path, mode_t mode)
206 {
207 int (*cg_mkdir)(const char *path, mode_t mode);
208 char *error;
209 dlerror(); /* Clear any existing error */
210 cg_mkdir = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_mkdir");
211 error = dlerror();
212 if (error != NULL) {
213 fprintf(stderr, "cg_mkdir: %s\n", error);
214 return -1;
215 }
216
217 return cg_mkdir(path, mode);
218 }
219
220 static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
221 {
222 int (*cg_chown)(const char *path, uid_t uid, gid_t gid);
223 char *error;
224 dlerror(); /* Clear any existing error */
225 cg_chown = (int (*)(const char *, uid_t, gid_t)) dlsym(dlopen_handle, "cg_chown");
226 error = dlerror();
227 if (error != NULL) {
228 fprintf(stderr, "cg_chown: %s\n", error);
229 return -1;
230 }
231
232 return cg_chown(path, uid, gid);
233 }
234
235 static int do_cg_rmdir(const char *path)
236 {
237 int (*cg_rmdir)(const char *path);
238 char *error;
239 dlerror(); /* Clear any existing error */
240 cg_rmdir = (int (*)(const char *path)) dlsym(dlopen_handle, "cg_rmdir");
241 error = dlerror();
242 if (error != NULL) {
243 fprintf(stderr, "cg_rmdir: %s\n", error);
244 return -1;
245 }
246
247 return cg_rmdir(path);
248 }
249
250 static int do_cg_chmod(const char *path, mode_t mode)
251 {
252 int (*cg_chmod)(const char *path, mode_t mode);
253 char *error;
254 dlerror(); /* Clear any existing error */
255 cg_chmod = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_chmod");
256 error = dlerror();
257 if (error != NULL) {
258 fprintf(stderr, "cg_chmod: %s\n", error);
259 return -1;
260 }
261
262 return cg_chmod(path, mode);
263 }
264
265 static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
266 struct fuse_file_info *fi)
267 {
268 int (*cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
269 struct fuse_file_info *fi);
270 char *error;
271
272 dlerror(); /* Clear any existing error */
273 cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_readdir");
274 error = dlerror();
275 if (error != NULL) {
276 fprintf(stderr, "cg_readdir: %s\n", error);
277 return -1;
278 }
279
280 return cg_readdir(path, buf, filler, offset, fi);
281 }
282
283 static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
284 struct fuse_file_info *fi)
285 {
286 int (*proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
287 struct fuse_file_info *fi);
288 char *error;
289
290 dlerror(); /* Clear any existing error */
291 proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_readdir");
292 error = dlerror();
293 if (error != NULL) {
294 fprintf(stderr, "proc_readdir: %s\n", error);
295 return -1;
296 }
297
298 return proc_readdir(path, buf, filler, offset, fi);
299 }
300
301 static int do_cg_open(const char *path, struct fuse_file_info *fi)
302 {
303 int (*cg_open)(const char *path, struct fuse_file_info *fi);
304 char *error;
305 dlerror(); /* Clear any existing error */
306 cg_open = (int (*)(const char *, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_open");
307 error = dlerror();
308 if (error != NULL) {
309 fprintf(stderr, "cg_open: %s\n", error);
310 return -1;
311 }
312
313 return cg_open(path, fi);
314 }
315
316 static int do_proc_open(const char *path, struct fuse_file_info *fi)
317 {
318 int (*proc_open)(const char *path, struct fuse_file_info *fi);
319 char *error;
320 dlerror(); /* Clear any existing error */
321 proc_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "proc_open");
322 error = dlerror();
323 if (error != NULL) {
324 fprintf(stderr, "proc_open: %s\n", error);
325 return -1;
326 }
327
328 return proc_open(path, fi);
329 }
330
331 static int do_cg_release(const char *path, struct fuse_file_info *fi)
332 {
333 int (*cg_release)(const char *path, struct fuse_file_info *fi);
334 char *error;
335 dlerror(); /* Clear any existing error */
336 cg_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_release");
337 error = dlerror();
338 if (error != NULL) {
339 fprintf(stderr, "cg_release: %s\n", error);
340 return -1;
341 }
342
343 return cg_release(path, fi);
344 }
345
346 static int do_proc_release(const char *path, struct fuse_file_info *fi)
347 {
348 int (*proc_release)(const char *path, struct fuse_file_info *fi);
349 char *error;
350 dlerror(); /* Clear any existing error */
351 proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
352 error = dlerror();
353 if (error != NULL) {
354 fprintf(stderr, "proc_release: %s\n", error);
355 return -1;
356 }
357
358 return proc_release(path, fi);
359 }
360
361 static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
362 {
363 int (*cg_opendir)(const char *path, struct fuse_file_info *fi);
364 char *error;
365 dlerror(); /* Clear any existing error */
366 cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "cg_opendir");
367 error = dlerror();
368 if (error != NULL) {
369 fprintf(stderr, "cg_opendir: %s\n", error);
370 return -1;
371 }
372
373 return cg_opendir(path, fi);
374 }
375
376 static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
377 {
378 int (*cg_releasedir)(const char *path, struct fuse_file_info *fi);
379 char *error;
380 dlerror(); /* Clear any existing error */
381 cg_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_releasedir");
382 error = dlerror();
383 if (error != NULL) {
384 fprintf(stderr, "cg_releasedir: %s\n", error);
385 return -1;
386 }
387
388 return cg_releasedir(path, fi);
389 }
390
391 /*
392 * FUSE ops for /
393 * these just delegate to the /proc and /cgroup ops as
394 * needed
395 */
396
397 static int lxcfs_getattr(const char *path, struct stat *sb)
398 {
399 int ret;
400 if (strcmp(path, "/") == 0) {
401 sb->st_mode = S_IFDIR | 00755;
402 sb->st_nlink = 2;
403 return 0;
404 }
405 if (strncmp(path, "/cgroup", 7) == 0) {
406 up_users();
407 ret = do_cg_getattr(path, sb);
408 down_users();
409 return ret;
410 }
411 if (strncmp(path, "/proc", 5) == 0) {
412 up_users();
413 ret = do_proc_getattr(path, sb);
414 down_users();
415 return ret;
416 }
417 return -EINVAL;
418 }
419
420 static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
421 {
422 int ret;
423 if (strcmp(path, "/") == 0)
424 return 0;
425
426 if (strncmp(path, "/cgroup", 7) == 0) {
427 up_users();
428 ret = do_cg_opendir(path, fi);
429 down_users();
430 return ret;
431 }
432 if (strcmp(path, "/proc") == 0)
433 return 0;
434 return -ENOENT;
435 }
436
437 static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
438 struct fuse_file_info *fi)
439 {
440 int ret;
441 if (strcmp(path, "/") == 0) {
442 if (filler(buf, "proc", NULL, 0) != 0 ||
443 filler(buf, "cgroup", NULL, 0) != 0)
444 return -EINVAL;
445 return 0;
446 }
447 if (strncmp(path, "/cgroup", 7) == 0) {
448 up_users();
449 ret = do_cg_readdir(path, buf, filler, offset, fi);
450 down_users();
451 return ret;
452 }
453 if (strcmp(path, "/proc") == 0) {
454 up_users();
455 ret = do_proc_readdir(path, buf, filler, offset, fi);
456 down_users();
457 return ret;
458 }
459 return -EINVAL;
460 }
461
462 static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
463 {
464 int ret;
465 if (strcmp(path, "/") == 0)
466 return 0;
467 if (strncmp(path, "/cgroup", 7) == 0) {
468 up_users();
469 ret = do_cg_releasedir(path, fi);
470 down_users();
471 return ret;
472 }
473 if (strcmp(path, "/proc") == 0)
474 return 0;
475 return -EINVAL;
476 }
477
478 static int lxcfs_open(const char *path, struct fuse_file_info *fi)
479 {
480 int ret;
481 if (strncmp(path, "/cgroup", 7) == 0) {
482 up_users();
483 ret = do_cg_open(path, fi);
484 down_users();
485 return ret;
486 }
487 if (strncmp(path, "/proc", 5) == 0) {
488 up_users();
489 ret = do_proc_open(path, fi);
490 down_users();
491 return ret;
492 }
493
494 return -EINVAL;
495 }
496
497 static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
498 struct fuse_file_info *fi)
499 {
500 int ret;
501 if (strncmp(path, "/cgroup", 7) == 0) {
502 up_users();
503 ret = do_cg_read(path, buf, size, offset, fi);
504 down_users();
505 return ret;
506 }
507 if (strncmp(path, "/proc", 5) == 0) {
508 up_users();
509 ret = do_proc_read(path, buf, size, offset, fi);
510 down_users();
511 return ret;
512 }
513
514 return -EINVAL;
515 }
516
517 int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
518 struct fuse_file_info *fi)
519 {
520 int ret;
521 if (strncmp(path, "/cgroup", 7) == 0) {
522 up_users();
523 ret = do_cg_write(path, buf, size, offset, fi);
524 down_users();
525 return ret;
526 }
527
528 return -EINVAL;
529 }
530
531 static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
532 {
533 return 0;
534 }
535
536 static int lxcfs_release(const char *path, struct fuse_file_info *fi)
537 {
538 int ret;
539 if (strncmp(path, "/cgroup", 7) == 0) {
540 up_users();
541 ret = do_cg_release(path, fi);
542 down_users();
543 return ret;
544 }
545 if (strncmp(path, "/proc", 5) == 0) {
546 up_users();
547 ret = do_proc_release(path, fi);
548 down_users();
549 return ret;
550 }
551
552 return -EINVAL;
553 }
554
555 static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
556 {
557 return 0;
558 }
559
560 int lxcfs_mkdir(const char *path, mode_t mode)
561 {
562 int ret;
563 if (strncmp(path, "/cgroup", 7) == 0) {
564 up_users();
565 ret = do_cg_mkdir(path, mode);
566 down_users();
567 return ret;
568 }
569
570 return -EINVAL;
571 }
572
573 int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
574 {
575 int ret;
576 if (strncmp(path, "/cgroup", 7) == 0) {
577 up_users();
578 ret = do_cg_chown(path, uid, gid);
579 down_users();
580 return ret;
581 }
582
583 return -EINVAL;
584 }
585
586 /*
587 * cat first does a truncate before doing ops->write. This doesn't
588 * really make sense for cgroups. So just return 0 always but do
589 * nothing.
590 */
591 int lxcfs_truncate(const char *path, off_t newsize)
592 {
593 if (strncmp(path, "/cgroup", 7) == 0)
594 return 0;
595 return -EINVAL;
596 }
597
598 int lxcfs_rmdir(const char *path)
599 {
600 int ret;
601 if (strncmp(path, "/cgroup", 7) == 0) {
602 up_users();
603 ret = do_cg_rmdir(path);
604 down_users();
605 return ret;
606 }
607 return -EINVAL;
608 }
609
610 int lxcfs_chmod(const char *path, mode_t mode)
611 {
612 int ret;
613 if (strncmp(path, "/cgroup", 7) == 0) {
614 up_users();
615 ret = do_cg_chmod(path, mode);
616 down_users();
617 return ret;
618 }
619 return -EINVAL;
620 }
621
622 const struct fuse_operations lxcfs_ops = {
623 .getattr = lxcfs_getattr,
624 .readlink = NULL,
625 .getdir = NULL,
626 .mknod = NULL,
627 .mkdir = lxcfs_mkdir,
628 .unlink = NULL,
629 .rmdir = lxcfs_rmdir,
630 .symlink = NULL,
631 .rename = NULL,
632 .link = NULL,
633 .chmod = lxcfs_chmod,
634 .chown = lxcfs_chown,
635 .truncate = lxcfs_truncate,
636 .utime = NULL,
637
638 .open = lxcfs_open,
639 .read = lxcfs_read,
640 .release = lxcfs_release,
641 .write = lxcfs_write,
642
643 .statfs = NULL,
644 .flush = lxcfs_flush,
645 .fsync = lxcfs_fsync,
646
647 .setxattr = NULL,
648 .getxattr = NULL,
649 .listxattr = NULL,
650 .removexattr = NULL,
651
652 .opendir = lxcfs_opendir,
653 .readdir = lxcfs_readdir,
654 .releasedir = lxcfs_releasedir,
655
656 .fsyncdir = NULL,
657 .init = NULL,
658 .destroy = NULL,
659 .access = NULL,
660 .create = NULL,
661 .ftruncate = NULL,
662 .fgetattr = NULL,
663 };
664
665 static void usage(const char *me)
666 {
667 fprintf(stderr, "Usage:\n");
668 fprintf(stderr, "\n");
669 fprintf(stderr, "%s [-p pidfile] mountpoint\n", me);
670 fprintf(stderr, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH);
671 fprintf(stderr, "%s -h\n", me);
672 exit(1);
673 }
674
675 static bool is_help(char *w)
676 {
677 if (strcmp(w, "-h") == 0 ||
678 strcmp(w, "--help") == 0 ||
679 strcmp(w, "-help") == 0 ||
680 strcmp(w, "help") == 0)
681 return true;
682 return false;
683 }
684
685 void swallow_arg(int *argcp, char *argv[], char *which)
686 {
687 int i;
688
689 for (i = 1; argv[i]; i++) {
690 if (strcmp(argv[i], which) != 0)
691 continue;
692 for (; argv[i]; i++) {
693 argv[i] = argv[i+1];
694 }
695 (*argcp)--;
696 return;
697 }
698 }
699
700 bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
701 {
702 int i;
703
704 for (i = 1; argv[i]; i++) {
705 if (!argv[i+1])
706 continue;
707 if (strcmp(argv[i], opt) != 0)
708 continue;
709 do {
710 *v = strdup(argv[i+1]);
711 } while (!*v);
712 for (; argv[i+1]; i++) {
713 argv[i] = argv[i+2];
714 }
715 (*argcp) -= 2;
716 return true;
717 }
718 return false;
719 }
720
721 static bool mkdir_p(const char *dir, mode_t mode)
722 {
723 const char *tmp = dir;
724 const char *orig = dir;
725 char *makeme;
726
727 do {
728 dir = tmp + strspn(tmp, "/");
729 tmp = dir + strcspn(dir, "/");
730 makeme = strndup(orig, dir - orig);
731 if (!makeme)
732 return false;
733 if (mkdir(makeme, mode) && errno != EEXIST) {
734 fprintf(stderr, "failed to create directory '%s': %s",
735 makeme, strerror(errno));
736 free(makeme);
737 return false;
738 }
739 free(makeme);
740 } while(tmp != dir);
741
742 return true;
743 }
744
745 static bool umount_if_mounted(void)
746 {
747 if (umount2(basedir, MNT_DETACH) < 0 && errno != EINVAL) {
748 fprintf(stderr, "failed to umount %s: %s\n", basedir,
749 strerror(errno));
750 return false;
751 }
752 return true;
753 }
754
755 static bool setup_cgfs_dir(void)
756 {
757 if (!mkdir_p(basedir, 0700)) {
758 fprintf(stderr, "Failed to create lxcfs cgdir\n");
759 return false;
760 }
761 if (!umount_if_mounted()) {
762 fprintf(stderr, "Failed to clean up old lxcfs cgdir\n");
763 return false;
764 }
765 if (mount("tmpfs", basedir, "tmpfs", 0, "size=100000,mode=700") < 0) {
766 fprintf(stderr, "Failed to mount tmpfs for private controllers\n");
767 return false;
768 }
769 return true;
770 }
771
772 static bool do_mount_cgroup(char *controller)
773 {
774 char *target;
775 size_t len;
776 int ret;
777
778 len = strlen(basedir) + strlen(controller) + 2;
779 target = alloca(len);
780 ret = snprintf(target, len, "%s/%s", basedir, controller);
781 if (ret < 0 || ret >= len)
782 return false;
783 if (mkdir(target, 0755) < 0 && errno != EEXIST)
784 return false;
785 if (mount(controller, target, "cgroup", 0, controller) < 0) {
786 fprintf(stderr, "Failed mounting cgroup %s\n", controller);
787 return false;
788 }
789 return true;
790 }
791
792 static bool do_mount_cgroups(void)
793 {
794 bool ret;
795 FILE *f;
796 char *line = NULL;
797 size_t len = 0;
798
799 if ((f = fopen("/proc/self/cgroup", "r")) == NULL) {
800 fprintf(stderr, "Error opening /proc/self/cgroup: %s\n", strerror(errno));
801 return false;
802 }
803
804 while (getline(&line, &len, f) != -1) {
805 char *p, *p2;
806
807 p = strchr(line, ':');
808 if (!p)
809 goto out;
810 *(p++) = '\0';
811
812 p2 = strrchr(p, ':');
813 if (!p2)
814 goto out;
815 *p2 = '\0';
816
817 if (!do_mount_cgroup(p))
818 goto out;
819 }
820 ret = true;
821
822 out:
823 free(line);
824 fclose(f);
825 return ret;
826 }
827
828 static bool cgfs_setup_controllers(void)
829 {
830 if (!setup_cgfs_dir()) {
831 return false;
832 }
833
834 if (!do_mount_cgroups()) {
835 fprintf(stderr, "Failed to set up cgroup mounts\n");
836 return false;
837 }
838
839 return true;
840 }
841
842 static int set_pidfile(char *pidfile)
843 {
844 int fd;
845 char buf[50];
846 struct flock fl;
847
848 fl.l_type = F_WRLCK;
849 fl.l_whence = SEEK_SET;
850 fl.l_start = 0;
851 fl.l_len = 0;
852
853 fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
854 if (fd == -1) {
855 fprintf(stderr, "Could not open pidfile %s: %m", pidfile);
856 return -1;
857 }
858
859 if (fcntl(fd, F_SETLK, &fl) == -1) {
860 if (errno == EAGAIN || errno == EACCES) {
861 fprintf(stderr, "PID file '%s' is already locked.\n", pidfile);
862 close(fd);
863 return -1;
864 }
865 fprintf(stderr, "Warning; unable to lock PID file, proceeding.\n");
866 }
867
868 if (ftruncate(fd, 0) == -1) {
869 fprintf(stderr, "Error truncating PID file '%s': %m", pidfile);
870 close(fd);
871 return -1;
872 }
873
874 snprintf(buf, 50, "%ld\n", (long) getpid());
875 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
876 fprintf(stderr, "Error writing to PID file '%s': %m", pidfile);
877 close(fd);
878 return -1;
879 }
880
881 return fd;
882 }
883
884 int main(int argc, char *argv[])
885 {
886 int ret = -1, pidfd;
887 char *pidfile = NULL, *v = NULL;
888 size_t pidfile_len;
889 /*
890 * what we pass to fuse_main is:
891 * argv[0] -s -f -o allow_other,directio argv[1] NULL
892 */
893 int nargs = 5, cnt = 0;
894 char *newargv[6];
895
896 /* accomodate older init scripts */
897 swallow_arg(&argc, argv, "-s");
898 swallow_arg(&argc, argv, "-f");
899 if (swallow_option(&argc, argv, "-o", &v)) {
900 if (strcmp(v, "allow_other") != 0) {
901 fprintf(stderr, "Warning: unexpected fuse option %s\n", v);
902 exit(1);
903 }
904 free(v);
905 v = NULL;
906 }
907 if (swallow_option(&argc, argv, "-p", &v))
908 pidfile = v;
909
910 if (argc == 2 && strcmp(argv[1], "--version") == 0) {
911 fprintf(stderr, "%s\n", VERSION);
912 exit(0);
913 }
914 if (argc != 2 || is_help(argv[1]))
915 usage(argv[0]);
916
917 do_reload();
918 signal(SIGUSR1, reload_handler);
919
920 newargv[cnt++] = argv[0];
921 newargv[cnt++] = "-f";
922 newargv[cnt++] = "-o";
923 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
924 newargv[cnt++] = argv[1];
925 newargv[cnt++] = NULL;
926
927 if (!cgfs_setup_controllers())
928 goto out;
929
930 if (!pidfile) {
931 pidfile_len = strlen(RUNTIME_PATH) + strlen("/lxcfs.pid") + 1;
932 pidfile = alloca(pidfile_len);
933 snprintf(pidfile, pidfile_len, "%s/lxcfs.pid", RUNTIME_PATH);
934 }
935 if ((pidfd = set_pidfile(pidfile)) < 0)
936 goto out;
937
938 ret = fuse_main(nargs, newargv, &lxcfs_ops, NULL);
939
940 dlclose(dlopen_handle);
941 unlink(pidfile);
942 close(pidfd);
943
944 out:
945 return ret;
946 }