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