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