File: | src/sbin/scsi/scsi.c |
Warning: | line 317, column 17 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: scsi.c,v 1.31 2021/06/22 14:51:29 jmc Exp $ */ | |||
2 | /* $FreeBSD: scsi.c,v 1.11 1996/04/06 11:00:28 joerg Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Written By Julian ELischer | |||
6 | * Copyright julian Elischer 1993. | |||
7 | * Permission is granted to use or redistribute this file in any way as long | |||
8 | * as this notice remains. Julian Elischer does not guarantee that this file | |||
9 | * is totally correct for any given task and users of this file must | |||
10 | * accept responsibility for any damage that occurs from the application of this | |||
11 | * file. | |||
12 | * | |||
13 | * (julian@tfs.com julian@dialix.oz.au) | |||
14 | * | |||
15 | * User SCSI hooks added by Peter Dufault: | |||
16 | * | |||
17 | * Copyright (c) 1994 HD Associates | |||
18 | * (contact: dufault@hda.com) | |||
19 | * All rights reserved. | |||
20 | * | |||
21 | * Redistribution and use in source and binary forms, with or without | |||
22 | * modification, are permitted provided that the following conditions | |||
23 | * are met: | |||
24 | * 1. Redistributions of source code must retain the above copyright | |||
25 | * notice, this list of conditions and the following disclaimer. | |||
26 | * 2. Redistributions in binary form must reproduce the above copyright | |||
27 | * notice, this list of conditions and the following disclaimer in the | |||
28 | * documentation and/or other materials provided with the distribution. | |||
29 | * 3. The name of HD Associates | |||
30 | * may not be used to endorse or promote products derived from this software | |||
31 | * without specific prior written permission. | |||
32 | * | |||
33 | * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND | |||
34 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
35 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
36 | * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES BE LIABLE | |||
37 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
38 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
39 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
40 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
41 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
42 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
43 | * SUCH DAMAGE. | |||
44 | */ | |||
45 | ||||
46 | #include <sys/types.h> | |||
47 | #include <sys/wait.h> | |||
48 | ||||
49 | #include <fcntl.h> | |||
50 | #include <stdio.h> | |||
51 | #include <string.h> | |||
52 | #include <stdlib.h> | |||
53 | #include <unistd.h> | |||
54 | #include <errno(*__errno()).h> | |||
55 | #include <sys/scsiio.h> | |||
56 | #include <ctype.h> | |||
57 | #include <signal.h> | |||
58 | #include <err.h> | |||
59 | #include <paths.h> | |||
60 | ||||
61 | #include "libscsi.h" | |||
62 | ||||
63 | int fd; | |||
64 | int debuglevel; | |||
65 | int debugflag; | |||
66 | int commandflag; | |||
67 | int verbose = 0; | |||
68 | ||||
69 | int modeflag; | |||
70 | int editflag; | |||
71 | int modepage = 0; /* Read this mode page */ | |||
72 | int pagectl = 0; /* Mode sense page control */ | |||
73 | int seconds = 2; | |||
74 | ||||
75 | void procargs(int *argc_p, char ***argv_p); | |||
76 | int iget(void *hook, char *name); | |||
77 | char *cget(void *hook, char *name); | |||
78 | void arg_put(void *hook, int letter, void *arg, int count, char *name); | |||
79 | void mode_sense(int fd, u_char *data, int len, int pc, int page); | |||
80 | void mode_select(int fd, u_char *data, int len, int perm); | |||
81 | int editit(const char *pathname); | |||
82 | ||||
83 | static void | |||
84 | usage(void) | |||
85 | { | |||
86 | fprintf(stderr(&__sF[2]), | |||
87 | "usage: scsi -f device -d debug_level\n" | |||
88 | " scsi -f device -m page [-e] [-P pc]\n" | |||
89 | " scsi -f device [-v] [-s seconds] -c cmd_fmt [arg ...]" | |||
90 | " -o count out_fmt\n" | |||
91 | " [arg ...] -i count in_fmt [arg ...]\n"); | |||
92 | ||||
93 | exit (1); | |||
94 | } | |||
95 | ||||
96 | void | |||
97 | procargs(int *argc_p, char ***argv_p) | |||
98 | { | |||
99 | int argc = *argc_p; | |||
100 | char **argv = *argv_p; | |||
101 | int fflag, ch; | |||
102 | ||||
103 | fflag = 0; | |||
104 | commandflag = 0; | |||
105 | debugflag = 0; | |||
106 | while ((ch = getopt(argc, argv, "cef:d:m:P:s:v")) != -1) { | |||
107 | switch (ch) { | |||
108 | case 'c': | |||
109 | commandflag = 1; | |||
110 | break; | |||
111 | case 'e': | |||
112 | editflag = 1; | |||
113 | break; | |||
114 | case 'f': | |||
115 | if ((fd = scsi_open(optarg, O_RDWR0x0002)) < 0) | |||
116 | err(1, "unable to open device %s", optarg); | |||
117 | fflag = 1; | |||
118 | break; | |||
119 | case 'd': | |||
120 | debuglevel = strtol(optarg, 0, 0); | |||
121 | debugflag = 1; | |||
122 | break; | |||
123 | case 'm': | |||
124 | modeflag = 1; | |||
125 | modepage = strtol(optarg, 0, 0); | |||
126 | break; | |||
127 | case 'P': | |||
128 | pagectl = strtol(optarg, 0, 0); | |||
129 | break; | |||
130 | case 's': | |||
131 | seconds = strtol(optarg, 0, 0); | |||
132 | break; | |||
133 | case 'v': | |||
134 | verbose = 1; | |||
135 | break; | |||
136 | case '?': | |||
137 | default: | |||
138 | usage(); | |||
139 | } | |||
140 | } | |||
141 | *argc_p = argc - optind; | |||
142 | *argv_p = argv + optind; | |||
143 | ||||
144 | if (!fflag) usage(); | |||
145 | } | |||
146 | ||||
147 | /* get_hook: Structure for evaluating args in a callback. | |||
148 | */ | |||
149 | struct get_hook | |||
150 | { | |||
151 | int argc; | |||
152 | char **argv; | |||
153 | int got; | |||
154 | }; | |||
155 | ||||
156 | /* iget: Integer argument callback | |||
157 | */ | |||
158 | int | |||
159 | iget(void *hook, char *name) | |||
160 | { | |||
161 | struct get_hook *h = (struct get_hook *)hook; | |||
162 | int arg; | |||
163 | ||||
164 | if (h->got >= h->argc) | |||
165 | { | |||
166 | fprintf(stderr(&__sF[2]), "Expecting an integer argument.\n"); | |||
167 | usage(); | |||
168 | } | |||
169 | arg = strtol(h->argv[h->got], 0, 0); | |||
170 | h->got++; | |||
171 | ||||
172 | if (verbose && name && *name) | |||
173 | printf("%s: %d\n", name, arg); | |||
174 | ||||
175 | return arg; | |||
176 | } | |||
177 | ||||
178 | /* cget: char * argument callback | |||
179 | */ | |||
180 | char * | |||
181 | cget(void *hook, char *name) | |||
182 | { | |||
183 | struct get_hook *h = (struct get_hook *)hook; | |||
184 | char *arg; | |||
185 | ||||
186 | if (h->got >= h->argc) | |||
187 | { | |||
188 | fprintf(stderr(&__sF[2]), "Expecting a character pointer argument.\n"); | |||
189 | usage(); | |||
190 | } | |||
191 | arg = h->argv[h->got]; | |||
192 | h->got++; | |||
193 | ||||
194 | if (verbose && name) | |||
195 | printf("cget: %s: %s", name, arg); | |||
196 | ||||
197 | return arg; | |||
198 | } | |||
199 | ||||
200 | /* arg_put: "put argument" callback | |||
201 | */ | |||
202 | void arg_put(void *hook, int letter, void *arg, int count, char *name) | |||
203 | { | |||
204 | if (verbose && name && *name) | |||
205 | printf("%s: ", name); | |||
206 | ||||
207 | switch(letter) | |||
208 | { | |||
209 | case 'i': | |||
210 | case 'b': | |||
211 | printf("%ld ", (long)arg); | |||
212 | break; | |||
213 | ||||
214 | case 'c': | |||
215 | case 'z': | |||
216 | { | |||
217 | char *p = malloc(count + 1); | |||
218 | if (p == NULL((void *)0)) | |||
219 | err(1, NULL((void *)0)); | |||
220 | ||||
221 | p[count] = 0; | |||
222 | strncpy(p, (char *)arg, count); | |||
223 | if (letter == 'z') | |||
224 | { | |||
225 | int i; | |||
226 | for (i = count - 1; i >= 0; i--) | |||
227 | if (p[i] == ' ') | |||
228 | p[i] = 0; | |||
229 | else | |||
230 | break; | |||
231 | } | |||
232 | printf("%s ", p); | |||
233 | free(p); | |||
234 | } | |||
235 | ||||
236 | break; | |||
237 | ||||
238 | default: | |||
239 | printf("Unknown format letter: '%c'\n", letter); | |||
240 | } | |||
241 | if (verbose) | |||
242 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
243 | } | |||
244 | ||||
245 | /* data_phase: SCSI bus data phase: DATA IN, DATA OUT, or no data transfer. | |||
246 | */ | |||
247 | enum data_phase {none = 0, in, out}; | |||
248 | ||||
249 | /* do_cmd: Send a command to a SCSI device | |||
250 | */ | |||
251 | static void | |||
252 | do_cmd(int fd, char *fmt, int argc, char **argv) | |||
253 | { | |||
254 | struct get_hook h; | |||
255 | scsireq_t *scsireq = scsireq_new(); | |||
256 | enum data_phase data_phase; | |||
257 | int count, amount; | |||
258 | char *data_fmt, *bp; | |||
259 | ||||
260 | h.argc = argc; | |||
261 | h.argv = argv; | |||
262 | h.got = 0; | |||
263 | ||||
264 | scsireq_reset(scsireq); | |||
265 | ||||
266 | scsireq_build_visit(scsireq, 0, 0, 0, fmt, iget, (void *)&h); | |||
267 | ||||
268 | /* Three choices here: | |||
269 | * 1. We've used up all the args and have no data phase. | |||
270 | * 2. We have input data ("-i") | |||
271 | * 3. We have output data ("-o") | |||
272 | */ | |||
273 | ||||
274 | if (h.got >= h.argc) | |||
275 | { | |||
276 | data_phase = none; | |||
277 | count = scsireq->datalen = 0; | |||
278 | } | |||
279 | else | |||
280 | { | |||
281 | char *flag = cget(&h, 0); | |||
282 | ||||
283 | if (strcmp(flag, "-o") == 0) | |||
284 | { | |||
285 | data_phase = out; | |||
286 | scsireq->flags = SCCMD_WRITE0x00000002; | |||
287 | } | |||
288 | else if (strcmp(flag, "-i") == 0) | |||
289 | { | |||
290 | data_phase = in; | |||
291 | scsireq->flags = SCCMD_READ0x00000001; | |||
292 | } | |||
293 | else | |||
294 | { | |||
295 | fprintf(stderr(&__sF[2]), | |||
296 | "Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag); | |||
297 | usage(); | |||
298 | } | |||
299 | ||||
300 | count = scsireq->datalen = iget(&h, 0); | |||
301 | if (count) { | |||
302 | data_fmt = cget(&h, 0); | |||
303 | ||||
304 | scsireq->databuf = malloc(count); | |||
305 | if (scsireq->databuf == NULL((void *)0)) | |||
306 | err(1, NULL((void *)0)); | |||
307 | ||||
308 | if (data_phase
| |||
309 | if (strcmp(data_fmt, "-") == 0) { | |||
310 | bp = (char *)scsireq->databuf; | |||
311 | while (count > 0 && | |||
312 | (amount = read(STDIN_FILENO0, | |||
313 | bp, count)) > 0) { | |||
314 | count -= amount; | |||
315 | bp += amount; | |||
316 | } | |||
317 | if (amount == -1) | |||
| ||||
318 | err(1, "read"); | |||
319 | else if (amount == 0) { | |||
320 | /* early EOF */ | |||
321 | fprintf(stderr(&__sF[2]), | |||
322 | "Warning: only read %lu bytes out of %lu.\n", | |||
323 | scsireq->datalen - (u_long)count, | |||
324 | scsireq->datalen); | |||
325 | scsireq->datalen -= (u_long)count; | |||
326 | } | |||
327 | } | |||
328 | else | |||
329 | { | |||
330 | bzero(scsireq->databuf, count); | |||
331 | scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h); | |||
332 | } | |||
333 | } | |||
334 | } | |||
335 | } | |||
336 | ||||
337 | ||||
338 | scsireq->timeout = seconds * 1000; | |||
339 | ||||
340 | if (scsireq_enter(fd, scsireq) == -1) | |||
341 | { | |||
342 | scsi_debug(stderr(&__sF[2]), -1, scsireq); | |||
343 | exit(1); | |||
344 | } | |||
345 | ||||
346 | if (SCSIREQ_ERROR(scsireq)(scsireq->senselen_used || scsireq->status || scsireq-> retsts || scsireq->error)) | |||
347 | scsi_debug(stderr(&__sF[2]), 0, scsireq); | |||
348 | ||||
349 | if (count && data_phase == in) | |||
350 | { | |||
351 | if (strcmp(data_fmt, "-") == 0) /* stdout */ | |||
352 | { | |||
353 | bp = (char *)scsireq->databuf; | |||
354 | while (count > 0 && (amount = write(STDOUT_FILENO1, bp, count)) > 0) | |||
355 | { | |||
356 | count -= amount; | |||
357 | bp += amount; | |||
358 | } | |||
359 | if (amount < 0) | |||
360 | err(1, "write"); | |||
361 | else if (amount == 0) | |||
362 | fprintf(stderr(&__sF[2]), "Warning: wrote only %lu bytes out of %lu.\n", | |||
363 | scsireq->datalen - count, | |||
364 | scsireq->datalen); | |||
365 | ||||
366 | } | |||
367 | else | |||
368 | { | |||
369 | scsireq_decode_visit(scsireq, data_fmt, arg_put, 0); | |||
370 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
371 | } | |||
372 | } | |||
373 | } | |||
374 | ||||
375 | void mode_sense(int fd, u_char *data, int len, int pc, int page) | |||
376 | { | |||
377 | scsireq_t *scsireq; | |||
378 | ||||
379 | bzero(data, len); | |||
380 | ||||
381 | scsireq = scsireq_new(); | |||
382 | ||||
383 | if (scsireq_enter(fd, scsireq_build(scsireq, | |||
384 | len, data, SCCMD_READ0x00000001, | |||
385 | "1A 0 v:2 {Page Control} v:6 {Page Code} 0 v:i1 {Allocation Length} 0", | |||
386 | pc, page, len)) == -1) /* Mode sense */ | |||
387 | { | |||
388 | scsi_debug(stderr(&__sF[2]), -1, scsireq); | |||
389 | exit(1); | |||
390 | } | |||
391 | ||||
392 | if (SCSIREQ_ERROR(scsireq)(scsireq->senselen_used || scsireq->status || scsireq-> retsts || scsireq->error)) | |||
393 | { | |||
394 | scsi_debug(stderr(&__sF[2]), 0, scsireq); | |||
395 | exit(1); | |||
396 | } | |||
397 | ||||
398 | free(scsireq); | |||
399 | } | |||
400 | ||||
401 | void mode_select(int fd, u_char *data, int len, int perm) | |||
402 | { | |||
403 | scsireq_t *scsireq; | |||
404 | ||||
405 | scsireq = scsireq_new(); | |||
406 | ||||
407 | if (scsireq_enter(fd, scsireq_build(scsireq, | |||
408 | len, data, SCCMD_WRITE0x00000002, | |||
409 | "15 0:7 v:1 {SP} 0 0 v:i1 {Allocation Length} 0", perm, len)) == -1) /* Mode select */ | |||
410 | { | |||
411 | scsi_debug(stderr(&__sF[2]), -1, scsireq); | |||
412 | exit(1); | |||
413 | } | |||
414 | ||||
415 | if (SCSIREQ_ERROR(scsireq)(scsireq->senselen_used || scsireq->status || scsireq-> retsts || scsireq->error)) | |||
416 | { | |||
417 | scsi_debug(stderr(&__sF[2]), 0, scsireq); | |||
418 | exit(1); | |||
419 | } | |||
420 | ||||
421 | free(scsireq); | |||
422 | } | |||
423 | ||||
424 | ||||
425 | #define START_ENTRY'{' '{' | |||
426 | #define END_ENTRY'}' '}' | |||
427 | ||||
428 | static void | |||
429 | skipwhite(FILE *f) | |||
430 | { | |||
431 | int c; | |||
432 | ||||
433 | skip_again: | |||
434 | ||||
435 | while (isspace(c = getc(f)(!__isthreaded ? (--(f)->_r < 0 ? __srget(f) : (int)(*( f)->_p++)) : (getc)(f)))) | |||
436 | continue; | |||
437 | ||||
438 | if (c == '#') { | |||
439 | while ((c = getc(f)(!__isthreaded ? (--(f)->_r < 0 ? __srget(f) : (int)(*( f)->_p++)) : (getc)(f))) != '\n' && c != EOF(-1)) | |||
440 | continue; | |||
441 | goto skip_again; | |||
442 | } | |||
443 | ||||
444 | ungetc(c, f); | |||
445 | } | |||
446 | ||||
447 | /* mode_lookup: Lookup a format description for a given page. | |||
448 | */ | |||
449 | char *mode_db = "/usr/share/misc/scsi_modes"; | |||
450 | static char *mode_lookup(int page) | |||
451 | { | |||
452 | char *new_db; | |||
453 | FILE *modes; | |||
454 | int match, next, found, c; | |||
455 | static char fmt[1024]; /* XXX This should be with strealloc */ | |||
456 | int page_desc; | |||
457 | new_db = getenv("SCSI_MODES"); | |||
458 | ||||
459 | if (new_db) | |||
460 | mode_db = new_db; | |||
461 | ||||
462 | modes = fopen(mode_db, "r"); | |||
463 | if (modes == NULL((void *)0)) | |||
464 | return 0; | |||
465 | ||||
466 | next = 0; | |||
467 | found = 0; | |||
468 | ||||
469 | while (!found) { | |||
470 | ||||
471 | skipwhite(modes); | |||
472 | ||||
473 | if (fscanf(modes, "%i", &page_desc) != 1) | |||
474 | break; | |||
475 | ||||
476 | if (page_desc == page) | |||
477 | found = 1; | |||
478 | ||||
479 | skipwhite(modes); | |||
480 | if (getc(modes)(!__isthreaded ? (--(modes)->_r < 0 ? __srget(modes) : ( int)(*(modes)->_p++)) : (getc)(modes)) != START_ENTRY'{') { | |||
481 | errx(1, "Expected %c", START_ENTRY'{'); | |||
482 | } | |||
483 | ||||
484 | match = 1; | |||
485 | while (match != 0) { | |||
486 | c = getc(modes)(!__isthreaded ? (--(modes)->_r < 0 ? __srget(modes) : ( int)(*(modes)->_p++)) : (getc)(modes)); | |||
487 | if (c == EOF(-1)) | |||
488 | fprintf(stderr(&__sF[2]), "Expected %c.\n", END_ENTRY'}'); | |||
489 | ||||
490 | if (c == START_ENTRY'{') { | |||
491 | match++; | |||
492 | } | |||
493 | if (c == END_ENTRY'}') { | |||
494 | match--; | |||
495 | if (match == 0) | |||
496 | break; | |||
497 | } | |||
498 | if (found && c != '\n') { | |||
499 | if (next >= sizeof(fmt)) { | |||
500 | errx(1, "Stupid program: Buffer overflow.\n"); | |||
501 | } | |||
502 | ||||
503 | fmt[next++] = (u_char)c; | |||
504 | } | |||
505 | } | |||
506 | } | |||
507 | fclose(modes); | |||
508 | fmt[next] = 0; | |||
509 | ||||
510 | return (found) ? fmt : 0; | |||
511 | } | |||
512 | ||||
513 | /* -------- edit: Mode Select Editor --------- | |||
514 | */ | |||
515 | struct editinfo | |||
516 | { | |||
517 | long can_edit; | |||
518 | long default_value; | |||
519 | } editinfo[64]; /* XXX Bogus fixed size */ | |||
520 | ||||
521 | static int editind; | |||
522 | volatile int edit_opened; | |||
523 | static FILE *edit_file; | |||
524 | static char edit_name[L_tmpnam1024]; | |||
525 | ||||
526 | static void | |||
527 | edit_rewind(void) | |||
528 | { | |||
529 | editind = 0; | |||
530 | } | |||
531 | ||||
532 | static void | |||
533 | edit_done(void) | |||
534 | { | |||
535 | int opened; | |||
536 | ||||
537 | sigset_t all, prev; | |||
538 | sigfillset(&all); | |||
539 | ||||
540 | (void)sigprocmask(SIG_SETMASK3, &all, &prev); | |||
541 | ||||
542 | opened = (int)edit_opened; | |||
543 | edit_opened = 0; | |||
544 | ||||
545 | (void)sigprocmask(SIG_SETMASK3, &prev, 0); | |||
546 | ||||
547 | if (opened) | |||
548 | { | |||
549 | if (fclose(edit_file)) | |||
550 | perror(edit_name); | |||
551 | if (unlink(edit_name)) | |||
552 | perror(edit_name); | |||
553 | } | |||
554 | } | |||
555 | ||||
556 | static void | |||
557 | edit_init(void) | |||
558 | { | |||
559 | int fd; | |||
560 | ||||
561 | edit_rewind(); | |||
562 | strlcpy(edit_name, "/var/tmp/scXXXXXXXX", sizeof edit_name); | |||
563 | if ((fd = mkstemp(edit_name)) == -1) | |||
564 | err(1, "mkstemp"); | |||
565 | if ( (edit_file = fdopen(fd, "w+")) == 0) | |||
566 | err(1, "fdopen"); | |||
567 | edit_opened = 1; | |||
568 | ||||
569 | atexit(edit_done); | |||
570 | } | |||
571 | ||||
572 | static void | |||
573 | edit_check(void *hook, int letter, void *arg, int count, char *name) | |||
574 | { | |||
575 | if (letter != 'i' && letter != 'b') { | |||
576 | errx(1, "Can't edit format %c.\n", letter); | |||
577 | } | |||
578 | ||||
579 | if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) { | |||
580 | errx(1, "edit table overflow"); | |||
581 | } | |||
582 | editinfo[editind].can_edit = ((long)arg != 0); | |||
583 | editind++; | |||
584 | } | |||
585 | ||||
586 | static void | |||
587 | edit_defaults(void *hook, int letter, void *arg, int count, char *name) | |||
588 | { | |||
589 | if (letter != 'i' && letter != 'b') { | |||
590 | errx(1, "Can't edit format %c.\n", letter); | |||
591 | } | |||
592 | ||||
593 | editinfo[editind].default_value = ((long)arg); | |||
594 | editind++; | |||
595 | } | |||
596 | ||||
597 | static void | |||
598 | edit_report(void *hook, int letter, void *arg, int count, char *name) | |||
599 | { | |||
600 | if (editinfo[editind].can_edit) { | |||
601 | if (letter != 'i' && letter != 'b') { | |||
602 | errx(1, "Can't report format %c.\n", letter); | |||
603 | } | |||
604 | ||||
605 | fprintf(edit_file, "%s: %ld\n", name, (long)arg); | |||
606 | } | |||
607 | ||||
608 | editind++; | |||
609 | } | |||
610 | ||||
611 | static int | |||
612 | edit_get(void *hook, char *name) | |||
613 | { | |||
614 | int arg = editinfo[editind].default_value; | |||
615 | ||||
616 | if (editinfo[editind].can_edit) { | |||
617 | char line[80]; | |||
618 | size_t len; | |||
619 | if (fgets(line, sizeof(line), edit_file) == NULL((void *)0)) | |||
620 | err(1, "fgets"); | |||
621 | ||||
622 | len = strlen(line); | |||
623 | if (len && line[len - 1] == '\n') | |||
624 | line[len - 1] = '\0'; | |||
625 | ||||
626 | if (strncmp(name, line, strlen(name)) != 0) { | |||
627 | errx(1, "Expected \"%s\" and read \"%s\"\n", | |||
628 | name, line); | |||
629 | } | |||
630 | ||||
631 | arg = strtoul(line + strlen(name) + 2, 0, 0); | |||
632 | } | |||
633 | ||||
634 | editind++; | |||
635 | return arg; | |||
636 | } | |||
637 | ||||
638 | int | |||
639 | editit(const char *pathname) | |||
640 | { | |||
641 | char *argp[] = {"sh", "-c", NULL((void *)0), NULL((void *)0)}, *ed, *p; | |||
642 | sig_t sighup, sigint, sigquit; | |||
643 | pid_t pid; | |||
644 | int st; | |||
645 | ||||
646 | ed = getenv("VISUAL"); | |||
647 | if (ed == NULL((void *)0) || ed[0] == '\0') | |||
648 | ed = getenv("EDITOR"); | |||
649 | if (ed == NULL((void *)0) || ed[0] == '\0') | |||
650 | ed = _PATH_VI"/usr/bin/vi"; | |||
651 | if (asprintf(&p, "%s %s", ed, pathname) == -1) | |||
652 | return (-1); | |||
653 | argp[2] = p; | |||
654 | ||||
655 | top: | |||
656 | sighup = signal(SIGHUP1, SIG_IGN(void (*)(int))1); | |||
657 | sigint = signal(SIGINT2, SIG_IGN(void (*)(int))1); | |||
658 | sigquit = signal(SIGQUIT3, SIG_IGN(void (*)(int))1); | |||
659 | if ((pid = fork()) == -1) { | |||
660 | int saved_errno = errno(*__errno()); | |||
661 | ||||
662 | (void)signal(SIGHUP1, sighup); | |||
663 | (void)signal(SIGINT2, sigint); | |||
664 | (void)signal(SIGQUIT3, sigquit); | |||
665 | if (saved_errno == EAGAIN35) { | |||
666 | sleep(1); | |||
667 | goto top; | |||
668 | } | |||
669 | free(p); | |||
670 | errno(*__errno()) = saved_errno; | |||
671 | return (-1); | |||
672 | } | |||
673 | if (pid == 0) { | |||
674 | execv(_PATH_BSHELL"/bin/sh", argp); | |||
675 | _exit(127); | |||
676 | } | |||
677 | free(p); | |||
678 | for (;;) { | |||
679 | if (waitpid(pid, &st, 0) == -1) { | |||
680 | if (errno(*__errno()) != EINTR4) | |||
681 | return (-1); | |||
682 | } else | |||
683 | break; | |||
684 | } | |||
685 | (void)signal(SIGHUP1, sighup); | |||
686 | (void)signal(SIGINT2, sigint); | |||
687 | (void)signal(SIGQUIT3, sigquit); | |||
688 | if (!WIFEXITED(st)(((st) & 0177) == 0) || WEXITSTATUS(st)(int)(((unsigned)(st) >> 8) & 0xff) != 0) { | |||
689 | errno(*__errno()) = ECHILD10; | |||
690 | return (-1); | |||
691 | } | |||
692 | return (0); | |||
693 | } | |||
694 | ||||
695 | static void | |||
696 | mode_edit(int fd, int page, int edit, int argc, char *argv[]) | |||
697 | { | |||
698 | int i; | |||
699 | u_char data[255]; | |||
700 | u_char *mode_pars; | |||
701 | struct mode_header | |||
702 | { | |||
703 | u_char mdl; /* Mode data length */ | |||
704 | u_char medium_type; | |||
705 | u_char dev_spec_par; | |||
706 | u_char bdl; /* Block descriptor length */ | |||
707 | }; | |||
708 | ||||
709 | struct mode_page_header | |||
710 | { | |||
711 | u_char page_code; | |||
712 | u_char page_length; | |||
713 | }; | |||
714 | ||||
715 | struct mode_header *mh; | |||
716 | struct mode_page_header *mph; | |||
717 | ||||
718 | char *fmt = mode_lookup(page); | |||
719 | if (!fmt && verbose) { | |||
720 | fprintf(stderr(&__sF[2]), | |||
721 | "No mode data base entry in \"%s\" for page %d; binary %s only.\n", | |||
722 | mode_db, page, (edit ? "edit" : "display")); | |||
723 | } | |||
724 | ||||
725 | if (edit) { | |||
726 | if (!fmt) { | |||
727 | errx(1, "Sorry: can't edit without a format.\n"); | |||
728 | } | |||
729 | ||||
730 | if (pagectl != 0 && pagectl != 3) { | |||
731 | errx(1, | |||
732 | "It only makes sense to edit page 0 (current) or page 3 (saved values)\n"); | |||
733 | } | |||
734 | ||||
735 | verbose = 1; | |||
736 | ||||
737 | mode_sense(fd, data, sizeof(data), 1, page); | |||
738 | ||||
739 | mh = (struct mode_header *)data; | |||
740 | mph = (struct mode_page_header *) | |||
741 | (((char *)mh) + sizeof(*mh) + mh->bdl); | |||
742 | ||||
743 | mode_pars = (char *)mph + sizeof(*mph); | |||
744 | ||||
745 | edit_init(); | |||
746 | scsireq_buff_decode_visit(mode_pars, mh->mdl, | |||
747 | fmt, edit_check, 0); | |||
748 | ||||
749 | mode_sense(fd, data, sizeof(data), 0, page); | |||
750 | ||||
751 | edit_rewind(); | |||
752 | scsireq_buff_decode_visit(mode_pars, mh->mdl, | |||
753 | fmt, edit_defaults, 0); | |||
754 | ||||
755 | edit_rewind(); | |||
756 | scsireq_buff_decode_visit(mode_pars, mh->mdl, | |||
757 | fmt, edit_report, 0); | |||
758 | ||||
759 | fclose(edit_file); | |||
760 | if (editit(edit_name) == -1 && errno(*__errno()) != ECHILD10) | |||
761 | err(1, "edit %s", edit_name); | |||
762 | if ((edit_file = fopen(edit_name, "r")) == NULL((void *)0)) | |||
763 | err(1, "open %s", edit_name); | |||
764 | ||||
765 | edit_rewind(); | |||
766 | scsireq_buff_encode_visit(mode_pars, mh->mdl, | |||
767 | fmt, edit_get, 0); | |||
768 | ||||
769 | /* Eliminate block descriptors: | |||
770 | */ | |||
771 | bcopy((char *)mph, ((char *)mh) + sizeof(*mh), | |||
772 | sizeof(*mph) + mph->page_length); | |||
773 | ||||
774 | mh->bdl = 0; | |||
775 | mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); | |||
776 | mode_pars = ((char *)mph) + 2; | |||
777 | ||||
778 | #if 0 | |||
779 | /* Turn this on to see what you're sending to the | |||
780 | * device: | |||
781 | */ | |||
782 | edit_rewind(); | |||
783 | scsireq_buff_decode_visit(mode_pars, | |||
784 | mh->mdl, fmt, arg_put, 0); | |||
785 | #endif | |||
786 | ||||
787 | edit_done(); | |||
788 | ||||
789 | /* Make it permanent if pageselect is three. | |||
790 | */ | |||
791 | ||||
792 | mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ | |||
793 | mh->mdl = 0; /* Reserved for mode select */ | |||
794 | ||||
795 | mode_select(fd, (char *)mh, | |||
796 | sizeof(*mh) + mh->bdl + sizeof(*mph) + mph->page_length, | |||
797 | (pagectl == 3)); | |||
798 | ||||
799 | exit(0); | |||
800 | } | |||
801 | ||||
802 | mode_sense(fd, data, sizeof(data), pagectl, page); | |||
803 | ||||
804 | /* Skip over the block descriptors. | |||
805 | */ | |||
806 | mh = (struct mode_header *)data; | |||
807 | mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); | |||
808 | mode_pars = (char *)mph + sizeof(*mph); | |||
809 | ||||
810 | if (!fmt) { | |||
811 | for (i = 0; i < mh->mdl; i++) { | |||
812 | printf("%02x%c",mode_pars[i], | |||
813 | (((i + 1) % 8) == 0) ? '\n' : ' '); | |||
814 | } | |||
815 | putc('\n', stdout)(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
816 | } else { | |||
817 | verbose = 1; | |||
818 | scsireq_buff_decode_visit(mode_pars, | |||
819 | mh->mdl, fmt, arg_put, 0); | |||
820 | } | |||
821 | } | |||
822 | ||||
823 | int | |||
824 | main(int argc, char **argv) | |||
825 | { | |||
826 | procargs(&argc,&argv); | |||
827 | ||||
828 | /* XXX This has grown to the point that it should be cleaned up. | |||
829 | */ | |||
830 | if (debugflag) { | |||
| ||||
831 | if (ioctl(fd,SCIOCDEBUG((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('Q')) << 8) | ((2))),&debuglevel) == -1) | |||
832 | err(1, "SCIOCDEBUG"); | |||
833 | } else if (commandflag) { | |||
834 | char *fmt; | |||
835 | ||||
836 | if (argc < 1) { | |||
837 | fprintf(stderr(&__sF[2]), "Need the command format string.\n"); | |||
838 | usage(); | |||
839 | } | |||
840 | ||||
841 | ||||
842 | fmt = argv[0]; | |||
843 | ||||
844 | argc -= 1; | |||
845 | argv += 1; | |||
846 | ||||
847 | do_cmd(fd, fmt, argc, argv); | |||
848 | } else if (modeflag) | |||
849 | mode_edit(fd, modepage, editflag, argc, argv); | |||
850 | ||||
851 | exit(0); | |||
852 | } |