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