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