]> git.proxmox.com Git - mirror_lxcfs.git/commitdiff
sys: virtualize /sys/devices/system/cpu/cpu*
authorZhiwei Li <cyzz_a102@126.com>
Tue, 18 May 2021 07:03:01 +0000 (15:03 +0800)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 26 May 2021 08:36:45 +0000 (10:36 +0200)
Signed-off-by: Zhiwei Li <cyzz_a102@126.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
README.md
src/bindings.h
src/lxcfs.c
src/sysfs_fuse.c
src/sysfs_fuse.h

index 54d3eabfcaf572172ccaa61087937b9523759411..ff65f75c3ec00cb03747cad9820c88bde5a24f6c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ such as:
 /proc/swaps
 /proc/uptime
 /proc/slabinfo
+/sys/devices/system/cpu
 /sys/devices/system/cpu/online
 ```
 
index dc0c23e1a5d1f84df01045f43d8ec10eddda71e2..460639abbc0c6d2a6aa07e4ebf652ae92db5665e 100644 (file)
@@ -65,9 +65,12 @@ enum lxcfs_virt_t {
        LXC_TYPE_PROC_SLABINFO,
 #define LXC_TYPE_PROC_SLABINFO_PATH "/proc/slabinfo"
 
+       LXC_TYPE_SYS,
        LXC_TYPE_SYS_DEVICES,
        LXC_TYPE_SYS_DEVICES_SYSTEM,
        LXC_TYPE_SYS_DEVICES_SYSTEM_CPU,
+       LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBDIR,
+       LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBFILE,
 
        LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE,
 #define LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH "/sys/devices/system/cpu/online"
index e1db84c4bf861f34475ed3b665fa673e5e093ff3..88a5cf400ef69658e6e18810818c6b686f7a19f3 100644 (file)
@@ -298,6 +298,22 @@ static int do_cg_write(const char *path, const char *buf, size_t size,
        return __cg_write(path, buf, size, offset, fi);
 }
 
+static int do_sys_write(const char *path, const char *buf, size_t size,
+                      off_t offset, struct fuse_file_info *fi)
+{
+       char *error;
+       int (*__sys_write)(const char *path, const char *buf, size_t size,
+                         off_t offset, struct fuse_file_info *fi);
+
+       dlerror();
+       __sys_write = (int (*)(const char *, const char *, size_t, off_t, struct fuse_file_info *))dlsym(dlopen_handle, "sys_write");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_write()", error);
+
+       return __sys_write(path, buf, size, offset, fi);
+}
+
 static int do_cg_mkdir(const char *path, mode_t mode)
 {
        char *error;
@@ -402,6 +418,19 @@ static int do_sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
        return __sys_readdir(path, buf, filler, offset, fi);
 }
 
+static int do_sys_readlink(const char *path, char *buf, size_t size)
+{
+       char *error;
+       int (*__sys_readlink)(const char *path, char *buf, size_t size);
+
+       dlerror();
+       __sys_readlink = (int (*)(const char *, char *, size_t))dlsym(dlopen_handle, "sys_readlink");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_readlink()", error);
+
+       return __sys_readlink(path, buf, size);
+}
 
 static int do_cg_open(const char *path, struct fuse_file_info *fi)
 {
@@ -473,6 +502,20 @@ static int do_sys_open(const char *path, struct fuse_file_info *fi)
        return __sys_open(path, fi);
 }
 
+static int do_sys_opendir(const char *path, struct fuse_file_info *fi)
+{
+       char *error;
+       int (*__sys_opendir)(const char *path, struct fuse_file_info *fi);
+
+       dlerror();
+       __sys_opendir = (int (*)(const char *path, struct fuse_file_info *fi))dlsym(dlopen_handle, "sys_opendir");
+       error = dlerror();
+       if (error)
+               return log_error(-1, "%s - Failed to find sys_opendir()", error);
+
+       return __sys_opendir(path, fi);
+}
+
 static int do_sys_access(const char *path, int mode)
 {
        char *error;
@@ -632,8 +675,12 @@ static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
        if (strcmp(path, "/proc") == 0)
                return 0;
 
-       if (strncmp(path, "/sys", 4) == 0)
-               return 0;
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_opendir(path, fi);
+               down_users();
+               return ret;
+       }
 
        return -ENOENT;
 }
@@ -810,6 +857,27 @@ int lxcfs_write(const char *path, const char *buf, size_t size, off_t offset,
                return ret;
        }
 
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_write(path, buf, size, offset, fi);
+               down_users();
+               return ret;
+       }
+
+       return -EINVAL;
+}
+
+int lxcfs_readlink(const char *path, char *buf, size_t size)
+{
+       int ret;
+
+       if (strncmp(path, "/sys", 4) == 0) {
+               up_users();
+               ret = do_sys_readlink(path, buf, size);
+               down_users();
+               return ret;
+       }
+
        return -EINVAL;
 }
 
@@ -903,6 +971,9 @@ int lxcfs_truncate(const char *path, off_t newsize)
        if (strncmp(path, "/cgroup", 7) == 0)
                return 0;
 
+       if (strncmp(path, "/sys", 4) == 0)
+               return 0;
+
        return -EPERM;
 }
 
@@ -961,6 +1032,7 @@ const struct fuse_operations lxcfs_ops = {
        .rmdir          = lxcfs_rmdir,
        .truncate       = lxcfs_truncate,
        .write          = lxcfs_write,
+       .readlink       = lxcfs_readlink,
 
        .create         = NULL,
        .destroy        = NULL,
@@ -977,7 +1049,6 @@ const struct fuse_operations lxcfs_ops = {
        .link           = NULL,
        .listxattr      = NULL,
        .mknod          = NULL,
-       .readlink       = NULL,
        .rename         = NULL,
        .removexattr    = NULL,
        .setxattr       = NULL,
index b5585fb3585cf42af740356e0e1054bd808dfe0a..8f7b3ea904acc6a2024534f3df15f12e6ce9d797 100644 (file)
 #endif
 #endif
 
+/* Taken over modified from the kernel sources. */
+#define NBITS 32 /* bits in uint32_t */
+#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, NBITS)
+
 #define _FILE_OFFSET_BITS 64
 
 #define __STDC_FORMAT_MACROS
 #include "sysfs_fuse.h"
 #include "utils.h"
 
+static ssize_t get_max_cpus(char *cpulist)
+{
+       char *c1, *c2;
+       char *maxcpus = cpulist;
+       size_t cpus = 0;
+
+       c1 = strrchr(maxcpus, ',');
+       if (c1)
+               c1++;
+
+       c2 = strrchr(maxcpus, '-');
+       if (c2)
+               c2++;
+
+       if (!c1 && !c2)
+               c1 = maxcpus;
+       else if (c1 > c2)
+               c2 = c1;
+       else if (c1 < c2)
+               c1 = c2;
+       else if (!c1 && c2)
+               c1 = c2;
+
+       errno = 0;
+       cpus = strtoul(c1, NULL, 0);
+       if (errno != 0)
+               return -1;
+
+       return cpus;
+}
+
+static void set_bit(unsigned bit, uint32_t *bitarr)
+{
+       bitarr[bit / NBITS] |= (1 << (bit % NBITS));
+}
+
+static bool is_set(unsigned bit, uint32_t *bitarr)
+{
+       return (bitarr[bit / NBITS] & (1 << (bit % NBITS))) != 0;
+}
+
+/* Create cpumask from cpulist aka turn:
+ *
+ *     0,2-3
+ *
+ * into bit array
+ *
+ *     1 0 1 1
+ */
+static uint32_t *lxc_cpumask(char *buf, size_t nbits)
+{
+       __do_free uint32_t *bitarr = NULL;
+       char *token;
+       size_t arrlen;
+
+       arrlen = BITS_TO_LONGS(nbits);
+       bitarr = calloc(arrlen, sizeof(uint32_t));
+       if (!bitarr)
+               return ret_set_errno(NULL, ENOMEM);
+
+       lxc_iterate_parts(token, buf, ",") {
+               errno = 0;
+               unsigned end, start;
+               char *range;
+
+               start = strtoul(token, NULL, 0);
+               end = start;
+               range = strchr(token, '-');
+               if (range)
+                       end = strtoul(range + 1, NULL, 0);
+
+               if (!(start <= end))
+                       return ret_set_errno(NULL, EINVAL);
+
+               if (end >= nbits)
+                       return ret_set_errno(NULL, EINVAL);
+
+               while (start <= end)
+                       set_bit(start++, bitarr);
+       }
+
+       return move_ptr(bitarr);
+}
+
 static int sys_devices_system_cpu_online_read(char *buf, size_t size,
                                              off_t offset,
                                              struct fuse_file_info *fi)
@@ -101,6 +190,7 @@ static int sys_devices_system_cpu_online_read(char *buf, size_t size,
                use_view = true;
        else
                use_view = false;
+
        if (use_view)
                max_cpus = max_cpu_count(cg);
 
@@ -126,6 +216,85 @@ static int sys_devices_system_cpu_online_read(char *buf, size_t size,
        return total_len;
 }
 
+static int filler_sys_devices_system_cpu(const char *path, void *buf,
+                                        fuse_fill_dir_t filler)
+{
+       __do_free uint32_t *cpumask = NULL;
+       __do_free char *cg = NULL, *cpuset = NULL;
+       __do_closedir DIR *dir = NULL;
+       struct dirent *dirent;
+       struct fuse_context *fc = fuse_get_context();
+       pid_t initpid;
+       ssize_t max_cpus;
+       size_t len;
+       char cpu[100];
+
+       initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 1 || is_shared_pidns(initpid))
+               initpid = fc->pid;
+
+       cg = get_pid_cgroup(initpid, "cpuset");
+       if (!cg)
+               return 0;
+       prune_init_slice(cg);
+
+       cpuset = get_cpuset(cg);
+       if (!cpuset)
+               return 0;
+
+       max_cpus = get_max_cpus(cpuset);
+       if (max_cpus < 0 || max_cpus >= (INT_MAX - 1))
+               return -1;
+       max_cpus++;
+
+       cpumask = lxc_cpumask(cpuset, max_cpus);
+       if (!cpumask)
+               return -errno;
+
+       for (size_t i = 0; i < max_cpus; i++) {
+               int ret;
+
+               if (!is_set(i, cpumask))
+                       continue;
+
+               ret = snprintf(cpu, sizeof(cpu), "cpu%ld", i);
+               if (ret < 0 || ret >= sizeof(cpu))
+                       continue;
+
+               if (DIR_FILLER(filler, buf, cpu, NULL, 0) != 0)
+                       return -ENOENT;
+       }
+
+       dir = opendir(path);
+       if (!dir)
+               return -ENOENT;
+
+       while ((dirent = readdir(dir))) {
+               len = strlen(dirent->d_name);
+               if (strncmp(dirent->d_name, "cpu", 3) == 0 &&
+                   dirent->d_name[len - 1] >= '0' &&
+                   dirent->d_name[len - 1] <= '9')
+                       continue;
+
+               if (DIR_FILLER(filler, buf, dirent->d_name, NULL, 0) != 0)
+                       return -ENOENT;
+       }
+
+       return 0;
+}
+
+static mode_t get_st_mode(const char *path)
+{
+       struct stat sb;
+       int ret;
+
+       ret = lstat(path, &sb);
+       if (ret < 0)
+               return -ENOENT;
+
+       return sb.st_mode;
+}
+
 static off_t get_sysfile_size(const char *which)
 {
        __do_fclose FILE *f = NULL;
@@ -146,6 +315,10 @@ static off_t get_sysfile_size(const char *which)
 __lxcfs_fuse_ops int sys_getattr(const char *path, struct stat *sb)
 {
        struct timespec now;
+       mode_t st_mode;
+
+       if (!liblxcfs_functional())
+               return -EIO;
 
        memset(sb, 0, sizeof(struct stat));
        if (clock_gettime(CLOCK_REALTIME, &now) < 0)
@@ -153,33 +326,20 @@ __lxcfs_fuse_ops int sys_getattr(const char *path, struct stat *sb)
 
        sb->st_uid = sb->st_gid = 0;
        sb->st_atim = sb->st_mtim = sb->st_ctim = now;
-       if (strcmp(path, "/sys") == 0) {
-               sb->st_mode = S_IFDIR | 00555;
-               sb->st_nlink = 2;
-               return 0;
-       }
 
-       if (strcmp(path, "/sys/devices") == 0) {
-               sb->st_mode = S_IFDIR | 00555;
-               sb->st_nlink = 2;
-               return 0;
-       }
-
-       if (strcmp(path, "/sys/devices/system") == 0) {
-               sb->st_mode = S_IFDIR | 00555;
-               sb->st_nlink = 2;
-               return 0;
-       }
+       st_mode = get_st_mode(path);
+       if (st_mode < 0)
+               return -ENOENT;
 
-       if (strcmp(path, "/sys/devices/system/cpu") == 0) {
-               sb->st_mode = S_IFDIR | 00555;
+       if (S_ISDIR(st_mode)) {
+               sb->st_mode = st_mode;
                sb->st_nlink = 2;
                return 0;
        }
 
-       if (strcmp(path, "/sys/devices/system/cpu/online") == 0) {
-               sb->st_size = get_sysfile_size (path);
-               sb->st_mode = S_IFREG | 00444;
+       if (S_ISREG(st_mode) || S_ISLNK(st_mode)) {
+               sb->st_size = get_sysfile_size(path);
+               sb->st_mode = st_mode;
                sb->st_nlink = 1;
                return 0;
        }
@@ -187,59 +347,111 @@ __lxcfs_fuse_ops int sys_getattr(const char *path, struct stat *sb)
        return -ENOENT;
 }
 
+__lxcfs_fuse_ops int sys_write(const char *path, const char *buf,
+                       size_t size, off_t offset,
+                       struct fuse_file_info *fi)
+{
+       __do_close int fd = -EBADF;
+       struct file_info *f = INTTYPE_TO_PTR(fi->fh);
+
+       if (!liblxcfs_functional())
+               return -EIO;
+
+       if (f->type != LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBFILE)
+               return -EINVAL;
+
+       fd = open(path, O_WRONLY | O_CLOEXEC);
+       if (fd == -1)
+               return -errno;
+
+       return pwrite(fd, buf, size, offset);
+}
+
 __lxcfs_fuse_ops int sys_readdir(const char *path, void *buf,
-                                fuse_fill_dir_t filler, off_t offset,
-                                struct fuse_file_info *fi)
+                               fuse_fill_dir_t filler, off_t offset,
+                               struct fuse_file_info *fi)
 {
-       if (strcmp(path, "/sys") == 0) {
-               if (DIR_FILLER(filler, buf, ".",        NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "..",       NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "devices",  NULL, 0) != 0)
-                       return -ENOENT;
+       __do_closedir DIR *dir = NULL;
+       struct dirent *dirent;
+       struct file_info *f = INTTYPE_TO_PTR(fi->fh);
 
-               return 0;
-       }
-       if (strcmp(path, "/sys/devices") == 0) {
-               if (DIR_FILLER(filler, buf, ".",        NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "..",       NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "system",   NULL, 0) != 0)
-                       return -ENOENT;
+       if (!liblxcfs_functional())
+               return -EIO;
 
-               return 0;
-       }
-       if (strcmp(path, "/sys/devices/system") == 0) {
-               if (DIR_FILLER(filler, buf, ".",        NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "..",       NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "cpu",      NULL, 0) != 0)
-                       return -ENOENT;
+       switch (f->type) {
+       case LXC_TYPE_SYS: {
+                       if (DIR_FILLER(filler, buf, ".",    NULL, 0) != 0 ||
+                           DIR_FILLER(filler, buf, "..",   NULL, 0) != 0 ||
+                           DIR_FILLER(filler, buf, "devices",  NULL, 0) != 0)
+                                       return -ENOENT;
 
-               return 0;
-       }
-       if (strcmp(path, "/sys/devices/system/cpu") == 0) {
-               if (DIR_FILLER(filler, buf, ".",        NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "..",       NULL, 0) != 0 ||
-                   DIR_FILLER(filler, buf, "online",   NULL, 0) != 0)
-                       return -ENOENT;
+                       return 0;
+               }
+       case LXC_TYPE_SYS_DEVICES: {
+                       if (DIR_FILLER(filler, buf, ".",    NULL, 0) != 0 ||
+                           DIR_FILLER(filler, buf, "..",   NULL, 0) != 0 ||
+                           DIR_FILLER(filler, buf, "system",  NULL, 0) != 0)
+                                       return -ENOENT;
 
-               return 0;
+                       return 0;
+               }
+       case LXC_TYPE_SYS_DEVICES_SYSTEM: {
+                       if (DIR_FILLER(filler, buf, ".",    NULL, 0) != 0 ||
+                           DIR_FILLER(filler, buf, "..",   NULL, 0) != 0 ||
+                           DIR_FILLER(filler, buf, "cpu",  NULL, 0) != 0)
+                                       return -ENOENT;
+
+                       return 0;
+               }
+       case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
+                       return filler_sys_devices_system_cpu(path, buf, filler);
+       case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBDIR: {
+                       dir = opendir(path);
+                       if (!dir)
+                               return -ENOENT;
+
+                       while ((dirent = readdir(dir))) {
+                               if (DIR_FILLER(filler, buf, dirent->d_name, NULL, 0) != 0)
+                                       return -ENOENT;
+                       }
+
+                       return 0;
+               }
        }
 
-       return 0;
+       return -EINVAL;
 }
 
+__lxcfs_fuse_ops int sys_readlink(const char *path, char *buf, size_t size)
+{
+       int ret = readlink(path, buf, size);
+
+       if (!liblxcfs_functional())
+               return -EIO;
+
+       if (ret < 0)
+               return -errno;
+       if (ret > size)
+               return -1;
+
+       buf[ret] = '\0';
+
+       return 0;
+}
 __lxcfs_fuse_ops int sys_open(const char *path, struct fuse_file_info *fi)
 {
        __do_free struct file_info *info = NULL;
        int type = -1;
 
-       if (strcmp(path, "/sys/devices") == 0)
-               type = LXC_TYPE_SYS_DEVICES;
-       if (strcmp(path, "/sys/devices/system") == 0)
-               type = LXC_TYPE_SYS_DEVICES_SYSTEM;
-       if (strcmp(path, "/sys/devices/system/cpu") == 0)
-               type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
+       if (!liblxcfs_functional())
+               return -EIO;
+
        if (strcmp(path, "/sys/devices/system/cpu/online") == 0)
                type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE;
+       else if (strncmp(path, "/sys/devices/system/cpu/",
+                        STRLITERALLEN("/sys/devices/system/cpu/")) == 0 &&
+                S_ISREG(get_st_mode(path)))
+               type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBFILE;
        if (type == -1)
                return -ENOENT;
 
@@ -264,28 +476,51 @@ __lxcfs_fuse_ops int sys_open(const char *path, struct fuse_file_info *fi)
        return 0;
 }
 
-__lxcfs_fuse_ops int sys_access(const char *path, int mask)
+__lxcfs_fuse_ops int sys_opendir(const char *path, struct fuse_file_info *fi)
 {
-       if (strcmp(path, "/sys") == 0 && access(path, R_OK) == 0)
-               return 0;
+       __do_free struct file_info *dir_info = NULL;
+       int type = -1;
 
-       if (strcmp(path, "/sys/devices") == 0 && access(path, R_OK) == 0)
-               return 0;
+       if (!liblxcfs_functional())
+               return -EIO;
 
-       if (strcmp(path, "/sys/devices/system") == 0 && access(path, R_OK) == 0)
-               return 0;
+       if (strcmp(path, "/sys") == 0)
+               type = LXC_TYPE_SYS;
+       if (strcmp(path, "/sys/devices") == 0)
+               type = LXC_TYPE_SYS_DEVICES;
+       if (strcmp(path, "/sys/devices/system") == 0)
+               type = LXC_TYPE_SYS_DEVICES_SYSTEM;
+       if (strcmp(path, "/sys/devices/system/cpu") == 0)
+               type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
+       if (strncmp(path, "/sys/devices/system/cpu/",
+                   STRLITERALLEN("/sys/devices/system/cpu/")) == 0 &&
+           S_ISDIR(get_st_mode(path)))
+               type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBDIR;
+       if (type == -1)
+               return -ENOENT;
 
-       if (strcmp(path, "/sys/devices/system/cpu") == 0 &&
-           access(path, R_OK) == 0)
-               return 0;
+       dir_info = malloc(sizeof(*dir_info));
+       if (!dir_info)
+               return -ENOMEM;
 
-       /* these are all read-only */
-       if ((mask & ~R_OK) != 0)
-               return -EACCES;
+       memset(dir_info, 0, sizeof(*dir_info));
+       dir_info->type = type;
+       dir_info->buf = NULL;
+       dir_info->file = NULL;
+       dir_info->buflen = 0;
 
+       fi->fh = PTR_TO_UINT64(move_ptr(dir_info));
        return 0;
 }
 
+__lxcfs_fuse_ops int sys_access(const char *path, int mask)
+{
+       if (!liblxcfs_functional())
+               return -EIO;
+
+       return access(path, mask);
+}
+
 __lxcfs_fuse_ops int sys_release(const char *path, struct fuse_file_info *fi)
 {
        do_release_file_info(fi);
@@ -299,23 +534,18 @@ __lxcfs_fuse_ops int sys_releasedir(const char *path, struct fuse_file_info *fi)
 }
 
 __lxcfs_fuse_ops int sys_read(const char *path, char *buf, size_t size,
-                             off_t offset, struct fuse_file_info *fi)
+                       off_t offset, struct fuse_file_info *fi)
 {
        struct file_info *f = INTTYPE_TO_PTR(fi->fh);
 
+       if (!liblxcfs_functional())
+               return -EIO;
+
        switch (f->type) {
        case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE:
-               if (liblxcfs_functional())
-                       return sys_devices_system_cpu_online_read(buf, size, offset, fi);
-
-               return read_file_fuse_with_offset(LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH,
-                                                 buf, size, offset, f);
-       case LXC_TYPE_SYS_DEVICES:
-               break;
-       case LXC_TYPE_SYS_DEVICES_SYSTEM:
-               break;
-       case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
-               break;
+               return sys_devices_system_cpu_online_read(buf, size, offset, fi);
+       case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_SUBFILE:
+               return read_file_fuse_with_offset(path, buf, size, offset, f);
        }
 
        return -EINVAL;
index b9b965f85ed6fe9697130f5b80b6dd3a6ebccd2b..592e8ecb7be1de9912efc8723a42b998b7723150 100644 (file)
 
 __visible extern int sys_getattr(const char *path, struct stat *sb);
 __visible extern int sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi);
+__visible extern int sys_readlink(const char *path, char *buf, size_t size);
 __visible extern int sys_release(const char *path, struct fuse_file_info *fi);
 __visible extern int sys_releasedir(const char *path, struct fuse_file_info *fi);
 __visible extern int sys_open(const char *path, struct fuse_file_info *fi);
+__visible extern int sys_opendir(const char *path, struct fuse_file_info *fi);
 __visible extern int sys_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi);
+__visible extern int sys_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi);
 __visible extern int sys_access(const char *path, int mask);
 
 #endif /* __LXCFS_SYSFS_FUSE_H */