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