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