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