diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2020-01-12 23:12:18 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2020-01-12 23:12:18 +0100 |
commit | ee15e45224d94ff84471e5ac4c05eb189dbe5980 (patch) | |
tree | 63991bcff06889b92cc3b4433dc0cde0f1930d00 | |
parent | 9e94a5eadcdbef406c22833b8afa9e380b698fdf (diff) | |
download | rockbox-ee15e45224d94ff84471e5ac4c05eb189dbe5980.tar.gz rockbox-ee15e45224d94ff84471e5ac4c05eb189dbe5980.zip |
nwztool/scsitool: rewrite device detection on linux to make it simpler
Change-Id: I8f393a53ea64c82f05e437923bcba05aa8a7a75c
-rw-r--r-- | utils/scsi/rbscsi.c | 130 |
1 files changed, 27 insertions, 103 deletions
diff --git a/utils/scsi/rbscsi.c b/utils/scsi/rbscsi.c index 8e15f1fd6a..adfecd8d0a 100644 --- a/utils/scsi/rbscsi.c +++ b/utils/scsi/rbscsi.c | |||
@@ -157,52 +157,10 @@ void rb_scsi_close(rb_scsi_device_t dev) | |||
157 | free(dev); | 157 | free(dev); |
158 | } | 158 | } |
159 | 159 | ||
160 | static int is_hctl(const char *name) | 160 | /* find the first entry of a directory (which is expended to contain only one) and turn |
161 | { | 161 | * it into a /dev/ path */ |
162 | char *end; | ||
163 | strtoul(name, &end, 0); /* h */ | ||
164 | if(*end != ':') | ||
165 | return 0; | ||
166 | strtoul(end + 1, &end, 0); /* c */ | ||
167 | if(*end != ':') | ||
168 | return 0; | ||
169 | strtoul(end + 1, &end, 0); /* t */ | ||
170 | if(*end != ':') | ||
171 | return 0; | ||
172 | strtoul(end + 1, &end, 0); /* l */ | ||
173 | return *end == 0; | ||
174 | } | ||
175 | |||
176 | static int _resolve_link_dev_path(char *path, size_t pathsz) | ||
177 | { | ||
178 | /* make sure it is a directory */ | ||
179 | struct stat st; | ||
180 | if(stat(path, &st) < 0) | ||
181 | return 0; | ||
182 | if(!S_ISDIR(st.st_mode)) | ||
183 | return 0; | ||
184 | if(chdir(path) < 0) | ||
185 | return 0; | ||
186 | if(getcwd(path, pathsz) == NULL) | ||
187 | return 0; | ||
188 | return 1; | ||
189 | } | ||
190 | |||
191 | static int resolve_link_dev_path(char *path, size_t pathsz) | ||
192 | { | ||
193 | /* change directory, ask the current path and resolve current directory */ | ||
194 | char curdir[PATH_MAX]; | ||
195 | if(getcwd(curdir, sizeof(curdir)) == NULL) | ||
196 | return 0; | ||
197 | int ret = _resolve_link_dev_path(path, pathsz); | ||
198 | chdir(curdir); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int scan_resolve_first_dev_path(char *path, size_t pathsz) | 162 | static int scan_resolve_first_dev_path(char *path, size_t pathsz) |
203 | { | 163 | { |
204 | size_t pathlen = strlen(path); | ||
205 | char *pathend = path + pathlen; | ||
206 | DIR *dir = opendir(path); | 164 | DIR *dir = opendir(path); |
207 | if(dir == NULL) | 165 | if(dir == NULL) |
208 | return 0; | 166 | return 0; |
@@ -212,13 +170,8 @@ static int scan_resolve_first_dev_path(char *path, size_t pathsz) | |||
212 | { | 170 | { |
213 | if(!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) | 171 | if(!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) |
214 | continue; | 172 | continue; |
215 | /* we found the entry, if it is a symlink, resolve it, otherwise it must be a directory */ | 173 | /* we expect a directory, but it could be a symlink, only the name matters */ |
216 | if(d->d_type == DT_LNK) | 174 | if(d->d_type == DT_LNK || d->d_type == DT_DIR) |
217 | { | ||
218 | snprintf(pathend, pathsz - pathlen, "/%s", d->d_name); | ||
219 | ret = resolve_link_dev_path(path, pathsz); | ||
220 | } | ||
221 | else if(d->d_type == DT_DIR) | ||
222 | { | 175 | { |
223 | snprintf(path, pathsz, "/dev/%s", d->d_name); | 176 | snprintf(path, pathsz, "/dev/%s", d->d_name); |
224 | ret = 1; | 177 | ret = 1; |
@@ -229,33 +182,6 @@ static int scan_resolve_first_dev_path(char *path, size_t pathsz) | |||
229 | return ret; | 182 | return ret; |
230 | } | 183 | } |
231 | 184 | ||
232 | static int scan_resolve_dev_path(char *path, size_t pathsz, const char *match) | ||
233 | { | ||
234 | size_t pathlen = strlen(path); | ||
235 | char *pathend = path + pathlen; | ||
236 | DIR *dir = opendir(path); | ||
237 | if(dir == NULL) | ||
238 | return 0; | ||
239 | struct dirent *d; | ||
240 | int ret = 0; | ||
241 | while((d = readdir(dir))) | ||
242 | { | ||
243 | if(strcmp(d->d_name, match)) | ||
244 | continue; | ||
245 | /* we found the entry, there are two case: | ||
246 | * - directory: we need to scan it and find the first entry | ||
247 | * - symlink: we need to see where it goes and extract the basename */ | ||
248 | snprintf(pathend, pathsz - pathlen, "/%s", d->d_name); | ||
249 | if(d->d_type == DT_DIR) | ||
250 | ret = scan_resolve_first_dev_path(path, pathsz); | ||
251 | else if(d->d_type == DT_LNK) | ||
252 | ret = resolve_link_dev_path(path, pathsz); | ||
253 | break; | ||
254 | } | ||
255 | closedir(dir); | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | static char *read_file_or_null(const char *path) | 185 | static char *read_file_or_null(const char *path) |
260 | { | 186 | { |
261 | FILE *f = fopen(path, "r"); | 187 | FILE *f = fopen(path, "r"); |
@@ -277,9 +203,9 @@ static char *read_file_or_null(const char *path) | |||
277 | 203 | ||
278 | struct rb_scsi_devent_t *rb_scsi_list(void) | 204 | struct rb_scsi_devent_t *rb_scsi_list(void) |
279 | { | 205 | { |
280 | /* list devices in /sys/bus/scsi/devices | 206 | /* list devices in /sys/class/scsi_generic |
281 | * we only keep entries of the form h:c:t:l */ | 207 | * we only keep entries of the form sgX */ |
282 | #define SYS_SCSI_DEV_PATH "/sys/bus/scsi/devices" | 208 | #define SYS_SCSI_DEV_PATH "/sys/class/scsi_generic" |
283 | DIR *dir = opendir(SYS_SCSI_DEV_PATH); | 209 | DIR *dir = opendir(SYS_SCSI_DEV_PATH); |
284 | if(dir == NULL) | 210 | if(dir == NULL) |
285 | return NULL; | 211 | return NULL; |
@@ -292,31 +218,29 @@ struct rb_scsi_devent_t *rb_scsi_list(void) | |||
292 | { | 218 | { |
293 | if(!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) | 219 | if(!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) |
294 | continue; | 220 | continue; |
295 | /* make sure the name is of the form h:c:t:l, we do not want targets or hosts */ | 221 | /* make sure the name is of the form sgX, and extract X */ |
296 | if(!is_hctl(d->d_name)) | 222 | int sg_idx; |
223 | if(sscanf(d->d_name, "sg%d", &sg_idx) != 1) | ||
297 | continue; | 224 | continue; |
298 | /* we now need to scan the directory to find the block and scsi generic device path: | ||
299 | * block: there should be a 'block' entry | ||
300 | * scsi: there should be a 'scsi_generic' entry | ||
301 | * Both entries can either be a symlink to the devide, or a directory with a single entry */ | ||
302 | char scsi_path[PATH_MAX]; | ||
303 | snprintf(scsi_path, sizeof(scsi_path), SYS_SCSI_DEV_PATH "/%s", d->d_name); | ||
304 | if(!scan_resolve_dev_path(scsi_path, sizeof(scsi_path), "scsi_generic")) | ||
305 | continue; | ||
306 | char block_path[PATH_MAX]; | ||
307 | snprintf(block_path, sizeof(block_path), SYS_SCSI_DEV_PATH "/%s", d->d_name); | ||
308 | if(!scan_resolve_dev_path(block_path, sizeof(block_path), "block")) | ||
309 | block_path[0] = 0; | ||
310 | dev = realloc(dev, (2 + nr_dev) * sizeof(struct rb_scsi_devent_t)); | 225 | dev = realloc(dev, (2 + nr_dev) * sizeof(struct rb_scsi_devent_t)); |
311 | dev[nr_dev].scsi_path = strdup(scsi_path); | 226 | |
312 | dev[nr_dev].block_path = block_path[0] == 0 ? NULL : strdup(block_path); | 227 | char path[PATH_MAX]; |
228 | snprintf(path, sizeof(path), "/dev/sg%d", sg_idx); | ||
229 | dev[nr_dev].scsi_path = strdup(path); | ||
230 | /* /sys/class/scsi_generic/sgX is a folder containing a subfolder 'device' that contains | ||
231 | * - a 'block' folder with a single entry: the block device | ||
232 | * - the vendor/model/rev files */ | ||
233 | snprintf(path, sizeof(path), SYS_SCSI_DEV_PATH "/sg%d/device/block", sg_idx); | ||
234 | if(!scan_resolve_first_dev_path(path, sizeof(path))) | ||
235 | path[0] = 0; | ||
236 | dev[nr_dev].block_path = path[0] == 0 ? NULL : strdup(path); | ||
313 | /* fill vendor/model/rev */ | 237 | /* fill vendor/model/rev */ |
314 | snprintf(scsi_path, sizeof(scsi_path), SYS_SCSI_DEV_PATH "/%s/vendor", d->d_name); | 238 | snprintf(path, sizeof(path), SYS_SCSI_DEV_PATH "/sg%d/device/vendor", sg_idx); |
315 | dev[nr_dev].vendor = read_file_or_null(scsi_path); | 239 | dev[nr_dev].vendor = read_file_or_null(path); |
316 | snprintf(scsi_path, sizeof(scsi_path), SYS_SCSI_DEV_PATH "/%s/model", d->d_name); | 240 | snprintf(path, sizeof(path), SYS_SCSI_DEV_PATH "/sg%d/device/model", sg_idx); |
317 | dev[nr_dev].model = read_file_or_null(scsi_path); | 241 | dev[nr_dev].model = read_file_or_null(path); |
318 | snprintf(scsi_path, sizeof(scsi_path), SYS_SCSI_DEV_PATH "/%s/rev", d->d_name); | 242 | snprintf(path, sizeof(path), SYS_SCSI_DEV_PATH "/sg%d/device/rev", sg_idx); |
319 | dev[nr_dev].rev = read_file_or_null(scsi_path); | 243 | dev[nr_dev].rev = read_file_or_null(path); |
320 | 244 | ||
321 | /* sentinel */ | 245 | /* sentinel */ |
322 | dev[++nr_dev].scsi_path = NULL; | 246 | dev[++nr_dev].scsi_path = NULL; |