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