]> git.proxmox.com Git - mirror_lxcfs.git/blame - src/lxcfs.c
lxcfs: preparation for FUSE_INTERRUPT support
[mirror_lxcfs.git] / src / lxcfs.c
CommitLineData
db0463bf 1/* SPDX-License-Identifier: LGPL-2.1+ */
758ad80c 2
f834b6bf
SP
3#include "config.h"
4
4e3f18fb 5#include <alloca.h>
758ad80c 6#include <dirent.h>
1ece80b2
CB
7#include <dlfcn.h>
8#include <errno.h>
758ad80c 9#include <fcntl.h>
64a7d94d 10#include <getopt.h>
cf02ccbe 11#include <inttypes.h>
758ad80c 12#include <libgen.h>
b11c6ec0 13#include <pthread.h>
1ece80b2
CB
14#include <sched.h>
15#include <stdbool.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20#include <unistd.h>
21#include <wait.h>
41bb9357 22#include <linux/sched.h>
5b2dfd85 23#include <sys/epoll.h>
1ece80b2
CB
24#include <sys/mount.h>
25#include <sys/socket.h>
9dd49ba5 26#include <linux/limits.h>
758ad80c 27
bb4e3c8f 28#include "lxcfs_fuse.h"
0a5da718 29
237e200e 30#include "bindings.h"
ec2043ed 31#include "lxcfs_fuse_compat.h"
12a60884
CB
32#include "macro.h"
33#include "memory_utils.h"
758ad80c 34
237e200e 35void *dlopen_handle;
b11c6ec0 36
237e200e 37/* Functions to keep track of number of threads using the library */
6d1308cb 38
237e200e
SH
39static int users_count;
40static pthread_mutex_t user_count_mutex = PTHREAD_MUTEX_INITIALIZER;
b11c6ec0 41static void lock_mutex(pthread_mutex_t *l)
2c51f8dd 42{
b11c6ec0 43 int ret;
2c51f8dd 44
02aeab4b
CB
45 ret = pthread_mutex_lock(l);
46 if (ret)
47 log_exit("%s - returned: %d\n", strerror(ret), ret);
b11c6ec0 48}
2c51f8dd 49
237e200e 50static void unlock_mutex(pthread_mutex_t *l)
23ce2127 51{
237e200e 52 int ret;
2dc17609 53
02aeab4b
CB
54 ret = pthread_mutex_unlock(l);
55 if (ret)
56 log_exit("%s - returned: %d\n", strerror(ret), ret);
237e200e 57}
2dc17609 58
02aeab4b 59static inline void users_lock(void)
237e200e
SH
60{
61 lock_mutex(&user_count_mutex);
62}
b731895e 63
02aeab4b 64static inline void users_unlock(void)
237e200e
SH
65{
66 unlock_mutex(&user_count_mutex);
67}
e1068397 68
cf02ccbe
MI
69/* Returns file info type of custom type declaration carried
70 * in fuse_file_info */
71static inline enum lxcfs_virt_t file_info_type(struct fuse_file_info *fi)
72{
73 struct file_info *f;
74
75 f = INTTYPE_TO_PTR(fi->fh);
76 if (!f)
77 return -1;
78
79 if (!LXCFS_TYPE_OK(f->type))
80 return -1;
81
82 return f->type;
83}
84
a83618e2
JS
85static pthread_t loadavg_pid = 0;
86
87/* Returns zero on success */
971aa868
CB
88static int start_loadavg(void)
89{
a83618e2 90 char *error;
9ce186dc 91 pthread_t (*__load_daemon)(int);
a83618e2 92
971aa868
CB
93 dlerror();
94 __load_daemon = (pthread_t(*)(int))dlsym(dlopen_handle, "load_daemon");
a83618e2 95 error = dlerror();
971aa868
CB
96 if (error)
97 return log_error(-1, "%s - Failed to start loadavg daemon", error);
98
9ce186dc 99 loadavg_pid = __load_daemon(1);
971aa868 100 if (!loadavg_pid)
a83618e2
JS
101 return -1;
102
103 return 0;
104}
105
106/* Returns zero on success */
971aa868
CB
107static int stop_loadavg(void)
108{
a83618e2 109 char *error;
9ce186dc 110 int (*__stop_load_daemon)(pthread_t);
a83618e2 111
971aa868 112 __stop_load_daemon = (int (*)(pthread_t))dlsym(dlopen_handle, "stop_load_daemon");
a83618e2 113 error = dlerror();
971aa868
CB
114 if (error)
115 return log_error(-1, "%s - Failed to stop loadavg daemon", error);
a83618e2 116
971aa868 117 if (__stop_load_daemon(loadavg_pid))
a83618e2
JS
118 return -1;
119
120 return 0;
121}
122
81d17d8f 123static volatile sig_atomic_t need_reload;
59120f04 124
cb784d69
WB
125static int lxcfs_init_library(void)
126{
127 char *error;
128 void *(*__lxcfs_fuse_init)(struct fuse_conn_info * conn, void * cfg);
129
130 dlerror();
131 __lxcfs_fuse_init = (void *(*)(struct fuse_conn_info * conn, void * cfg))dlsym(dlopen_handle, "lxcfs_fuse_init");
132 error = dlerror();
133 if (error)
134 return log_error(-1, "%s - Failed to find lxcfs_fuse_init()", error);
135
136 __lxcfs_fuse_init(NULL, NULL);
137
138 return 0;
139}
140
237e200e
SH
141/* do_reload - reload the dynamic library. Done under
142 * lock and when we know the user_count was 0 */
5976d034 143static void do_reload(bool reinit)
237e200e 144{
1b8fb279 145 int ret;
9dd49ba5 146 char lxcfs_lib_path[PATH_MAX];
a83618e2
JS
147
148 if (loadavg_pid > 0)
149 stop_loadavg();
150
b8defc3d 151 if (dlopen_handle) {
0b5e6053 152 lxcfs_info("Closed liblxcfs.so");
237e200e 153 dlclose(dlopen_handle);
b8defc3d 154 }
e1068397 155
59120f04 156 /* First try loading using ld.so */
c7894bc7
CB
157#ifdef RESOLVE_NOW
158 dlopen_handle = dlopen("liblxcfs.so", RTLD_NOW);
159#else
237e200e 160 dlopen_handle = dlopen("liblxcfs.so", RTLD_LAZY);
c7894bc7 161#endif
b8defc3d 162 if (dlopen_handle) {
0b5e6053 163 lxcfs_debug("Opened liblxcfs.so");
59120f04 164 goto good;
b8defc3d 165 }
59120f04 166
9dd49ba5
DK
167#ifdef LIBDIR
168 /* LIBDIR: autoconf will setup this MACRO. Default value is $PREFIX/lib */
1b8fb279 169 ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "%s/lxcfs/liblxcfs.so", LIBDIR);
9dd49ba5 170#else
1b8fb279 171 ret = snprintf(lxcfs_lib_path, sizeof(lxcfs_lib_path), "/usr/local/lib/lxcfs/liblxcfs.so");
9dd49ba5 172#endif
3cf1e562 173 if (ret < 0 || (size_t)ret >= sizeof(lxcfs_lib_path))
1b8fb279
CB
174 log_exit("Failed to create path to open liblxcfs");
175
9dd49ba5 176 dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY);
1b8fb279
CB
177 if (!dlopen_handle)
178 log_exit("%s - Failed to open liblxcfs.so", dlerror());
179 else
0b5e6053 180 lxcfs_debug("Opened %s", lxcfs_lib_path);
59120f04
SH
181
182good:
cb784d69 183 /* initialize the library */
5976d034 184 if (reinit && lxcfs_init_library() < 0) {
cb784d69
WB
185 log_exit("Failed to initialize liblxcfs.so");
186 }
187
a83618e2
JS
188 if (loadavg_pid > 0)
189 start_loadavg();
190
59120f04 191 if (need_reload)
0b5e6053 192 lxcfs_info("Reloaded LXCFS");
237e200e 193 need_reload = 0;
23ce2127
SH
194}
195
237e200e 196static void up_users(void)
23ce2127 197{
237e200e
SH
198 users_lock();
199 if (users_count == 0 && need_reload)
5976d034 200 do_reload(true);
237e200e
SH
201 users_count++;
202 users_unlock();
203}
23ce2127 204
237e200e
SH
205static void down_users(void)
206{
207 users_lock();
208 users_count--;
209 users_unlock();
23ce2127
SH
210}
211
dee86006 212static void sigusr1_reload(int signo, siginfo_t *info, void *extra)
237e200e 213{
237e200e 214 need_reload = 1;
237e200e 215}
23ce2127 216
237e200e
SH
217/* Functions to run the library methods */
218static int do_cg_getattr(const char *path, struct stat *sb)
aeb56147 219{
237e200e 220 char *error;
971aa868
CB
221 int (*__cg_getattr)(const char *path, struct stat *sb);
222
223 dlerror();
224 __cg_getattr = (int (*)(const char *, struct stat *))dlsym(dlopen_handle, "cg_getattr");
237e200e 225 error = dlerror();
971aa868
CB
226 if (error)
227 return log_error(-1, "%s - Failed to find cg_getattr()", error);
aeb56147 228
9ce186dc 229 return __cg_getattr(path, sb);
aeb56147
SH
230}
231
237e200e 232static int do_proc_getattr(const char *path, struct stat *sb)
23ce2127 233{
237e200e 234 char *error;
971aa868
CB
235 int (*__proc_getattr)(const char *path, struct stat *sb);
236
237 dlerror();
9ce186dc 238 __proc_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "proc_getattr");
237e200e 239 error = dlerror();
971aa868
CB
240 if (error)
241 return log_error(-1, "%s - Failed to find proc_getattr()", error);
23ce2127 242
9ce186dc 243 return __proc_getattr(path, sb);
23ce2127
SH
244}
245
71f17cd2
YB
246static int do_sys_getattr(const char *path, struct stat *sb)
247{
71f17cd2 248 char *error;
971aa868
CB
249 int (*__sys_getattr)(const char *path, struct stat *sb);
250
251 dlerror();
9ce186dc 252 __sys_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "sys_getattr");
71f17cd2 253 error = dlerror();
971aa868
CB
254 if (error)
255 return log_error(-1, "%s - Failed to find sys_getattr()", error);
71f17cd2 256
9ce186dc 257 return __sys_getattr(path, sb);
71f17cd2
YB
258}
259
237e200e 260static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
971aa868 261 struct fuse_file_info *fi)
23ce2127 262{
971aa868 263 char *error;
9ce186dc
CB
264 int (*__cg_read)(const char *path, char *buf, size_t size, off_t offset,
265 struct fuse_file_info *fi);
23ce2127 266
971aa868
CB
267 dlerror();
268 __cg_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_read");
237e200e 269 error = dlerror();
971aa868
CB
270 if (error)
271 return log_error(-1, "%s - Failed to find cg_read()", error);
23ce2127 272
9ce186dc 273 return __cg_read(path, buf, size, offset, fi);
23ce2127
SH
274}
275
237e200e 276static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
9ce186dc 277 struct fuse_file_info *fi)
23ce2127 278{
971aa868 279 char *error;
9ce186dc
CB
280 int (*__proc_read)(const char *path, char *buf, size_t size,
281 off_t offset, struct fuse_file_info *fi);
aeb56147 282
971aa868
CB
283 dlerror();
284 __proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "proc_read");
237e200e 285 error = dlerror();
971aa868
CB
286 if (error)
287 return log_error(-1, "%s - Failed to find proc_read()", error);
97f1f27b 288
9ce186dc 289 return __proc_read(path, buf, size, offset, fi);
237e200e 290}
97f1f27b 291
71f17cd2 292static int do_sys_read(const char *path, char *buf, size_t size, off_t offset,
971aa868 293 struct fuse_file_info *fi)
71f17cd2 294{
971aa868 295 char *error;
9ce186dc
CB
296 int (*__sys_read)(const char *path, char *buf, size_t size,
297 off_t offset, struct fuse_file_info *fi);
71f17cd2 298
971aa868
CB
299 dlerror();
300 __sys_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_read");
71f17cd2 301 error = dlerror();
971aa868
CB
302 if (error)
303 return log_error(-1, "%s - Failed to find sys_read()", error);
71f17cd2 304
9ce186dc 305 return __sys_read(path, buf, size, offset, fi);
71f17cd2
YB
306}
307
971aa868
CB
308static int do_cg_write(const char *path, const char *buf, size_t size,
309 off_t offset, struct fuse_file_info *fi)
237e200e 310{
971aa868 311 char *error;
9ce186dc
CB
312 int (*__cg_write)(const char *path, const char *buf, size_t size,
313 off_t offset, struct fuse_file_info *fi);
971aa868
CB
314
315 dlerror();
316 __cg_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_write");
237e200e 317 error = dlerror();
971aa868
CB
318 if (error)
319 return log_error(-1, "%s - Failed to find cg_write()", error);
97f1f27b 320
9ce186dc 321 return __cg_write(path, buf, size, offset, fi);
23ce2127
SH
322}
323
26b717d0
ZL
324static int do_sys_write(const char *path, const char *buf, size_t size,
325 off_t offset, struct fuse_file_info *fi)
326{
327 char *error;
328 int (*__sys_write)(const char *path, const char *buf, size_t size,
329 off_t offset, struct fuse_file_info *fi);
330
331 dlerror();
332 __sys_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_write");
333 error = dlerror();
334 if (error)
335 return log_error(-1, "%s - Failed to find sys_write()", error);
336
337 return __sys_write(path, buf, size, offset, fi);
338}
339
237e200e 340static int do_cg_mkdir(const char *path, mode_t mode)
41bb9357 341{
237e200e 342 char *error;
971aa868 343 int (*__cg_mkdir)(const char *path, mode_t mode);
9ce186dc 344
971aa868
CB
345 dlerror();
346 __cg_mkdir = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_mkdir");
237e200e 347 error = dlerror();
971aa868
CB
348 if (error)
349 return log_error(-1, "%s - Failed to find cg_mkdir()", error);
41bb9357 350
9ce186dc 351 return __cg_mkdir(path, mode);
41bb9357
SH
352}
353
237e200e 354static int do_cg_chown(const char *path, uid_t uid, gid_t gid)
0b6af11b 355{
237e200e 356 char *error;
971aa868 357 int (*__cg_chown)(const char *path, uid_t uid, gid_t gid);
9ce186dc 358
971aa868
CB
359 dlerror();
360 __cg_chown = (int (*)(const char *, uid_t, gid_t))dlsym(dlopen_handle, "cg_chown");
237e200e 361 error = dlerror();
971aa868
CB
362 if (error)
363 return log_error(-1, "%s - Failed to find cg_chown()", error);
0b6af11b 364
9ce186dc 365 return __cg_chown(path, uid, gid);
41bb9357
SH
366}
367
237e200e 368static int do_cg_rmdir(const char *path)
23ce2127 369{
237e200e 370 char *error;
971aa868 371 int (*__cg_rmdir)(const char *path);
9ce186dc 372
971aa868
CB
373 dlerror();
374 __cg_rmdir = (int (*)(const char *path))dlsym(dlopen_handle, "cg_rmdir");
237e200e 375 error = dlerror();
971aa868
CB
376 if (error)
377 return log_error(-1, "%s - Failed to find cg_rmdir()", error);
97f1f27b 378
9ce186dc 379 return __cg_rmdir(path);
237e200e 380}
f6c0b279 381
237e200e
SH
382static int do_cg_chmod(const char *path, mode_t mode)
383{
237e200e 384 char *error;
971aa868 385 int (*__cg_chmod)(const char *path, mode_t mode);
9ce186dc 386
971aa868
CB
387 dlerror();
388 __cg_chmod = (int (*)(const char *, mode_t))dlsym(dlopen_handle, "cg_chmod");
237e200e 389 error = dlerror();
971aa868
CB
390 if (error)
391 return log_error(-1, "%s - Failed to find cg_chmod()", error);
cdcdb29b 392
9ce186dc 393 return __cg_chmod(path, mode);
23ce2127
SH
394}
395
9ce186dc
CB
396static int do_cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
397 off_t offset, struct fuse_file_info *fi)
49878439 398{
971aa868 399 char *error;
9ce186dc
CB
400 int (*__cg_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
401 off_t offset, struct fuse_file_info *fi);
49878439 402
971aa868
CB
403 dlerror();
404 __cg_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "cg_readdir");
237e200e 405 error = dlerror();
971aa868
CB
406 if (error)
407 return log_error(-1, "%s - Failed to find cg_readdir()", error);
49878439 408
9ce186dc 409 return __cg_readdir(path, buf, filler, offset, fi);
237e200e 410}
49878439 411
9ce186dc
CB
412static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
413 off_t offset, struct fuse_file_info *fi)
237e200e 414{
971aa868 415 char *error;
9ce186dc
CB
416 int (*__proc_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
417 off_t offset, struct fuse_file_info *fi);
49878439 418
971aa868
CB
419 dlerror();
420 __proc_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "proc_readdir");
237e200e 421 error = dlerror();
971aa868
CB
422 if (error)
423 return log_error(-1, "%s - Failed to find proc_readdir()", error);
49878439 424
9ce186dc 425 return __proc_readdir(path, buf, filler, offset, fi);
49878439
YY
426}
427
9ce186dc
CB
428static int do_sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
429 off_t offset, struct fuse_file_info *fi)
71f17cd2 430{
71f17cd2 431 char *error;
971aa868
CB
432 int (*__sys_readdir)(const char *path, void *buf, fuse_fill_dir_t filler,
433 off_t offset, struct fuse_file_info *fi);
71f17cd2 434
971aa868
CB
435 dlerror();
436 __sys_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_readdir");
71f17cd2 437 error = dlerror();
971aa868
CB
438 if (error)
439 return log_error(-1, "%s - Failed to find sys_readdir()", error);
71f17cd2 440
9ce186dc 441 return __sys_readdir(path, buf, filler, offset, fi);
71f17cd2
YB
442}
443
26b717d0
ZL
444static int do_sys_readlink(const char *path, char *buf, size_t size)
445{
446 char *error;
447 int (*__sys_readlink)(const char *path, char *buf, size_t size);
448
449 dlerror();
450 __sys_readlink = (int (*)(const char *, char *, size_t))dlsym(dlopen_handle, "sys_readlink");
451 error = dlerror();
452 if (error)
453 return log_error(-1, "%s - Failed to find sys_readlink()", error);
454
455 return __sys_readlink(path, buf, size);
456}
71f17cd2 457
237e200e 458static int do_cg_open(const char *path, struct fuse_file_info *fi)
23ce2127 459{
237e200e 460 char *error;
971aa868
CB
461 int (*__cg_open)(const char *path, struct fuse_file_info *fi);
462
463 dlerror();
464 __cg_open = (int (*)(const char *, struct fuse_file_info *))dlsym(dlopen_handle, "cg_open");
237e200e 465 error = dlerror();
971aa868
CB
466 if (error)
467 return log_error(-1, "%s - Failed to find cg_open()", error);
23ce2127 468
9ce186dc 469 return __cg_open(path, fi);
23ce2127
SH
470}
471
bddbb106
SH
472static int do_cg_access(const char *path, int mode)
473{
bddbb106 474 char *error;
971aa868
CB
475 int (*__cg_access)(const char *path, int mode);
476
477 dlerror();
478 __cg_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "cg_access");
bddbb106 479 error = dlerror();
971aa868
CB
480 if (error)
481 return log_error(-1, "%s - Failed to find cg_access()", error);
bddbb106 482
9ce186dc 483 return __cg_access(path, mode);
bddbb106
SH
484}
485
237e200e 486static int do_proc_open(const char *path, struct fuse_file_info *fi)
758ad80c 487{
237e200e 488 char *error;
971aa868
CB
489 int (*__proc_open)(const char *path, struct fuse_file_info *fi);
490
491 dlerror();
492 __proc_open = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "proc_open");
237e200e 493 error = dlerror();
971aa868
CB
494 if (error)
495 return log_error(-1, "%s - Failed to find proc_open()", error);
35629743 496
9ce186dc 497 return __proc_open(path, fi);
35629743
SH
498}
499
bddbb106
SH
500static int do_proc_access(const char *path, int mode)
501{
bddbb106 502 char *error;
971aa868
CB
503 int (*__proc_access)(const char *path, int mode);
504
505 dlerror();
506 __proc_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "proc_access");
bddbb106 507 error = dlerror();
971aa868
CB
508 if (error)
509 return log_error(-1, "%s - Failed to find proc_access()", error);
bddbb106 510
9ce186dc 511 return __proc_access(path, mode);
bddbb106
SH
512}
513
71f17cd2
YB
514static int do_sys_open(const char *path, struct fuse_file_info *fi)
515{
71f17cd2 516 char *error;
971aa868
CB
517 int (*__sys_open)(const char *path, struct fuse_file_info *fi);
518
519 dlerror();
520 __sys_open = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_open");
71f17cd2 521 error = dlerror();
971aa868
CB
522 if (error)
523 return log_error(-1, "%s - Failed to find sys_open()", error);
71f17cd2 524
9ce186dc 525 return __sys_open(path, fi);
71f17cd2
YB
526}
527
26b717d0
ZL
528static int do_sys_opendir(const char *path, struct fuse_file_info *fi)
529{
530 char *error;
531 int (*__sys_opendir)(const char *path, struct fuse_file_info *fi);
532
533 dlerror();
534 __sys_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_opendir");
535 error = dlerror();
536 if (error)
537 return log_error(-1, "%s - Failed to find sys_opendir()", error);
538
539 return __sys_opendir(path, fi);
540}
541
71f17cd2
YB
542static int do_sys_access(const char *path, int mode)
543{
71f17cd2 544 char *error;
971aa868
CB
545 int (*__sys_access)(const char *path, int mode);
546
547 dlerror();
548 __sys_access = (int (*)(const char *, int mode))dlsym(dlopen_handle, "sys_access");
71f17cd2 549 error = dlerror();
971aa868
CB
550 if (error)
551 return log_error(-1, "%s - Failed to find sys_access()", error);
71f17cd2 552
9ce186dc 553 return __sys_access(path, mode);
71f17cd2
YB
554}
555
237e200e 556static int do_cg_release(const char *path, struct fuse_file_info *fi)
35629743 557{
237e200e 558 char *error;
971aa868
CB
559 int (*__cg_release)(const char *path, struct fuse_file_info *fi);
560
561 dlerror();
562 __cg_release = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "cg_release");
237e200e 563 error = dlerror();
971aa868
CB
564 if (error)
565 return log_error(-1, "%s - Failed to find cg_release()", error);
237e200e 566
9ce186dc 567 return __cg_release(path, fi);
758ad80c
SH
568}
569
237e200e 570static int do_proc_release(const char *path, struct fuse_file_info *fi)
35629743 571{
237e200e 572 char *error;
971aa868
CB
573 int (*__proc_release)(const char *path, struct fuse_file_info *fi);
574
575 dlerror();
9ce186dc 576 __proc_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_release");
237e200e 577 error = dlerror();
971aa868
CB
578 if (error)
579 return log_error(-1, "%s - Failed to find proc_release()", error);
97f1f27b 580
9ce186dc 581 return __proc_release(path, fi);
96fc5ee6
SH
582}
583
71f17cd2
YB
584static int do_sys_release(const char *path, struct fuse_file_info *fi)
585{
71f17cd2 586 char *error;
971aa868
CB
587 int (*__sys_release)(const char *path, struct fuse_file_info *fi);
588
589 dlerror();
590 __sys_release = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_release");
71f17cd2 591 error = dlerror();
971aa868
CB
592 if (error)
593 return log_error(-1, "%s - Failed to find sys_release()", error);
71f17cd2 594
9ce186dc 595 return __sys_release(path, fi);
71f17cd2
YB
596}
597
237e200e 598static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
96fc5ee6 599{
237e200e 600 char *error;
971aa868
CB
601 int (*__cg_opendir)(const char *path, struct fuse_file_info *fi);
602
603 dlerror();
604 __cg_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "cg_opendir");
237e200e 605 error = dlerror();
971aa868
CB
606 if (error)
607 return log_error(-1, "%s - Failed to find cg_opendir()", error);
96fc5ee6 608
9ce186dc 609 return __cg_opendir(path, fi);
35629743
SH
610}
611
237e200e 612static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
35629743 613{
237e200e 614 char *error;
971aa868
CB
615 int (*__cg_releasedir)(const char *path, struct fuse_file_info *fi);
616
617 dlerror();
618 __cg_releasedir = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "cg_releasedir");
237e200e 619 error = dlerror();
971aa868
CB
620 if (error)
621 return log_error(-1, "%s - Failed to find cg_releasedir()", error);
237e200e 622
9ce186dc 623 return __cg_releasedir(path, fi);
35629743
SH
624}
625
71f17cd2
YB
626static int do_sys_releasedir(const char *path, struct fuse_file_info *fi)
627{
71f17cd2 628 char *error;
971aa868
CB
629 int (*__sys_releasedir)(const char *path, struct fuse_file_info *fi);
630
631 dlerror();
632 __sys_releasedir = (int (*)(const char *path, struct fuse_file_info *))dlsym(dlopen_handle, "sys_releasedir");
71f17cd2 633 error = dlerror();
971aa868
CB
634 if (error)
635 return log_error(-1, "%s - Failed to find sys_releasedir()", error);
71f17cd2 636
9ce186dc 637 return __sys_releasedir(path, fi);
71f17cd2
YB
638}
639
cb61c9e1 640#if HAVE_FUSE3
f834b6bf
SP
641static int lxcfs_getattr(const char *path, struct stat *sb, struct fuse_file_info *fi)
642#else
758ad80c 643static int lxcfs_getattr(const char *path, struct stat *sb)
f834b6bf 644#endif
758ad80c 645{
237e200e 646 int ret;
17e6e1e2
CB
647 struct timespec now;
648
758ad80c 649 if (strcmp(path, "/") == 0) {
17e6e1e2
CB
650 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
651 return -EINVAL;
652 sb->st_uid = sb->st_gid = 0;
653 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
654 sb->st_size = 0;
758ad80c
SH
655 sb->st_mode = S_IFDIR | 00755;
656 sb->st_nlink = 2;
657 return 0;
658 }
17e6e1e2 659
758ad80c 660 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
661 up_users();
662 ret = do_cg_getattr(path, sb);
663 down_users();
664 return ret;
758ad80c 665 }
971aa868 666
35629743 667 if (strncmp(path, "/proc", 5) == 0) {
237e200e
SH
668 up_users();
669 ret = do_proc_getattr(path, sb);
670 down_users();
671 return ret;
758ad80c 672 }
971aa868 673
71f17cd2
YB
674 if (strncmp(path, "/sys", 4) == 0) {
675 up_users();
676 ret = do_sys_getattr(path, sb);
677 down_users();
678 return ret;
679 }
971aa868 680
f9b24a3e 681 return -ENOENT;
758ad80c
SH
682}
683
684static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
685{
237e200e 686 int ret;
971aa868 687
758ad80c
SH
688 if (strcmp(path, "/") == 0)
689 return 0;
690
691 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
692 up_users();
693 ret = do_cg_opendir(path, fi);
694 down_users();
695 return ret;
758ad80c 696 }
971aa868 697
35629743
SH
698 if (strcmp(path, "/proc") == 0)
699 return 0;
971aa868 700
26b717d0
ZL
701 if (strncmp(path, "/sys", 4) == 0) {
702 up_users();
703 ret = do_sys_opendir(path, fi);
704 down_users();
705 return ret;
706 }
71f17cd2 707
35629743 708 return -ENOENT;
758ad80c
SH
709}
710
cb61c9e1 711#if HAVE_FUSE3
f834b6bf
SP
712static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
713 off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
714#else
971aa868
CB
715static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
716 off_t offset, struct fuse_file_info *fi)
f834b6bf 717#endif
758ad80c 718{
237e200e 719 int ret;
971aa868 720
758ad80c 721 if (strcmp(path, "/") == 0) {
5aff2eb2
CBM
722 if (dir_filler(filler, buf, ".", 0) != 0 ||
723 dir_filler(filler, buf, "..", 0) != 0 ||
724 dir_filler(filler, buf, "proc", 0) != 0 ||
725 dir_filler(filler, buf, "sys", 0) != 0 ||
726 dir_filler(filler, buf, "cgroup", 0) != 0)
f9b24a3e 727 return -ENOMEM;
971aa868 728
758ad80c
SH
729 return 0;
730 }
971aa868 731
237e200e
SH
732 if (strncmp(path, "/cgroup", 7) == 0) {
733 up_users();
734 ret = do_cg_readdir(path, buf, filler, offset, fi);
735 down_users();
736 return ret;
737 }
971aa868 738
237e200e
SH
739 if (strcmp(path, "/proc") == 0) {
740 up_users();
741 ret = do_proc_readdir(path, buf, filler, offset, fi);
742 down_users();
743 return ret;
744 }
71f17cd2
YB
745
746 if (strncmp(path, "/sys", 4) == 0) {
747 up_users();
748 ret = do_sys_readdir(path, buf, filler, offset, fi);
749 down_users();
750 return ret;
751 }
752
f9b24a3e 753 return -ENOENT;
758ad80c
SH
754}
755
bddbb106
SH
756static int lxcfs_access(const char *path, int mode)
757{
758 int ret;
17e6e1e2 759
f9b24a3e 760 if (strcmp(path, "/") == 0 && (mode & W_OK) == 0)
17e6e1e2
CB
761 return 0;
762
bddbb106
SH
763 if (strncmp(path, "/cgroup", 7) == 0) {
764 up_users();
765 ret = do_cg_access(path, mode);
766 down_users();
767 return ret;
768 }
971aa868 769
bddbb106
SH
770 if (strncmp(path, "/proc", 5) == 0) {
771 up_users();
772 ret = do_proc_access(path, mode);
773 down_users();
774 return ret;
775 }
971aa868 776
71f17cd2
YB
777 if (strncmp(path, "/sys", 4) == 0) {
778 up_users();
779 ret = do_sys_access(path, mode);
780 down_users();
781 return ret;
782 }
783
f9b24a3e 784 return -EACCES;
bddbb106
SH
785}
786
758ad80c
SH
787static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
788{
237e200e 789 int ret;
cf02ccbe 790 enum lxcfs_virt_t type;
971aa868 791
cf02ccbe 792 type = file_info_type(fi);
971aa868 793
cf02ccbe 794 if (LXCFS_TYPE_CGROUP(type)) {
237e200e
SH
795 up_users();
796 ret = do_cg_releasedir(path, fi);
797 down_users();
798 return ret;
758ad80c 799 }
971aa868 800
cf02ccbe 801 if (LXCFS_TYPE_SYS(type)) {
71f17cd2
YB
802 up_users();
803 ret = do_sys_releasedir(path, fi);
804 down_users();
805 return ret;
806 }
807
cf02ccbe
MI
808 if (path) {
809 if (strcmp(path, "/") == 0)
810 return 0;
811 if (strcmp(path, "/proc") == 0)
812 return 0;
813 }
814
815 lxcfs_error("unknown file type: path=%s, type=%d, fi->fh=%" PRIu64,
816 path, type, fi->fh);
817
758ad80c
SH
818 return -EINVAL;
819}
820
99978832
SH
821static int lxcfs_open(const char *path, struct fuse_file_info *fi)
822{
237e200e 823 int ret;
971aa868 824
237e200e
SH
825 if (strncmp(path, "/cgroup", 7) == 0) {
826 up_users();
827 ret = do_cg_open(path, fi);
828 down_users();
829 return ret;
830 }
971aa868 831
237e200e
SH
832 if (strncmp(path, "/proc", 5) == 0) {
833 up_users();
834 ret = do_proc_open(path, fi);
835 down_users();
836 return ret;
837 }
971aa868 838
71f17cd2
YB
839 if (strncmp(path, "/sys", 4) == 0) {
840 up_users();
841 ret = do_sys_open(path, fi);
842 down_users();
843 return ret;
844 }
845
f9b24a3e 846 return -EACCES;
99978832
SH
847}
848
849static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
971aa868 850 struct fuse_file_info *fi)
99978832 851{
237e200e 852 int ret;
971aa868 853
237e200e
SH
854 if (strncmp(path, "/cgroup", 7) == 0) {
855 up_users();
856 ret = do_cg_read(path, buf, size, offset, fi);
857 down_users();
858 return ret;
859 }
971aa868 860
237e200e
SH
861 if (strncmp(path, "/proc", 5) == 0) {
862 up_users();
863 ret = do_proc_read(path, buf, size, offset, fi);
864 down_users();
865 return ret;
866 }
971aa868 867
71f17cd2
YB
868 if (strncmp(path, "/sys", 4) == 0) {
869 up_users();
870 ret = do_sys_read(path, buf, size, offset, fi);
871 down_users();
872 return ret;
873 }
874
99978832
SH
875 return -EINVAL;
876}
877
2ad6d2bd 878int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
971aa868 879 struct fuse_file_info *fi)
2ad6d2bd 880{
237e200e 881 int ret;
971aa868 882
2ad6d2bd 883 if (strncmp(path, "/cgroup", 7) == 0) {
237e200e
SH
884 up_users();
885 ret = do_cg_write(path, buf, size, offset, fi);
886 down_users();
887 return ret;
2ad6d2bd
SH
888 }
889
26b717d0
ZL
890 if (strncmp(path, "/sys", 4) == 0) {
891 up_users();
892 ret = do_sys_write(path, buf, size, offset, fi);
893 down_users();
894 return ret;
895 }
896
897 return -EINVAL;
898}
899
900int lxcfs_readlink(const char *path, char *buf, size_t size)
901{
902 int ret;
903
904 if (strncmp(path, "/sys", 4) == 0) {
905 up_users();
906 ret = do_sys_readlink(path, buf, size);
907 down_users();
908 return ret;
909 }
910
2ad6d2bd
SH
911 return -EINVAL;
912}
913
99978832
SH
914static int lxcfs_flush(const char *path, struct fuse_file_info *fi)
915{
916 return 0;
917}
918
919static int lxcfs_release(const char *path, struct fuse_file_info *fi)
758ad80c 920{
237e200e 921 int ret;
cf02ccbe 922 enum lxcfs_virt_t type;
971aa868 923
cf02ccbe
MI
924 type = file_info_type(fi);
925
926 if (LXCFS_TYPE_CGROUP(type)) {
237e200e
SH
927 up_users();
928 ret = do_cg_release(path, fi);
929 down_users();
930 return ret;
931 }
971aa868 932
cf02ccbe 933 if (LXCFS_TYPE_PROC(type)) {
237e200e
SH
934 up_users();
935 ret = do_proc_release(path, fi);
936 down_users();
937 return ret;
938 }
971aa868 939
cf02ccbe 940 if (LXCFS_TYPE_SYS(type)) {
71f17cd2
YB
941 up_users();
942 ret = do_sys_release(path, fi);
943 down_users();
944 return ret;
945 }
946
cf02ccbe
MI
947 lxcfs_error("unknown file type: path=%s, type=%d, fi->fh=%" PRIu64,
948 path, type, fi->fh);
949
8f6e8f5e 950 return -EINVAL;
99978832
SH
951}
952
953static int lxcfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
954{
955 return 0;
758ad80c
SH
956}
957
ab54b798
SH
958int lxcfs_mkdir(const char *path, mode_t mode)
959{
237e200e 960 int ret;
971aa868 961
237e200e
SH
962 if (strncmp(path, "/cgroup", 7) == 0) {
963 up_users();
964 ret = do_cg_mkdir(path, mode);
965 down_users();
966 return ret;
967 }
ab54b798 968
f9b24a3e 969 return -EPERM;
ab54b798
SH
970}
971
cb61c9e1 972#if HAVE_FUSE3
f834b6bf
SP
973int lxcfs_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi)
974#else
341b21ad 975int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
f834b6bf 976#endif
341b21ad 977{
237e200e 978 int ret;
971aa868 979
237e200e
SH
980 if (strncmp(path, "/cgroup", 7) == 0) {
981 up_users();
982 ret = do_cg_chown(path, uid, gid);
983 down_users();
984 return ret;
985 }
341b21ad 986
f9b24a3e
CB
987 if (strncmp(path, "/proc", 5) == 0)
988 return -EPERM;
989
1f5596dd 990 if (strncmp(path, "/sys", 4) == 0)
71f17cd2 991 return -EPERM;
971aa868 992
f9b24a3e 993 return -ENOENT;
341b21ad
SH
994}
995
2ad6d2bd
SH
996/*
997 * cat first does a truncate before doing ops->write. This doesn't
998 * really make sense for cgroups. So just return 0 always but do
999 * nothing.
1000 */
cb61c9e1 1001#if HAVE_FUSE3
f834b6bf
SP
1002int lxcfs_truncate(const char *path, off_t newsize, struct fuse_file_info *fi)
1003#else
2ad6d2bd 1004int lxcfs_truncate(const char *path, off_t newsize)
f834b6bf 1005#endif
2ad6d2bd
SH
1006{
1007 if (strncmp(path, "/cgroup", 7) == 0)
1008 return 0;
971aa868 1009
26b717d0
ZL
1010 if (strncmp(path, "/sys", 4) == 0)
1011 return 0;
1012
f9b24a3e 1013 return -EPERM;
2ad6d2bd
SH
1014}
1015
50d8d5b5
SH
1016int lxcfs_rmdir(const char *path)
1017{
237e200e 1018 int ret;
971aa868 1019
237e200e
SH
1020 if (strncmp(path, "/cgroup", 7) == 0) {
1021 up_users();
1022 ret = do_cg_rmdir(path);
1023 down_users();
1024 return ret;
1025 }
971aa868 1026
f9b24a3e 1027 return -EPERM;
50d8d5b5
SH
1028}
1029
cb61c9e1 1030#if HAVE_FUSE3
f834b6bf
SP
1031int lxcfs_chmod(const char *path, mode_t mode, struct fuse_file_info *fi)
1032#else
fd2e4e03 1033int lxcfs_chmod(const char *path, mode_t mode)
f834b6bf 1034#endif
fd2e4e03 1035{
237e200e 1036 int ret;
971aa868 1037
237e200e
SH
1038 if (strncmp(path, "/cgroup", 7) == 0) {
1039 up_users();
1040 ret = do_cg_chmod(path, mode);
1041 down_users();
1042 return ret;
1043 }
f9b24a3e
CB
1044
1045 if (strncmp(path, "/proc", 5) == 0)
1046 return -EPERM;
1047
71f17cd2
YB
1048 if (strncmp(path, "/sys", 4) == 0)
1049 return -EPERM;
1050
f9b24a3e 1051 return -ENOENT;
fd2e4e03
SH
1052}
1053
3ea25890
AM
1054#if HAVE_FUSE3
1055static void fuse_intr_sighandler(int sig)
1056{
1057 (void) sig;
1058 /* Nothing to do */
1059}
1060
1061static int fuse_init_intr_signal(int signum)
1062{
1063 struct sigaction old_sa;
1064 struct sigaction sa;
1065
1066 if (sigaction(signum, NULL, &old_sa) == -1)
1067 return log_error(-1, "cannot get old signal handler\n");
1068
1069 if (old_sa.sa_handler != SIG_DFL)
1070 return log_error(-1, "%d has non-default handler\n", signum);
1071
1072 memset(&sa, 0, sizeof(struct sigaction));
1073
1074 /*
1075 * We *must* enable SA_RESTART, otherwise we may accidentally
1076 * break some code which is not ready to signals/fuse interrupt.
1077 */
1078 sa.sa_flags = SA_RESTART;
1079
1080 sa.sa_handler = fuse_intr_sighandler;
1081 sigemptyset(&sa.sa_mask);
1082
1083 if (sigaction(signum, &sa, NULL) == -1)
1084 return log_error(-1, "cannot set interrupt signal handler\n");
1085
1086 return 0;
1087}
1088#endif
1089
cb61c9e1 1090#if HAVE_FUSE3
285aea40 1091static void *lxcfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
0d5383b7
CB
1092#else
1093static void *lxcfs_init(struct fuse_conn_info *conn)
1094#endif
285aea40 1095{
cb784d69
WB
1096 if (lxcfs_init_library() < 0)
1097 return NULL;
285aea40 1098
c2b4b508
AM
1099#if HAVE_FUSE3
1100 cfg->direct_io = 1;
3ea25890
AM
1101 cfg->intr = 1;
1102 cfg->intr_signal = LXCFS_INTR_SIGNAL;
c2b4b508
AM
1103#endif
1104
cb784d69 1105 return fuse_get_context()->private_data;
285aea40
CB
1106}
1107
758ad80c 1108const struct fuse_operations lxcfs_ops = {
971aa868
CB
1109 .access = lxcfs_access,
1110 .chmod = lxcfs_chmod,
1111 .chown = lxcfs_chown,
1112 .flush = lxcfs_flush,
1113 .fsync = lxcfs_fsync,
1114 .getattr = lxcfs_getattr,
285aea40 1115 .init = lxcfs_init,
971aa868
CB
1116 .mkdir = lxcfs_mkdir,
1117 .open = lxcfs_open,
1118 .opendir = lxcfs_opendir,
1119 .read = lxcfs_read,
1120 .readdir = lxcfs_readdir,
1121 .release = lxcfs_release,
1122 .releasedir = lxcfs_releasedir,
1123 .rmdir = lxcfs_rmdir,
1124 .truncate = lxcfs_truncate,
1125 .write = lxcfs_write,
26b717d0 1126 .readlink = lxcfs_readlink,
971aa868
CB
1127
1128 .create = NULL,
1129 .destroy = NULL,
cb61c9e1 1130#if !HAVE_FUSE3
971aa868 1131 .fgetattr = NULL,
f834b6bf 1132#endif
971aa868 1133 .fsyncdir = NULL,
cb61c9e1 1134#if !HAVE_FUSE3
971aa868
CB
1135 .ftruncate = NULL,
1136 .getdir = NULL,
f834b6bf 1137#endif
971aa868 1138 .getxattr = NULL,
971aa868
CB
1139 .link = NULL,
1140 .listxattr = NULL,
1141 .mknod = NULL,
971aa868
CB
1142 .rename = NULL,
1143 .removexattr = NULL,
1144 .setxattr = NULL,
1145 .statfs = NULL,
1146 .symlink = NULL,
1147 .unlink = NULL,
cb61c9e1 1148#if !HAVE_FUSE3
971aa868 1149 .utime = NULL,
f834b6bf 1150#endif
758ad80c
SH
1151};
1152
9b96e96e 1153static void usage(void)
758ad80c 1154{
a47192da 1155 lxcfs_info("Usage: lxcfs <directory>\n");
077d9d2f 1156 lxcfs_info("lxcfs is a FUSE-based proc, sys and cgroup virtualizing filesystem\n");
a47192da 1157 lxcfs_info("Options :");
b40c8afe 1158 lxcfs_info(" -d, --debug Run lxcfs with debugging enabled");
b40c8afe
CB
1159 lxcfs_info(" -f, --foreground Run lxcfs in the foreground");
1160 lxcfs_info(" -n, --help Print help");
1161 lxcfs_info(" -l, --enable-loadavg Enable loadavg virtualization");
1162 lxcfs_info(" -o Options to pass directly through fuse");
1163 lxcfs_info(" -p, --pidfile=FILE Path to use for storing lxcfs pid");
1164 lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH);
1165 lxcfs_info(" -u, --disable-swap Disable swap virtualization");
1166 lxcfs_info(" -v, --version Print lxcfs version");
23ffaadd 1167 lxcfs_info(" --enable-cfs Enable CPU virtualization via CPU shares");
b40c8afe 1168 lxcfs_info(" --enable-pidfd Use pidfd for process tracking");
b0073134 1169 exit(EXIT_FAILURE);
758ad80c
SH
1170}
1171
e190ee91
SH
1172static int set_pidfile(char *pidfile)
1173{
05b7a16d 1174 __do_close int fd = -EBADF;
971aa868
CB
1175 char buf[INTTYPE_TO_STRLEN(long)];
1176 int ret;
1177 struct flock fl = {
b4bc238c
CB
1178 .l_type = F_WRLCK,
1179 .l_whence = SEEK_SET,
1180 .l_start = 0,
1181 .l_len = 0,
971aa868 1182 };
e190ee91 1183
3326c17e 1184 fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | O_CLOEXEC);
971aa868
CB
1185 if (fd < 0)
1186 return log_error(-1, "Could not open pidfile %s: %m", pidfile);
e190ee91 1187
971aa868 1188 if (fcntl(fd, F_SETLK, &fl) < 0) {
12a60884 1189 if (errno == EAGAIN || errno == EACCES)
971aa868
CB
1190 return log_error(-1, "PID file '%s' is already locked", pidfile);
1191 lxcfs_error("Warning; unable to lock PID file, proceeding");
e190ee91
SH
1192 }
1193
12a60884 1194 if (ftruncate(fd, 0))
971aa868
CB
1195 return log_error(-1, "Error truncating PID file '%s': %m", pidfile);
1196
1197 ret = snprintf(buf, sizeof(buf), "%ld\n", (long)getpid());
3cf1e562 1198 if (ret < 0 || (size_t)ret >= sizeof(buf))
971aa868 1199 return log_error(-1, "Failed to convert pid to string %m");
e190ee91 1200
971aa868
CB
1201 if (write(fd, buf, ret) != ret)
1202 return log_error(-1, "Error writing to PID file '%s': %m", pidfile);
e190ee91 1203
12a60884 1204 return move_fd(fd);
e190ee91
SH
1205}
1206
64a7d94d 1207static const struct option long_options[] = {
1208 {"debug", no_argument, 0, 'd' },
1209 {"disable-swap", no_argument, 0, 'u' },
1210 {"enable-loadavg", no_argument, 0, 'l' },
1211 {"foreground", no_argument, 0, 'f' },
1212 {"help", no_argument, 0, 'h' },
1213 {"version", no_argument, 0, 'v' },
1214
1215 {"enable-cfs", no_argument, 0, 0 },
1216 {"enable-pidfd", no_argument, 0, 0 },
1217
1218 {"pidfile", required_argument, 0, 'p' },
1219 { },
1220};
1221
1222static int append_comma_separate(char **s, const char *append)
1223{
1224 int ret;
1225 char *news;
1226 size_t append_len, len;
1227
1228 if (!append)
1229 return 0;
1230
1231 append_len = strlen(append);
1232 if (!append_len)
1233 return 0;
1234
1235 if (*s) {
1236 len = strlen(*s);
1237 news = realloc(*s, len + append_len + 2);
1238 } else {
1239 len = 0;
1240 news = realloc(NULL, append_len + 1);
1241 }
1242 if (!news)
1243 return -ENOMEM;
1244
1245 if (*s)
1246 ret = snprintf(news + len, append_len + 2, ",%s", append);
1247 else
1248 ret = snprintf(news, append_len + 1, "%s", append);
1249 if (ret < 0)
1250 return -EIO;
1251
1252 *s = news;
1253 return 0;
1254}
1255
758ad80c
SH
1256int main(int argc, char *argv[])
1257{
05b7a16d 1258 int pidfile_fd = -EBADF;
47f5266f 1259 int ret = EXIT_FAILURE;
64a7d94d 1260 char *pidfile = NULL, *token = NULL;
bae92d21 1261 char pidfile_buf[STRLITERALLEN(RUNTIME_PATH) + STRLITERALLEN("/lxcfs.pid") + 1] = {};
51c38c8b 1262 bool debug = false, foreground = false;
cb61c9e1 1263#if !HAVE_FUSE3
51c38c8b
SP
1264 bool nonempty = false;
1265#endif
6db4f7a3 1266 bool load_use = false;
0b0f73db
SH
1267 /*
1268 * what we pass to fuse_main is:
1de81503 1269 * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
0b0f73db 1270 */
64a7d94d 1271 int fuse_argc = 0;
1272 int c, idx, new_argc;
1273 char *fuse_argv[7];
1274 const char *fuse_opts = NULL;
1275 char *new_fuse_opts = NULL;
1276 char *const *new_argv;
7e60aa1b 1277 struct lxcfs_opts *opts;
4ec5c9da 1278
7e60aa1b 1279 opts = malloc(sizeof(struct lxcfs_opts));
1280 if (opts == NULL) {
971aa868 1281 lxcfs_error("Error allocating memory for options");
7e60aa1b 1282 goto out;
1283 }
64a7d94d 1284
7e60aa1b 1285 opts->swap_off = false;
2aa59b2e 1286 opts->use_pidfd = false;
3b24c6c4 1287 opts->use_cfs = false;
285aea40 1288 opts->version = 1;
7e60aa1b 1289
64a7d94d 1290 while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) {
1291 switch (c) {
1292 case 0:
1293 if (strcmp(long_options[idx].name, "enable-pidfd") == 0)
1294 opts->use_pidfd = true;
1295 else if (strcmp(long_options[idx].name, "enable-cfs") == 0)
1296 opts->use_cfs = true;
1297 else
1298 usage();
1299 break;
1300 case 'd':
1301 debug = true;
1302 break;
1303 case 'f':
1304 foreground = true;
1305 break;
1306 case 'l':
1307 load_use = true;
1308 break;
1309 case 'o':
1310 if (fuse_opts) {
1311 lxcfs_error("Specifying -o multiple times is unsupported");
1312 usage();
1313 }
b0073134 1314
64a7d94d 1315 fuse_opts = optarg;
1316 break;
1317 case 'p':
1318 pidfile = optarg;
1319 break;
1320 case 's':
1321 /* legacy argument: ignore */
1322 break;
1323 case 'u':
1324 opts->swap_off = true;
1325 break;
10deeaaf 1326 case 'v':
10deeaaf 1327 lxcfs_info("%s", STRINGIFY(PROJECT_VERSION));
1328 exit(EXIT_SUCCESS);
64a7d94d 1329 default:
1330 usage();
1331 }
1332 }
b0073134
CB
1333
1334 if (foreground && debug)
1335 log_exit("Both --debug and --forgreound specified");
1336
64a7d94d 1337 new_argv = &argv[optind];
1338 new_argc = argc - optind;
c021765e
CB
1339
1340 /* Older LXCFS versions printed help when used without any argument. */
1341 if (new_argc == 0)
10deeaaf 1342 usage();
c021765e 1343
64a7d94d 1344 if (new_argc != 1) {
1345 lxcfs_error("Missing mountpoint");
1346 goto out;
1347 }
1348
1349 fuse_argv[fuse_argc++] = argv[0];
1350 if (debug)
1351 fuse_argv[fuse_argc++] = "-d";
1352 else
1353 fuse_argv[fuse_argc++] = "-f";
1354 fuse_argv[fuse_argc++] = "-o";
1355
1356 /* Parse additional fuse options. */
1357 if (fuse_opts) {
1358 char *dup;
1359
1360 dup = strdup(fuse_opts);
1361 if (!dup) {
1362 lxcfs_error("Failed to copy fuse options");
1363 goto out;
1364 }
1365
1366 lxc_iterate_parts(token, dup, ",") {
1367 /* default */
1368 if (strcmp(token, "allow_other") == 0)
1369 continue;
1370
1371 /* default for LXCFS */
1372 if (strcmp(token, "direct_io") == 0)
1373 continue;
1374
1375 /* default for LXCFS */
1376 if (strncmp(token, "entry_timeout", STRLITERALLEN("entry_timeout")) == 0)
1377 continue;
1378
1379 /* default for LXCFS */
1380 if (strncmp(token, "attr_timeout", STRLITERALLEN("entry_timeout")) == 0)
1381 continue;
1382
1383 /* default for LXCFS */
1384 if (strncmp(token, "allow_other", STRLITERALLEN("allow_other")) == 0)
1385 continue;
1386
1387 /* default with fuse3 */
1388 if (strcmp(token, "nonempty") == 0) {
cb61c9e1 1389 #if !HAVE_FUSE3
482a80d4 1390 nonempty = true;
64a7d94d 1391 #endif
1392 continue;
1393 }
1394
1395 if (append_comma_separate(&new_fuse_opts, token)) {
1396 lxcfs_error("Failed to copy fuse argument \"%s\"", token);
1397 free(dup);
1398 goto out;
482a80d4 1399 }
e190ee91 1400 }
64a7d94d 1401 free(dup);
e190ee91 1402 }
b0073134 1403
64a7d94d 1404 if (append_comma_separate(&new_fuse_opts, "allow_other,entry_timeout=0.5,attr_timeout=0.5")) {
1405 lxcfs_error("Failed to copy fuse argument \"allow_other,entry_timeout=0.5,attr_timeout=0.5\"");
1406 goto out;
2e9c0b32 1407 }
23b42f47 1408
cb61c9e1 1409#if !HAVE_FUSE3
64a7d94d 1410 if (nonempty) {
1411 if (append_comma_separate(&new_fuse_opts, "nonempty")) {
1412 lxcfs_error("Failed to copy fuse argument \"nonempty\"");
1413 goto out;
1414 }
1415 }
758ad80c 1416
64a7d94d 1417 if (append_comma_separate(&new_fuse_opts, "direct_io")) {
1affba53 1418 lxcfs_error("Failed to copy fuse argument \"direct_io\"");
47f5266f 1419 goto out;
8fad16cd 1420 }
64a7d94d 1421#endif
8a03c08b
CB
1422
1423 /*
1424 * We can't use default_permissions since we still support systems that
1425 * don't have kernels with cgroup namespace support. On such kernels
1426 * lxcfs will provide a namespaced cgroup view and needs explicit
1427 * access helpers to make that work.
1428 * Another reason that came to me is that we can't or at least
1429 * shouldn't guarantee that we don't need more complicated access
1430 * helpers for proc and sys virtualization in the future.
1431 */
64a7d94d 1432
1433 fuse_argv[fuse_argc++] = new_fuse_opts;
1434 fuse_argv[fuse_argc++] = new_argv[0];
1435 fuse_argv[fuse_argc] = NULL;
1436
5976d034 1437 do_reload(false);
64a7d94d 1438 if (install_signal_handler(SIGUSR1, sigusr1_reload)) {
1439 lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno));
1440 goto out;
1441 }
758ad80c 1442
3ea25890
AM
1443#if HAVE_FUSE3
1444 if (fuse_init_intr_signal(LXCFS_INTR_SIGNAL)) {
1445 lxcfs_error("Failed to install fuse interrupt signal handler");
1446 goto out;
1447 }
1448#endif
1449
e190ee91 1450 if (!pidfile) {
bae92d21
CB
1451 snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH);
1452 pidfile = pidfile_buf;
e190ee91 1453 }
ed5ee4f9
CB
1454
1455 pidfile_fd = set_pidfile(pidfile);
1456 if (pidfile_fd < 0)
e190ee91
SH
1457 goto out;
1458
a83618e2
JS
1459 if (load_use && start_loadavg() != 0)
1460 goto out;
6db4f7a3 1461
64a7d94d 1462 if (!fuse_main(fuse_argc, fuse_argv, &lxcfs_ops, opts))
47f5266f 1463 ret = EXIT_SUCCESS;
51c38c8b 1464
a83618e2
JS
1465 if (load_use)
1466 stop_loadavg();
237e200e 1467
c0adec85 1468out:
47f5266f
CB
1469 if (dlopen_handle)
1470 dlclose(dlopen_handle);
1471 if (pidfile)
1472 unlink(pidfile);
64a7d94d 1473 free(new_fuse_opts);
b58c203b 1474 free(opts);
05b7a16d 1475 close_prot_errno_disarm(pidfile_fd);
47f5266f 1476 exit(ret);
2183082c 1477}