]> git.proxmox.com Git - mirror_lxcfs.git/blame - lxcfs.c
Per-container CPU usage in /proc/stat
[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
237e200e 208static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
23ce2127
SH
209 struct fuse_file_info *fi)
210{
237e200e
SH
211 int (*cg_read)(const char *path, char *buf, size_t size, off_t offset,
212 struct fuse_file_info *fi);
213 char *error;
23ce2127 214
237e200e
SH
215 dlerror(); /* Clear any existing error */
216 cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_read");
217 error = dlerror();
218 if (error != NULL) {
b8defc3d 219 lxcfs_error("%s\n", error);
237e200e 220 return -1;
23ce2127
SH
221 }
222
237e200e 223 return cg_read(path, buf, size, offset, fi);
23ce2127
SH
224}
225
237e200e 226static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
23ce2127
SH
227 struct fuse_file_info *fi)
228{
237e200e
SH
229 int (*proc_read)(const char *path, char *buf, size_t size, off_t offset,
230 struct fuse_file_info *fi);
231 char *error;
aeb56147 232
237e200e
SH
233 dlerror(); /* Clear any existing error */
234 proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_read");
235 error = dlerror();
236 if (error != NULL) {
b8defc3d 237 lxcfs_error("%s\n", error);
237e200e 238 return -1;
97f1f27b
YY
239 }
240
237e200e
SH
241 return proc_read(path, buf, size, offset, fi);
242}
97f1f27b 243
237e200e
SH
244static int do_cg_write(const char *path, const char *buf, size_t size, off_t offset,
245 struct fuse_file_info *fi)
246{
247 int (*cg_write)(const char *path, const char *buf, size_t size, off_t offset,
248 struct fuse_file_info *fi);
249 char *error;
250 dlerror(); /* Clear any existing error */
251 cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_write");
252 error = dlerror();
253 if (error != NULL) {
b8defc3d 254 lxcfs_error("%s\n", error);
237e200e 255 return -1;
97f1f27b
YY
256 }
257
237e200e 258 return cg_write(path, buf, size, offset, fi);
23ce2127
SH
259}
260
237e200e 261static int do_cg_mkdir(const char *path, mode_t mode)
41bb9357 262{
237e200e
SH
263 int (*cg_mkdir)(const char *path, mode_t mode);
264 char *error;
265 dlerror(); /* Clear any existing error */
266 cg_mkdir = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_mkdir");
267 error = dlerror();
268 if (error != NULL) {
b8defc3d 269 lxcfs_error("%s\n", error);
237e200e
SH
270 return -1;
271 }
41bb9357 272
237e200e 273 return cg_mkdir(path, mode);
41bb9357
SH
274}
275
237e200e 276static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
0b6af11b 277{
237e200e
SH
278 int (*cg_chown)(const char *path, uid_t uid, gid_t gid);
279 char *error;
280 dlerror(); /* Clear any existing error */
281 cg_chown = (int (*)(const char *, uid_t, gid_t)) dlsym(dlopen_handle, "cg_chown");
282 error = dlerror();
283 if (error != NULL) {
b8defc3d 284 lxcfs_error("%s\n", error);
237e200e
SH
285 return -1;
286 }
0b6af11b 287
237e200e 288 return cg_chown(path, uid, gid);
41bb9357
SH
289}
290
237e200e 291static int do_cg_rmdir(const char *path)
23ce2127 292{
237e200e
SH
293 int (*cg_rmdir)(const char *path);
294 char *error;
295 dlerror(); /* Clear any existing error */
296 cg_rmdir = (int (*)(const char *path)) dlsym(dlopen_handle, "cg_rmdir");
297 error = dlerror();
298 if (error != NULL) {
b8defc3d 299 lxcfs_error("%s\n", error);
237e200e 300 return -1;
97f1f27b
YY
301 }
302
237e200e
SH
303 return cg_rmdir(path);
304}
f6c0b279 305
237e200e
SH
306static int do_cg_chmod(const char *path, mode_t mode)
307{
308 int (*cg_chmod)(const char *path, mode_t mode);
309 char *error;
310 dlerror(); /* Clear any existing error */
311 cg_chmod = (int (*)(const char *, mode_t)) dlsym(dlopen_handle, "cg_chmod");
312 error = dlerror();
313 if (error != NULL) {
b8defc3d 314 lxcfs_error("%s\n", error);
237e200e 315 return -1;
e1068397 316 }
cdcdb29b 317
237e200e 318 return cg_chmod(path, mode);
23ce2127
SH
319}
320
237e200e 321static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
49878439
YY
322 struct fuse_file_info *fi)
323{
237e200e
SH
324 int (*cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
325 struct fuse_file_info *fi);
326 char *error;
49878439 327
237e200e
SH
328 dlerror(); /* Clear any existing error */
329 cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_readdir");
330 error = dlerror();
331 if (error != NULL) {
b8defc3d 332 lxcfs_error("%s\n", error);
237e200e 333 return -1;
97f1f27b 334 }
49878439 335
237e200e
SH
336 return cg_readdir(path, buf, filler, offset, fi);
337}
49878439 338
237e200e
SH
339static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
340 struct fuse_file_info *fi)
341{
342 int (*proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
343 struct fuse_file_info *fi);
344 char *error;
49878439 345
237e200e
SH
346 dlerror(); /* Clear any existing error */
347 proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_readdir");
348 error = dlerror();
349 if (error != NULL) {
b8defc3d 350 lxcfs_error("%s\n", error);
237e200e 351 return -1;
49878439
YY
352 }
353
237e200e 354 return proc_readdir(path, buf, filler, offset, fi);
49878439
YY
355}
356
237e200e 357static int do_cg_open(const char *path, struct fuse_file_info *fi)
23ce2127 358{
237e200e
SH
359 int (*cg_open)(const char *path, struct fuse_file_info *fi);
360 char *error;
361 dlerror(); /* Clear any existing error */
362 cg_open = (int (*)(const char *, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_open");
363 error = dlerror();
364 if (error != NULL) {
b8defc3d 365 lxcfs_error("%s\n", error);
237e200e
SH
366 return -1;
367 }
23ce2127 368
237e200e 369 return cg_open(path, fi);
23ce2127
SH
370}
371
bddbb106
SH
372static int do_cg_access(const char *path, int mode)
373{
374 int (*cg_access)(const char *path, int mode);
375 char *error;
376 dlerror(); /* Clear any existing error */
377 cg_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "cg_access");
378 error = dlerror();
379 if (error != NULL) {
b8defc3d 380 lxcfs_error("%s\n", error);
bddbb106
SH
381 return -1;
382 }
383
384 return cg_access(path, mode);
385}
386
237e200e 387static int do_proc_open(const char *path, struct fuse_file_info *fi)
758ad80c 388{
237e200e
SH
389 int (*proc_open)(const char *path, struct fuse_file_info *fi);
390 char *error;
391 dlerror(); /* Clear any existing error */
392 proc_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "proc_open");
393 error = dlerror();
394 if (error != NULL) {
b8defc3d 395 lxcfs_error("%s\n", error);
237e200e 396 return -1;
35629743
SH
397 }
398
237e200e 399 return proc_open(path, fi);
35629743
SH
400}
401
bddbb106
SH
402static int do_proc_access(const char *path, int mode)
403{
404 int (*proc_access)(const char *path, int mode);
405 char *error;
406 dlerror(); /* Clear any existing error */
407 proc_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "proc_access");
408 error = dlerror();
409 if (error != NULL) {
b8defc3d 410 lxcfs_error("%s\n", error);
bddbb106
SH
411 return -1;
412 }
413
414 return proc_access(path, mode);
415}
416
237e200e 417static int do_cg_release(const char *path, struct fuse_file_info *fi)
35629743 418{
237e200e
SH
419 int (*cg_release)(const char *path, struct fuse_file_info *fi);
420 char *error;
421 dlerror(); /* Clear any existing error */
422 cg_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_release");
423 error = dlerror();
424 if (error != NULL) {
b8defc3d 425 lxcfs_error("%s\n", error);
237e200e
SH
426 return -1;
427 }
428
429 return cg_release(path, fi);
758ad80c
SH
430}
431
237e200e 432static int do_proc_release(const char *path, struct fuse_file_info *fi)
35629743 433{
237e200e
SH
434 int (*proc_release)(const char *path, struct fuse_file_info *fi);
435 char *error;
436 dlerror(); /* Clear any existing error */
437 proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
438 error = dlerror();
439 if (error != NULL) {
b8defc3d 440 lxcfs_error("%s\n", error);
237e200e
SH
441 return -1;
442 }
97f1f27b 443
237e200e 444 return proc_release(path, fi);
96fc5ee6
SH
445}
446
237e200e 447static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
96fc5ee6 448{
237e200e
SH
449 int (*cg_opendir)(const char *path, struct fuse_file_info *fi);
450 char *error;
451 dlerror(); /* Clear any existing error */
452 cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "cg_opendir");
453 error = dlerror();
454 if (error != NULL) {
b8defc3d 455 lxcfs_error("%s\n", error);
237e200e
SH
456 return -1;
457 }
96fc5ee6 458
237e200e 459 return cg_opendir(path, fi);
35629743
SH
460}
461
237e200e 462static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
35629743 463{
237e200e
SH
464 int (*cg_releasedir)(const char *path, struct fuse_file_info *fi);
465 char *error;
466 dlerror(); /* Clear any existing error */
467 cg_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "cg_releasedir");
468 error = dlerror();
469 if (error != NULL) {
b8defc3d 470 lxcfs_error("%s\n", error);
237e200e 471 return -1;
96fc5ee6 472 }
237e200e
SH
473
474 return cg_releasedir(path, fi);
35629743
SH
475}
476
2ad6d2bd
SH
477/*
478 * FUSE ops for /
479 * these just delegate to the /proc and /cgroup ops as
480 * needed
481 */
758ad80c
SH
482
483static int lxcfs_getattr(const char *path, struct stat *sb)
484{
237e200e 485 int ret;
17e6e1e2
CB
486 struct timespec now;
487
758ad80c 488 if (strcmp(path, "/") == 0) {
17e6e1e2
CB
489 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
490 return -EINVAL;
491 sb->st_uid = sb->st_gid = 0;
492 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
493 sb->st_size = 0;
758ad80c
SH
494 sb->st_mode = S_IFDIR | 00755;
495 sb->st_nlink = 2;
496 return 0;
497 }
17e6e1e2 498
758ad80c 499 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
500 up_users();
501 ret = do_cg_getattr(path, sb);
502 down_users();
503 return ret;
758ad80c 504 }
35629743 505 if (strncmp(path, "/proc", 5) == 0) {
237e200e
SH
506 up_users();
507 ret = do_proc_getattr(path, sb);
508 down_users();
509 return ret;
758ad80c 510 }
f9b24a3e 511 return -ENOENT;
758ad80c
SH
512}
513
514static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
515{
237e200e 516 int ret;
758ad80c
SH
517 if (strcmp(path, "/") == 0)
518 return 0;
519
520 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
521 up_users();
522 ret = do_cg_opendir(path, fi);
523 down_users();
524 return ret;
758ad80c 525 }
35629743
SH
526 if (strcmp(path, "/proc") == 0)
527 return 0;
528 return -ENOENT;
758ad80c
SH
529}
530
531static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
532 struct fuse_file_info *fi)
533{
237e200e 534 int ret;
758ad80c 535 if (strcmp(path, "/") == 0) {
d639f863
CB
536 if (filler(buf, ".", NULL, 0) != 0 ||
537 filler(buf, "..", NULL, 0) != 0 ||
538 filler(buf, "proc", NULL, 0) != 0 ||
539 filler(buf, "cgroup", NULL, 0) != 0)
f9b24a3e 540 return -ENOMEM;
758ad80c
SH
541 return 0;
542 }
237e200e
SH
543 if (strncmp(path, "/cgroup", 7) == 0) {
544 up_users();
545 ret = do_cg_readdir(path, buf, filler, offset, fi);
546 down_users();
547 return ret;
548 }
549 if (strcmp(path, "/proc") == 0) {
550 up_users();
551 ret = do_proc_readdir(path, buf, filler, offset, fi);
552 down_users();
553 return ret;
554 }
f9b24a3e 555 return -ENOENT;
758ad80c
SH
556}
557
bddbb106
SH
558static int lxcfs_access(const char *path, int mode)
559{
560 int ret;
17e6e1e2 561
f9b24a3e 562 if (strcmp(path, "/") == 0 && (mode & W_OK) == 0)
17e6e1e2
CB
563 return 0;
564
bddbb106
SH
565 if (strncmp(path, "/cgroup", 7) == 0) {
566 up_users();
567 ret = do_cg_access(path, mode);
568 down_users();
569 return ret;
570 }
571 if (strncmp(path, "/proc", 5) == 0) {
572 up_users();
573 ret = do_proc_access(path, mode);
574 down_users();
575 return ret;
576 }
577
f9b24a3e 578 return -EACCES;
bddbb106
SH
579}
580
758ad80c
SH
581static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
582{
237e200e 583 int ret;
758ad80c
SH
584 if (strcmp(path, "/") == 0)
585 return 0;
586 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
587 up_users();
588 ret = do_cg_releasedir(path, fi);
589 down_users();
590 return ret;
758ad80c 591 }
35629743
SH
592 if (strcmp(path, "/proc") == 0)
593 return 0;
758ad80c
SH
594 return -EINVAL;
595}
596
99978832
SH
597static int lxcfs_open(const char *path, struct fuse_file_info *fi)
598{
237e200e
SH
599 int ret;
600 if (strncmp(path, "/cgroup", 7) == 0) {
601 up_users();
602 ret = do_cg_open(path, fi);
603 down_users();
604 return ret;
605 }
606 if (strncmp(path, "/proc", 5) == 0) {
607 up_users();
608 ret = do_proc_open(path, fi);
609 down_users();
610 return ret;
611 }
99978832 612
f9b24a3e 613 return -EACCES;
99978832
SH
614}
615
616static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
617 struct fuse_file_info *fi)
618{
237e200e
SH
619 int ret;
620 if (strncmp(path, "/cgroup", 7) == 0) {
621 up_users();
622 ret = do_cg_read(path, buf, size, offset, fi);
623 down_users();
624 return ret;
625 }
626 if (strncmp(path, "/proc", 5) == 0) {
627 up_users();
628 ret = do_proc_read(path, buf, size, offset, fi);
629 down_users();
630 return ret;
631 }
99978832
SH
632
633 return -EINVAL;
634}
635
2ad6d2bd
SH
636int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
637 struct fuse_file_info *fi)
638{
237e200e 639 int ret;
2ad6d2bd 640 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
641 up_users();
642 ret = do_cg_write(path, buf, size, offset, fi);
643 down_users();
644 return ret;
2ad6d2bd
SH
645 }
646
647 return -EINVAL;
648}
649
99978832
SH
650static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
651{
652 return 0;
653}
654
655static int lxcfs_release(const char *path, struct fuse_file_info *fi)
758ad80c 656{
237e200e
SH
657 int ret;
658 if (strncmp(path, "/cgroup", 7) == 0) {
659 up_users();
660 ret = do_cg_release(path, fi);
661 down_users();
662 return ret;
663 }
664 if (strncmp(path, "/proc", 5) == 0) {
665 up_users();
666 ret = do_proc_release(path, fi);
667 down_users();
668 return ret;
669 }
8f6e8f5e
SH
670
671 return -EINVAL;
99978832
SH
672}
673
674static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
675{
676 return 0;
758ad80c
SH
677}
678
ab54b798
SH
679int lxcfs_mkdir(const char *path, mode_t mode)
680{
237e200e
SH
681 int ret;
682 if (strncmp(path, "/cgroup", 7) == 0) {
683 up_users();
684 ret = do_cg_mkdir(path, mode);
685 down_users();
686 return ret;
687 }
ab54b798 688
f9b24a3e 689 return -EPERM;
ab54b798
SH
690}
691
341b21ad
SH
692int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
693{
237e200e
SH
694 int ret;
695 if (strncmp(path, "/cgroup", 7) == 0) {
696 up_users();
697 ret = do_cg_chown(path, uid, gid);
698 down_users();
699 return ret;
700 }
341b21ad 701
f9b24a3e
CB
702 if (strncmp(path, "/proc", 5) == 0)
703 return -EPERM;
704
705 return -ENOENT;
341b21ad
SH
706}
707
2ad6d2bd
SH
708/*
709 * cat first does a truncate before doing ops->write. This doesn't
710 * really make sense for cgroups. So just return 0 always but do
711 * nothing.
712 */
713int lxcfs_truncate(const char *path, off_t newsize)
714{
715 if (strncmp(path, "/cgroup", 7) == 0)
716 return 0;
f9b24a3e 717 return -EPERM;
2ad6d2bd
SH
718}
719
50d8d5b5
SH
720int lxcfs_rmdir(const char *path)
721{
237e200e
SH
722 int ret;
723 if (strncmp(path, "/cgroup", 7) == 0) {
724 up_users();
725 ret = do_cg_rmdir(path);
726 down_users();
727 return ret;
728 }
f9b24a3e 729 return -EPERM;
50d8d5b5
SH
730}
731
fd2e4e03
SH
732int lxcfs_chmod(const char *path, mode_t mode)
733{
237e200e
SH
734 int ret;
735 if (strncmp(path, "/cgroup", 7) == 0) {
736 up_users();
737 ret = do_cg_chmod(path, mode);
738 down_users();
739 return ret;
740 }
f9b24a3e
CB
741
742 if (strncmp(path, "/proc", 5) == 0)
743 return -EPERM;
744
745 return -ENOENT;
fd2e4e03
SH
746}
747
758ad80c
SH
748const struct fuse_operations lxcfs_ops = {
749 .getattr = lxcfs_getattr,
750 .readlink = NULL,
751 .getdir = NULL,
752 .mknod = NULL,
ab54b798 753 .mkdir = lxcfs_mkdir,
758ad80c 754 .unlink = NULL,
50d8d5b5 755 .rmdir = lxcfs_rmdir,
758ad80c
SH
756 .symlink = NULL,
757 .rename = NULL,
758 .link = NULL,
fd2e4e03 759 .chmod = lxcfs_chmod,
341b21ad 760 .chown = lxcfs_chown,
2ad6d2bd 761 .truncate = lxcfs_truncate,
758ad80c 762 .utime = NULL,
99978832
SH
763
764 .open = lxcfs_open,
765 .read = lxcfs_read,
766 .release = lxcfs_release,
2ad6d2bd 767 .write = lxcfs_write,
99978832 768
758ad80c 769 .statfs = NULL,
99978832
SH
770 .flush = lxcfs_flush,
771 .fsync = lxcfs_fsync,
758ad80c
SH
772
773 .setxattr = NULL,
774 .getxattr = NULL,
775 .listxattr = NULL,
776 .removexattr = NULL,
777
778 .opendir = lxcfs_opendir,
779 .readdir = lxcfs_readdir,
780 .releasedir = lxcfs_releasedir,
781
782 .fsyncdir = NULL,
783 .init = NULL,
784 .destroy = NULL,
bddbb106 785 .access = lxcfs_access,
758ad80c
SH
786 .create = NULL,
787 .ftruncate = NULL,
788 .fgetattr = NULL,
789};
790
c3fb7d7f 791static void usage()
758ad80c
SH
792{
793 fprintf(stderr, "Usage:\n");
794 fprintf(stderr, "\n");
6db4f7a3 795 fprintf(stderr, "lxcfs [-f|-d] -l [-p pidfile] mountpoint\n");
1de81503 796 fprintf(stderr, " -f running foreground by default; -d enable debug output \n");
6db4f7a3 797 fprintf(stderr, " -l use loadavg \n");
e190ee91 798 fprintf(stderr, " Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH);
c3fb7d7f 799 fprintf(stderr, "lxcfs -h\n");
758ad80c
SH
800 exit(1);
801}
802
99978832 803static bool is_help(char *w)
758ad80c
SH
804{
805 if (strcmp(w, "-h") == 0 ||
806 strcmp(w, "--help") == 0 ||
807 strcmp(w, "-help") == 0 ||
808 strcmp(w, "help") == 0)
809 return true;
810 return false;
811}
812
1de81503 813bool swallow_arg(int *argcp, char *argv[], char *which)
0b0f73db
SH
814{
815 int i;
816
817 for (i = 1; argv[i]; i++) {
818 if (strcmp(argv[i], which) != 0)
819 continue;
820 for (; argv[i]; i++) {
821 argv[i] = argv[i+1];
822 }
823 (*argcp)--;
1de81503 824 return true;
0b0f73db 825 }
1de81503 826 return false;
0b0f73db
SH
827}
828
e190ee91 829bool swallow_option(int *argcp, char *argv[], char *opt, char **v)
0b0f73db
SH
830{
831 int i;
832
833 for (i = 1; argv[i]; i++) {
834 if (!argv[i+1])
835 continue;
836 if (strcmp(argv[i], opt) != 0)
837 continue;
e190ee91
SH
838 do {
839 *v = strdup(argv[i+1]);
840 } while (!*v);
0b0f73db
SH
841 for (; argv[i+1]; i++) {
842 argv[i] = argv[i+2];
843 }
844 (*argcp) -= 2;
e190ee91 845 return true;
0b0f73db 846 }
e190ee91 847 return false;
0b0f73db
SH
848}
849
e190ee91
SH
850static int set_pidfile(char *pidfile)
851{
852 int fd;
853 char buf[50];
854 struct flock fl;
855
856 fl.l_type = F_WRLCK;
857 fl.l_whence = SEEK_SET;
858 fl.l_start = 0;
859 fl.l_len = 0;
860
861 fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
862 if (fd == -1) {
b8defc3d 863 fprintf(stderr, "Could not open pidfile %s: %m\n", pidfile);
e190ee91
SH
864 return -1;
865 }
866
867 if (fcntl(fd, F_SETLK, &fl) == -1) {
868 if (errno == EAGAIN || errno == EACCES) {
869 fprintf(stderr, "PID file '%s' is already locked.\n", pidfile);
870 close(fd);
871 return -1;
872 }
873 fprintf(stderr, "Warning; unable to lock PID file, proceeding.\n");
874 }
875
876 if (ftruncate(fd, 0) == -1) {
877 fprintf(stderr, "Error truncating PID file '%s': %m", pidfile);
878 close(fd);
879 return -1;
880 }
881
882 snprintf(buf, 50, "%ld\n", (long) getpid());
883 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
884 fprintf(stderr, "Error writing to PID file '%s': %m", pidfile);
885 close(fd);
886 return -1;
887 }
888
889 return fd;
890}
891
758ad80c
SH
892int main(int argc, char *argv[])
893{
47f5266f
CB
894 int ret = EXIT_FAILURE;
895 int pidfd = -1;
482a80d4 896 char *pidfile = NULL, *saveptr = NULL, *token = NULL, *v = NULL;
29a73c2f 897 size_t pidfile_len;
482a80d4 898 bool debug = false, nonempty = false;
6db4f7a3 899 bool load_use = false;
0b0f73db
SH
900 /*
901 * what we pass to fuse_main is:
1de81503 902 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
0b0f73db 903 */
2c51f8dd
SH
904 int nargs = 5, cnt = 0;
905 char *newargv[6];
758ad80c 906
0b0f73db
SH
907 /* accomodate older init scripts */
908 swallow_arg(&argc, argv, "-s");
909 swallow_arg(&argc, argv, "-f");
1de81503 910 debug = swallow_arg(&argc, argv, "-d");
6db4f7a3 911 if (swallow_arg(&argc, argv, "-l")) {
912 load_use = true;
913 }
e190ee91 914 if (swallow_option(&argc, argv, "-o", &v)) {
482a80d4
G
915 /* Parse multiple values */
916 for (; (token = strtok_r(v, ",", &saveptr)); v = NULL) {
917 if (strcmp(token, "allow_other") == 0) {
918 /* Noop. this is the default. Always enabled. */
919 } else if (strcmp(token, "nonempty") == 0) {
920 nonempty = true;
921 } else {
922 free(v);
923 fprintf(stderr, "Warning: unexpected fuse option %s\n", v);
924 exit(EXIT_FAILURE);
925 }
e190ee91
SH
926 }
927 free(v);
928 v = NULL;
929 }
930 if (swallow_option(&argc, argv, "-p", &v))
931 pidfile = v;
0b0f73db 932
2e9c0b32
SH
933 if (argc == 2 && strcmp(argv[1], "--version") == 0) {
934 fprintf(stderr, "%s\n", VERSION);
47f5266f 935 exit(EXIT_SUCCESS);
2e9c0b32 936 }
0b0f73db 937 if (argc != 2 || is_help(argv[1]))
c3fb7d7f 938 usage();
758ad80c 939
59120f04 940 do_reload();
8fad16cd 941 if (signal(SIGUSR1, reload_handler) == SIG_ERR) {
8dcde249 942 fprintf(stderr, "Error setting USR1 signal handler: %m\n");
47f5266f 943 goto out;
8fad16cd 944 }
e190ee91 945
38a76a91 946 newargv[cnt++] = argv[0];
482a80d4
G
947 if (debug)
948 newargv[cnt++] = "-d";
949 else
950 newargv[cnt++] = "-f";
38a76a91 951 newargv[cnt++] = "-o";
482a80d4
G
952 if (nonempty)
953 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5,nonempty";
954 else
955 newargv[cnt++] = "allow_other,direct_io,entry_timeout=0.5,attr_timeout=0.5";
38a76a91
SH
956 newargv[cnt++] = argv[1];
957 newargv[cnt++] = NULL;
758ad80c 958
e190ee91
SH
959 if (!pidfile) {
960 pidfile_len = strlen(RUNTIME_PATH) + strlen("/lxcfs.pid") + 1;
961 pidfile = alloca(pidfile_len);
962 snprintf(pidfile, pidfile_len, "%s/lxcfs.pid", RUNTIME_PATH);
963 }
964 if ((pidfd = set_pidfile(pidfile)) < 0)
965 goto out;
966
a83618e2
JS
967 if (load_use && start_loadavg() != 0)
968 goto out;
6db4f7a3 969
47f5266f
CB
970 if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL))
971 ret = EXIT_SUCCESS;
a83618e2
JS
972 if (load_use)
973 stop_loadavg();
237e200e 974
c0adec85 975out:
47f5266f
CB
976 if (dlopen_handle)
977 dlclose(dlopen_handle);
978 if (pidfile)
979 unlink(pidfile);
980 if (pidfd > 0)
981 close(pidfd);
47f5266f 982 exit(ret);
2183082c 983}