]> git.proxmox.com Git - mirror_lxcfs.git/blame - lxcfs.c
bindings: document new code
[mirror_lxcfs.git] / lxcfs.c
CommitLineData
758ad80c
SH
1/* lxcfs
2 *
b11c6ec0 3 * Copyright © 2014-2016 Canonical, Inc
758ad80c
SH
4 * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
5 *
f2799430 6 * See COPYING file for details.
758ad80c
SH
7 */
8
758ad80c
SH
9#define FUSE_USE_VERSION 26
10
4e3f18fb 11#include <alloca.h>
758ad80c 12#include <dirent.h>
1ece80b2
CB
13#include <dlfcn.h>
14#include <errno.h>
758ad80c
SH
15#include <fcntl.h>
16#include <fuse.h>
758ad80c 17#include <libgen.h>
b11c6ec0 18#include <pthread.h>
1ece80b2
CB
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>
41bb9357 27#include <linux/sched.h>
5b2dfd85 28#include <sys/epoll.h>
4e3f18fb 29#include <sys/mman.h>
1ece80b2
CB
30#include <sys/mount.h>
31#include <sys/socket.h>
8cb31294 32#include <sys/syscall.h>
758ad80c 33
237e200e 34#include "bindings.h"
1ece80b2 35#include "config.h" // for VERSION
758ad80c 36
8cb31294
CB
37/* Define pivot_root() if missing from the C library */
38#ifndef HAVE_PIVOT_ROOT
39static int pivot_root(const char * new_root, const char * put_old)
40{
41#ifdef __NR_pivot_root
42return syscall(__NR_pivot_root, new_root, put_old);
43#else
44errno = ENOSYS;
45return -1;
46#endif
47}
48#else
49extern int pivot_root(const char * new_root, const char * put_old);
50#endif
51
237e200e 52void *dlopen_handle;
b11c6ec0 53
237e200e 54/* Functions to keep track of number of threads using the library */
6d1308cb 55
237e200e
SH
56static int users_count;
57static pthread_mutex_t user_count_mutex = PTHREAD_MUTEX_INITIALIZER;
b11c6ec0 58static void lock_mutex(pthread_mutex_t *l)
2c51f8dd 59{
b11c6ec0 60 int ret;
2c51f8dd 61
b11c6ec0
SH
62 if ((ret = pthread_mutex_lock(l)) != 0) {
63 fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
64 exit(1);
65 }
66}
2c51f8dd 67
237e200e 68static void unlock_mutex(pthread_mutex_t *l)
23ce2127 69{
237e200e 70 int ret;
2dc17609 71
237e200e
SH
72 if ((ret = pthread_mutex_unlock(l)) != 0) {
73 fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
74 exit(1);
97f1f27b 75 }
237e200e 76}
2dc17609 77
237e200e
SH
78static void users_lock(void)
79{
80 lock_mutex(&user_count_mutex);
81}
b731895e 82
237e200e
SH
83static void users_unlock(void)
84{
85 unlock_mutex(&user_count_mutex);
86}
e1068397 87
81d17d8f 88static volatile sig_atomic_t need_reload;
59120f04 89
237e200e
SH
90/* do_reload - reload the dynamic library. Done under
91 * lock and when we know the user_count was 0 */
92static void do_reload(void)
93{
94 if (dlopen_handle)
95 dlclose(dlopen_handle);
e1068397 96
59120f04 97 /* First try loading using ld.so */
237e200e 98 dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY);
59120f04
SH
99 if (dlopen_handle)
100 goto good;
101
7c82d95e 102 dlopen_handle = dlopen("/usr/lib/lxcfs/liblxcfs.so", RTLD_LAZY);
237e200e
SH
103 if (!dlopen_handle) {
104 fprintf(stderr, "Failed to open liblxcfs\n");
105 _exit(1);
2dc17609 106 }
59120f04
SH
107
108good:
109 if (need_reload)
110 fprintf(stderr, "lxcfs: reloaded\n");
237e200e 111 need_reload = 0;
23ce2127
SH
112}
113
237e200e 114static void up_users(void)
23ce2127 115{
237e200e
SH
116 users_lock();
117 if (users_count == 0 && need_reload)
118 do_reload();
119 users_count++;
120 users_unlock();
121}
23ce2127 122
237e200e
SH
123static void down_users(void)
124{
125 users_lock();
126 users_count--;
127 users_unlock();
23ce2127
SH
128}
129
237e200e
SH
130static void reload_handler(int sig)
131{
237e200e 132 need_reload = 1;
237e200e 133}
23ce2127 134
4e3f18fb
CB
135/*
136 * Functions and types to ease the use of clone()/__clone2()
137 */
138pid_t lxcfs_clone(int (*fn)(void *), void *arg, int flags)
139{
140 size_t stack_size = sysconf(_SC_PAGESIZE);
141 void *stack = alloca(stack_size);
142 pid_t ret;
143
144#ifdef __ia64__
145 ret = __clone2(do_clone, stack,
146 stack_size, flags | SIGCHLD, &clone_arg);
147#else
148 ret = clone(fn, stack + stack_size, flags | SIGCHLD, &arg);
149#endif
150 if (ret < 0)
151 fprintf(stderr, "failed to clone (%#x): %s", flags, strerror(errno));
152
153 return ret;
154}
155
237e200e
SH
156/* Functions to run the library methods */
157static int do_cg_getattr(const char *path, struct stat *sb)
aeb56147 158{
237e200e
SH
159 int (*cg_getattr)(const char *path, struct stat *sb);
160 char *error;
161 dlerror(); /* Clear any existing error */
162 cg_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "cg_getattr");
163 error = dlerror();
164 if (error != NULL) {
165 fprintf(stderr, "cg_getattr: %s\n", error);
166 return -1;
167 }
aeb56147 168
237e200e 169 return cg_getattr(path, sb);
aeb56147
SH
170}
171
237e200e 172static int do_proc_getattr(const char *path, struct stat *sb)
23ce2127 173{
237e200e
SH
174 int (*proc_getattr)(const char *path, struct stat *sb);
175 char *error;
176 dlerror(); /* Clear any existing error */
177 proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
178 error = dlerror();
179 if (error != NULL) {
180 fprintf(stderr, "proc_getattr: %s\n", error);
181 return -1;
182 }
23ce2127 183
237e200e 184 return proc_getattr(path, sb);
23ce2127
SH
185}
186
237e200e 187static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
23ce2127
SH
188 struct fuse_file_info *fi)
189{
237e200e
SH
190 int (*cg_read)(const char *path, char *buf, size_t size, off_t offset,
191 struct fuse_file_info *fi);
192 char *error;
23ce2127 193
237e200e
SH
194 dlerror(); /* Clear any existing error */
195 cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_read");
196 error = dlerror();
197 if (error != NULL) {
198 fprintf(stderr, "cg_read: %s\n", error);
199 return -1;
23ce2127
SH
200 }
201
237e200e 202 return cg_read(path, buf, size, offset, fi);
23ce2127
SH
203}
204
237e200e 205static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
23ce2127
SH
206 struct fuse_file_info *fi)
207{
237e200e
SH
208 int (*proc_read)(const char *path, char *buf, size_t size, off_t offset,
209 struct fuse_file_info *fi);
210 char *error;
aeb56147 211
237e200e
SH
212 dlerror(); /* Clear any existing error */
213 proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_read");
214 error = dlerror();
215 if (error != NULL) {
216 fprintf(stderr, "proc_read: %s\n", error);
217 return -1;
97f1f27b
YY
218 }
219
237e200e
SH
220 return proc_read(path, buf, size, offset, fi);
221}
97f1f27b 222
237e200e
SH
223static int do_cg_write(const char *path, const char *buf, size_t size, off_t offset,
224 struct fuse_file_info *fi)
225{
226 int (*cg_write)(const char *path, const char *buf, size_t size, off_t offset,
227 struct fuse_file_info *fi);
228 char *error;
229 dlerror(); /* Clear any existing error */
230 cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_write");
231 error = dlerror();
232 if (error != NULL) {
233 fprintf(stderr, "cg_write: %s\n", error);
234 return -1;
97f1f27b
YY
235 }
236
237e200e 237 return cg_write(path, buf, size, offset, fi);
23ce2127
SH
238}
239
237e200e 240static int do_cg_mkdir(const char *path, mode_t mode)
41bb9357 241{
237e200e
SH
242 int (*cg_mkdir)(const char *path, mode_t mode);
243 char *error;
244 dlerror(); /* Clear any existing error */
245 cg_mkdir = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_mkdir");
246 error = dlerror();
247 if (error != NULL) {
248 fprintf(stderr, "cg_mkdir: %s\n", error);
249 return -1;
250 }
41bb9357 251
237e200e 252 return cg_mkdir(path, mode);
41bb9357
SH
253}
254
237e200e 255static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
0b6af11b 256{
237e200e
SH
257 int (*cg_chown)(const char *path, uid_t uid, gid_t gid);
258 char *error;
259 dlerror(); /* Clear any existing error */
260 cg_chown = (int (*)(const char *, uid_t, gid_t)) dlsym(dlopen_handle, "cg_chown");
261 error = dlerror();
262 if (error != NULL) {
263 fprintf(stderr, "cg_chown: %s\n", error);
264 return -1;
265 }
0b6af11b 266
237e200e 267 return cg_chown(path, uid, gid);
41bb9357
SH
268}
269
237e200e 270static int do_cg_rmdir(const char *path)
23ce2127 271{
237e200e
SH
272 int (*cg_rmdir)(const char *path);
273 char *error;
274 dlerror(); /* Clear any existing error */
275 cg_rmdir = (int (*)(const char *path)) dlsym(dlopen_handle, "cg_rmdir");
276 error = dlerror();
277 if (error != NULL) {
278 fprintf(stderr, "cg_rmdir: %s\n", error);
279 return -1;
97f1f27b
YY
280 }
281
237e200e
SH
282 return cg_rmdir(path);
283}
f6c0b279 284
237e200e
SH
285static int do_cg_chmod(const char *path, mode_t mode)
286{
287 int (*cg_chmod)(const char *path, mode_t mode);
288 char *error;
289 dlerror(); /* Clear any existing error */
290 cg_chmod = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_chmod");
291 error = dlerror();
292 if (error != NULL) {
293 fprintf(stderr, "cg_chmod: %s\n", error);
294 return -1;
e1068397 295 }
cdcdb29b 296
237e200e 297 return cg_chmod(path, mode);
23ce2127
SH
298}
299
237e200e 300static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
49878439
YY
301 struct fuse_file_info *fi)
302{
237e200e
SH
303 int (*cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
304 struct fuse_file_info *fi);
305 char *error;
49878439 306
237e200e
SH
307 dlerror(); /* Clear any existing error */
308 cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_readdir");
309 error = dlerror();
310 if (error != NULL) {
311 fprintf(stderr, "cg_readdir: %s\n", error);
312 return -1;
97f1f27b 313 }
49878439 314
237e200e
SH
315 return cg_readdir(path, buf, filler, offset, fi);
316}
49878439 317
237e200e
SH
318static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
319 struct fuse_file_info *fi)
320{
321 int (*proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
322 struct fuse_file_info *fi);
323 char *error;
49878439 324
237e200e
SH
325 dlerror(); /* Clear any existing error */
326 proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_readdir");
327 error = dlerror();
328 if (error != NULL) {
329 fprintf(stderr, "proc_readdir: %s\n", error);
330 return -1;
49878439
YY
331 }
332
237e200e 333 return proc_readdir(path, buf, filler, offset, fi);
49878439
YY
334}
335
237e200e 336static int do_cg_open(const char *path, struct fuse_file_info *fi)
23ce2127 337{
237e200e
SH
338 int (*cg_open)(const char *path, struct fuse_file_info *fi);
339 char *error;
340 dlerror(); /* Clear any existing error */
341 cg_open = (int (*)(const char *, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_open");
342 error = dlerror();
343 if (error != NULL) {
344 fprintf(stderr, "cg_open: %s\n", error);
345 return -1;
346 }
23ce2127 347
237e200e 348 return cg_open(path, fi);
23ce2127
SH
349}
350
bddbb106
SH
351static int do_cg_access(const char *path, int mode)
352{
353 int (*cg_access)(const char *path, int mode);
354 char *error;
355 dlerror(); /* Clear any existing error */
356 cg_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "cg_access");
357 error = dlerror();
358 if (error != NULL) {
359 fprintf(stderr, "cg_access: %s\n", error);
360 return -1;
361 }
362
363 return cg_access(path, mode);
364}
365
237e200e 366static int do_proc_open(const char *path, struct fuse_file_info *fi)
758ad80c 367{
237e200e
SH
368 int (*proc_open)(const char *path, struct fuse_file_info *fi);
369 char *error;
370 dlerror(); /* Clear any existing error */
371 proc_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "proc_open");
372 error = dlerror();
373 if (error != NULL) {
374 fprintf(stderr, "proc_open: %s\n", error);
375 return -1;
35629743
SH
376 }
377
237e200e 378 return proc_open(path, fi);
35629743
SH
379}
380
bddbb106
SH
381static int do_proc_access(const char *path, int mode)
382{
383 int (*proc_access)(const char *path, int mode);
384 char *error;
385 dlerror(); /* Clear any existing error */
386 proc_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "proc_access");
387 error = dlerror();
388 if (error != NULL) {
389 fprintf(stderr, "proc_access: %s\n", error);
390 return -1;
391 }
392
393 return proc_access(path, mode);
394}
395
237e200e 396static int do_cg_release(const char *path, struct fuse_file_info *fi)
35629743 397{
237e200e
SH
398 int (*cg_release)(const char *path, struct fuse_file_info *fi);
399 char *error;
400 dlerror(); /* Clear any existing error */
401 cg_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_release");
402 error = dlerror();
403 if (error != NULL) {
404 fprintf(stderr, "cg_release: %s\n", error);
405 return -1;
406 }
407
408 return cg_release(path, fi);
758ad80c
SH
409}
410
237e200e 411static int do_proc_release(const char *path, struct fuse_file_info *fi)
35629743 412{
237e200e
SH
413 int (*proc_release)(const char *path, struct fuse_file_info *fi);
414 char *error;
415 dlerror(); /* Clear any existing error */
416 proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
417 error = dlerror();
418 if (error != NULL) {
419 fprintf(stderr, "proc_release: %s\n", error);
420 return -1;
421 }
97f1f27b 422
237e200e 423 return proc_release(path, fi);
96fc5ee6
SH
424}
425
237e200e 426static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
96fc5ee6 427{
237e200e
SH
428 int (*cg_opendir)(const char *path, struct fuse_file_info *fi);
429 char *error;
430 dlerror(); /* Clear any existing error */
431 cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "cg_opendir");
432 error = dlerror();
433 if (error != NULL) {
434 fprintf(stderr, "cg_opendir: %s\n", error);
435 return -1;
436 }
96fc5ee6 437
237e200e 438 return cg_opendir(path, fi);
35629743
SH
439}
440
237e200e 441static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
35629743 442{
237e200e
SH
443 int (*cg_releasedir)(const char *path, struct fuse_file_info *fi);
444 char *error;
445 dlerror(); /* Clear any existing error */
446 cg_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_releasedir");
447 error = dlerror();
448 if (error != NULL) {
449 fprintf(stderr, "cg_releasedir: %s\n", error);
450 return -1;
96fc5ee6 451 }
237e200e
SH
452
453 return cg_releasedir(path, fi);
35629743
SH
454}
455
2ad6d2bd
SH
456/*
457 * FUSE ops for /
458 * these just delegate to the /proc and /cgroup ops as
459 * needed
460 */
758ad80c
SH
461
462static int lxcfs_getattr(const char *path, struct stat *sb)
463{
237e200e 464 int ret;
758ad80c
SH
465 if (strcmp(path, "/") == 0) {
466 sb->st_mode = S_IFDIR | 00755;
467 sb->st_nlink = 2;
468 return 0;
469 }
470 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
471 up_users();
472 ret = do_cg_getattr(path, sb);
473 down_users();
474 return ret;
758ad80c 475 }
35629743 476 if (strncmp(path, "/proc", 5) == 0) {
237e200e
SH
477 up_users();
478 ret = do_proc_getattr(path, sb);
479 down_users();
480 return ret;
758ad80c
SH
481 }
482 return -EINVAL;
483}
484
485static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
486{
237e200e 487 int ret;
758ad80c
SH
488 if (strcmp(path, "/") == 0)
489 return 0;
490
491 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
492 up_users();
493 ret = do_cg_opendir(path, fi);
494 down_users();
495 return ret;
758ad80c 496 }
35629743
SH
497 if (strcmp(path, "/proc") == 0)
498 return 0;
499 return -ENOENT;
758ad80c
SH
500}
501
502static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
503 struct fuse_file_info *fi)
504{
237e200e 505 int ret;
758ad80c
SH
506 if (strcmp(path, "/") == 0) {
507 if (filler(buf, "proc", NULL, 0) != 0 ||
508 filler(buf, "cgroup", NULL, 0) != 0)
509 return -EINVAL;
510 return 0;
511 }
237e200e
SH
512 if (strncmp(path, "/cgroup", 7) == 0) {
513 up_users();
514 ret = do_cg_readdir(path, buf, filler, offset, fi);
515 down_users();
516 return ret;
517 }
518 if (strcmp(path, "/proc") == 0) {
519 up_users();
520 ret = do_proc_readdir(path, buf, filler, offset, fi);
521 down_users();
522 return ret;
523 }
758ad80c
SH
524 return -EINVAL;
525}
526
bddbb106
SH
527static int lxcfs_access(const char *path, int mode)
528{
529 int ret;
530 if (strncmp(path, "/cgroup", 7) == 0) {
531 up_users();
532 ret = do_cg_access(path, mode);
533 down_users();
534 return ret;
535 }
536 if (strncmp(path, "/proc", 5) == 0) {
537 up_users();
538 ret = do_proc_access(path, mode);
539 down_users();
540 return ret;
541 }
542
543 return -EINVAL;
544}
545
758ad80c
SH
546static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
547{
237e200e 548 int ret;
758ad80c
SH
549 if (strcmp(path, "/") == 0)
550 return 0;
551 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
552 up_users();
553 ret = do_cg_releasedir(path, fi);
554 down_users();
555 return ret;
758ad80c 556 }
35629743
SH
557 if (strcmp(path, "/proc") == 0)
558 return 0;
758ad80c
SH
559 return -EINVAL;
560}
561
99978832
SH
562static int lxcfs_open(const char *path, struct fuse_file_info *fi)
563{
237e200e
SH
564 int ret;
565 if (strncmp(path, "/cgroup", 7) == 0) {
566 up_users();
567 ret = do_cg_open(path, fi);
568 down_users();
569 return ret;
570 }
571 if (strncmp(path, "/proc", 5) == 0) {
572 up_users();
573 ret = do_proc_open(path, fi);
574 down_users();
575 return ret;
576 }
99978832
SH
577
578 return -EINVAL;
579}
580
581static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
582 struct fuse_file_info *fi)
583{
237e200e
SH
584 int ret;
585 if (strncmp(path, "/cgroup", 7) == 0) {
586 up_users();
587 ret = do_cg_read(path, buf, size, offset, fi);
588 down_users();
589 return ret;
590 }
591 if (strncmp(path, "/proc", 5) == 0) {
592 up_users();
593 ret = do_proc_read(path, buf, size, offset, fi);
594 down_users();
595 return ret;
596 }
99978832
SH
597
598 return -EINVAL;
599}
600
2ad6d2bd
SH
601int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
602 struct fuse_file_info *fi)
603{
237e200e 604 int ret;
2ad6d2bd 605 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
606 up_users();
607 ret = do_cg_write(path, buf, size, offset, fi);
608 down_users();
609 return ret;
2ad6d2bd
SH
610 }
611
612 return -EINVAL;
613}
614
99978832
SH
615static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
616{
617 return 0;
618}
619
620static int lxcfs_release(const char *path, struct fuse_file_info *fi)
758ad80c 621{
237e200e
SH
622 int ret;
623 if (strncmp(path, "/cgroup", 7) == 0) {
624 up_users();
625 ret = do_cg_release(path, fi);
626 down_users();
627 return ret;
628 }
629 if (strncmp(path, "/proc", 5) == 0) {
630 up_users();
631 ret = do_proc_release(path, fi);
632 down_users();
633 return ret;
634 }
8f6e8f5e
SH
635
636 return -EINVAL;
99978832
SH
637}
638
639static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
640{
641 return 0;
758ad80c
SH
642}
643
ab54b798
SH
644int lxcfs_mkdir(const char *path, mode_t mode)
645{
237e200e
SH
646 int ret;
647 if (strncmp(path, "/cgroup", 7) == 0) {
648 up_users();
649 ret = do_cg_mkdir(path, mode);
650 down_users();
651 return ret;
652 }
ab54b798
SH
653
654 return -EINVAL;
655}
656
341b21ad
SH
657int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
658{
237e200e
SH
659 int ret;
660 if (strncmp(path, "/cgroup", 7) == 0) {
661 up_users();
662 ret = do_cg_chown(path, uid, gid);
663 down_users();
664 return ret;
665 }
341b21ad
SH
666
667 return -EINVAL;
668}
669
2ad6d2bd
SH
670/*
671 * cat first does a truncate before doing ops->write. This doesn't
672 * really make sense for cgroups. So just return 0 always but do
673 * nothing.
674 */
675int lxcfs_truncate(const char *path, off_t newsize)
676{
677 if (strncmp(path, "/cgroup", 7) == 0)
678 return 0;
679 return -EINVAL;
680}
681
50d8d5b5
SH
682int lxcfs_rmdir(const char *path)
683{
237e200e
SH
684 int ret;
685 if (strncmp(path, "/cgroup", 7) == 0) {
686 up_users();
687 ret = do_cg_rmdir(path);
688 down_users();
689 return ret;
690 }
50d8d5b5
SH
691 return -EINVAL;
692}
693
fd2e4e03
SH
694int lxcfs_chmod(const char *path, mode_t mode)
695{
237e200e
SH
696 int ret;
697 if (strncmp(path, "/cgroup", 7) == 0) {
698 up_users();
699 ret = do_cg_chmod(path, mode);
700 down_users();
701 return ret;
702 }
fd2e4e03
SH
703 return -EINVAL;
704}
705
758ad80c
SH
706const struct fuse_operations lxcfs_ops = {
707 .getattr = lxcfs_getattr,
708 .readlink = NULL,
709 .getdir = NULL,
710 .mknod = NULL,
ab54b798 711 .mkdir = lxcfs_mkdir,
758ad80c 712 .unlink = NULL,
50d8d5b5 713 .rmdir = lxcfs_rmdir,
758ad80c
SH
714 .symlink = NULL,
715 .rename = NULL,
716 .link = NULL,
fd2e4e03 717 .chmod = lxcfs_chmod,
341b21ad 718 .chown = lxcfs_chown,
2ad6d2bd 719 .truncate = lxcfs_truncate,
758ad80c 720 .utime = NULL,
99978832
SH
721
722 .open = lxcfs_open,
723 .read = lxcfs_read,
724 .release = lxcfs_release,
2ad6d2bd 725 .write = lxcfs_write,
99978832 726
758ad80c 727 .statfs = NULL,
99978832
SH
728 .flush = lxcfs_flush,
729 .fsync = lxcfs_fsync,
758ad80c
SH
730
731 .setxattr = NULL,
732 .getxattr = NULL,
733 .listxattr = NULL,
734 .removexattr = NULL,
735
736 .opendir = lxcfs_opendir,
737 .readdir = lxcfs_readdir,
738 .releasedir = lxcfs_releasedir,
739
740 .fsyncdir = NULL,
741 .init = NULL,
742 .destroy = NULL,
bddbb106 743 .access = lxcfs_access,
758ad80c
SH
744 .create = NULL,
745 .ftruncate = NULL,
746 .fgetattr = NULL,
747};
748
99978832 749static void usage(const char *me)
758ad80c
SH
750{
751 fprintf(stderr, "Usage:\n");
752 fprintf(stderr, "\n");
e190ee91
SH
753 fprintf(stderr, "%s [-p pidfile] mountpoint\n", me);
754 fprintf(stderr, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH);
0b0f73db 755 fprintf(stderr, "%s -h\n", me);
758ad80c
SH
756 exit(1);
757}
758
99978832 759static bool is_help(char *w)
758ad80c
SH
760{
761 if (strcmp(w, "-h") == 0 ||
762 strcmp(w, "--help") == 0 ||
763 strcmp(w, "-help") == 0 ||
764 strcmp(w, "help") == 0)
765 return true;
766 return false;
767}
768
0b0f73db
SH
769void swallow_arg(int *argcp, char *argv[], char *which)
770{
771 int i;
772
773 for (i = 1; argv[i]; i++) {
774 if (strcmp(argv[i], which) != 0)
775 continue;
776 for (; argv[i]; i++) {
777 argv[i] = argv[i+1];
778 }
779 (*argcp)--;
780 return;
781 }
782}
783
e190ee91 784bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
0b0f73db
SH
785{
786 int i;
787
788 for (i = 1; argv[i]; i++) {
789 if (!argv[i+1])
790 continue;
791 if (strcmp(argv[i], opt) != 0)
792 continue;
e190ee91
SH
793 do {
794 *v = strdup(argv[i+1]);
795 } while (!*v);
0b0f73db
SH
796 for (; argv[i+1]; i++) {
797 argv[i] = argv[i+2];
798 }
799 (*argcp) -= 2;
e190ee91 800 return true;
0b0f73db 801 }
e190ee91 802 return false;
0b0f73db
SH
803}
804
237e200e
SH
805static bool mkdir_p(const char *dir, mode_t mode)
806{
807 const char *tmp = dir;
808 const char *orig = dir;
809 char *makeme;
810
811 do {
812 dir = tmp + strspn(tmp, "/");
813 tmp = dir + strcspn(dir, "/");
814 makeme = strndup(orig, dir - orig);
815 if (!makeme)
816 return false;
817 if (mkdir(makeme, mode) && errno != EEXIST) {
818 fprintf(stderr, "failed to create directory '%s': %s",
819 makeme, strerror(errno));
820 free(makeme);
821 return false;
822 }
823 free(makeme);
824 } while(tmp != dir);
825
826 return true;
827}
828
829static bool umount_if_mounted(void)
830{
cc97d34c
CB
831 if (umount2(BASEDIR, MNT_DETACH) < 0 && errno != EINVAL) {
832 fprintf(stderr, "failed to umount %s: %s\n", BASEDIR,
237e200e
SH
833 strerror(errno));
834 return false;
835 }
836 return true;
837}
838
8cb31294
CB
839static int pivot_enter(void)
840{
841 int ret = -1, oldroot = -1, newroot = -1;
842
843 oldroot = open("/", O_DIRECTORY | O_RDONLY);
844 if (oldroot < 0) {
845 fprintf(stderr, "%s: Failed to open old root for fchdir.\n", __func__);
846 return ret;
847 }
848
849 newroot = open(ROOTDIR, O_DIRECTORY | O_RDONLY);
850 if (newroot < 0) {
851 fprintf(stderr, "%s: Failed to open new root for fchdir.\n", __func__);
852 goto err;
853 }
854
855 /* change into new root fs */
856 if (fchdir(newroot) < 0) {
857 fprintf(stderr, "%s: Failed to change directory to new rootfs: %s.\n", __func__, ROOTDIR);
858 goto err;
859 }
860
861 /* pivot_root into our new root fs */
862 if (pivot_root(".", ".") < 0) {
863 fprintf(stderr, "%s: pivot_root() syscall failed: %s.\n", __func__, strerror(errno));
864 goto err;
865 }
866
867 /*
868 * At this point the old-root is mounted on top of our new-root.
869 * To unmounted it we must not be chdir'd into it, so escape back
870 * to the old-root.
871 */
872 if (fchdir(oldroot) < 0) {
873 fprintf(stderr, "%s: Failed to enter old root.\n", __func__);
874 goto err;
875 }
876 if (umount2(".", MNT_DETACH) < 0) {
877 fprintf(stderr, "%s: Failed to detach old root.\n", __func__);
878 goto err;
879 }
880
881 if (fchdir(newroot) < 0) {
882 fprintf(stderr, "%s: Failed to re-enter new root.\n", __func__);
883 goto err;
884 }
885
886 ret = 0;
887
888err:
889 if (oldroot > 0)
890 close(oldroot);
891 if (newroot > 0)
892 close(newroot);
893 return ret;
894}
895
896/* Prepare our new clean root. */
897static int pivot_prepare(void)
898{
899 if (mkdir(ROOTDIR, 0700) < 0 && errno != EEXIST) {
900 fprintf(stderr, "%s: Failed to create directory for new root.\n", __func__);
901 return -1;
902 }
903
904 if (mount("/", ROOTDIR, NULL, MS_BIND, 0) < 0) {
905 fprintf(stderr, "%s: Failed to bind-mount / for new root: %s.\n", __func__, strerror(errno));
906 return -1;
907 }
908
909 if (mount(RUNTIME_PATH, ROOTDIR RUNTIME_PATH, NULL, MS_BIND, 0) < 0) {
910 fprintf(stderr, "%s: Failed to bind-mount /run into new root: %s.\n", __func__, strerror(errno));
911 return -1;
912 }
913
914 if (mount(BASEDIR, ROOTDIR BASEDIR, NULL, MS_REC | MS_MOVE, 0) < 0) {
915 printf("%s: failed to move " BASEDIR " into new root: %s.\n", __func__, strerror(errno));
916 return -1;
917 }
918
919 return 0;
920}
921
4e3f18fb 922static bool pivot_new_root(void)
8cb31294
CB
923{
924 /* Prepare new root. */
925 if (pivot_prepare() < 0)
4e3f18fb 926 return false;
8cb31294
CB
927
928 /* Pivot into new root. */
929 if (pivot_enter() < 0)
4e3f18fb 930 return false;
8cb31294 931
4e3f18fb 932 return true;
8cb31294
CB
933}
934
237e200e
SH
935static bool setup_cgfs_dir(void)
936{
cc97d34c 937 if (!mkdir_p(BASEDIR, 0700)) {
237e200e
SH
938 fprintf(stderr, "Failed to create lxcfs cgdir\n");
939 return false;
940 }
941 if (!umount_if_mounted()) {
942 fprintf(stderr, "Failed to clean up old lxcfs cgdir\n");
943 return false;
944 }
cc97d34c 945 if (mount("tmpfs", BASEDIR, "tmpfs", 0, "size=100000,mode=700") < 0) {
237e200e
SH
946 fprintf(stderr, "Failed to mount tmpfs for private controllers\n");
947 return false;
948 }
949 return true;
950}
951
4e3f18fb 952static bool do_mount_cgroups(void)
237e200e
SH
953{
954 char *target;
4e3f18fb 955 size_t clen, len;
47f5266f 956 int i, ret;
4e3f18fb
CB
957
958 for (i = 0; i < num_hierarchies; i++) {
959 char *controller = hierarchies[i];
960 clen = strlen(controller);
961 len = strlen(BASEDIR) + clen + 2;
962 target = malloc(len);
963 if (!target)
964 return false;
965 ret = snprintf(target, len, "%s/%s", BASEDIR, controller);
966 if (ret < 0 || ret >= len) {
967 free(target);
968 return false;
969 }
970 if (mkdir(target, 0755) < 0 && errno != EEXIST) {
971 free(target);
972 return false;
973 }
974 if (mount(controller, target, "cgroup", 0, controller) < 0) {
975 fprintf(stderr, "Failed mounting cgroup %s\n", controller);
976 free(target);
977 return false;
978 }
237e200e 979
47f5266f
CB
980 fd_hierarchies[i] = open(target, O_DIRECTORY);
981 if (fd_hierarchies[i] < 0) {
4e3f18fb
CB
982 free(target);
983 return false;
984 }
4e3f18fb 985 free(target);
237e200e
SH
986 }
987 return true;
988}
989
4e3f18fb 990static int cgfs_setup_controllers(void *data)
237e200e 991{
4e3f18fb
CB
992 if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) < 0) {
993 fprintf(stderr, "%s: Failed to re-mount / private: %s.\n", __func__, strerror(errno));
994 return -1;
237e200e 995 }
8cb31294 996
237e200e
SH
997 if (!setup_cgfs_dir()) {
998 return false;
999 }
1000
1001 if (!do_mount_cgroups()) {
1002 fprintf(stderr, "Failed to set up cgroup mounts\n");
1003 return false;
1004 }
1005
4e3f18fb
CB
1006 if (!pivot_new_root())
1007 return false;
1008
237e200e
SH
1009 return true;
1010}
1011
e190ee91
SH
1012static int set_pidfile(char *pidfile)
1013{
1014 int fd;
1015 char buf[50];
1016 struct flock fl;
1017
1018 fl.l_type = F_WRLCK;
1019 fl.l_whence = SEEK_SET;
1020 fl.l_start = 0;
1021 fl.l_len = 0;
1022
1023 fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1024 if (fd == -1) {
1025 fprintf(stderr, "Could not open pidfile %s: %m", pidfile);
1026 return -1;
1027 }
1028
1029 if (fcntl(fd, F_SETLK, &fl) == -1) {
1030 if (errno == EAGAIN || errno == EACCES) {
1031 fprintf(stderr, "PID file '%s' is already locked.\n", pidfile);
1032 close(fd);
1033 return -1;
1034 }
1035 fprintf(stderr, "Warning; unable to lock PID file, proceeding.\n");
1036 }
1037
1038 if (ftruncate(fd, 0) == -1) {
1039 fprintf(stderr, "Error truncating PID file '%s': %m", pidfile);
1040 close(fd);
1041 return -1;
1042 }
1043
1044 snprintf(buf, 50, "%ld\n", (long) getpid());
1045 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
1046 fprintf(stderr, "Error writing to PID file '%s': %m", pidfile);
1047 close(fd);
1048 return -1;
1049 }
1050
1051 return fd;
1052}
1053
47f5266f
CB
1054static void close_fd_hierarchies(void)
1055{
1056 int i;
1057 for (i = 0; i < num_hierarchies; i++)
1058 if (fd_hierarchies[i] > 0)
1059 close(fd_hierarchies[i]);
1060}
1061
758ad80c
SH
1062int main(int argc, char *argv[])
1063{
47f5266f
CB
1064 int ret = EXIT_FAILURE;
1065 int pidfd = -1;
e190ee91 1066 char *pidfile = NULL, *v = NULL;
47f5266f 1067 size_t pidfile_len, mmap_len = 0;
0b0f73db
SH
1068 /*
1069 * what we pass to fuse_main is:
1070 * argv[0] -s -f -o allow_other,directio argv[1] NULL
1071 */
2c51f8dd
SH
1072 int nargs = 5, cnt = 0;
1073 char *newargv[6];
758ad80c 1074
0b0f73db
SH
1075 /* accomodate older init scripts */
1076 swallow_arg(&argc, argv, "-s");
1077 swallow_arg(&argc, argv, "-f");
e190ee91
SH
1078 if (swallow_option(&argc, argv, "-o", &v)) {
1079 if (strcmp(v, "allow_other") != 0) {
1080 fprintf(stderr, "Warning: unexpected fuse option %s\n", v);
47f5266f 1081 exit(EXIT_FAILURE);
e190ee91
SH
1082 }
1083 free(v);
1084 v = NULL;
1085 }
1086 if (swallow_option(&argc, argv, "-p", &v))
1087 pidfile = v;
0b0f73db 1088
2e9c0b32
SH
1089 if (argc == 2 && strcmp(argv[1], "--version") == 0) {
1090 fprintf(stderr, "%s\n", VERSION);
47f5266f 1091 exit(EXIT_SUCCESS);
2e9c0b32 1092 }
0b0f73db 1093 if (argc != 2 || is_help(argv[1]))
758ad80c
SH
1094 usage(argv[0]);
1095
59120f04 1096 do_reload();
8fad16cd 1097 if (signal(SIGUSR1, reload_handler) == SIG_ERR) {
8dcde249 1098 fprintf(stderr, "Error setting USR1 signal handler: %m\n");
47f5266f 1099 goto out;
8fad16cd 1100 }
e190ee91 1101
38a76a91 1102 newargv[cnt++] = argv[0];
38a76a91
SH
1103 newargv[cnt++] = "-f";
1104 newargv[cnt++] = "-o";
f466a31e 1105 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
38a76a91
SH
1106 newargv[cnt++] = argv[1];
1107 newargv[cnt++] = NULL;
758ad80c 1108
9b2a2a74
CB
1109 /* Now use clone(CLONE_NEWNS | CLONE_FILES) to mount cgroup hierarchies
1110 * in a private mount namespace to hide them from other processes that
1111 * would otherwise get confused. As fuse needs to be able to perform
1112 * file operations on the cgroup hierarchies. Hence we share open file
1113 * descriptors opened in the private mount namespace referring to those
1114 * hierarchies between child and parent process. */
47f5266f
CB
1115 mmap_len = sizeof(int *) * num_hierarchies;
1116 fd_hierarchies = mmap(NULL, mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
4e3f18fb
CB
1117 if (!fd_hierarchies)
1118 goto out;
1119
4e3f18fb
CB
1120 pid_t pid = lxcfs_clone(cgfs_setup_controllers, NULL, CLONE_NEWNS | CLONE_FILES);
1121 if (pid < 0) {
1122 fprintf(stderr, "%s: Error cloning new mount namespace: %s\n", __func__, strerror(errno));
c0adec85 1123 goto out;
4e3f18fb
CB
1124 }
1125 if (waitpid(pid, NULL, 0) < 0) {
1126 fprintf(stderr, "%s: Error waiting on cloned child: %s\n", __func__, strerror(errno));
1127 goto out;
1128 }
758ad80c 1129
e190ee91
SH
1130 if (!pidfile) {
1131 pidfile_len = strlen(RUNTIME_PATH) + strlen("/lxcfs.pid") + 1;
1132 pidfile = alloca(pidfile_len);
1133 snprintf(pidfile, pidfile_len, "%s/lxcfs.pid", RUNTIME_PATH);
1134 }
1135 if ((pidfd = set_pidfile(pidfile)) < 0)
1136 goto out;
1137
47f5266f
CB
1138 if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL))
1139 ret = EXIT_SUCCESS;
237e200e 1140
c0adec85 1141out:
47f5266f
CB
1142 if (dlopen_handle)
1143 dlclose(dlopen_handle);
1144 if (pidfile)
1145 unlink(pidfile);
1146 if (pidfd > 0)
1147 close(pidfd);
1148 close_fd_hierarchies();
1149 if (fd_hierarchies)
1150 munmap(fd_hierarchies, mmap_len);
1151 exit(ret);
2183082c 1152}