diff --git a/Makefile.am b/Makefile.am --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,7 @@ lxcfs_LTLIBRARIES = liblxcfs.la EXTRA_LTLIBRARIES = liblxcfstest.la lxcfs_SOURCES = lxcfs.c -lxcfs_LDADD = -ldl +lxcfs_LDADD = -ldl -lsecurec lxcfs_CFLAGS = $(AM_CFLAGS) lxcfs_LDFLAGS = $(AM_LDFLAGS) bin_PROGRAMS = lxcfs diff --git a/bindings.c b/bindings.c --- a/bindings.c +++ b/bindings.c @@ -39,6 +39,7 @@ #include "bindings.h" #include "config.h" // for VERSION +#include "securec.h" /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */ #define LXCFS_NUMSTRLEN64 21 @@ -67,6 +68,7 @@ enum { LXC_TYPE_PROC_STAT, LXC_TYPE_PROC_DISKSTATS, LXC_TYPE_PROC_SWAPS, + LXC_TYPE_PROC_PARTITIONS, }; struct file_info { @@ -112,7 +114,7 @@ struct pidns_init_store { static struct pidns_init_store *pidns_hash_table[PIDNS_HASH_SIZE]; static pthread_mutex_t pidns_store_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t slurp_file_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t diskstats_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t container_dev_mutex = PTHREAD_MUTEX_INITIALIZER; static void lock_mutex(pthread_mutex_t *l) { int ret; @@ -4226,9 +4228,9 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset, if (!f) goto err; - lock_mutex(&diskstats_mutex); + lock_mutex(&container_dev_mutex); container_devinfo = container_dev_read(initpid); - unlock_mutex(&diskstats_mutex); + unlock_mutex(&container_dev_mutex); while (getline(&line, &linelen, f) != -1) { ssize_t l; @@ -4426,6 +4428,132 @@ err: return rv; } +static int proc_partitions_read(char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int ret = 0; + char dev_name[72] = {0}; + struct fuse_context *fc = fuse_get_context(); + struct file_info *d = (struct file_info *)fi->fh; + struct devinfo *container_devinfo = NULL, *ptr = NULL; + char *cg = NULL; + char *cache = d->buf; + size_t cache_size = d->buflen; + char *line = NULL; + size_t linelen = 0, total_len = 0; + int rv = 0; + unsigned int major = 0, minor = 0; + unsigned long long blocks = 0; + int i = 0, lines = 0; + bool found = false; + FILE *f = NULL; + + if (offset > 0){ + if (offset > d->size) + return -EINVAL; + if (d->cached == 0) + return 0; + int left = d->size - offset; + total_len = left > size ? size: left; + ret = memcpy_s(buf, size, cache + offset, total_len); + if (ret != 0) { + lxcfs_error("%s\n", "Internal error: memcpy buf failed"); + rv = 0; + goto err; + } + + return total_len; + } + + pid_t initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 0) + initpid = fc->pid; + cg = get_pid_cgroup(initpid, "blkio"); + if (cg == NULL) + return read_file("/proc/partitions", buf, size, d); + prune_init_slice(cg); + + f = fopen("/proc/partitions", "r"); + if (f == NULL) + goto err; + + lock_mutex(&container_dev_mutex); + container_devinfo = container_dev_read(initpid); + unlock_mutex(&container_dev_mutex); + + while (getline(&line, &linelen, f) != -1) { + ssize_t l; + char lbuf[256]; + + if (lines < 2) { + ret = strncpy_s(lbuf, 256, line, 255); + if (ret != 0) { + lxcfs_error("%s\n", "Internal error: strncpy line failed"); + rv = 0; + goto err; + } + + lines++; + } else { + ret = memset_s(dev_name, sizeof(dev_name), 0, sizeof(dev_name)); + if (ret != 0) { + lxcfs_error("%s\n", "Internal error: memset devname failed"); + rv = 0; + goto err; + } + + i = sscanf(line, "%u %u %llu %71s", &major, &minor, &blocks, dev_name); + if (i != 4) + continue; + found = false; + for (ptr = container_devinfo; ptr != NULL; ptr = ptr->next) { + if (major == ptr->major && minor == ptr->minor) { + snprintf(lbuf, 256, "%4u %7u %10llu %s\n", major, minor, blocks, ptr->name); + found = true; + } + } + if (!found) + continue; + } + + l = snprintf(cache, cache_size, "%s", lbuf); + if (l < 0) { + perror("Error writing to fuse buf"); + rv = 0; + goto err; + } + if (l >= cache_size) { + lxcfs_error("%s\n", "Internal error: truncated write to cache."); + rv = 0; + goto err; + } + cache += l; + cache_size -= l; + total_len += l; + } + d->cached = 1; + d->size = total_len; + if (total_len > size ) + total_len = size; + + ret = memcpy_s(buf, size, d->buf, total_len); + if (ret != 0) { + lxcfs_error("%s\n", "Internal error: memcpy buf failed"); + rv = 0; + goto err; + } + + rv = total_len; +err: + free(cg); + if (f != NULL) + fclose(f); + free(line); + line = NULL; + free_devinfo_list(container_devinfo); + return rv; +} + static off_t get_procfile_size(const char *which) { FILE *f = fopen(which, "r"); @@ -4463,7 +4591,8 @@ int proc_getattr(const char *path, struct stat *sb) strcmp(path, "/proc/uptime") == 0 || strcmp(path, "/proc/stat") == 0 || strcmp(path, "/proc/diskstats") == 0 || - strcmp(path, "/proc/swaps") == 0) { + strcmp(path, "/proc/swaps") == 0 || + strcmp(path, "/proc/partitions") == 0) { sb->st_size = 0; sb->st_mode = S_IFREG | 00444; sb->st_nlink = 1; @@ -4483,7 +4612,8 @@ int proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offs filler(buf, "stat", NULL, 0) != 0 || filler(buf, "uptime", NULL, 0) != 0 || filler(buf, "diskstats", NULL, 0) != 0 || - filler(buf, "swaps", NULL, 0) != 0) + filler(buf, "swaps", NULL, 0) != 0 || + filler(buf, "partitions", NULL, 0) != 0) return -EINVAL; return 0; } @@ -4507,6 +4637,8 @@ int proc_open(const char *path, struct fuse_file_info *fi) type = LXC_TYPE_PROC_DISKSTATS; else if (strcmp(path, "/proc/swaps") == 0) type = LXC_TYPE_PROC_SWAPS; + else if (strcmp(path, "/proc/partitions") == 0) + type = LXC_TYPE_PROC_PARTITIONS; if (type == -1) return -ENOENT; @@ -4568,6 +4700,8 @@ int proc_read(const char *path, char *buf, size_t size, off_t offset, return proc_diskstats_read(buf, size, offset, fi); case LXC_TYPE_PROC_SWAPS: return proc_swaps_read(buf, size, offset, fi); + case LXC_TYPE_PROC_PARTITIONS: + return proc_partitions_read(buf, size, offset, fi); default: return -EINVAL; } -- 1.8.3.1