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