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