File: | src/sbin/scsi/scsi.c |
Warning: | line 316, column 17 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: scsi.c,v 1.32 2022/12/04 23:50:47 cheloha 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 | default: | |||
137 | usage(); | |||
138 | } | |||
139 | } | |||
140 | *argc_p = argc - optind; | |||
141 | *argv_p = argv + optind; | |||
142 | ||||
143 | if (!fflag) usage(); | |||
144 | } | |||
145 | ||||
146 | /* get_hook: Structure for evaluating args in a callback. | |||
147 | */ | |||
148 | struct get_hook | |||
149 | { | |||
150 | int argc; | |||
151 | char **argv; | |||
152 | int got; | |||
153 | }; | |||
154 | ||||
155 | /* iget: Integer argument callback | |||
156 | */ | |||
157 | int | |||
158 | iget(void *hook, char *name) | |||
159 | { | |||
160 | struct get_hook *h = (struct get_hook *)hook; | |||
161 | int arg; | |||
162 | ||||
163 | if (h->got >= h->argc) | |||
164 | { | |||
165 | fprintf(stderr(&__sF[2]), "Expecting an integer argument.\n"); | |||
166 | usage(); | |||
167 | } | |||
168 | arg = strtol(h->argv[h->got], 0, 0); | |||
169 | h->got++; | |||
170 | ||||
171 | if (verbose && name && *name) | |||
172 | printf("%s: %d\n", name, arg); | |||
173 | ||||
174 | return arg; | |||
175 | } | |||
176 | ||||
177 | /* cget: char * argument callback | |||
178 | */ | |||
179 | char * | |||
180 | cget(void *hook, char *name) | |||
181 | { | |||
182 | struct get_hook *h = (struct get_hook *)hook; | |||
183 | char *arg; | |||
184 | ||||
185 | if (h->got >= h->argc) | |||
186 | { | |||
187 | fprintf(stderr(&__sF[2]), "Expecting a character pointer argument.\n"); | |||
188 | usage(); | |||
189 | } | |||
190 | arg = h->argv[h->got]; | |||
191 | h->got++; | |||
192 | ||||
193 | if (verbose && name) | |||
194 | printf("cget: %s: %s", name, arg); | |||
195 | ||||
196 | return arg; | |||
197 | } | |||
198 | ||||
199 | /* arg_put: "put argument" callback | |||
200 | */ | |||
201 | void arg_put(void *hook, int letter, void *arg, int count, char *name) | |||
202 | { | |||
203 | if (verbose && name && *name) | |||
204 | printf("%s: ", name); | |||
205 | ||||
206 | switch(letter) | |||
207 | { | |||
208 | case 'i': | |||
209 | case 'b': | |||
210 | printf("%ld ", (long)arg); | |||
211 | break; | |||
212 | ||||
213 | case 'c': | |||
214 | case 'z': | |||
215 | { | |||
216 | char *p = malloc(count + 1); | |||
217 | if (p == NULL((void *)0)) | |||
218 | err(1, NULL((void *)0)); | |||
219 | ||||
220 | p[count] = 0; | |||
221 | strncpy(p, (char *)arg, count); | |||
222 | if (letter == 'z') | |||
223 | { | |||
224 | int i; | |||
225 | for (i = count - 1; i >= 0; i--) | |||
226 | if (p[i] == ' ') | |||
227 | p[i] = 0; | |||
228 | else | |||
229 | break; | |||
230 | } | |||
231 | printf("%s ", p); | |||
232 | free(p); | |||
233 | } | |||
234 | ||||
235 | break; | |||
236 | ||||
237 | default: | |||
238 | printf("Unknown format letter: '%c'\n", letter); | |||
239 | } | |||
240 | if (verbose) | |||
241 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
242 | } | |||
243 | ||||
244 | /* data_phase: SCSI bus data phase: DATA IN, DATA OUT, or no data transfer. | |||
245 | */ | |||
246 | enum data_phase {none = 0, in, out}; | |||
247 | ||||
248 | /* do_cmd: Send a command to a SCSI device | |||
249 | */ | |||
250 | static void | |||
251 | do_cmd(int fd, char *fmt, int argc, char **argv) | |||
252 | { | |||
253 | struct get_hook h; | |||
254 | scsireq_t *scsireq = scsireq_new(); | |||
255 | enum data_phase data_phase; | |||
256 | int count, amount; | |||
257 | char *data_fmt, *bp; | |||
258 | ||||
259 | h.argc = argc; | |||
260 | h.argv = argv; | |||
261 | h.got = 0; | |||
262 | ||||
263 | scsireq_reset(scsireq); | |||
264 | ||||
265 | scsireq_build_visit(scsireq, 0, 0, 0, fmt, iget, (void *)&h); | |||
266 | ||||
267 | /* Three choices here: | |||
268 | * 1. We've used up all the args and have no data phase. | |||
269 | * 2. We have input data ("-i") | |||
270 | * 3. We have output data ("-o") | |||
271 | */ | |||
272 | ||||
273 | if (h.got >= h.argc) | |||
274 | { | |||
275 | data_phase = none; | |||
276 | count = scsireq->datalen = 0; | |||
277 | } | |||
278 | else | |||
279 | { | |||
280 | char *flag = cget(&h, 0); | |||
281 | ||||
282 | if (strcmp(flag, "-o") == 0) | |||
283 | { | |||
284 | data_phase = out; | |||
285 | scsireq->flags = SCCMD_WRITE0x00000002; | |||
286 | } | |||
287 | else if (strcmp(flag, "-i") == 0) | |||
288 | { | |||
289 | data_phase = in; | |||
290 | scsireq->flags = SCCMD_READ0x00000001; | |||
291 | } | |||
292 | else | |||
293 | { | |||
294 | fprintf(stderr(&__sF[2]), | |||
295 | "Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag); | |||
296 | usage(); | |||
297 | } | |||
298 | ||||
299 | count = scsireq->datalen = iget(&h, 0); | |||
300 | if (count) { | |||
301 | data_fmt = cget(&h, 0); | |||
302 | ||||
303 | scsireq->databuf = malloc(count); | |||
304 | if (scsireq->databuf == NULL((void *)0)) | |||
305 | err(1, NULL((void *)0)); | |||
306 | ||||
307 | if (data_phase
| |||
308 | if (strcmp(data_fmt, "-") == 0) { | |||
309 | bp = (char *)scsireq->databuf; | |||
310 | while (count > 0 && | |||
311 | (amount = read(STDIN_FILENO0, | |||
312 | bp, count)) > 0) { | |||
313 | count -= amount; | |||
314 | bp += amount; | |||
315 | } | |||
316 | if (amount == -1) | |||
| ||||
317 | err(1, "read"); | |||
318 | else if (amount == 0) { | |||
319 | /* early EOF */ | |||
320 | fprintf(stderr(&__sF[2]), | |||
321 | "Warning: only read %lu bytes out of %lu.\n", | |||
322 | scsireq->datalen - (u_long)count, | |||
323 | scsireq->datalen); | |||
324 | scsireq->datalen -= (u_long)count; | |||
325 | } | |||
326 | } | |||
327 | else | |||
328 | { | |||
329 | bzero(scsireq->databuf, count); | |||
330 | scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h); | |||
331 | } | |||
332 | } | |||
333 | } | |||
334 | } | |||
335 | ||||
336 | ||||
337 | scsireq->timeout = seconds * 1000; | |||
338 | ||||
339 | if (scsireq_enter(fd, scsireq) == -1) | |||
340 | { | |||
341 | scsi_debug(stderr(&__sF[2]), -1, scsireq); | |||
342 | exit(1); | |||
343 | } | |||
344 | ||||
345 | if (SCSIREQ_ERROR(scsireq)(scsireq->senselen_used || scsireq->status || scsireq-> retsts || scsireq->error)) | |||
346 | scsi_debug(stderr(&__sF[2]), 0, scsireq); | |||
347 | ||||
348 | if (count && data_phase == in) | |||
349 | { | |||
350 | if (strcmp(data_fmt, "-") == 0) /* stdout */ | |||
351 | { | |||
352 | bp = (char *)scsireq->databuf; | |||
353 | while (count > 0 && (amount = write(STDOUT_FILENO1, bp, count)) > 0) | |||
354 | { | |||
355 | count -= amount; | |||
356 | bp += amount; | |||
357 | } | |||
358 | if (amount < 0) | |||
359 | err(1, "write"); | |||
360 | else if (amount == 0) | |||
361 | fprintf(stderr(&__sF[2]), "Warning: wrote only %lu bytes out of %lu.\n", | |||
362 | scsireq->datalen - count, | |||
363 | scsireq->datalen); | |||
364 | ||||
365 | } | |||
366 | else | |||
367 | { | |||
368 | scsireq_decode_visit(scsireq, data_fmt, arg_put, 0); | |||
369 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
370 | } | |||
371 | } | |||
372 | } | |||
373 | ||||
374 | void mode_sense(int fd, u_char *data, int len, int pc, int page) | |||
375 | { | |||
376 | scsireq_t *scsireq; | |||
377 | ||||
378 | bzero(data, len); | |||
379 | ||||
380 | scsireq = scsireq_new(); | |||
381 | ||||
382 | if (scsireq_enter(fd, scsireq_build(scsireq, | |||
383 | len, data, SCCMD_READ0x00000001, | |||
384 | "1A 0 v:2 {Page Control} v:6 {Page Code} 0 v:i1 {Allocation Length} 0", | |||
385 | pc, page, len)) == -1) /* Mode sense */ | |||
386 | { | |||
387 | scsi_debug(stderr(&__sF[2]), -1, scsireq); | |||
388 | exit(1); | |||
389 | } | |||
390 | ||||
391 | if (SCSIREQ_ERROR(scsireq)(scsireq->senselen_used || scsireq->status || scsireq-> retsts || scsireq->error)) | |||
392 | { | |||
393 | scsi_debug(stderr(&__sF[2]), 0, scsireq); | |||
394 | exit(1); | |||
395 | } | |||
396 | ||||
397 | free(scsireq); | |||
398 | } | |||
399 | ||||
400 | void mode_select(int fd, u_char *data, int len, int perm) | |||
401 | { | |||
402 | scsireq_t *scsireq; | |||
403 | ||||
404 | scsireq = scsireq_new(); | |||
405 | ||||
406 | if (scsireq_enter(fd, scsireq_build(scsireq, | |||
407 | len, data, SCCMD_WRITE0x00000002, | |||
408 | "15 0:7 v:1 {SP} 0 0 v:i1 {Allocation Length} 0", perm, len)) == -1) /* Mode select */ | |||
409 | { | |||
410 | scsi_debug(stderr(&__sF[2]), -1, scsireq); | |||
411 | exit(1); | |||
412 | } | |||
413 | ||||
414 | if (SCSIREQ_ERROR(scsireq)(scsireq->senselen_used || scsireq->status || scsireq-> retsts || scsireq->error)) | |||
415 | { | |||
416 | scsi_debug(stderr(&__sF[2]), 0, scsireq); | |||
417 | exit(1); | |||
418 | } | |||
419 | ||||
420 | free(scsireq); | |||
421 | } | |||
422 | ||||
423 | ||||
424 | #define START_ENTRY'{' '{' | |||
425 | #define END_ENTRY'}' '}' | |||
426 | ||||
427 | static void | |||
428 | skipwhite(FILE *f) | |||
429 | { | |||
430 | int c; | |||
431 | ||||
432 | skip_again: | |||
433 | ||||
434 | while (isspace(c = getc(f)(!__isthreaded ? (--(f)->_r < 0 ? __srget(f) : (int)(*( f)->_p++)) : (getc)(f)))) | |||
435 | continue; | |||
436 | ||||
437 | if (c == '#') { | |||
438 | while ((c = getc(f)(!__isthreaded ? (--(f)->_r < 0 ? __srget(f) : (int)(*( f)->_p++)) : (getc)(f))) != '\n' && c != EOF(-1)) | |||
439 | continue; | |||
440 | goto skip_again; | |||
441 | } | |||
442 | ||||
443 | ungetc(c, f); | |||
444 | } | |||
445 | ||||
446 | /* mode_lookup: Lookup a format description for a given page. | |||
447 | */ | |||
448 | char *mode_db = "/usr/share/misc/scsi_modes"; | |||
449 | static char *mode_lookup(int page) | |||
450 | { | |||
451 | char *new_db; | |||
452 | FILE *modes; | |||
453 | int match, next, found, c; | |||
454 | static char fmt[1024]; /* XXX This should be with strealloc */ | |||
455 | int page_desc; | |||
456 | new_db = getenv("SCSI_MODES"); | |||
457 | ||||
458 | if (new_db) | |||
459 | mode_db = new_db; | |||
460 | ||||
461 | modes = fopen(mode_db, "r"); | |||
462 | if (modes == NULL((void *)0)) | |||
463 | return 0; | |||
464 | ||||
465 | next = 0; | |||
466 | found = 0; | |||
467 | ||||
468 | while (!found) { | |||
469 | ||||
470 | skipwhite(modes); | |||
471 | ||||
472 | if (fscanf(modes, "%i", &page_desc) != 1) | |||
473 | break; | |||
474 | ||||
475 | if (page_desc == page) | |||
476 | found = 1; | |||
477 | ||||
478 | skipwhite(modes); | |||
479 | if (getc(modes)(!__isthreaded ? (--(modes)->_r < 0 ? __srget(modes) : ( int)(*(modes)->_p++)) : (getc)(modes)) != START_ENTRY'{') { | |||
480 | errx(1, "Expected %c", START_ENTRY'{'); | |||
481 | } | |||
482 | ||||
483 | match = 1; | |||
484 | while (match != 0) { | |||
485 | c = getc(modes)(!__isthreaded ? (--(modes)->_r < 0 ? __srget(modes) : ( int)(*(modes)->_p++)) : (getc)(modes)); | |||
486 | if (c == EOF(-1)) | |||
487 | fprintf(stderr(&__sF[2]), "Expected %c.\n", END_ENTRY'}'); | |||
488 | ||||
489 | if (c == START_ENTRY'{') { | |||
490 | match++; | |||
491 | } | |||
492 | if (c == END_ENTRY'}') { | |||
493 | match--; | |||
494 | if (match == 0) | |||
495 | break; | |||
496 | } | |||
497 | if (found && c != '\n') { | |||
498 | if (next >= sizeof(fmt)) { | |||
499 | errx(1, "Stupid program: Buffer overflow.\n"); | |||
500 | } | |||
501 | ||||
502 | fmt[next++] = (u_char)c; | |||
503 | } | |||
504 | } | |||
505 | } | |||
506 | fclose(modes); | |||
507 | fmt[next] = 0; | |||
508 | ||||
509 | return (found) ? fmt : 0; | |||
510 | } | |||
511 | ||||
512 | /* -------- edit: Mode Select Editor --------- | |||
513 | */ | |||
514 | struct editinfo | |||
515 | { | |||
516 | long can_edit; | |||
517 | long default_value; | |||
518 | } editinfo[64]; /* XXX Bogus fixed size */ | |||
519 | ||||
520 | static int editind; | |||
521 | volatile int edit_opened; | |||
522 | static FILE *edit_file; | |||
523 | static char edit_name[L_tmpnam1024]; | |||
524 | ||||
525 | static void | |||
526 | edit_rewind(void) | |||
527 | { | |||
528 | editind = 0; | |||
529 | } | |||
530 | ||||
531 | static void | |||
532 | edit_done(void) | |||
533 | { | |||
534 | int opened; | |||
535 | ||||
536 | sigset_t all, prev; | |||
537 | sigfillset(&all); | |||
538 | ||||
539 | (void)sigprocmask(SIG_SETMASK3, &all, &prev); | |||
540 | ||||
541 | opened = (int)edit_opened; | |||
542 | edit_opened = 0; | |||
543 | ||||
544 | (void)sigprocmask(SIG_SETMASK3, &prev, 0); | |||
545 | ||||
546 | if (opened) | |||
547 | { | |||
548 | if (fclose(edit_file)) | |||
549 | perror(edit_name); | |||
550 | if (unlink(edit_name)) | |||
551 | perror(edit_name); | |||
552 | } | |||
553 | } | |||
554 | ||||
555 | static void | |||
556 | edit_init(void) | |||
557 | { | |||
558 | int fd; | |||
559 | ||||
560 | edit_rewind(); | |||
561 | strlcpy(edit_name, "/var/tmp/scXXXXXXXX", sizeof edit_name); | |||
562 | if ((fd = mkstemp(edit_name)) == -1) | |||
563 | err(1, "mkstemp"); | |||
564 | if ( (edit_file = fdopen(fd, "w+")) == 0) | |||
565 | err(1, "fdopen"); | |||
566 | edit_opened = 1; | |||
567 | ||||
568 | atexit(edit_done); | |||
569 | } | |||
570 | ||||
571 | static void | |||
572 | edit_check(void *hook, int letter, void *arg, int count, char *name) | |||
573 | { | |||
574 | if (letter != 'i' && letter != 'b') { | |||
575 | errx(1, "Can't edit format %c.\n", letter); | |||
576 | } | |||
577 | ||||
578 | if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) { | |||
579 | errx(1, "edit table overflow"); | |||
580 | } | |||
581 | editinfo[editind].can_edit = ((long)arg != 0); | |||
582 | editind++; | |||
583 | } | |||
584 | ||||
585 | static void | |||
586 | edit_defaults(void *hook, int letter, void *arg, int count, char *name) | |||
587 | { | |||
588 | if (letter != 'i' && letter != 'b') { | |||
589 | errx(1, "Can't edit format %c.\n", letter); | |||
590 | } | |||
591 | ||||
592 | editinfo[editind].default_value = ((long)arg); | |||
593 | editind++; | |||
594 | } | |||
595 | ||||
596 | static void | |||
597 | edit_report(void *hook, int letter, void *arg, int count, char *name) | |||
598 | { | |||
599 | if (editinfo[editind].can_edit) { | |||
600 | if (letter != 'i' && letter != 'b') { | |||
601 | errx(1, "Can't report format %c.\n", letter); | |||
602 | } | |||
603 | ||||
604 | fprintf(edit_file, "%s: %ld\n", name, (long)arg); | |||
605 | } | |||
606 | ||||
607 | editind++; | |||
608 | } | |||
609 | ||||
610 | static int | |||
611 | edit_get(void *hook, char *name) | |||
612 | { | |||
613 | int arg = editinfo[editind].default_value; | |||
614 | ||||
615 | if (editinfo[editind].can_edit) { | |||
616 | char line[80]; | |||
617 | size_t len; | |||
618 | if (fgets(line, sizeof(line), edit_file) == NULL((void *)0)) | |||
619 | err(1, "fgets"); | |||
620 | ||||
621 | len = strlen(line); | |||
622 | if (len && line[len - 1] == '\n') | |||
623 | line[len - 1] = '\0'; | |||
624 | ||||
625 | if (strncmp(name, line, strlen(name)) != 0) { | |||
626 | errx(1, "Expected \"%s\" and read \"%s\"\n", | |||
627 | name, line); | |||
628 | } | |||
629 | ||||
630 | arg = strtoul(line + strlen(name) + 2, 0, 0); | |||
631 | } | |||
632 | ||||
633 | editind++; | |||
634 | return arg; | |||
635 | } | |||
636 | ||||
637 | int | |||
638 | editit(const char *pathname) | |||
639 | { | |||
640 | char *argp[] = {"sh", "-c", NULL((void *)0), NULL((void *)0)}, *ed, *p; | |||
641 | sig_t sighup, sigint, sigquit; | |||
642 | pid_t pid; | |||
643 | int st; | |||
644 | ||||
645 | ed = getenv("VISUAL"); | |||
646 | if (ed == NULL((void *)0) || ed[0] == '\0') | |||
647 | ed = getenv("EDITOR"); | |||
648 | if (ed == NULL((void *)0) || ed[0] == '\0') | |||
649 | ed = _PATH_VI"/usr/bin/vi"; | |||
650 | if (asprintf(&p, "%s %s", ed, pathname) == -1) | |||
651 | return (-1); | |||
652 | argp[2] = p; | |||
653 | ||||
654 | top: | |||
655 | sighup = signal(SIGHUP1, SIG_IGN(void (*)(int))1); | |||
656 | sigint = signal(SIGINT2, SIG_IGN(void (*)(int))1); | |||
657 | sigquit = signal(SIGQUIT3, SIG_IGN(void (*)(int))1); | |||
658 | if ((pid = fork()) == -1) { | |||
659 | int saved_errno = errno(*__errno()); | |||
660 | ||||
661 | (void)signal(SIGHUP1, sighup); | |||
662 | (void)signal(SIGINT2, sigint); | |||
663 | (void)signal(SIGQUIT3, sigquit); | |||
664 | if (saved_errno == EAGAIN35) { | |||
665 | sleep(1); | |||
666 | goto top; | |||
667 | } | |||
668 | free(p); | |||
669 | errno(*__errno()) = saved_errno; | |||
670 | return (-1); | |||
671 | } | |||
672 | if (pid == 0) { | |||
673 | execv(_PATH_BSHELL"/bin/sh", argp); | |||
674 | _exit(127); | |||
675 | } | |||
676 | free(p); | |||
677 | for (;;) { | |||
678 | if (waitpid(pid, &st, 0) == -1) { | |||
679 | if (errno(*__errno()) != EINTR4) | |||
680 | return (-1); | |||
681 | } else | |||
682 | break; | |||
683 | } | |||
684 | (void)signal(SIGHUP1, sighup); | |||
685 | (void)signal(SIGINT2, sigint); | |||
686 | (void)signal(SIGQUIT3, sigquit); | |||
687 | if (!WIFEXITED(st)(((st) & 0177) == 0) || WEXITSTATUS(st)(int)(((unsigned)(st) >> 8) & 0xff) != 0) { | |||
688 | errno(*__errno()) = ECHILD10; | |||
689 | return (-1); | |||
690 | } | |||
691 | return (0); | |||
692 | } | |||
693 | ||||
694 | static void | |||
695 | mode_edit(int fd, int page, int edit, int argc, char *argv[]) | |||
696 | { | |||
697 | int i; | |||
698 | u_char data[255]; | |||
699 | u_char *mode_pars; | |||
700 | struct mode_header | |||
701 | { | |||
702 | u_char mdl; /* Mode data length */ | |||
703 | u_char medium_type; | |||
704 | u_char dev_spec_par; | |||
705 | u_char bdl; /* Block descriptor length */ | |||
706 | }; | |||
707 | ||||
708 | struct mode_page_header | |||
709 | { | |||
710 | u_char page_code; | |||
711 | u_char page_length; | |||
712 | }; | |||
713 | ||||
714 | struct mode_header *mh; | |||
715 | struct mode_page_header *mph; | |||
716 | ||||
717 | char *fmt = mode_lookup(page); | |||
718 | if (!fmt && verbose) { | |||
719 | fprintf(stderr(&__sF[2]), | |||
720 | "No mode data base entry in \"%s\" for page %d; binary %s only.\n", | |||
721 | mode_db, page, (edit ? "edit" : "display")); | |||
722 | } | |||
723 | ||||
724 | if (edit) { | |||
725 | if (!fmt) { | |||
726 | errx(1, "Sorry: can't edit without a format.\n"); | |||
727 | } | |||
728 | ||||
729 | if (pagectl != 0 && pagectl != 3) { | |||
730 | errx(1, | |||
731 | "It only makes sense to edit page 0 (current) or page 3 (saved values)\n"); | |||
732 | } | |||
733 | ||||
734 | verbose = 1; | |||
735 | ||||
736 | mode_sense(fd, data, sizeof(data), 1, page); | |||
737 | ||||
738 | mh = (struct mode_header *)data; | |||
739 | mph = (struct mode_page_header *) | |||
740 | (((char *)mh) + sizeof(*mh) + mh->bdl); | |||
741 | ||||
742 | mode_pars = (char *)mph + sizeof(*mph); | |||
743 | ||||
744 | edit_init(); | |||
745 | scsireq_buff_decode_visit(mode_pars, mh->mdl, | |||
746 | fmt, edit_check, 0); | |||
747 | ||||
748 | mode_sense(fd, data, sizeof(data), 0, page); | |||
749 | ||||
750 | edit_rewind(); | |||
751 | scsireq_buff_decode_visit(mode_pars, mh->mdl, | |||
752 | fmt, edit_defaults, 0); | |||
753 | ||||
754 | edit_rewind(); | |||
755 | scsireq_buff_decode_visit(mode_pars, mh->mdl, | |||
756 | fmt, edit_report, 0); | |||
757 | ||||
758 | fclose(edit_file); | |||
759 | if (editit(edit_name) == -1 && errno(*__errno()) != ECHILD10) | |||
760 | err(1, "edit %s", edit_name); | |||
761 | if ((edit_file = fopen(edit_name, "r")) == NULL((void *)0)) | |||
762 | err(1, "open %s", edit_name); | |||
763 | ||||
764 | edit_rewind(); | |||
765 | scsireq_buff_encode_visit(mode_pars, mh->mdl, | |||
766 | fmt, edit_get, 0); | |||
767 | ||||
768 | /* Eliminate block descriptors: | |||
769 | */ | |||
770 | bcopy((char *)mph, ((char *)mh) + sizeof(*mh), | |||
771 | sizeof(*mph) + mph->page_length); | |||
772 | ||||
773 | mh->bdl = 0; | |||
774 | mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); | |||
775 | mode_pars = ((char *)mph) + 2; | |||
776 | ||||
777 | #if 0 | |||
778 | /* Turn this on to see what you're sending to the | |||
779 | * device: | |||
780 | */ | |||
781 | edit_rewind(); | |||
782 | scsireq_buff_decode_visit(mode_pars, | |||
783 | mh->mdl, fmt, arg_put, 0); | |||
784 | #endif | |||
785 | ||||
786 | edit_done(); | |||
787 | ||||
788 | /* Make it permanent if pageselect is three. | |||
789 | */ | |||
790 | ||||
791 | mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ | |||
792 | mh->mdl = 0; /* Reserved for mode select */ | |||
793 | ||||
794 | mode_select(fd, (char *)mh, | |||
795 | sizeof(*mh) + mh->bdl + sizeof(*mph) + mph->page_length, | |||
796 | (pagectl == 3)); | |||
797 | ||||
798 | exit(0); | |||
799 | } | |||
800 | ||||
801 | mode_sense(fd, data, sizeof(data), pagectl, page); | |||
802 | ||||
803 | /* Skip over the block descriptors. | |||
804 | */ | |||
805 | mh = (struct mode_header *)data; | |||
806 | mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); | |||
807 | mode_pars = (char *)mph + sizeof(*mph); | |||
808 | ||||
809 | if (!fmt) { | |||
810 | for (i = 0; i < mh->mdl; i++) { | |||
811 | printf("%02x%c",mode_pars[i], | |||
812 | (((i + 1) % 8) == 0) ? '\n' : ' '); | |||
813 | } | |||
814 | putc('\n', stdout)(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
815 | } else { | |||
816 | verbose = 1; | |||
817 | scsireq_buff_decode_visit(mode_pars, | |||
818 | mh->mdl, fmt, arg_put, 0); | |||
819 | } | |||
820 | } | |||
821 | ||||
822 | int | |||
823 | main(int argc, char **argv) | |||
824 | { | |||
825 | procargs(&argc,&argv); | |||
826 | ||||
827 | /* XXX This has grown to the point that it should be cleaned up. | |||
828 | */ | |||
829 | if (debugflag) { | |||
| ||||
830 | if (ioctl(fd,SCIOCDEBUG((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('Q')) << 8) | ((2))),&debuglevel) == -1) | |||
831 | err(1, "SCIOCDEBUG"); | |||
832 | } else if (commandflag) { | |||
833 | char *fmt; | |||
834 | ||||
835 | if (argc < 1) { | |||
836 | fprintf(stderr(&__sF[2]), "Need the command format string.\n"); | |||
837 | usage(); | |||
838 | } | |||
839 | ||||
840 | ||||
841 | fmt = argv[0]; | |||
842 | ||||
843 | argc -= 1; | |||
844 | argv += 1; | |||
845 | ||||
846 | do_cmd(fd, fmt, argc, argv); | |||
847 | } else if (modeflag) | |||
848 | mode_edit(fd, modepage, editflag, argc, argv); | |||
849 | ||||
850 | exit(0); | |||
851 | } |