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