Bug Summary

File:src/bin/chio/chio.c
Warning:line 570, column 13
The left operand of '==' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name chio.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/bin/chio/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/bin/chio/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/bin/chio/chio.c
1/* $OpenBSD: chio.c,v 1.29 2021/10/24 21:24:21 deraadt Exp $ */
2/* $NetBSD: chio.c,v 1.1.1.1 1996/04/03 00:34:38 thorpej Exp $ */
3
4/*
5 * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgments:
18 * This product includes software developed by Jason R. Thorpe
19 * for And Communications, http://www.and.com/
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/types.h>
37#include <sys/ioctl.h>
38#include <sys/mtio.h>
39#include <sys/chio.h>
40#include <err.h>
41#include <errno(*__errno()).h>
42#include <fcntl.h>
43#include <limits.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48#include <util.h>
49
50#include "defs.h"
51#include "pathnames.h"
52
53#define _PATH_CH_CONF"/etc/chio.conf" "/etc/chio.conf"
54extern char *parse_tapedev(const char *, const char *, int); /* parse.y */
55extern char *__progname; /* from crt0.o */
56
57static void usage(void);
58static int parse_element_type(char *);
59static int parse_element_unit(char *);
60static int parse_special(char *);
61static int is_special(char *);
62static const char * element_type_name(int et);
63static char *bits_to_string(int, const char *);
64static void find_voltag(char *, int *, int *);
65static void check_source_drive(int);
66
67static int do_move(char *, int, char **);
68static int do_exchange(char *, int, char **);
69static int do_position(char *, int, char **);
70static int do_params(char *, int, char **);
71static int do_getpicker(char *, int, char **);
72static int do_setpicker(char *, int, char **);
73static int do_status(char *, int, char **);
74
75/* Valid changer element types. */
76const struct element_type elements[] = {
77 { "drive", CHET_DT3 },
78 { "picker", CHET_MT0 },
79 { "portal", CHET_IE2 },
80 { "slot", CHET_ST1 },
81 { NULL((void *)0), 0 },
82};
83
84/* Valid commands. */
85const struct changer_command commands[] = {
86 { "exchange", do_exchange },
87 { "getpicker", do_getpicker },
88 { "move", do_move },
89 { "params", do_params },
90 { "position", do_position },
91 { "setpicker", do_setpicker },
92 { "status", do_status },
93 { NULL((void *)0), 0 },
94};
95
96/* Valid special words. */
97const struct special_word specials[] = {
98 { "inv", SW_INVERT1 },
99 { "inv1", SW_INVERT12 },
100 { "inv2", SW_INVERT23 },
101 { NULL((void *)0), 0 },
102};
103
104static int changer_fd;
105static char *changer_name;
106static int avoltag;
107static int pvoltag;
108static int sense;
109static int source;
110
111int
112main(int argc, char *argv[])
113{
114 int ch, i;
115
116 while ((ch = getopt(argc, argv, "f:")) != -1) {
117 switch (ch) {
118 case 'f':
119 changer_name = optarg;
120 break;
121 default:
122 usage();
123 }
124 }
125 argc -= optind;
126 argv += optind;
127
128 if (argc == 0)
129 usage();
130
131 /* Get the default changer if not already specified. */
132 if (changer_name == NULL((void *)0))
133 if ((changer_name = getenv(CHANGER_ENV_VAR"CHANGER")) == NULL((void *)0))
134 changer_name = _PATH_CH"/dev/ch0";
135
136 /* Open the changer device. */
137 if ((changer_fd = open(changer_name, O_RDWR0x0002)) == -1)
138 err(1, "%s: open", changer_name);
139
140 /* Find the specified command. */
141 for (i = 0; commands[i].cc_name != NULL((void *)0); ++i)
142 if (strcmp(*argv, commands[i].cc_name) == 0)
143 break;
144 if (commands[i].cc_name == NULL((void *)0)) {
145 /* look for abbreviation */
146 for (i = 0; commands[i].cc_name != NULL((void *)0); ++i)
147 if (strncmp(*argv, commands[i].cc_name,
148 strlen(*argv)) == 0)
149 break;
150 }
151 if (commands[i].cc_name == NULL((void *)0))
152 errx(1, "unknown command: %s", *argv);
153
154 exit((*commands[i].cc_handler)(commands[i].cc_name, argc, argv));
155}
156
157static int
158do_move(char *cname, int argc, char *argv[])
159{
160 struct changer_move cmd;
161 int val;
162
163 /*
164 * On a move command, we expect the following:
165 *
166 * <from ET> <from EU> <to ET> <to EU> [inv]
167 *
168 * where ET == element type and EU == element unit.
169 */
170
171 ++argv; --argc;
172
173 if (argc < 4) {
174 warnx("%s: too few arguments", cname);
175 goto usage;
176 } else if (argc > 5) {
177 warnx("%s: too many arguments", cname);
178 goto usage;
179 }
180 bzero(&cmd, sizeof(cmd));
181
182 /*
183 * Get the from ET and EU - we search for it if the ET is
184 * "voltag", otherwise, we just use the ET and EU given to us.
185 */
186 if (strcmp(*argv, "voltag") == 0) {
187 ++argv; --argc;
188 find_voltag(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit);
189 ++argv; --argc;
190 } else {
191 cmd.cm_fromtype = parse_element_type(*argv);
192 ++argv; --argc;
193 cmd.cm_fromunit = parse_element_unit(*argv);
194 ++argv; --argc;
195 }
196
197 if (cmd.cm_fromtype == CHET_DT3)
198 check_source_drive(cmd.cm_fromunit);
199
200 /*
201 * Don't allow voltag on the to ET, using a volume
202 * as a destination makes no sense on a move
203 */
204 cmd.cm_totype = parse_element_type(*argv);
205 ++argv; --argc;
206 cmd.cm_tounit = parse_element_unit(*argv);
207 ++argv; --argc;
208
209 /* Deal with optional command modifier. */
210 if (argc) {
211 val = parse_special(*argv);
212 switch (val) {
213 case SW_INVERT1:
214 cmd.cm_flags |= CM_INVERT0x01;
215 break;
216
217 default:
218 errx(1, "%s: inappropriate modifier `%s'",
219 cname, *argv);
220 /* NOTREACHED */
221 }
222 }
223
224 /* Send command to changer. */
225 if (ioctl(changer_fd, CHIOMOVE((unsigned long)0x80000000 | ((sizeof(struct changer_move) &
0x1fff) << 16) | ((('c')) << 8) | ((0x41)))
, &cmd) == -1)
226 err(1, "%s: CHIOMOVE", changer_name);
227
228 return (0);
229
230 usage:
231 fprintf(stderr(&__sF[2]), "usage: %s %s "
232 "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname);
233 return (1);
234}
235
236static int
237do_exchange(char *cname, int argc, char *argv[])
238{
239 struct changer_exchange cmd;
240 int val;
241
242 /*
243 * On an exchange command, we expect the following:
244 *
245 * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2]
246 *
247 * where ET == element type and EU == element unit.
248 */
249
250 ++argv; --argc;
251
252 if (argc < 4) {
253 warnx("%s: too few arguments", cname);
254 goto usage;
255 } else if (argc > 8) {
256 warnx("%s: too many arguments", cname);
257 goto usage;
258 }
259 bzero(&cmd, sizeof(cmd));
260
261 /* <src ET> */
262 cmd.ce_srctype = parse_element_type(*argv);
263 ++argv; --argc;
264
265 /* <src EU> */
266 cmd.ce_srcunit = parse_element_unit(*argv);
267 ++argv; --argc;
268
269 /* <dst1 ET> */
270 cmd.ce_fdsttype = parse_element_type(*argv);
271 ++argv; --argc;
272
273 /* <dst1 EU> */
274 cmd.ce_fdstunit = parse_element_unit(*argv);
275 ++argv; --argc;
276
277 /*
278 * If the next token is a special word or there are no more
279 * arguments, then this is a case of simple exchange.
280 * dst2 == src.
281 */
282 if ((argc == 0) || is_special(*argv)) {
283 cmd.ce_sdsttype = cmd.ce_srctype;
284 cmd.ce_sdstunit = cmd.ce_srcunit;
285 goto do_special;
286 }
287
288 /* <dst2 ET> */
289 cmd.ce_sdsttype = parse_element_type(*argv);
290 ++argv; --argc;
291
292 /* <dst2 EU> */
293 cmd.ce_sdstunit = parse_element_unit(*argv);
294 ++argv; --argc;
295
296 do_special:
297 /* Deal with optional command modifiers. */
298 while (argc) {
299 val = parse_special(*argv);
300 ++argv; --argc;
301 switch (val) {
302 case SW_INVERT12:
303 cmd.ce_flags |= CE_INVERT10x01;
304 break;
305
306 case SW_INVERT23:
307 cmd.ce_flags |= CE_INVERT20x02;
308 break;
309
310 default:
311 errx(1, "%s: inappropriate modifier `%s'",
312 cname, *argv);
313 /* NOTREACHED */
314 }
315 }
316
317 /* Send command to changer. */
318 if (ioctl(changer_fd, CHIOEXCHANGE((unsigned long)0x80000000 | ((sizeof(struct changer_exchange
) & 0x1fff) << 16) | ((('c')) << 8) | ((0x42)
))
, &cmd) == -1)
319 err(1, "%s: CHIOEXCHANGE", changer_name);
320
321 return (0);
322
323 usage:
324 fprintf(stderr(&__sF[2]), "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n"
325 " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n",
326 __progname, cname);
327 return (1);
328}
329
330static int
331do_position(char *cname, int argc, char *argv[])
332{
333 struct changer_position cmd;
334 int val;
335
336 /*
337 * On a position command, we expect the following:
338 *
339 * <to ET> <to EU> [inv]
340 *
341 * where ET == element type and EU == element unit.
342 */
343
344 ++argv; --argc;
345
346 if (argc < 2) {
347 warnx("%s: too few arguments", cname);
348 goto usage;
349 } else if (argc > 3) {
350 warnx("%s: too many arguments", cname);
351 goto usage;
352 }
353 bzero(&cmd, sizeof(cmd));
354
355 /* <to ET> */
356 cmd.cp_type = parse_element_type(*argv);
357 ++argv; --argc;
358
359 /* <to EU> */
360 cmd.cp_unit = parse_element_unit(*argv);
361 ++argv; --argc;
362
363 /* Deal with optional command modifier. */
364 if (argc) {
365 val = parse_special(*argv);
366 switch (val) {
367 case SW_INVERT1:
368 cmd.cp_flags |= CP_INVERT0x01;
369 break;
370
371 default:
372 errx(1, "%s: inappropriate modifier `%s'",
373 cname, *argv);
374 /* NOTREACHED */
375 }
376 }
377
378 /* Send command to changer. */
379 if (ioctl(changer_fd, CHIOPOSITION((unsigned long)0x80000000 | ((sizeof(struct changer_position
) & 0x1fff) << 16) | ((('c')) << 8) | ((0x43)
))
, &cmd) == -1)
380 err(1, "%s: CHIOPOSITION", changer_name);
381
382 return (0);
383
384 usage:
385 fprintf(stderr(&__sF[2]), "usage: %s %s <to ET> <to EU> [inv]\n",
386 __progname, cname);
387 return (1);
388}
389
390static int
391do_params(char *cname, int argc, char *argv[])
392{
393 struct changer_params data;
394
395 /* No arguments to this command. */
396
397 ++argv; --argc;
398
399 if (argc) {
400 warnx("%s: no arguments expected", cname);
401 goto usage;
402 }
403
404 /* Get params from changer and display them. */
405 bzero(&data, sizeof(data));
406 if (ioctl(changer_fd, CHIOGPARAMS((unsigned long)0x40000000 | ((sizeof(struct changer_params) &
0x1fff) << 16) | ((('c')) << 8) | ((0x46)))
, &data) == -1)
407 err(1, "%s: CHIOGPARAMS", changer_name);
408
409 printf("%s: %d slot%s, %d drive%s, %d picker%s",
410 changer_name,
411 data.cp_nslots, (data.cp_nslots > 1) ? "s" : "",
412 data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "",
413 data.cp_npickers, (data.cp_npickers > 1) ? "s" : "");
414 if (data.cp_nportals)
415 printf(", %d portal%s", data.cp_nportals,
416 (data.cp_nportals > 1) ? "s" : "");
417 printf("\n%s: current picker: %d\n", changer_name, data.cp_curpicker);
418
419 return (0);
420
421 usage:
422 fprintf(stderr(&__sF[2]), "usage: %s %s\n", __progname, cname);
423 return (1);
424}
425
426static int
427do_getpicker(char *cname, int argc, char *argv[])
428{
429 int picker;
430
431 /* No arguments to this command. */
432
433 ++argv; --argc;
434
435 if (argc) {
436 warnx("%s: no arguments expected", cname);
437 goto usage;
438 }
439
440 /* Get current picker from changer and display it. */
441 if (ioctl(changer_fd, CHIOGPICKER((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('c')) << 8) | ((0x44)))
, &picker) == -1)
442 err(1, "%s: CHIOGPICKER", changer_name);
443
444 printf("%s: current picker: %d\n", changer_name, picker);
445
446 return (0);
447
448 usage:
449 fprintf(stderr(&__sF[2]), "usage: %s %s\n", __progname, cname);
450 return (1);
451}
452
453static int
454do_setpicker(char *cname, int argc, char *argv[])
455{
456 int picker;
457
458 ++argv; --argc;
459
460 if (argc < 1) {
461 warnx("%s: too few arguments", cname);
462 goto usage;
463 } else if (argc > 1) {
464 warnx("%s: too many arguments", cname);
465 goto usage;
466 }
467
468 picker = parse_element_unit(*argv);
469
470 /* Set the changer picker. */
471 if (ioctl(changer_fd, CHIOSPICKER((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('c')) << 8) | ((0x45)))
, &picker) == -1)
472 err(1, "%s: CHIOSPICKER", changer_name);
473
474 return (0);
475
476 usage:
477 fprintf(stderr(&__sF[2]), "usage: %s %s <picker>\n", __progname, cname);
478 return (1);
479}
480
481static int
482do_status(char *cname, int argc, char *argv[])
483{
484 struct changer_element_status_request cmd;
485 struct changer_params data;
486 int i, chet, schet, echet, c;
487 char *description;
488 size_t count;
1
'count' declared without an initial value
489
490 optreset = 1;
491 optind = 1;
492 while ((c = getopt(argc, argv, "SsvVa")) != -1) {
2
Assuming the condition is false
3
Loop condition is false. Execution continues on line 514
493 switch (c) {
494 case 's':
495 sense = 1;
496 break;
497 case 'S':
498 source = 1;
499 break;
500 case 'v':
501 pvoltag = 1;
502 break;
503 case 'V':
504 avoltag = 1;
505 break;
506 case 'a':
507 pvoltag = avoltag = source = sense = 1;
508 break;
509 default:
510 goto usage;
511 }
512 }
513
514 argc -= optind;
515 argv += optind;
516
517 /*
518 * On a status command, we expect the following:
519 *
520 * [<ET>]
521 *
522 * where ET == element type.
523 *
524 * If we get no arguments, we get the status of all
525 * known element types.
526 */
527 if (argc > 1) {
4
Assuming 'argc' is <= 1
5
Taking false branch
528 warnx("%s: too many arguments", cname);
529 goto usage;
530 }
531
532 /*
533 * Get params from changer. Specifically, we need the element
534 * counts.
535 */
536 bzero(&data, sizeof(data));
537 if (ioctl(changer_fd, CHIOGPARAMS((unsigned long)0x40000000 | ((sizeof(struct changer_params) &
0x1fff) << 16) | ((('c')) << 8) | ((0x46)))
, &data) == -1
)
6
Assuming the condition is false
7
Taking false branch
538 err(1, "%s: CHIOGPARAMS", changer_name);
539
540 if (argc)
8
Assuming 'argc' is not equal to 0
9
Taking true branch
541 schet = echet = parse_element_type(*argv);
542 else {
543 schet = CHET_MT0;
544 echet = CHET_DT3;
545 }
546
547 for (chet = schet; chet <= echet; ++chet) {
10
Loop condition is true. Entering loop body
548 switch (chet) {
11
'Default' branch taken. Execution continues on line 570
549 case CHET_MT0:
550 count = data.cp_npickers;
551 description = "picker";
552 break;
553
554 case CHET_ST1:
555 count = data.cp_nslots;
556 description = "slot";
557 break;
558
559 case CHET_IE2:
560 count = data.cp_nportals;
561 description = "portal";
562 break;
563
564 case CHET_DT3:
565 count = data.cp_ndrives;
566 description = "drive";
567 break;
568 }
569
570 if (count == 0) {
12
The left operand of '==' is a garbage value
571 if (argc == 0)
572 continue;
573 else {
574 printf("%s: no %s elements\n",
575 changer_name, description);
576 return (0);
577 }
578 }
579
580 bzero(&cmd, sizeof(cmd));
581
582 cmd.cesr_type = chet;
583 /* Allocate storage for the status info. */
584 cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data));
585 if ((cmd.cesr_data) == NULL((void *)0))
586 errx(1, "can't allocate status storage");
587 if (avoltag || pvoltag)
588 cmd.cesr_flags |= CESR_VOLTAGS0x01;
589
590 if (ioctl(changer_fd, CHIOGSTATUS((unsigned long)0x80000000 | ((sizeof(struct changer_element_status_request
) & 0x1fff) << 16) | ((('c')) << 8) | ((0x48)
))
, &cmd) == -1) {
591 free(cmd.cesr_data);
592 err(1, "%s: CHIOGSTATUS", changer_name);
593 }
594
595 /* Dump the status for each element of this type. */
596 for (i = 0; i < count; ++i) {
597 struct changer_element_status *ces =
598 &(cmd.cesr_data[i]);
599 printf("%s %d: %s", description, i,
600 bits_to_string(ces->ces_flags, CESTATUS_BITS"\20\6INEAB\5EXENAB\4ACCESS\3EXCEPT\2IMPEXP\1FULL"));
601 if (sense)
602 printf(" sense: <0x%02x/0x%02x>",
603 ces->ces_sensecode,
604 ces->ces_sensequal);
605 if (pvoltag)
606 printf(" voltag: <%s:%d>",
607 ces->ces_pvoltag.cv_volid,
608 ces->ces_pvoltag.cv_serial);
609 if (avoltag)
610 printf(" avoltag: <%s:%d>",
611 ces->ces_avoltag.cv_volid,
612 ces->ces_avoltag.cv_serial);
613 if (source) {
614 if (ces->ces_flags & CESTATUS_ACCESS0x08)
615 printf(" source: <%s %d>",
616 element_type_name(
617 ces->ces_source_type),
618 ces->ces_source_addr);
619 else
620 printf(" source: <>");
621 }
622 printf("\n");
623 }
624
625 free(cmd.cesr_data);
626 }
627
628 return (0);
629
630 usage:
631 fprintf(stderr(&__sF[2]), "usage: %s %s [<element type>]\n", __progname,
632 cname);
633 return (1);
634}
635
636/*
637 * Check a drive unit as the source for a move or exchange
638 * operation. If the drive is not accessible, we attempt
639 * to unmount the tape in it before moving to avoid
640 * errors in "disconnected" type pickers where the drive
641 * is on a separate target from the changer.
642 */
643static void
644check_source_drive(int unit)
645{
646 struct mtop mtoffl = { MTOFFL6, 1 };
647 struct changer_element_status_request cmd;
648 struct changer_element_status *ces;
649 struct changer_params data;
650 size_t count = 0;
651 int mtfd;
652 char *tapedev;
653
654 /*
655 * Get params from changer. Specifically, we need the element
656 * counts.
657 */
658 bzero(&data, sizeof(data));
659 if (ioctl(changer_fd, CHIOGPARAMS((unsigned long)0x40000000 | ((sizeof(struct changer_params) &
0x1fff) << 16) | ((('c')) << 8) | ((0x46)))
, &data) == -1)
660 err(1, "%s: CHIOGPARAMS", changer_name);
661
662 count = data.cp_ndrives;
663 if (unit < 0 || unit >= count)
664 err(1, "%s: invalid drive: drive %d", changer_name, unit);
665
666 bzero(&cmd, sizeof(cmd));
667 cmd.cesr_type = CHET_DT3;
668 /* Allocate storage for the status info. */
669 cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data));
670 if ((cmd.cesr_data) == NULL((void *)0))
671 errx(1, "can't allocate status storage");
672
673 if (ioctl(changer_fd, CHIOGSTATUS((unsigned long)0x80000000 | ((sizeof(struct changer_element_status_request
) & 0x1fff) << 16) | ((('c')) << 8) | ((0x48)
))
, &cmd) == -1) {
674 free(cmd.cesr_data);
675 err(1, "%s: CHIOGSTATUS", changer_name);
676 }
677 ces = &(cmd.cesr_data[unit]);
678
679 if ((ces->ces_flags & CESTATUS_FULL0x01) != CESTATUS_FULL0x01)
680 err(1, "%s: drive %d is empty!", changer_name, unit);
681
682 if ((ces->ces_flags & CESTATUS_ACCESS0x08) == CESTATUS_ACCESS0x08)
683 return; /* changer thinks all is well - trust it */
684
685 /*
686 * Otherwise, drive is FULL, but not accessible.
687 * Try to make it accessible by doing an mt offline.
688 */
689 tapedev = parse_tapedev(_PATH_CH_CONF"/etc/chio.conf", changer_name, unit);
690 mtfd = opendev(tapedev, O_RDONLY0x0000, 0, NULL((void *)0));
691 if (mtfd == -1)
692 err(1, "%s drive %d (%s): open", changer_name, unit, tapedev);
693 if (ioctl(mtfd, MTIOCTOP((unsigned long)0x80000000 | ((sizeof(struct mtop) & 0x1fff
) << 16) | ((('m')) << 8) | ((1)))
, &mtoffl) == -1)
694 err(1, "%s drive %d (%s): rewoffl", changer_name, unit,
695 tapedev);
696 close(mtfd);
697}
698
699void
700find_voltag(char *voltag, int *type, int *unit)
701{
702 struct changer_element_status_request cmd;
703 struct changer_params data;
704 int i, chet, schet, echet, found;
705 size_t count = 0;
706
707 /*
708 * Get params from changer. Specifically, we need the element
709 * counts.
710 */
711 bzero(&data, sizeof(data));
712 if (ioctl(changer_fd, CHIOGPARAMS((unsigned long)0x40000000 | ((sizeof(struct changer_params) &
0x1fff) << 16) | ((('c')) << 8) | ((0x46)))
, &data) == -1)
713 err(1, "%s: CHIOGPARAMS", changer_name);
714
715 found = 0;
716 schet = CHET_MT0;
717 echet = CHET_DT3;
718
719 /*
720 * For each type of element, iterate through each one until
721 * we find the correct volume id.
722 */
723 for (chet = schet; chet <= echet; ++chet) {
724 switch (chet) {
725 case CHET_MT0:
726 count = data.cp_npickers;
727 break;
728 case CHET_ST1:
729 count = data.cp_nslots;
730 break;
731 case CHET_IE2:
732 count = data.cp_nportals;
733 break;
734 case CHET_DT3:
735 count = data.cp_ndrives;
736 break;
737 }
738 if (count == 0 || found)
739 continue;
740
741 bzero(&cmd, sizeof(cmd));
742 cmd.cesr_type = chet;
743 /* Allocate storage for the status info. */
744 cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data));
745 if ((cmd.cesr_data) == NULL((void *)0))
746 errx(1, "can't allocate status storage");
747 cmd.cesr_flags |= CESR_VOLTAGS0x01;
748
749 if (ioctl(changer_fd, CHIOGSTATUS((unsigned long)0x80000000 | ((sizeof(struct changer_element_status_request
) & 0x1fff) << 16) | ((('c')) << 8) | ((0x48)
))
, &cmd) == -1) {
750 free(cmd.cesr_data);
751 err(1, "%s: CHIOGSTATUS", changer_name);
752 }
753
754 /*
755 * look through each element to see if it has our desired
756 * volume tag.
757 */
758 for (i = 0; i < count; ++i) {
759 struct changer_element_status *ces =
760 &(cmd.cesr_data[i]);
761 if ((ces->ces_flags & CESTATUS_FULL0x01) != CESTATUS_FULL0x01)
762 continue; /* no tape in drive */
763 if (strcasecmp(voltag, ces->ces_pvoltag.cv_volid)
764 == 0) {
765 *type = chet;
766 *unit = i;
767 found = 1;
768 free(cmd.cesr_data);
769 return;
770 }
771 }
772 free(cmd.cesr_data);
773 }
774 errx(1, "%s: unable to locate voltag: %s", changer_name, voltag);
775}
776
777
778static int
779parse_element_type(char *cp)
780{
781 int i;
782
783 for (i = 0; elements[i].et_name != NULL((void *)0); ++i)
784 if (strcmp(elements[i].et_name, cp) == 0)
785 return (elements[i].et_type);
786
787 errx(1, "invalid element type `%s'", cp);
788}
789
790static const char *
791element_type_name(int et)
792{
793 int i;
794
795 for (i = 0; elements[i].et_name != NULL((void *)0); i++)
796 if (elements[i].et_type == et)
797 return elements[i].et_name;
798
799 return "unknown";
800}
801
802static int
803parse_element_unit(char *cp)
804{
805 int i;
806 char *p;
807
808 i = (int)strtol(cp, &p, 10);
809 if ((i < 0) || (*p != '\0'))
810 errx(1, "invalid unit number `%s'", cp);
811
812 return (i);
813}
814
815static int
816parse_special(char *cp)
817{
818 int val;
819
820 val = is_special(cp);
821 if (val)
822 return (val);
823
824 errx(1, "invalid modifier `%s'", cp);
825}
826
827static int
828is_special(char *cp)
829{
830 int i;
831
832 for (i = 0; specials[i].sw_name != NULL((void *)0); ++i)
833 if (strcmp(specials[i].sw_name, cp) == 0)
834 return (specials[i].sw_value);
835
836 return (0);
837}
838
839static char *
840bits_to_string(int v, const char *cp)
841{
842 const char *np;
843 char f, sep, *bp;
844 static char buf[128];
845
846 bp = buf;
847 bzero(buf, sizeof(buf));
848
849 for (sep = '<'; (f = *cp++) != 0; cp = np) {
850 for (np = cp; *np >= ' ';)
851 np++;
852 if ((v & (1 << (f - 1))) == 0)
853 continue;
854 (void)snprintf(bp, sizeof(buf) - (bp - &buf[0]),
855 "%c%.*s", sep, (int)(np - cp), cp);
856 bp += strlen(bp);
857 sep = ',';
858 }
859 if (sep != '<')
860 *bp = '>';
861
862 return (buf);
863}
864
865static void
866usage(void)
867{
868 int i;
869
870 fprintf(stderr(&__sF[2]), "usage: %s [-f changer] command [arg ...]\n",
871 __progname);
872 exit(1);
873}