|
7 | 7 | #include <dirent.h>
|
8 | 8 | #include <errno.h>
|
9 | 9 | #include <fcntl.h>
|
| 10 | +#include <libgen.h> |
10 | 11 | #include <limits.h>
|
11 | 12 | #include <string.h>
|
12 | 13 | #include <unistd.h>
|
13 | 14 |
|
14 | 15 | #include <linux/fs.h>
|
| 16 | +#include <linux/limits.h> |
15 | 17 |
|
16 | 18 | #include <sys/ioctl.h>
|
17 | 19 | #include <sys/stat.h>
|
|
20 | 22 | /* Local */
|
21 | 23 |
|
22 | 24 | #include "cli.h"
|
| 25 | +#include "common.h" |
23 | 26 | #include "gzip.h"
|
24 | 27 | #include "ept.h"
|
25 | 28 |
|
@@ -88,51 +91,128 @@ char *
|
88 | 91 | io_find_disk(
|
89 | 92 | char const * const path
|
90 | 93 | ){
|
91 |
| - const char* const name = basename(path); |
| 94 | + char *path_disk = NULL; |
| 95 | + |
| 96 | + size_t const len_path = strnlen(path, PATH_MAX); |
| 97 | + if (!len_path || len_path >= PATH_MAX) { |
| 98 | + pr_error("IO find disk: Path to disk '%s' is too long\n", path); |
| 99 | + goto result; |
| 100 | + } |
| 101 | + |
| 102 | + char *const path_dup = malloc(len_path + 1); |
| 103 | + if (!path_dup) { |
| 104 | + pr_error_with_errno("IO find disk: Failed to allocate memory for duplicated path"); |
| 105 | + goto result; |
| 106 | + } |
| 107 | + memcpy(path_dup, path, len_path); |
| 108 | + path_dup[len_path] = '\0'; |
| 109 | + |
| 110 | + char const *const name = basename(path_dup); |
| 111 | + if (!name || name[0] == '\0') { |
| 112 | + pr_error("IO find disk: Could not figure out base name of disk path '%s'\n", path); |
| 113 | + goto free_path; |
| 114 | + } |
92 | 115 | pr_error("IO find disk: Trying to find corresponding full disk drive of '%s' (name %s) so more advanced operations (partition migration, actual table manipulation, partprobe, etc) can be performed\n", path, name);
|
93 |
| - const size_t len_name = strlen(name); |
| 116 | + |
| 117 | + size_t const len_name = strnlen(name, len_path); |
| 118 | + if (!len_name || len_name >= PATH_MAX) { |
| 119 | + pr_error("IO find disk: Could not figure out length of disk name '%s'\n", name); |
| 120 | + goto free_path; |
| 121 | + } |
| 122 | + |
94 | 123 | struct stat st;
|
95 | 124 | if (stat(path, &st)) {
|
96 |
| - pr_error("IO find disk: Failed to get stat of '%s', errno: %d, error: %s\n", path, errno, strerror(errno)); |
97 |
| - return NULL; |
| 125 | + pr_error_with_errno("IO find disk: Failed to get stat of '%s'", path); |
| 126 | + goto free_path; |
98 | 127 | }
|
99 | 128 | char major_minor[23];
|
100 |
| - snprintf(major_minor, 23, "%u:%u\n", major(st.st_rdev), minor(st.st_rdev)); |
101 |
| - DIR *dir = opendir("/sys/block"); |
| 129 | + int len_devnode = snprintf(major_minor, 23, "%u:%u\n", major(st.st_rdev), minor(st.st_rdev)); |
| 130 | + if (len_devnode < 0) { |
| 131 | + pr_error_with_errno("IO find disk: Failed to snprintf to get major:minor dev name"); |
| 132 | + goto free_path; |
| 133 | + } else if (len_devnode == 23) { |
| 134 | + pr_error("IO find disk: name of devnode is impossibly long\n"); |
| 135 | + goto free_path; |
| 136 | + } |
| 137 | + |
| 138 | + int dir_fd = open("/sys/block", O_RDONLY | O_DIRECTORY); |
| 139 | + if (dir_fd < 0) { |
| 140 | + pr_error_with_errno("IO find disk: Failed to open /sys/block vdir"); |
| 141 | + goto free_path; |
| 142 | + } |
| 143 | + |
| 144 | + int dup_dir_fd = dup(dir_fd); |
| 145 | + if (dup_dir_fd < 0) { |
| 146 | + pr_error_with_errno("IO find disk: Failed to duplicate dir fd"); |
| 147 | + goto free_path; |
| 148 | + } |
| 149 | + |
| 150 | + DIR *dir = fdopendir(dup_dir_fd); |
102 | 151 | if (!dir) {
|
103 |
| - return NULL; |
| 152 | + pr_error_with_errno("IO find disk: Failed to fdopendir /sys/block vdir"); |
| 153 | + close(dup_dir_fd); |
| 154 | + goto close_fd; |
104 | 155 | }
|
105 |
| - char dev_file[17 + 2*NAME_MAX] = "/sys/block/"; // 11 for /sys/block/, 256 for disk+/, 256 for name+/, 4 for dev\0 |
| 156 | + |
| 157 | + char dev_file[6 + 2*NAME_MAX]; // 256 for disk+/, 256 for name+/, 4 for dev\0 |
106 | 158 | char dev_content[23];
|
107 | 159 | struct dirent * dir_entry;
|
108 | 160 | int fd;
|
109 |
| - size_t len_entry; |
110 | 161 | while ((dir_entry = readdir(dir))) {
|
111 |
| - if (dir_entry->d_name[0] && dir_entry->d_name[0] != '.') { |
112 |
| - len_entry = strlen(dir_entry->d_name); |
113 |
| - snprintf(dev_file + 11, 6 + len_name + len_entry, "%s/%s/dev", dir_entry->d_name, name); |
114 |
| - fd = open(dev_file, O_RDONLY); |
115 |
| - if (fd < 0) { |
116 |
| - continue; |
117 |
| - } |
118 |
| - memset(dev_content, 0, 23); |
119 |
| - read(fd, dev_content, 23); |
120 |
| - close(fd); |
121 |
| - if (!strcmp(major_minor, dev_content)) { |
122 |
| - char *path_real = malloc((6 + len_entry) * sizeof *path_real); // /dev/ is 5, name max 256 |
123 |
| - if (!path_real) { |
124 |
| - return NULL; |
125 |
| - } |
126 |
| - snprintf(path_real, 6 + len_entry, "/dev/%s", dir_entry->d_name); |
127 |
| - pr_error("IO find disk: Corresponding disk drive for '%s' is '%s'\n", path, path_real); |
128 |
| - closedir(dir); |
129 |
| - return path_real; |
130 |
| - } |
| 162 | + switch (dir_entry->d_name[0]) { |
| 163 | + case '\0': |
| 164 | + case '.': |
| 165 | + continue; |
| 166 | + default: |
| 167 | + break; |
| 168 | + } |
| 169 | + size_t len_entry = strnlen(dir_entry->d_name, NAME_MAX); |
| 170 | + if (!len_entry || len_entry > NAME_MAX) { |
| 171 | + pr_error_with_errno("IO find disk: entry name is too long or empty"); |
| 172 | + goto close_dir; |
| 173 | + } |
| 174 | + memcpy(dev_file, dir_entry->d_name, len_entry); |
| 175 | + dev_file[len_entry] = '/'; |
| 176 | + memcpy(dev_file + len_entry + 1, name, len_name); |
| 177 | + memcpy(dev_file + len_entry + 1 + len_name, "/dev", 5); |
| 178 | + fd = openat(dir_fd, dev_file, O_RDONLY); |
| 179 | + if (fd < 0) { |
| 180 | + pr_error_with_errno("IO find disk: Failed to open dev file '%s' as read-only", dev_file); |
| 181 | + goto close_dir; |
131 | 182 | }
|
| 183 | + memset(dev_content, 0, 23); |
| 184 | + read(fd, dev_content, 23); |
| 185 | + close(fd); |
| 186 | + if (strncmp(major_minor, dev_content, 23)) { |
| 187 | + continue; |
| 188 | + } |
| 189 | + path_disk = malloc(6 + len_entry); // /dev/ is 5, name max 256 |
| 190 | + if (!path_disk) { |
| 191 | + pr_error_with_errno("IO find disk: Failed to allocate memory for result path"); |
| 192 | + goto close_dir; |
| 193 | + } |
| 194 | + memcpy(path_disk, "/dev/", 5); |
| 195 | + memcpy(path_disk + 5, dir_entry->d_name, len_entry); |
| 196 | + path_disk[5 + len_entry] = '\0'; |
| 197 | + break; |
| 198 | + } |
| 199 | + if (path_disk) { |
| 200 | + pr_error("IO find disk: Corresponding disk drive for '%s' is '%s'\n", path, path_disk); |
| 201 | + } else { |
| 202 | + pr_error("IO find disk: Could not find corresponding disk drive for '%s'\n", path); |
| 203 | + } |
| 204 | +close_dir: |
| 205 | + if (closedir(dir)) { |
| 206 | + pr_error_with_errno("IO find disk: Failed to close dir"); |
| 207 | + } |
| 208 | +close_fd: |
| 209 | + if (close(dir_fd)) { |
| 210 | + pr_error_with_errno("IO Find disk: Failed to close dir fd"); |
132 | 211 | }
|
133 |
| - pr_error("IO find disk: Could not find corresponding disk drive for '%s'\n", path); |
134 |
| - closedir(dir); |
135 |
| - return NULL; |
| 212 | +free_path: |
| 213 | + free(path_dup); |
| 214 | +result: |
| 215 | + return (char *)path_disk; |
136 | 216 | }
|
137 | 217 |
|
138 | 218 | void
|
|
0 commit comments