File: | build-scan/../src/udev/scsi_id/scsi_id.c |
Warning: | line 290, column 34 Potential leak of memory pointed to by 'buffer' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||||
2 | /* | ||||
3 | * Copyright © IBM Corp. 2003 | ||||
4 | * Copyright © SUSE Linux Products GmbH, 2006 | ||||
5 | * | ||||
6 | */ | ||||
7 | |||||
8 | #include <ctype.h> | ||||
9 | #include <errno(*__errno_location ()).h> | ||||
10 | #include <fcntl.h> | ||||
11 | #include <getopt.h> | ||||
12 | #include <signal.h> | ||||
13 | #include <stdarg.h> | ||||
14 | #include <stdbool.h> | ||||
15 | #include <stdio.h> | ||||
16 | #include <stdlib.h> | ||||
17 | #include <string.h> | ||||
18 | #include <sys/stat.h> | ||||
19 | #include <unistd.h> | ||||
20 | |||||
21 | #include "libudev.h" | ||||
22 | |||||
23 | #include "fd-util.h" | ||||
24 | #include "libudev-private.h" | ||||
25 | #include "scsi_id.h" | ||||
26 | #include "string-util.h" | ||||
27 | #include "udev-util.h" | ||||
28 | |||||
29 | static const struct option options[] = { | ||||
30 | { "device", required_argument1, NULL((void*)0), 'd' }, | ||||
31 | { "config", required_argument1, NULL((void*)0), 'f' }, | ||||
32 | { "page", required_argument1, NULL((void*)0), 'p' }, | ||||
33 | { "blacklisted", no_argument0, NULL((void*)0), 'b' }, | ||||
34 | { "whitelisted", no_argument0, NULL((void*)0), 'g' }, | ||||
35 | { "replace-whitespace", no_argument0, NULL((void*)0), 'u' }, | ||||
36 | { "sg-version", required_argument1, NULL((void*)0), 's' }, | ||||
37 | { "verbose", no_argument0, NULL((void*)0), 'v' }, | ||||
38 | { "version", no_argument0, NULL((void*)0), 'V' }, /* don't advertise -V */ | ||||
39 | { "export", no_argument0, NULL((void*)0), 'x' }, | ||||
40 | { "help", no_argument0, NULL((void*)0), 'h' }, | ||||
41 | {} | ||||
42 | }; | ||||
43 | |||||
44 | static bool_Bool all_good = false0; | ||||
45 | static bool_Bool dev_specified = false0; | ||||
46 | static char config_file[MAX_PATH_LEN512] = "/etc/scsi_id.config"; | ||||
47 | static enum page_code default_page_code = PAGE_UNSPECIFIED; | ||||
48 | static int sg_version = 4; | ||||
49 | static bool_Bool reformat_serial = false0; | ||||
50 | static bool_Bool export = false0; | ||||
51 | static char vendor_str[64]; | ||||
52 | static char model_str[64]; | ||||
53 | static char vendor_enc_str[256]; | ||||
54 | static char model_enc_str[256]; | ||||
55 | static char revision_str[16]; | ||||
56 | static char type_str[16]; | ||||
57 | |||||
58 | static void set_type(const char *from, char *to, size_t len) | ||||
59 | { | ||||
60 | int type_num; | ||||
61 | char *eptr; | ||||
62 | const char *type = "generic"; | ||||
63 | |||||
64 | type_num = strtoul(from, &eptr, 0); | ||||
65 | if (eptr != from) { | ||||
66 | switch (type_num) { | ||||
67 | case 0: | ||||
68 | type = "disk"; | ||||
69 | break; | ||||
70 | case 1: | ||||
71 | type = "tape"; | ||||
72 | break; | ||||
73 | case 4: | ||||
74 | type = "optical"; | ||||
75 | break; | ||||
76 | case 5: | ||||
77 | type = "cd"; | ||||
78 | break; | ||||
79 | case 7: | ||||
80 | type = "optical"; | ||||
81 | break; | ||||
82 | case 0xe: | ||||
83 | type = "disk"; | ||||
84 | break; | ||||
85 | case 0xf: | ||||
86 | type = "optical"; | ||||
87 | break; | ||||
88 | default: | ||||
89 | break; | ||||
90 | } | ||||
91 | } | ||||
92 | strscpy(to, len, type); | ||||
93 | } | ||||
94 | |||||
95 | /* | ||||
96 | * get_value: | ||||
97 | * | ||||
98 | * buf points to an '=' followed by a quoted string ("foo") or a string ending | ||||
99 | * with a space or ','. | ||||
100 | * | ||||
101 | * Return a pointer to the NUL terminated string, returns NULL if no | ||||
102 | * matches. | ||||
103 | */ | ||||
104 | static char *get_value(char **buffer) | ||||
105 | { | ||||
106 | static const char *quote_string = "\"\n"; | ||||
107 | static const char *comma_string = ",\n"; | ||||
108 | char *val; | ||||
109 | const char *end; | ||||
110 | |||||
111 | if (**buffer == '"') { | ||||
112 | /* | ||||
113 | * skip leading quote, terminate when quote seen | ||||
114 | */ | ||||
115 | (*buffer)++; | ||||
116 | end = quote_string; | ||||
117 | } else { | ||||
118 | end = comma_string; | ||||
119 | } | ||||
120 | val = strsep(buffer, end); | ||||
121 | if (val && end == quote_string) | ||||
122 | /* | ||||
123 | * skip trailing quote | ||||
124 | */ | ||||
125 | (*buffer)++; | ||||
126 | |||||
127 | while (isspace(**buffer)((*__ctype_b_loc ())[(int) ((**buffer))] & (unsigned short int) _ISspace)) | ||||
128 | (*buffer)++; | ||||
129 | |||||
130 | return val; | ||||
131 | } | ||||
132 | |||||
133 | static int argc_count(char *opts) | ||||
134 | { | ||||
135 | int i = 0; | ||||
136 | while (*opts != '\0') | ||||
137 | if (*opts++ == ' ') | ||||
138 | i++; | ||||
139 | return i; | ||||
140 | } | ||||
141 | |||||
142 | /* | ||||
143 | * get_file_options: | ||||
144 | * | ||||
145 | * If vendor == NULL, find a line in the config file with only "OPTIONS="; | ||||
146 | * if vendor and model are set find the first OPTIONS line in the config | ||||
147 | * file that matches. Set argc and argv to match the OPTIONS string. | ||||
148 | * | ||||
149 | * vendor and model can end in '\n'. | ||||
150 | */ | ||||
151 | static int get_file_options(struct udev *udev, | ||||
152 | const char *vendor, const char *model, | ||||
153 | int *argc, char ***newargv) | ||||
154 | { | ||||
155 | _cleanup_free___attribute__((cleanup(freep))) char *buffer = NULL((void*)0); | ||||
156 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f; | ||||
157 | char *buf; | ||||
158 | char *str1; | ||||
159 | char *vendor_in, *model_in, *options_in; /* read in from file */ | ||||
160 | int lineno; | ||||
161 | int c; | ||||
162 | int retval = 0; | ||||
163 | |||||
164 | f = fopen(config_file, "re"); | ||||
165 | if (f == NULL((void*)0)) { | ||||
166 | if (errno(*__errno_location ()) == ENOENT2) | ||||
167 | return 1; | ||||
168 | else { | ||||
169 | log_error_errno(errno, "can't open %s: %m", config_file)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_UDEV); (log_get_max_level_realm(_realm) >= ( (_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/udev/scsi_id/scsi_id.c", 169, __func__ , "can't open %s: %m", config_file) : -abs(_e); }); | ||||
170 | return -1; | ||||
171 | } | ||||
172 | } | ||||
173 | |||||
174 | /* | ||||
175 | * Allocate a buffer rather than put it on the stack so we can | ||||
176 | * keep it around to parse any options (any allocated newargv | ||||
177 | * points into this buffer for its strings). | ||||
178 | */ | ||||
179 | buffer = malloc(MAX_BUFFER_LEN256); | ||||
180 | if (!buffer) | ||||
181 | return log_oom()log_oom_internal(LOG_REALM_UDEV, "../src/udev/scsi_id/scsi_id.c" , 181, __func__); | ||||
182 | |||||
183 | *newargv = NULL((void*)0); | ||||
184 | lineno = 0; | ||||
185 | for (;;) { | ||||
186 | vendor_in = model_in = options_in = NULL((void*)0); | ||||
187 | |||||
188 | buf = fgets(buffer, MAX_BUFFER_LEN256, f); | ||||
189 | if (buf == NULL((void*)0)) | ||||
190 | break; | ||||
191 | lineno++; | ||||
192 | if (buf[strlen(buffer) - 1] != '\n') { | ||||
193 | log_error("Config file line %d too long", lineno)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_UDEV ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/udev/scsi_id/scsi_id.c", 193, __func__, "Config file line %d too long" , lineno) : -abs(_e); }); | ||||
194 | break; | ||||
195 | } | ||||
196 | |||||
197 | while (isspace(*buf)((*__ctype_b_loc ())[(int) ((*buf))] & (unsigned short int ) _ISspace)) | ||||
198 | buf++; | ||||
199 | |||||
200 | /* blank or all whitespace line */ | ||||
201 | if (*buf == '\0') | ||||
202 | continue; | ||||
203 | |||||
204 | /* comment line */ | ||||
205 | if (*buf == '#') | ||||
206 | continue; | ||||
207 | |||||
208 | str1 = strsep(&buf, "="); | ||||
209 | if (str1 && strcaseeq(str1, "VENDOR")(strcasecmp((str1),("VENDOR")) == 0)) { | ||||
210 | str1 = get_value(&buf); | ||||
211 | if (!str1) { | ||||
212 | retval = log_oom()log_oom_internal(LOG_REALM_UDEV, "../src/udev/scsi_id/scsi_id.c" , 212, __func__); | ||||
213 | break; | ||||
214 | } | ||||
215 | vendor_in = str1; | ||||
216 | |||||
217 | str1 = strsep(&buf, "="); | ||||
218 | if (str1 && strcaseeq(str1, "MODEL")(strcasecmp((str1),("MODEL")) == 0)) { | ||||
219 | str1 = get_value(&buf); | ||||
220 | if (!str1) { | ||||
221 | retval = log_oom()log_oom_internal(LOG_REALM_UDEV, "../src/udev/scsi_id/scsi_id.c" , 221, __func__); | ||||
222 | break; | ||||
223 | } | ||||
224 | model_in = str1; | ||||
225 | str1 = strsep(&buf, "="); | ||||
226 | } | ||||
227 | } | ||||
228 | |||||
229 | if (str1 && strcaseeq(str1, "OPTIONS")(strcasecmp((str1),("OPTIONS")) == 0)) { | ||||
230 | str1 = get_value(&buf); | ||||
231 | if (!str1) { | ||||
232 | retval = log_oom()log_oom_internal(LOG_REALM_UDEV, "../src/udev/scsi_id/scsi_id.c" , 232, __func__); | ||||
233 | break; | ||||
234 | } | ||||
235 | options_in = str1; | ||||
236 | } | ||||
237 | |||||
238 | /* | ||||
239 | * Only allow: [vendor=foo[,model=bar]]options=stuff | ||||
240 | */ | ||||
241 | if (!options_in || (!vendor_in && model_in)) { | ||||
242 | log_error("Error parsing config file line %d '%s'", lineno, buffer)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_UDEV ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/udev/scsi_id/scsi_id.c", 242, __func__, "Error parsing config file line %d '%s'" , lineno, buffer) : -abs(_e); }); | ||||
243 | retval = -1; | ||||
244 | break; | ||||
245 | } | ||||
246 | if (vendor == NULL((void*)0)) { | ||||
247 | if (vendor_in == NULL((void*)0)) | ||||
248 | break; | ||||
249 | } else if (vendor_in && | ||||
250 | startswith(vendor, vendor_in) && | ||||
251 | (!model_in || startswith(model, model_in))) { | ||||
252 | /* | ||||
253 | * Matched vendor and optionally model. | ||||
254 | * | ||||
255 | * Note: a short vendor_in or model_in can | ||||
256 | * give a partial match (that is FOO | ||||
257 | * matches FOOBAR). | ||||
258 | */ | ||||
259 | break; | ||||
260 | } | ||||
261 | } | ||||
262 | |||||
263 | if (retval
| ||||
264 | if (vendor_in
| ||||
265 | options_in
| ||||
266 | /* | ||||
267 | * Something matched. Allocate newargv, and store | ||||
268 | * values found in options_in. | ||||
269 | */ | ||||
270 | strcpy(buffer, options_in); | ||||
271 | c = argc_count(buffer) + 2; | ||||
272 | *newargv = calloc(c, sizeof(**newargv)); | ||||
273 | if (!*newargv) | ||||
274 | retval = log_oom()log_oom_internal(LOG_REALM_UDEV, "../src/udev/scsi_id/scsi_id.c" , 274, __func__); | ||||
275 | else { | ||||
276 | *argc = c; | ||||
277 | c = 0; | ||||
278 | /* | ||||
279 | * argv[0] at 0 is skipped by getopt, but | ||||
280 | * store the buffer address there for | ||||
281 | * later freeing | ||||
282 | */ | ||||
283 | (*newargv)[c] = buffer; | ||||
284 | for (c = 1; c < *argc; c++) | ||||
285 | (*newargv)[c] = strsep(&buffer, " \t"); | ||||
286 | buffer = NULL((void*)0); | ||||
287 | } | ||||
288 | } else { | ||||
289 | /* No matches */ | ||||
290 | retval = 1; | ||||
| |||||
291 | } | ||||
292 | } | ||||
293 | return retval; | ||||
294 | } | ||||
295 | |||||
296 | static void help(void) { | ||||
297 | printf("Usage: %s [OPTION...] DEVICE\n\n" | ||||
298 | "SCSI device identification.\n\n" | ||||
299 | " -h --help Print this message\n" | ||||
300 | " --version Print version of the program\n\n" | ||||
301 | " -d --device= Device node for SG_IO commands\n" | ||||
302 | " -f --config= Location of config file\n" | ||||
303 | " -p --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n" | ||||
304 | " -s --sg-version=3|4 Use SGv3 or SGv4\n" | ||||
305 | " -b --blacklisted Treat device as blacklisted\n" | ||||
306 | " -g --whitelisted Treat device as whitelisted\n" | ||||
307 | " -u --replace-whitespace Replace all whitespace by underscores\n" | ||||
308 | " -v --verbose Verbose logging\n" | ||||
309 | " -x --export Print values as environment keys\n" | ||||
310 | , program_invocation_short_name); | ||||
311 | |||||
312 | } | ||||
313 | |||||
314 | static int set_options(struct udev *udev, | ||||
315 | int argc, char **argv, | ||||
316 | char *maj_min_dev) | ||||
317 | { | ||||
318 | int option; | ||||
319 | |||||
320 | /* | ||||
321 | * optind is a global extern used by getopt. Since we can call | ||||
322 | * set_options twice (once for command line, and once for config | ||||
323 | * file) we have to reset this back to 1. | ||||
324 | */ | ||||
325 | optind = 1; | ||||
326 | while ((option = getopt_long(argc, argv, "d:f:gp:uvVxhbs:", options, NULL((void*)0))) >= 0) | ||||
327 | switch (option) { | ||||
328 | case 'b': | ||||
329 | all_good = false0; | ||||
330 | break; | ||||
331 | |||||
332 | case 'd': | ||||
333 | dev_specified = true1; | ||||
334 | strscpy(maj_min_dev, MAX_PATH_LEN512, optarg); | ||||
335 | break; | ||||
336 | |||||
337 | case 'f': | ||||
338 | strscpy(config_file, MAX_PATH_LEN512, optarg); | ||||
339 | break; | ||||
340 | |||||
341 | case 'g': | ||||
342 | all_good = true1; | ||||
343 | break; | ||||
344 | |||||
345 | case 'h': | ||||
346 | help(); | ||||
347 | exit(EXIT_SUCCESS0); | ||||
348 | |||||
349 | case 'p': | ||||
350 | if (streq(optarg, "0x80")(strcmp((optarg),("0x80")) == 0)) | ||||
351 | default_page_code = PAGE_80; | ||||
352 | else if (streq(optarg, "0x83")(strcmp((optarg),("0x83")) == 0)) | ||||
353 | default_page_code = PAGE_83; | ||||
354 | else if (streq(optarg, "pre-spc3-83")(strcmp((optarg),("pre-spc3-83")) == 0)) | ||||
355 | default_page_code = PAGE_83_PRE_SPC3; | ||||
356 | else { | ||||
357 | log_error("Unknown page code '%s'", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_UDEV ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/udev/scsi_id/scsi_id.c", 357, __func__, "Unknown page code '%s'" , optarg) : -abs(_e); }); | ||||
358 | return -1; | ||||
359 | } | ||||
360 | break; | ||||
361 | |||||
362 | case 's': | ||||
363 | sg_version = atoi(optarg); | ||||
364 | if (sg_version < 3 || sg_version > 4) { | ||||
365 | log_error("Unknown SG version '%s'", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_UDEV ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/udev/scsi_id/scsi_id.c", 365, __func__, "Unknown SG version '%s'" , optarg) : -abs(_e); }); | ||||
366 | return -1; | ||||
367 | } | ||||
368 | break; | ||||
369 | |||||
370 | case 'u': | ||||
371 | reformat_serial = true1; | ||||
372 | break; | ||||
373 | |||||
374 | case 'v': | ||||
375 | log_set_target(LOG_TARGET_CONSOLE); | ||||
376 | log_set_max_level(LOG_DEBUG)log_set_max_level_realm(LOG_REALM_UDEV, (7)); | ||||
377 | log_open(); | ||||
378 | break; | ||||
379 | |||||
380 | case 'V': | ||||
381 | printf("%s\n", PACKAGE_VERSION"239"); | ||||
382 | exit(EXIT_SUCCESS0); | ||||
383 | |||||
384 | case 'x': | ||||
385 | export = true1; | ||||
386 | break; | ||||
387 | |||||
388 | case '?': | ||||
389 | return -1; | ||||
390 | |||||
391 | default: | ||||
392 | assert_not_reached("Unknown option")do { log_assert_failed_unreachable_realm(LOG_REALM_UDEV, ("Unknown option" ), "../src/udev/scsi_id/scsi_id.c", 392, __PRETTY_FUNCTION__) ; } while (0); | ||||
393 | } | ||||
394 | |||||
395 | if (optind < argc && !dev_specified) { | ||||
396 | dev_specified = true1; | ||||
397 | strscpy(maj_min_dev, MAX_PATH_LEN512, argv[optind]); | ||||
398 | } | ||||
399 | |||||
400 | return 0; | ||||
401 | } | ||||
402 | |||||
403 | static int per_dev_options(struct udev *udev, | ||||
404 | struct scsi_id_device *dev_scsi, int *good_bad, int *page_code) | ||||
405 | { | ||||
406 | int retval; | ||||
407 | int newargc; | ||||
408 | char **newargv = NULL((void*)0); | ||||
409 | int option; | ||||
410 | |||||
411 | *good_bad = all_good; | ||||
412 | *page_code = default_page_code; | ||||
413 | |||||
414 | retval = get_file_options(udev, vendor_str, model_str, &newargc, &newargv); | ||||
415 | |||||
416 | optind = 1; /* reset this global extern */ | ||||
417 | while (retval == 0) { | ||||
418 | option = getopt_long(newargc, newargv, "bgp:", options, NULL((void*)0)); | ||||
419 | if (option == -1) | ||||
420 | break; | ||||
421 | |||||
422 | switch (option) { | ||||
423 | case 'b': | ||||
424 | *good_bad = 0; | ||||
425 | break; | ||||
426 | |||||
427 | case 'g': | ||||
428 | *good_bad = 1; | ||||
429 | break; | ||||
430 | |||||
431 | case 'p': | ||||
432 | if (streq(optarg, "0x80")(strcmp((optarg),("0x80")) == 0)) { | ||||
433 | *page_code = PAGE_80; | ||||
434 | } else if (streq(optarg, "0x83")(strcmp((optarg),("0x83")) == 0)) { | ||||
435 | *page_code = PAGE_83; | ||||
436 | } else if (streq(optarg, "pre-spc3-83")(strcmp((optarg),("pre-spc3-83")) == 0)) { | ||||
437 | *page_code = PAGE_83_PRE_SPC3; | ||||
438 | } else { | ||||
439 | log_error("Unknown page code '%s'", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_UDEV ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/udev/scsi_id/scsi_id.c", 439, __func__, "Unknown page code '%s'" , optarg) : -abs(_e); }); | ||||
440 | retval = -1; | ||||
441 | } | ||||
442 | break; | ||||
443 | |||||
444 | default: | ||||
445 | log_error("Unknown or bad option '%c' (0x%x)", option, option)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_UDEV ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/udev/scsi_id/scsi_id.c", 445, __func__, "Unknown or bad option '%c' (0x%x)" , option, option) : -abs(_e); }); | ||||
446 | retval = -1; | ||||
447 | break; | ||||
448 | } | ||||
449 | } | ||||
450 | |||||
451 | if (newargv) { | ||||
452 | free(newargv[0]); | ||||
453 | free(newargv); | ||||
454 | } | ||||
455 | return retval; | ||||
456 | } | ||||
457 | |||||
458 | static int set_inq_values(struct udev *udev, struct scsi_id_device *dev_scsi, const char *path) | ||||
459 | { | ||||
460 | int retval; | ||||
461 | |||||
462 | dev_scsi->use_sg = sg_version; | ||||
463 | |||||
464 | retval = scsi_std_inquiry(udev, dev_scsi, path); | ||||
465 | if (retval) | ||||
466 | return retval; | ||||
467 | |||||
468 | udev_util_encode_string(dev_scsi->vendor, vendor_enc_str, sizeof(vendor_enc_str)); | ||||
469 | udev_util_encode_string(dev_scsi->model, model_enc_str, sizeof(model_enc_str)); | ||||
470 | |||||
471 | util_replace_whitespace(dev_scsi->vendor, vendor_str, sizeof(vendor_str)); | ||||
472 | util_replace_chars(vendor_str, NULL((void*)0)); | ||||
473 | util_replace_whitespace(dev_scsi->model, model_str, sizeof(model_str)); | ||||
474 | util_replace_chars(model_str, NULL((void*)0)); | ||||
475 | set_type(dev_scsi->type, type_str, sizeof(type_str)); | ||||
476 | util_replace_whitespace(dev_scsi->revision, revision_str, sizeof(revision_str)); | ||||
477 | util_replace_chars(revision_str, NULL((void*)0)); | ||||
478 | return 0; | ||||
479 | } | ||||
480 | |||||
481 | /* | ||||
482 | * scsi_id: try to get an id, if one is found, printf it to stdout. | ||||
483 | * returns a value passed to exit() - 0 if printed an id, else 1. | ||||
484 | */ | ||||
485 | static int scsi_id(struct udev *udev, char *maj_min_dev) | ||||
486 | { | ||||
487 | struct scsi_id_device dev_scsi = {}; | ||||
488 | int good_dev; | ||||
489 | int page_code; | ||||
490 | int retval = 0; | ||||
491 | |||||
492 | if (set_inq_values(udev, &dev_scsi, maj_min_dev) < 0) { | ||||
493 | retval = 1; | ||||
494 | goto out; | ||||
495 | } | ||||
496 | |||||
497 | /* get per device (vendor + model) options from the config file */ | ||||
498 | per_dev_options(udev, &dev_scsi, &good_dev, &page_code); | ||||
499 | if (!good_dev) { | ||||
500 | retval = 1; | ||||
501 | goto out; | ||||
502 | } | ||||
503 | |||||
504 | /* read serial number from mode pages (no values for optical drives) */ | ||||
505 | scsi_get_serial(udev, &dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN256); | ||||
506 | |||||
507 | if (export) { | ||||
508 | char serial_str[MAX_SERIAL_LEN256]; | ||||
509 | |||||
510 | printf("ID_SCSI=1\n"); | ||||
511 | printf("ID_VENDOR=%s\n", vendor_str); | ||||
512 | printf("ID_VENDOR_ENC=%s\n", vendor_enc_str); | ||||
513 | printf("ID_MODEL=%s\n", model_str); | ||||
514 | printf("ID_MODEL_ENC=%s\n", model_enc_str); | ||||
515 | printf("ID_REVISION=%s\n", revision_str); | ||||
516 | printf("ID_TYPE=%s\n", type_str); | ||||
517 | if (dev_scsi.serial[0] != '\0') { | ||||
518 | util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)); | ||||
519 | util_replace_chars(serial_str, NULL((void*)0)); | ||||
520 | printf("ID_SERIAL=%s\n", serial_str); | ||||
521 | util_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str)); | ||||
522 | util_replace_chars(serial_str, NULL((void*)0)); | ||||
523 | printf("ID_SERIAL_SHORT=%s\n", serial_str); | ||||
524 | } | ||||
525 | if (dev_scsi.wwn[0] != '\0') { | ||||
526 | printf("ID_WWN=0x%s\n", dev_scsi.wwn); | ||||
527 | if (dev_scsi.wwn_vendor_extension[0] != '\0') { | ||||
528 | printf("ID_WWN_VENDOR_EXTENSION=0x%s\n", dev_scsi.wwn_vendor_extension); | ||||
529 | printf("ID_WWN_WITH_EXTENSION=0x%s%s\n", dev_scsi.wwn, dev_scsi.wwn_vendor_extension); | ||||
530 | } else | ||||
531 | printf("ID_WWN_WITH_EXTENSION=0x%s\n", dev_scsi.wwn); | ||||
532 | } | ||||
533 | if (dev_scsi.tgpt_group[0] != '\0') | ||||
534 | printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group); | ||||
535 | if (dev_scsi.unit_serial_number[0] != '\0') | ||||
536 | printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number); | ||||
537 | goto out; | ||||
538 | } | ||||
539 | |||||
540 | if (dev_scsi.serial[0] == '\0') { | ||||
541 | retval = 1; | ||||
542 | goto out; | ||||
543 | } | ||||
544 | |||||
545 | if (reformat_serial) { | ||||
546 | char serial_str[MAX_SERIAL_LEN256]; | ||||
547 | |||||
548 | util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)); | ||||
549 | util_replace_chars(serial_str, NULL((void*)0)); | ||||
550 | printf("%s\n", serial_str); | ||||
551 | goto out; | ||||
552 | } | ||||
553 | |||||
554 | printf("%s\n", dev_scsi.serial); | ||||
555 | out: | ||||
556 | return retval; | ||||
557 | } | ||||
558 | |||||
559 | int main(int argc, char **argv) { | ||||
560 | _cleanup_(udev_unrefp)__attribute__((cleanup(udev_unrefp))) struct udev *udev; | ||||
561 | int retval = 0; | ||||
562 | char maj_min_dev[MAX_PATH_LEN512]; | ||||
563 | int newargc; | ||||
564 | char **newargv = NULL((void*)0); | ||||
565 | |||||
566 | log_set_target(LOG_TARGET_AUTO); | ||||
567 | udev_parse_config(); | ||||
568 | log_parse_environment()log_parse_environment_realm(LOG_REALM_UDEV); | ||||
569 | log_open(); | ||||
570 | |||||
571 | udev = udev_new(); | ||||
572 | if (udev == NULL((void*)0)) | ||||
| |||||
573 | goto exit; | ||||
574 | |||||
575 | /* | ||||
576 | * Get config file options. | ||||
577 | */ | ||||
578 | retval = get_file_options(udev, NULL((void*)0), NULL((void*)0), &newargc, &newargv); | ||||
579 | if (retval < 0) { | ||||
580 | retval = 1; | ||||
581 | goto exit; | ||||
582 | } | ||||
583 | if (retval == 0) { | ||||
584 | assert(newargv)do { if ((__builtin_expect(!!(!(newargv)),0))) log_assert_failed_realm (LOG_REALM_UDEV, ("newargv"), "../src/udev/scsi_id/scsi_id.c" , 584, __PRETTY_FUNCTION__); } while (0); | ||||
585 | |||||
586 | if (set_options(udev, newargc, newargv, maj_min_dev) < 0) { | ||||
587 | retval = 2; | ||||
588 | goto exit; | ||||
589 | } | ||||
590 | } | ||||
591 | |||||
592 | /* | ||||
593 | * Get command line options (overriding any config file settings). | ||||
594 | */ | ||||
595 | if (set_options(udev, argc, argv, maj_min_dev) < 0) | ||||
596 | exit(EXIT_FAILURE1); | ||||
597 | |||||
598 | if (!dev_specified) { | ||||
599 | log_error("No device specified.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_UDEV ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/udev/scsi_id/scsi_id.c", 599, __func__, "No device specified." ) : -abs(_e); }); | ||||
600 | retval = 1; | ||||
601 | goto exit; | ||||
602 | } | ||||
603 | |||||
604 | retval = scsi_id(udev, maj_min_dev); | ||||
605 | |||||
606 | exit: | ||||
607 | if (newargv) { | ||||
608 | free(newargv[0]); | ||||
609 | free(newargv); | ||||
610 | } | ||||
611 | log_close(); | ||||
612 | return retval; | ||||
613 | } |