Skip to content

Commit e6acead

Browse files
7Jineuschaefer
andcommitted
io_find_disk: rewrite for portability and robustness
closes #23 Co-authored-by: J. Neuschäfer <j.ne@posteo.net>
1 parent 9d1ddf0 commit e6acead

File tree

2 files changed

+112
-33
lines changed

2 files changed

+112
-33
lines changed

src/cli.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
/* System */
66

7-
#include <bits/getopt_core.h>
87
#include <errno.h>
98
#include <fcntl.h>
109
#include <getopt.h>

src/io.c

Lines changed: 112 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
#include <dirent.h>
88
#include <errno.h>
99
#include <fcntl.h>
10+
#include <libgen.h>
1011
#include <limits.h>
1112
#include <string.h>
1213
#include <unistd.h>
1314

1415
#include <linux/fs.h>
16+
#include <linux/limits.h>
1517

1618
#include <sys/ioctl.h>
1719
#include <sys/stat.h>
@@ -20,6 +22,7 @@
2022
/* Local */
2123

2224
#include "cli.h"
25+
#include "common.h"
2326
#include "gzip.h"
2427
#include "ept.h"
2528

@@ -88,51 +91,128 @@ char *
8891
io_find_disk(
8992
char const * const path
9093
){
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+
}
92115
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+
94123
struct stat st;
95124
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;
98127
}
99128
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);
102151
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;
104155
}
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
106158
char dev_content[23];
107159
struct dirent * dir_entry;
108160
int fd;
109-
size_t len_entry;
110161
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;
131182
}
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");
132211
}
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;
136216
}
137217

138218
void

0 commit comments

Comments
 (0)