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