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