]> git.proxmox.com Git - mirror_lxcfs.git/blame - lxcfs.c
Add compile method to README
[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
a83618e2
JS
72static pthread_t loadavg_pid = 0;
73
74/* Returns zero on success */
75static int start_loadavg(void) {
76 char *error;
77 pthread_t (*load_daemon)(int);
78
79 dlerror(); /* Clear any existing error */
80
81 load_daemon = (pthread_t (*)(int)) dlsym(dlopen_handle, "load_daemon");
82 error = dlerror();
83 if (error != NULL) {
84 lxcfs_error("load_daemon fails:%s\n", error);
85 return -1;
86 }
87 loadavg_pid = load_daemon(1);
88 if (loadavg_pid == 0)
89 return -1;
90
91 return 0;
92}
93
94/* Returns zero on success */
95static int stop_loadavg(void) {
96 char *error;
97 int (*stop_load_daemon)(pthread_t);
98
99 stop_load_daemon = (int (*)(pthread_t)) dlsym(dlopen_handle, "stop_load_daemon");
100 error = dlerror();
101 if (error != NULL) {
102 lxcfs_error("stop_load_daemon error: %s\n", error);
103 return -1;
104 }
105
106 if (stop_load_daemon(loadavg_pid) != 0)
107 return -1;
108
109 return 0;
110}
111
81d17d8f 112static volatile sig_atomic_t need_reload;
59120f04 113
237e200e
SH
114/* do_reload - reload the dynamic library. Done under
115 * lock and when we know the user_count was 0 */
116static void do_reload(void)
117{
9dd49ba5 118 char lxcfs_lib_path[PATH_MAX];
a83618e2
JS
119
120 if (loadavg_pid > 0)
121 stop_loadavg();
122
b8defc3d
CB
123 if (dlopen_handle) {
124 lxcfs_debug("%s\n", "Closing liblxcfs.so handle.");
237e200e 125 dlclose(dlopen_handle);
b8defc3d 126 }
e1068397 127
59120f04 128 /* First try loading using ld.so */
237e200e 129 dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY);
b8defc3d
CB
130 if (dlopen_handle) {
131 lxcfs_debug("%s\n", "Successfully called dlopen() on liblxcfs.so.");
59120f04 132 goto good;
b8defc3d 133 }
59120f04 134
9dd49ba5
DK
135#ifdef LIBDIR
136 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
137 snprintf(lxcfs_lib_path, PATH_MAX, "%s/lxcfs/liblxcfs.so", LIBDIR);
138#else
139 snprintf(lxcfs_lib_path, PATH_MAX, "/usr/local/lib/lxcfs/liblxcfs.so");
140#endif
141 dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY);
237e200e 142 if (!dlopen_handle) {
b8defc3d 143 lxcfs_error("Failed to open liblxcfs.so: %s.\n", dlerror());
237e200e 144 _exit(1);
2dc17609 145 }
59120f04
SH
146
147good:
a83618e2
JS
148 if (loadavg_pid > 0)
149 start_loadavg();
150
59120f04 151 if (need_reload)
b8defc3d 152 lxcfs_error("%s\n", "lxcfs: reloaded");
237e200e 153 need_reload = 0;
23ce2127
SH
154}
155
237e200e 156static void up_users(void)
23ce2127 157{
237e200e
SH
158 users_lock();
159 if (users_count == 0 && need_reload)
160 do_reload();
161 users_count++;
162 users_unlock();
163}
23ce2127 164
237e200e
SH
165static void down_users(void)
166{
167 users_lock();
168 users_count--;
169 users_unlock();
23ce2127
SH
170}
171
237e200e
SH
172static void reload_handler(int sig)
173{
237e200e 174 need_reload = 1;
237e200e 175}
23ce2127 176
237e200e
SH
177/* Functions to run the library methods */
178static int do_cg_getattr(const char *path, struct stat *sb)
aeb56147 179{
237e200e
SH
180 int (*cg_getattr)(const char *path, struct stat *sb);
181 char *error;
182 dlerror(); /* Clear any existing error */
183 cg_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "cg_getattr");
184 error = dlerror();
185 if (error != NULL) {
b8defc3d 186 lxcfs_error("%s\n", error);
237e200e
SH
187 return -1;
188 }
aeb56147 189
237e200e 190 return cg_getattr(path, sb);
aeb56147
SH
191}
192
237e200e 193static int do_proc_getattr(const char *path, struct stat *sb)
23ce2127 194{
237e200e
SH
195 int (*proc_getattr)(const char *path, struct stat *sb);
196 char *error;
197 dlerror(); /* Clear any existing error */
198 proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
199 error = dlerror();
200 if (error != NULL) {
b8defc3d 201 lxcfs_error("%s\n", error);
237e200e
SH
202 return -1;
203 }
23ce2127 204
237e200e 205 return proc_getattr(path, sb);
23ce2127
SH
206}
207
71f17cd2
YB
208static int do_sys_getattr(const char *path, struct stat *sb)
209{
210 int (*sys_getattr)(const char *path, struct stat *sb);
211 char *error;
212 dlerror(); /* Clear any existing error */
213 sys_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "sys_getattr");
214 error = dlerror();
215 if (error != NULL) {
216 lxcfs_error("%s\n", error);
217 return -1;
218 }
219
220 return sys_getattr(path, sb);
221}
222
237e200e 223static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
23ce2127
SH
224 struct fuse_file_info *fi)
225{
237e200e
SH
226 int (*cg_read)(const char *path, char *buf, size_t size, off_t offset,
227 struct fuse_file_info *fi);
228 char *error;
23ce2127 229
237e200e
SH
230 dlerror(); /* Clear any existing error */
231 cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_read");
232 error = dlerror();
233 if (error != NULL) {
b8defc3d 234 lxcfs_error("%s\n", error);
237e200e 235 return -1;
23ce2127
SH
236 }
237
237e200e 238 return cg_read(path, buf, size, offset, fi);
23ce2127
SH
239}
240
237e200e 241static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
23ce2127
SH
242 struct fuse_file_info *fi)
243{
237e200e
SH
244 int (*proc_read)(const char *path, char *buf, size_t size, off_t offset,
245 struct fuse_file_info *fi);
246 char *error;
aeb56147 247
237e200e
SH
248 dlerror(); /* Clear any existing error */
249 proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_read");
250 error = dlerror();
251 if (error != NULL) {
b8defc3d 252 lxcfs_error("%s\n", error);
237e200e 253 return -1;
97f1f27b
YY
254 }
255
237e200e
SH
256 return proc_read(path, buf, size, offset, fi);
257}
97f1f27b 258
71f17cd2
YB
259static int do_sys_read(const char *path, char *buf, size_t size, off_t offset,
260 struct fuse_file_info *fi)
261{
262 int (*sys_read)(const char *path, char *buf, size_t size, off_t offset,
263 struct fuse_file_info *fi);
264 char *error;
265
266 dlerror(); /* Clear any existing error */
267 sys_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_read");
268 error = dlerror();
269 if (error != NULL) {
270 lxcfs_error("%s\n", error);
271 return -1;
272 }
273
274 return sys_read(path, buf, size, offset, fi);
275}
276
237e200e
SH
277static int do_cg_write(const char *path, const char *buf, size_t size, off_t offset,
278 struct fuse_file_info *fi)
279{
280 int (*cg_write)(const char *path, const char *buf, size_t size, off_t offset,
281 struct fuse_file_info *fi);
282 char *error;
283 dlerror(); /* Clear any existing error */
284 cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_write");
285 error = dlerror();
286 if (error != NULL) {
b8defc3d 287 lxcfs_error("%s\n", error);
237e200e 288 return -1;
97f1f27b
YY
289 }
290
237e200e 291 return cg_write(path, buf, size, offset, fi);
23ce2127
SH
292}
293
237e200e 294static int do_cg_mkdir(const char *path, mode_t mode)
41bb9357 295{
237e200e
SH
296 int (*cg_mkdir)(const char *path, mode_t mode);
297 char *error;
298 dlerror(); /* Clear any existing error */
299 cg_mkdir = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_mkdir");
300 error = dlerror();
301 if (error != NULL) {
b8defc3d 302 lxcfs_error("%s\n", error);
237e200e
SH
303 return -1;
304 }
41bb9357 305
237e200e 306 return cg_mkdir(path, mode);
41bb9357
SH
307}
308
237e200e 309static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
0b6af11b 310{
237e200e
SH
311 int (*cg_chown)(const char *path, uid_t uid, gid_t gid);
312 char *error;
313 dlerror(); /* Clear any existing error */
314 cg_chown = (int (*)(const char *, uid_t, gid_t)) dlsym(dlopen_handle, "cg_chown");
315 error = dlerror();
316 if (error != NULL) {
b8defc3d 317 lxcfs_error("%s\n", error);
237e200e
SH
318 return -1;
319 }
0b6af11b 320
237e200e 321 return cg_chown(path, uid, gid);
41bb9357
SH
322}
323
237e200e 324static int do_cg_rmdir(const char *path)
23ce2127 325{
237e200e
SH
326 int (*cg_rmdir)(const char *path);
327 char *error;
328 dlerror(); /* Clear any existing error */
329 cg_rmdir = (int (*)(const char *path)) dlsym(dlopen_handle, "cg_rmdir");
330 error = dlerror();
331 if (error != NULL) {
b8defc3d 332 lxcfs_error("%s\n", error);
237e200e 333 return -1;
97f1f27b
YY
334 }
335
237e200e
SH
336 return cg_rmdir(path);
337}
f6c0b279 338
237e200e
SH
339static int do_cg_chmod(const char *path, mode_t mode)
340{
341 int (*cg_chmod)(const char *path, mode_t mode);
342 char *error;
343 dlerror(); /* Clear any existing error */
344 cg_chmod = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_chmod");
345 error = dlerror();
346 if (error != NULL) {
b8defc3d 347 lxcfs_error("%s\n", error);
237e200e 348 return -1;
e1068397 349 }
cdcdb29b 350
237e200e 351 return cg_chmod(path, mode);
23ce2127
SH
352}
353
237e200e 354static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
49878439
YY
355 struct fuse_file_info *fi)
356{
237e200e
SH
357 int (*cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
358 struct fuse_file_info *fi);
359 char *error;
49878439 360
237e200e
SH
361 dlerror(); /* Clear any existing error */
362 cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_readdir");
363 error = dlerror();
364 if (error != NULL) {
b8defc3d 365 lxcfs_error("%s\n", error);
237e200e 366 return -1;
97f1f27b 367 }
49878439 368
237e200e
SH
369 return cg_readdir(path, buf, filler, offset, fi);
370}
49878439 371
237e200e
SH
372static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
373 struct fuse_file_info *fi)
374{
375 int (*proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
376 struct fuse_file_info *fi);
377 char *error;
49878439 378
237e200e
SH
379 dlerror(); /* Clear any existing error */
380 proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_readdir");
381 error = dlerror();
382 if (error != NULL) {
b8defc3d 383 lxcfs_error("%s\n", error);
237e200e 384 return -1;
49878439
YY
385 }
386
237e200e 387 return proc_readdir(path, buf, filler, offset, fi);
49878439
YY
388}
389
71f17cd2
YB
390static int do_sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
391 struct fuse_file_info *fi)
392{
393 int (*sys_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
394 struct fuse_file_info *fi);
395 char *error;
396
397 dlerror(); /* Clear any existing error */
398 sys_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_readdir");
399 error = dlerror();
400 if (error != NULL) {
401 lxcfs_error("%s\n", error);
402 return -1;
403 }
404
405 return sys_readdir(path, buf, filler, offset, fi);
406}
407
408
237e200e 409static int do_cg_open(const char *path, struct fuse_file_info *fi)
23ce2127 410{
237e200e
SH
411 int (*cg_open)(const char *path, struct fuse_file_info *fi);
412 char *error;
413 dlerror(); /* Clear any existing error */
414 cg_open = (int (*)(const char *, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_open");
415 error = dlerror();
416 if (error != NULL) {
b8defc3d 417 lxcfs_error("%s\n", error);
237e200e
SH
418 return -1;
419 }
23ce2127 420
237e200e 421 return cg_open(path, fi);
23ce2127
SH
422}
423
bddbb106
SH
424static int do_cg_access(const char *path, int mode)
425{
426 int (*cg_access)(const char *path, int mode);
427 char *error;
428 dlerror(); /* Clear any existing error */
429 cg_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "cg_access");
430 error = dlerror();
431 if (error != NULL) {
b8defc3d 432 lxcfs_error("%s\n", error);
bddbb106
SH
433 return -1;
434 }
435
436 return cg_access(path, mode);
437}
438
237e200e 439static int do_proc_open(const char *path, struct fuse_file_info *fi)
758ad80c 440{
237e200e
SH
441 int (*proc_open)(const char *path, struct fuse_file_info *fi);
442 char *error;
443 dlerror(); /* Clear any existing error */
444 proc_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "proc_open");
445 error = dlerror();
446 if (error != NULL) {
b8defc3d 447 lxcfs_error("%s\n", error);
237e200e 448 return -1;
35629743
SH
449 }
450
237e200e 451 return proc_open(path, fi);
35629743
SH
452}
453
bddbb106
SH
454static int do_proc_access(const char *path, int mode)
455{
456 int (*proc_access)(const char *path, int mode);
457 char *error;
458 dlerror(); /* Clear any existing error */
459 proc_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "proc_access");
460 error = dlerror();
461 if (error != NULL) {
b8defc3d 462 lxcfs_error("%s\n", error);
bddbb106
SH
463 return -1;
464 }
465
466 return proc_access(path, mode);
467}
468
71f17cd2
YB
469static int do_sys_open(const char *path, struct fuse_file_info *fi)
470{
471 int (*sys_open)(const char *path, struct fuse_file_info *fi);
472 char *error;
473 dlerror(); /* Clear any existing error */
474 sys_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "sys_open");
475 error = dlerror();
476 if (error != NULL) {
477 lxcfs_error("%s\n", error);
478 return -1;
479 }
480
481 return sys_open(path, fi);
482}
483
484static int do_sys_access(const char *path, int mode)
485{
486 int (*sys_access)(const char *path, int mode);
487 char *error;
488 dlerror(); /* Clear any existing error */
489 sys_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "sys_access");
490 error = dlerror();
491 if (error != NULL) {
492 lxcfs_error("%s\n", error);
493 return -1;
494 }
495
496 return sys_access(path, mode);
497}
498
499
237e200e 500static int do_cg_release(const char *path, struct fuse_file_info *fi)
35629743 501{
237e200e
SH
502 int (*cg_release)(const char *path, struct fuse_file_info *fi);
503 char *error;
504 dlerror(); /* Clear any existing error */
505 cg_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_release");
506 error = dlerror();
507 if (error != NULL) {
b8defc3d 508 lxcfs_error("%s\n", error);
237e200e
SH
509 return -1;
510 }
511
512 return cg_release(path, fi);
758ad80c
SH
513}
514
237e200e 515static int do_proc_release(const char *path, struct fuse_file_info *fi)
35629743 516{
237e200e
SH
517 int (*proc_release)(const char *path, struct fuse_file_info *fi);
518 char *error;
519 dlerror(); /* Clear any existing error */
520 proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
521 error = dlerror();
522 if (error != NULL) {
b8defc3d 523 lxcfs_error("%s\n", error);
237e200e
SH
524 return -1;
525 }
97f1f27b 526
237e200e 527 return proc_release(path, fi);
96fc5ee6
SH
528}
529
71f17cd2
YB
530static int do_sys_release(const char *path, struct fuse_file_info *fi)
531{
532 int (*sys_release)(const char *path, struct fuse_file_info *fi);
533 char *error;
534 dlerror(); /* Clear any existing error */
535 sys_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_release");
536 error = dlerror();
537 if (error != NULL) {
538 lxcfs_error("%s\n", error);
539 return -1;
540 }
541
542 return sys_release(path, fi);
543}
544
237e200e 545static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
96fc5ee6 546{
237e200e
SH
547 int (*cg_opendir)(const char *path, struct fuse_file_info *fi);
548 char *error;
549 dlerror(); /* Clear any existing error */
550 cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "cg_opendir");
551 error = dlerror();
552 if (error != NULL) {
b8defc3d 553 lxcfs_error("%s\n", error);
237e200e
SH
554 return -1;
555 }
96fc5ee6 556
237e200e 557 return cg_opendir(path, fi);
35629743
SH
558}
559
237e200e 560static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
35629743 561{
237e200e
SH
562 int (*cg_releasedir)(const char *path, struct fuse_file_info *fi);
563 char *error;
564 dlerror(); /* Clear any existing error */
565 cg_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_releasedir");
566 error = dlerror();
567 if (error != NULL) {
b8defc3d 568 lxcfs_error("%s\n", error);
237e200e 569 return -1;
96fc5ee6 570 }
237e200e
SH
571
572 return cg_releasedir(path, fi);
35629743
SH
573}
574
71f17cd2
YB
575static int do_sys_releasedir(const char *path, struct fuse_file_info *fi)
576{
577 int (*sys_releasedir)(const char *path, struct fuse_file_info *fi);
578 char *error;
579 dlerror(); /* Clear any existing error */
580 sys_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_releasedir");
581 error = dlerror();
582 if (error != NULL) {
583 lxcfs_error("%s\n", error);
584 return -1;
585 }
586
587 return sys_releasedir(path, fi);
588}
589
2ad6d2bd
SH
590/*
591 * FUSE ops for /
592 * these just delegate to the /proc and /cgroup ops as
593 * needed
594 */
758ad80c
SH
595
596static int lxcfs_getattr(const char *path, struct stat *sb)
597{
237e200e 598 int ret;
17e6e1e2
CB
599 struct timespec now;
600
758ad80c 601 if (strcmp(path, "/") == 0) {
17e6e1e2
CB
602 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
603 return -EINVAL;
604 sb->st_uid = sb->st_gid = 0;
605 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
606 sb->st_size = 0;
758ad80c
SH
607 sb->st_mode = S_IFDIR | 00755;
608 sb->st_nlink = 2;
609 return 0;
610 }
17e6e1e2 611
758ad80c 612 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
613 up_users();
614 ret = do_cg_getattr(path, sb);
615 down_users();
616 return ret;
758ad80c 617 }
35629743 618 if (strncmp(path, "/proc", 5) == 0) {
237e200e
SH
619 up_users();
620 ret = do_proc_getattr(path, sb);
621 down_users();
622 return ret;
758ad80c 623 }
71f17cd2
YB
624 if (strncmp(path, "/sys", 4) == 0) {
625 up_users();
626 ret = do_sys_getattr(path, sb);
627 down_users();
628 return ret;
629 }
f9b24a3e 630 return -ENOENT;
758ad80c
SH
631}
632
633static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
634{
237e200e 635 int ret;
758ad80c
SH
636 if (strcmp(path, "/") == 0)
637 return 0;
638
639 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
640 up_users();
641 ret = do_cg_opendir(path, fi);
642 down_users();
643 return ret;
758ad80c 644 }
35629743
SH
645 if (strcmp(path, "/proc") == 0)
646 return 0;
71f17cd2
YB
647 if (strncmp(path, "/sys", 4) == 0)
648 return 0;
649
35629743 650 return -ENOENT;
758ad80c
SH
651}
652
653static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
654 struct fuse_file_info *fi)
655{
237e200e 656 int ret;
758ad80c 657 if (strcmp(path, "/") == 0) {
d639f863
CB
658 if (filler(buf, ".", NULL, 0) != 0 ||
659 filler(buf, "..", NULL, 0) != 0 ||
660 filler(buf, "proc", NULL, 0) != 0 ||
71f17cd2 661 filler(buf, "sys", NULL, 0) != 0 ||
d639f863 662 filler(buf, "cgroup", NULL, 0) != 0)
f9b24a3e 663 return -ENOMEM;
758ad80c
SH
664 return 0;
665 }
237e200e
SH
666 if (strncmp(path, "/cgroup", 7) == 0) {
667 up_users();
668 ret = do_cg_readdir(path, buf, filler, offset, fi);
669 down_users();
670 return ret;
671 }
672 if (strcmp(path, "/proc") == 0) {
673 up_users();
674 ret = do_proc_readdir(path, buf, filler, offset, fi);
675 down_users();
676 return ret;
677 }
71f17cd2
YB
678
679 if (strncmp(path, "/sys", 4) == 0) {
680 up_users();
681 ret = do_sys_readdir(path, buf, filler, offset, fi);
682 down_users();
683 return ret;
684 }
685
f9b24a3e 686 return -ENOENT;
758ad80c
SH
687}
688
bddbb106
SH
689static int lxcfs_access(const char *path, int mode)
690{
691 int ret;
17e6e1e2 692
f9b24a3e 693 if (strcmp(path, "/") == 0 && (mode & W_OK) == 0)
17e6e1e2
CB
694 return 0;
695
bddbb106
SH
696 if (strncmp(path, "/cgroup", 7) == 0) {
697 up_users();
698 ret = do_cg_access(path, mode);
699 down_users();
700 return ret;
701 }
702 if (strncmp(path, "/proc", 5) == 0) {
703 up_users();
704 ret = do_proc_access(path, mode);
705 down_users();
706 return ret;
707 }
71f17cd2
YB
708 if (strncmp(path, "/sys", 4) == 0) {
709 up_users();
710 ret = do_sys_access(path, mode);
711 down_users();
712 return ret;
713 }
714
bddbb106 715
f9b24a3e 716 return -EACCES;
bddbb106
SH
717}
718
758ad80c
SH
719static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
720{
237e200e 721 int ret;
758ad80c
SH
722 if (strcmp(path, "/") == 0)
723 return 0;
724 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
725 up_users();
726 ret = do_cg_releasedir(path, fi);
727 down_users();
728 return ret;
758ad80c 729 }
35629743
SH
730 if (strcmp(path, "/proc") == 0)
731 return 0;
71f17cd2
YB
732 if (strncmp(path, "/sys", 4) == 0){
733 up_users();
734 ret = do_sys_releasedir(path, fi);
735 down_users();
736 return ret;
737 }
738
758ad80c
SH
739 return -EINVAL;
740}
741
99978832
SH
742static int lxcfs_open(const char *path, struct fuse_file_info *fi)
743{
237e200e
SH
744 int ret;
745 if (strncmp(path, "/cgroup", 7) == 0) {
746 up_users();
747 ret = do_cg_open(path, fi);
748 down_users();
749 return ret;
750 }
751 if (strncmp(path, "/proc", 5) == 0) {
752 up_users();
753 ret = do_proc_open(path, fi);
754 down_users();
755 return ret;
756 }
71f17cd2
YB
757 if (strncmp(path, "/sys", 4) == 0) {
758 up_users();
759 ret = do_sys_open(path, fi);
760 down_users();
761 return ret;
762 }
763
99978832 764
f9b24a3e 765 return -EACCES;
99978832
SH
766}
767
768static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
769 struct fuse_file_info *fi)
770{
237e200e
SH
771 int ret;
772 if (strncmp(path, "/cgroup", 7) == 0) {
773 up_users();
774 ret = do_cg_read(path, buf, size, offset, fi);
775 down_users();
776 return ret;
777 }
778 if (strncmp(path, "/proc", 5) == 0) {
779 up_users();
780 ret = do_proc_read(path, buf, size, offset, fi);
781 down_users();
782 return ret;
783 }
71f17cd2
YB
784 if (strncmp(path, "/sys", 4) == 0) {
785 up_users();
786 ret = do_sys_read(path, buf, size, offset, fi);
787 down_users();
788 return ret;
789 }
790
99978832
SH
791
792 return -EINVAL;
793}
794
2ad6d2bd
SH
795int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
796 struct fuse_file_info *fi)
797{
237e200e 798 int ret;
2ad6d2bd 799 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
800 up_users();
801 ret = do_cg_write(path, buf, size, offset, fi);
802 down_users();
803 return ret;
2ad6d2bd
SH
804 }
805
806 return -EINVAL;
807}
808
99978832
SH
809static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
810{
811 return 0;
812}
813
814static int lxcfs_release(const char *path, struct fuse_file_info *fi)
758ad80c 815{
237e200e
SH
816 int ret;
817 if (strncmp(path, "/cgroup", 7) == 0) {
818 up_users();
819 ret = do_cg_release(path, fi);
820 down_users();
821 return ret;
822 }
823 if (strncmp(path, "/proc", 5) == 0) {
824 up_users();
825 ret = do_proc_release(path, fi);
826 down_users();
827 return ret;
828 }
71f17cd2
YB
829 if (strncmp(path, "/sys", 4) == 0) {
830 up_users();
831 ret = do_sys_release(path, fi);
832 down_users();
833 return ret;
834 }
835
8f6e8f5e
SH
836
837 return -EINVAL;
99978832
SH
838}
839
840static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
841{
842 return 0;
758ad80c
SH
843}
844
ab54b798
SH
845int lxcfs_mkdir(const char *path, mode_t mode)
846{
237e200e
SH
847 int ret;
848 if (strncmp(path, "/cgroup", 7) == 0) {
849 up_users();
850 ret = do_cg_mkdir(path, mode);
851 down_users();
852 return ret;
853 }
ab54b798 854
f9b24a3e 855 return -EPERM;
ab54b798
SH
856}
857
341b21ad
SH
858int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
859{
237e200e
SH
860 int ret;
861 if (strncmp(path, "/cgroup", 7) == 0) {
862 up_users();
863 ret = do_cg_chown(path, uid, gid);
864 down_users();
865 return ret;
866 }
341b21ad 867
f9b24a3e
CB
868 if (strncmp(path, "/proc", 5) == 0)
869 return -EPERM;
870
71f17cd2
YB
871 if (strncmp(path, "/sys", 4) == 0)
872 return -EPERM;
f9b24a3e 873 return -ENOENT;
341b21ad
SH
874}
875
2ad6d2bd
SH
876/*
877 * cat first does a truncate before doing ops->write. This doesn't
878 * really make sense for cgroups. So just return 0 always but do
879 * nothing.
880 */
881int lxcfs_truncate(const char *path, off_t newsize)
882{
883 if (strncmp(path, "/cgroup", 7) == 0)
884 return 0;
f9b24a3e 885 return -EPERM;
2ad6d2bd
SH
886}
887
50d8d5b5
SH
888int lxcfs_rmdir(const char *path)
889{
237e200e
SH
890 int ret;
891 if (strncmp(path, "/cgroup", 7) == 0) {
892 up_users();
893 ret = do_cg_rmdir(path);
894 down_users();
895 return ret;
896 }
f9b24a3e 897 return -EPERM;
50d8d5b5
SH
898}
899
fd2e4e03
SH
900int lxcfs_chmod(const char *path, mode_t mode)
901{
237e200e
SH
902 int ret;
903 if (strncmp(path, "/cgroup", 7) == 0) {
904 up_users();
905 ret = do_cg_chmod(path, mode);
906 down_users();
907 return ret;
908 }
f9b24a3e
CB
909
910 if (strncmp(path, "/proc", 5) == 0)
911 return -EPERM;
912
71f17cd2
YB
913 if (strncmp(path, "/sys", 4) == 0)
914 return -EPERM;
915
f9b24a3e 916 return -ENOENT;
fd2e4e03
SH
917}
918
758ad80c
SH
919const struct fuse_operations lxcfs_ops = {
920 .getattr = lxcfs_getattr,
921 .readlink = NULL,
922 .getdir = NULL,
923 .mknod = NULL,
ab54b798 924 .mkdir = lxcfs_mkdir,
758ad80c 925 .unlink = NULL,
50d8d5b5 926 .rmdir = lxcfs_rmdir,
758ad80c
SH
927 .symlink = NULL,
928 .rename = NULL,
929 .link = NULL,
fd2e4e03 930 .chmod = lxcfs_chmod,
341b21ad 931 .chown = lxcfs_chown,
2ad6d2bd 932 .truncate = lxcfs_truncate,
758ad80c 933 .utime = NULL,
99978832
SH
934
935 .open = lxcfs_open,
936 .read = lxcfs_read,
937 .release = lxcfs_release,
2ad6d2bd 938 .write = lxcfs_write,
99978832 939
758ad80c 940 .statfs = NULL,
99978832
SH
941 .flush = lxcfs_flush,
942 .fsync = lxcfs_fsync,
758ad80c
SH
943
944 .setxattr = NULL,
945 .getxattr = NULL,
946 .listxattr = NULL,
947 .removexattr = NULL,
948
949 .opendir = lxcfs_opendir,
950 .readdir = lxcfs_readdir,
951 .releasedir = lxcfs_releasedir,
952
953 .fsyncdir = NULL,
954 .init = NULL,
955 .destroy = NULL,
bddbb106 956 .access = lxcfs_access,
758ad80c
SH
957 .create = NULL,
958 .ftruncate = NULL,
959 .fgetattr = NULL,
960};
961
c3fb7d7f 962static void usage()
758ad80c
SH
963{
964 fprintf(stderr, "Usage:\n");
965 fprintf(stderr, "\n");
7e60aa1b 966 fprintf(stderr, "lxcfs [-f|-d] -u -l -n [-p pidfile] mountpoint\n");
1de81503 967 fprintf(stderr, " -f running foreground by default; -d enable debug output \n");
6db4f7a3 968 fprintf(stderr, " -l use loadavg \n");
7e60aa1b 969 fprintf(stderr, " -u no swap \n");
e190ee91 970 fprintf(stderr, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH);
c3fb7d7f 971 fprintf(stderr, "lxcfs -h\n");
758ad80c
SH
972 exit(1);
973}
974
99978832 975static bool is_help(char *w)
758ad80c
SH
976{
977 if (strcmp(w, "-h") == 0 ||
978 strcmp(w, "--help") == 0 ||
979 strcmp(w, "-help") == 0 ||
980 strcmp(w, "help") == 0)
981 return true;
982 return false;
983}
984
1de81503 985bool swallow_arg(int *argcp, char *argv[], char *which)
0b0f73db
SH
986{
987 int i;
988
989 for (i = 1; argv[i]; i++) {
990 if (strcmp(argv[i], which) != 0)
991 continue;
992 for (; argv[i]; i++) {
993 argv[i] = argv[i+1];
994 }
995 (*argcp)--;
1de81503 996 return true;
0b0f73db 997 }
1de81503 998 return false;
0b0f73db
SH
999}
1000
e190ee91 1001bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
0b0f73db
SH
1002{
1003 int i;
1004
1005 for (i = 1; argv[i]; i++) {
1006 if (!argv[i+1])
1007 continue;
1008 if (strcmp(argv[i], opt) != 0)
1009 continue;
e190ee91
SH
1010 do {
1011 *v = strdup(argv[i+1]);
1012 } while (!*v);
0b0f73db
SH
1013 for (; argv[i+1]; i++) {
1014 argv[i] = argv[i+2];
1015 }
1016 (*argcp) -= 2;
e190ee91 1017 return true;
0b0f73db 1018 }
e190ee91 1019 return false;
0b0f73db
SH
1020}
1021
e190ee91
SH
1022static int set_pidfile(char *pidfile)
1023{
1024 int fd;
1025 char buf[50];
1026 struct flock fl;
1027
1028 fl.l_type = F_WRLCK;
1029 fl.l_whence = SEEK_SET;
1030 fl.l_start = 0;
1031 fl.l_len = 0;
1032
1033 fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1034 if (fd == -1) {
b8defc3d 1035 fprintf(stderr, "Could not open pidfile %s: %m\n", pidfile);
e190ee91
SH
1036 return -1;
1037 }
1038
1039 if (fcntl(fd, F_SETLK, &fl) == -1) {
1040 if (errno == EAGAIN || errno == EACCES) {
1041 fprintf(stderr, "PID file '%s' is already locked.\n", pidfile);
1042 close(fd);
1043 return -1;
1044 }
1045 fprintf(stderr, "Warning; unable to lock PID file, proceeding.\n");
1046 }
1047
1048 if (ftruncate(fd, 0) == -1) {
1049 fprintf(stderr, "Error truncating PID file '%s': %m", pidfile);
1050 close(fd);
1051 return -1;
1052 }
1053
1054 snprintf(buf, 50, "%ld\n", (long) getpid());
1055 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
1056 fprintf(stderr, "Error writing to PID file '%s': %m", pidfile);
1057 close(fd);
1058 return -1;
1059 }
1060
1061 return fd;
1062}
1063
758ad80c
SH
1064int main(int argc, char *argv[])
1065{
47f5266f
CB
1066 int ret = EXIT_FAILURE;
1067 int pidfd = -1;
482a80d4 1068 char *pidfile = NULL, *saveptr = NULL, *token = NULL, *v = NULL;
29a73c2f 1069 size_t pidfile_len;
482a80d4 1070 bool debug = false, nonempty = false;
6db4f7a3 1071 bool load_use = false;
0b0f73db
SH
1072 /*
1073 * what we pass to fuse_main is:
1de81503 1074 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
0b0f73db 1075 */
2c51f8dd
SH
1076 int nargs = 5, cnt = 0;
1077 char *newargv[6];
758ad80c 1078
7e60aa1b 1079 struct lxcfs_opts *opts;
1080 opts = malloc(sizeof(struct lxcfs_opts));
1081 if (opts == NULL) {
1082 fprintf(stderr, "Error allocating memory for options.\n");
1083 goto out;
1084 }
1085 opts->swap_off = false;
1086
0b0f73db
SH
1087 /* accomodate older init scripts */
1088 swallow_arg(&argc, argv, "-s");
1089 swallow_arg(&argc, argv, "-f");
1de81503 1090 debug = swallow_arg(&argc, argv, "-d");
6db4f7a3 1091 if (swallow_arg(&argc, argv, "-l")) {
1092 load_use = true;
1093 }
7e60aa1b 1094 if (swallow_arg(&argc, argv, "-u")) {
1095 opts->swap_off = true;
1096 }
e190ee91 1097 if (swallow_option(&argc, argv, "-o", &v)) {
482a80d4
G
1098 /* Parse multiple values */
1099 for (; (token = strtok_r(v, ",", &saveptr)); v = NULL) {
1100 if (strcmp(token, "allow_other") == 0) {
1101 /* Noop. this is the default. Always enabled. */
1102 } else if (strcmp(token, "nonempty") == 0) {
1103 nonempty = true;
1104 } else {
1105 free(v);
1106 fprintf(stderr, "Warning: unexpected fuse option %s\n", v);
1107 exit(EXIT_FAILURE);
1108 }
e190ee91
SH
1109 }
1110 free(v);
1111 v = NULL;
1112 }
1113 if (swallow_option(&argc, argv, "-p", &v))
1114 pidfile = v;
0b0f73db 1115
2e9c0b32
SH
1116 if (argc == 2 && strcmp(argv[1], "--version") == 0) {
1117 fprintf(stderr, "%s\n", VERSION);
47f5266f 1118 exit(EXIT_SUCCESS);
2e9c0b32 1119 }
0b0f73db 1120 if (argc != 2 || is_help(argv[1]))
c3fb7d7f 1121 usage();
758ad80c 1122
59120f04 1123 do_reload();
8fad16cd 1124 if (signal(SIGUSR1, reload_handler) == SIG_ERR) {
8dcde249 1125 fprintf(stderr, "Error setting USR1 signal handler: %m\n");
47f5266f 1126 goto out;
8fad16cd 1127 }
e190ee91 1128
38a76a91 1129 newargv[cnt++] = argv[0];
482a80d4
G
1130 if (debug)
1131 newargv[cnt++] = "-d";
1132 else
1133 newargv[cnt++] = "-f";
38a76a91 1134 newargv[cnt++] = "-o";
482a80d4
G
1135 if (nonempty)
1136 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty";
1137 else
1138 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
38a76a91
SH
1139 newargv[cnt++] = argv[1];
1140 newargv[cnt++] = NULL;
758ad80c 1141
e190ee91
SH
1142 if (!pidfile) {
1143 pidfile_len = strlen(RUNTIME_PATH) + strlen("/lxcfs.pid") + 1;
1144 pidfile = alloca(pidfile_len);
1145 snprintf(pidfile, pidfile_len, "%s/lxcfs.pid", RUNTIME_PATH);
1146 }
1147 if ((pidfd = set_pidfile(pidfile)) < 0)
1148 goto out;
1149
a83618e2
JS
1150 if (load_use && start_loadavg() != 0)
1151 goto out;
6db4f7a3 1152
7e60aa1b 1153 if (!fuse_main(nargs, newargv, &lxcfs_ops, opts))
47f5266f 1154 ret = EXIT_SUCCESS;
a83618e2
JS
1155 if (load_use)
1156 stop_loadavg();
237e200e 1157
c0adec85 1158out:
47f5266f
CB
1159 if (dlopen_handle)
1160 dlclose(dlopen_handle);
1161 if (pidfile)
1162 unlink(pidfile);
1163 if (pidfd > 0)
1164 close(pidfd);
47f5266f 1165 exit(ret);
2183082c 1166}