]> git.proxmox.com Git - mirror_lxcfs.git/blob - lxcfs.c
Merge pull request #303 from yinhongbo/master
[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 exit(1);
973 }
974
975 static bool is_help(char *w)
976 {
977 if (strcmp(w, "-h") == 0 ||
978 strcmp(w, "--help") == 0 ||
979 strcmp(w, "-help") == 0 ||
980 strcmp(w, "help") == 0)
981 return true;
982 return false;
983 }
984
985 bool swallow_arg(int *argcp, char *argv[], char *which)
986 {
987 int i;
988
989 for (i = 1; argv[i]; i++) {
990 if (strcmp(argv[i], which) != 0)
991 continue;
992 for (; argv[i]; i++) {
993 argv[i] = argv[i+1];
994 }
995 (*argcp)--;
996 return true;
997 }
998 return false;
999 }
1000
1001 bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
1002 {
1003 int i;
1004
1005 for (i = 1; argv[i]; i++) {
1006 if (!argv[i+1])
1007 continue;
1008 if (strcmp(argv[i], opt) != 0)
1009 continue;
1010 do {
1011 *v = strdup(argv[i+1]);
1012 } while (!*v);
1013 for (; argv[i+1]; i++) {
1014 argv[i] = argv[i+2];
1015 }
1016 (*argcp) -= 2;
1017 return true;
1018 }
1019 return false;
1020 }
1021
1022 static int set_pidfile(char *pidfile)
1023 {
1024 int fd;
1025 char buf[50];
1026 struct flock fl;
1027
1028 fl.l_type = F_WRLCK;
1029 fl.l_whence = SEEK_SET;
1030 fl.l_start = 0;
1031 fl.l_len = 0;
1032
1033 fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1034 if (fd == -1) {
1035 fprintf(stderr, "Could not open pidfile %s: %m\n", pidfile);
1036 return -1;
1037 }
1038
1039 if (fcntl(fd, F_SETLK, &fl) == -1) {
1040 if (errno == EAGAIN || errno == EACCES) {
1041 fprintf(stderr, "PID file '%s' is already locked.\n", pidfile);
1042 close(fd);
1043 return -1;
1044 }
1045 fprintf(stderr, "Warning; unable to lock PID file, proceeding.\n");
1046 }
1047
1048 if (ftruncate(fd, 0) == -1) {
1049 fprintf(stderr, "Error truncating PID file '%s': %m", pidfile);
1050 close(fd);
1051 return -1;
1052 }
1053
1054 snprintf(buf, 50, "%ld\n", (long) getpid());
1055 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
1056 fprintf(stderr, "Error writing to PID file '%s': %m", pidfile);
1057 close(fd);
1058 return -1;
1059 }
1060
1061 return fd;
1062 }
1063
1064 int main(int argc, char *argv[])
1065 {
1066 int ret = EXIT_FAILURE;
1067 int pidfd = -1;
1068 char *pidfile = NULL, *saveptr = NULL, *token = NULL, *v = NULL;
1069 size_t pidfile_len;
1070 bool debug = false, nonempty = false;
1071 bool load_use = false;
1072 /*
1073 * what we pass to fuse_main is:
1074 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
1075 */
1076 int nargs = 5, cnt = 0;
1077 char *newargv[6];
1078
1079 struct lxcfs_opts *opts;
1080 opts = malloc(sizeof(struct lxcfs_opts));
1081 if (opts == NULL) {
1082 fprintf(stderr, "Error allocating memory for options.\n");
1083 goto out;
1084 }
1085 opts->swap_off = false;
1086
1087 /* accomodate older init scripts */
1088 swallow_arg(&argc, argv, "-s");
1089 swallow_arg(&argc, argv, "-f");
1090 debug = swallow_arg(&argc, argv, "-d");
1091 if (swallow_arg(&argc, argv, "-l")) {
1092 load_use = true;
1093 }
1094 if (swallow_arg(&argc, argv, "-u")) {
1095 opts->swap_off = true;
1096 }
1097 if (swallow_option(&argc, argv, "-o", &v)) {
1098 /* Parse multiple values */
1099 for (; (token = strtok_r(v, ",", &saveptr)); v = NULL) {
1100 if (strcmp(token, "allow_other") == 0) {
1101 /* Noop. this is the default. Always enabled. */
1102 } else if (strcmp(token, "nonempty") == 0) {
1103 nonempty = true;
1104 } else {
1105 free(v);
1106 fprintf(stderr, "Warning: unexpected fuse option %s\n", v);
1107 exit(EXIT_FAILURE);
1108 }
1109 }
1110 free(v);
1111 v = NULL;
1112 }
1113 if (swallow_option(&argc, argv, "-p", &v))
1114 pidfile = v;
1115
1116 if (argc == 2 && strcmp(argv[1], "--version") == 0) {
1117 fprintf(stderr, "%s\n", VERSION);
1118 exit(EXIT_SUCCESS);
1119 }
1120 if (argc != 2 || is_help(argv[1]))
1121 usage();
1122
1123 do_reload();
1124 if (signal(SIGUSR1, reload_handler) == SIG_ERR) {
1125 fprintf(stderr, "Error setting USR1 signal handler: %m\n");
1126 goto out;
1127 }
1128
1129 newargv[cnt++] = argv[0];
1130 if (debug)
1131 newargv[cnt++] = "-d";
1132 else
1133 newargv[cnt++] = "-f";
1134 newargv[cnt++] = "-o";
1135 if (nonempty)
1136 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty";
1137 else
1138 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
1139 newargv[cnt++] = argv[1];
1140 newargv[cnt++] = NULL;
1141
1142 if (!pidfile) {
1143 pidfile_len = strlen(RUNTIME_PATH) + strlen("/lxcfs.pid") + 1;
1144 pidfile = alloca(pidfile_len);
1145 snprintf(pidfile, pidfile_len, "%s/lxcfs.pid", RUNTIME_PATH);
1146 }
1147 if ((pidfd = set_pidfile(pidfile)) < 0)
1148 goto out;
1149
1150 if (load_use && start_loadavg() != 0)
1151 goto out;
1152
1153 if (!fuse_main(nargs, newargv, &lxcfs_ops, opts))
1154 ret = EXIT_SUCCESS;
1155 if (load_use)
1156 stop_loadavg();
1157
1158 out:
1159 if (dlopen_handle)
1160 dlclose(dlopen_handle);
1161 if (pidfile)
1162 unlink(pidfile);
1163 if (pidfd > 0)
1164 close(pidfd);
1165 exit(ret);
1166 }