diff --git a/bindings.c b/bindings.c index 6387012..91de9f9 100644 --- a/bindings.c +++ b/bindings.c @@ -3743,12 +3743,136 @@ static int proc_uptime_read(char *buf, size_t size, off_t offset, return total_len; } +struct devinfo { + char name[100]; + int major, minor; + struct devinfo *next; +}; + +int getns(pid_t pid, char *ns_type) +{ + char fpath[100]; + memset(fpath, 0, sizeof(fpath)); + snprintf(fpath, 99, "/proc/%d/ns/%s", pid, ns_type); + return open(fpath, O_RDONLY); +} + +struct devinfo* container_dev_read(pid_t pid) { + int nsfd; + DIR *dir; + struct dirent *ptr; + struct stat dev_stat; + struct devinfo *head = NULL, *end; + char fpath[100], dev_name[100]; + pid_t child_pid; + int mypipe[2]; + int dev_num; + FILE *stream; + + if (pipe(mypipe) < 0) { + perror("Error creating pipe"); + return head; + } + + child_pid = fork(); + if (child_pid < 0) { + close(mypipe[0]); + close(mypipe[1]); + perror("Error forking child"); + return head; + } + if (child_pid == 0) { + close(mypipe[0]); + stream = fdopen(mypipe[1], "w"); + if (stream == NULL) { + lxcfs_error("Error opening pipe for writing: %s\n", strerror(errno)); + goto child_out; + } + nsfd = getns(pid, "mnt"); + if (nsfd < 0) { + lxcfs_error("Error getting mnt ns: %s\n", strerror(errno)); + goto child_out; + } + if (setns(nsfd, 0) < 0) { + lxcfs_error("Error setting mnt ns: %s\n", strerror(errno)); + goto child_out; + } + dir = opendir("/dev"); + if (dir == NULL) { + lxcfs_error("Error opening dir /dev: %s\n", strerror(errno)); + goto child_out; + } + while ((ptr = readdir(dir)) != NULL) { + if (ptr->d_type != DT_BLK && ptr->d_type != DT_CHR) { + continue; + } + memset(fpath, 0, sizeof(fpath)); + snprintf(fpath, 99, "/dev/%s", ptr->d_name); + stat(fpath, &dev_stat); + fprintf(stream, "%s %d ", ptr->d_name, dev_stat.st_rdev); + fflush(stream); + } + closedir(dir); + stat("/", &dev_stat); + dev_num = dev_stat.st_dev & (~0xf); + fprintf(stream, "sda %d end 0 ", dev_num); + fflush(stream); +child_out: + fclose(stream); + exit(0); + } + + close(mypipe[1]); + stream = fdopen(mypipe[0], "r"); + if (stream == NULL) { + lxcfs_error("Error opening pipe for reading: %s\n", strerror(errno)); + goto err; + } + while (fscanf(stream, "%100s%d", dev_name, &dev_num) == 2) { + if (dev_num == 0) { + break; + } + if (head == NULL) { + do { + head = (struct devinfo*)malloc(sizeof(struct devinfo)); + } while (!head); + end = head; + } else { + do { + end->next = (struct devinfo*)malloc(sizeof(struct devinfo)); + } while (!end->next); + end = end->next; + } + end->next = NULL; + strncpy(end->name, dev_name, 100); + end->major = (dev_num & 0xff00) >> 8; + end->minor = dev_num & 0x00ff; + } +err: + if (stream) + fclose(stream); + if (child_pid > 0) + wait_for_pid(child_pid); + return head; +} + +void free_devinfo_list(struct devinfo *ptr) +{ + struct devinfo *tmp; + while (ptr != NULL) { + tmp = ptr; + ptr = ptr->next; + free(tmp); + } +} + static int proc_diskstats_read(char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { char dev_name[72]; struct fuse_context *fc = fuse_get_context(); struct file_info *d = (struct file_info *)fi->fh; + struct devinfo *container_devinfo = NULL, *ptr; char *cg; char *io_serviced_str = NULL, *io_merged_str = NULL, *io_service_bytes_str = NULL, *io_wait_time_str = NULL, *io_service_time_str = NULL; @@ -3801,13 +3925,21 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset, if (!f) goto err; + container_devinfo = container_dev_read(initpid); + while (getline(&line, &linelen, f) != -1) { ssize_t l; char lbuf[256]; + memset(dev_name, 0, sizeof(dev_name)); i = sscanf(line, "%u %u %71s", &major, &minor, dev_name); if (i != 3) continue; + for (ptr = container_devinfo; ptr != NULL; ptr = ptr->next) { + if (major == ptr->major && minor == ptr->minor) { + strncpy(dev_name, ptr->name, 71); + } + } get_blkio_io_value(io_serviced_str, major, minor, "Read", &read); get_blkio_io_value(io_serviced_str, major, minor, "Write", &write); @@ -3873,6 +4005,7 @@ err: free(io_service_bytes_str); free(io_wait_time_str); free(io_service_time_str); + free_devinfo_list(container_devinfo); return rv; }