Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/chio/chio.c
39475 views
1
/* $NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $ */
2
/*-
3
* Copyright (c) 1996 Jason R. Thorpe <[email protected]>
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. All advertising materials mentioning features or use of this software
15
* must display the following acknowledgements:
16
* This product includes software developed by Jason R. Thorpe
17
* for And Communications, http://www.and.com/
18
* 4. The name of the author may not be used to endorse or promote products
19
* derived from this software without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
/*
34
* Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr.
35
* Additional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications
36
*/
37
38
#include <sys/param.h>
39
#include <sys/chio.h>
40
#include <err.h>
41
#include <fcntl.h>
42
#include <stdio.h>
43
#include <stdint.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <unistd.h>
47
#include <langinfo.h>
48
#include <locale.h>
49
50
#include "defs.h"
51
#include "pathnames.h"
52
53
static void usage(void) __dead2;
54
static void cleanup(void);
55
static u_int16_t parse_element_type(char *);
56
static u_int16_t parse_element_unit(char *);
57
static const char * element_type_name(int et);
58
static int parse_special(char *);
59
static int is_special(char *);
60
static const char *bits_to_string(ces_status_flags, const char *);
61
62
static void find_element(char *, uint16_t *, uint16_t *);
63
static struct changer_element_status *get_element_status
64
(unsigned int, unsigned int, int);
65
66
static int do_move(const char *, int, char **);
67
static int do_exchange(const char *, int, char **);
68
static int do_position(const char *, int, char **);
69
static int do_params(const char *, int, char **);
70
static int do_getpicker(const char *, int, char **);
71
static int do_setpicker(const char *, int, char **);
72
static int do_status(const char *, int, char **);
73
static int do_ielem(const char *, int, char **);
74
static int do_return(const char *, int, char **);
75
static int do_voltag(const char *, int, char **);
76
static void print_designator(const char *, u_int8_t, u_int8_t);
77
78
#ifndef CHET_VT
79
#define CHET_VT 10 /* Completely Arbitrary */
80
#endif
81
82
/* Valid changer element types. */
83
static const struct element_type elements[] = {
84
{ "drive", CHET_DT },
85
{ "picker", CHET_MT },
86
{ "portal", CHET_IE },
87
{ "slot", CHET_ST },
88
{ "voltag", CHET_VT }, /* Select tapes by barcode */
89
{ NULL, 0 },
90
};
91
92
/* Valid commands. */
93
static const struct changer_command commands[] = {
94
{ "exchange", do_exchange },
95
{ "getpicker", do_getpicker },
96
{ "ielem", do_ielem },
97
{ "move", do_move },
98
{ "params", do_params },
99
{ "position", do_position },
100
{ "setpicker", do_setpicker },
101
{ "status", do_status },
102
{ "return", do_return },
103
{ "voltag", do_voltag },
104
{ NULL, 0 },
105
};
106
107
/* Valid special words. */
108
static const struct special_word specials[] = {
109
{ "inv", SW_INVERT },
110
{ "inv1", SW_INVERT1 },
111
{ "inv2", SW_INVERT2 },
112
{ NULL, 0 },
113
};
114
115
static int changer_fd;
116
static const char *changer_name;
117
118
int
119
main(int argc, char **argv)
120
{
121
int ch, i;
122
123
while ((ch = getopt(argc, argv, "f:")) != -1) {
124
switch (ch) {
125
case 'f':
126
changer_name = optarg;
127
break;
128
129
default:
130
usage();
131
}
132
}
133
argc -= optind;
134
argv += optind;
135
136
if (argc == 0)
137
usage();
138
139
/* Get the default changer if not already specified. */
140
if (changer_name == NULL)
141
if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL)
142
changer_name = _PATH_CH;
143
144
/* Open the changer device. */
145
if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1)
146
err(1, "%s: open", changer_name);
147
148
/* Register cleanup function. */
149
if (atexit(cleanup))
150
err(1, "can't register cleanup function");
151
152
/* Find the specified command. */
153
for (i = 0; commands[i].cc_name != NULL; ++i)
154
if (strcmp(*argv, commands[i].cc_name) == 0)
155
break;
156
if (commands[i].cc_name == NULL) {
157
/* look for abbreviation */
158
for (i = 0; commands[i].cc_name != NULL; ++i)
159
if (strncmp(*argv, commands[i].cc_name,
160
strlen(*argv)) == 0)
161
break;
162
}
163
164
if (commands[i].cc_name == NULL)
165
errx(1, "unknown command: %s", *argv);
166
167
exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv));
168
/* NOTREACHED */
169
}
170
171
static int
172
do_move(const char *cname, int argc, char **argv)
173
{
174
struct changer_move cmd;
175
int val;
176
177
/*
178
* On a move command, we expect the following:
179
*
180
* <from ET> <from EU> <to ET> <to EU> [inv]
181
*
182
* where ET == element type and EU == element unit.
183
*/
184
185
++argv; --argc;
186
187
if (argc < 4) {
188
warnx("%s: too few arguments", cname);
189
goto usage;
190
} else if (argc > 5) {
191
warnx("%s: too many arguments", cname);
192
goto usage;
193
}
194
(void) memset(&cmd, 0, sizeof(cmd));
195
196
/* <from ET> */
197
cmd.cm_fromtype = parse_element_type(*argv);
198
++argv; --argc;
199
200
/* Check for voltag virtual type */
201
if (CHET_VT == cmd.cm_fromtype) {
202
find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit);
203
} else {
204
/* <from EU> */
205
cmd.cm_fromunit = parse_element_unit(*argv);
206
}
207
++argv; --argc;
208
209
/* <to ET> */
210
cmd.cm_totype = parse_element_type(*argv);
211
++argv; --argc;
212
213
/* Check for voltag virtual type, and report error */
214
if (CHET_VT == cmd.cm_totype)
215
errx(1,"%s: voltag only makes sense as an element source",
216
cname);
217
218
/* <to EU> */
219
cmd.cm_tounit = parse_element_unit(*argv);
220
++argv; --argc;
221
222
/* Deal with optional command modifier. */
223
if (argc) {
224
val = parse_special(*argv);
225
switch (val) {
226
case SW_INVERT:
227
cmd.cm_flags |= CM_INVERT;
228
break;
229
230
default:
231
errx(1, "%s: inappropriate modifier `%s'",
232
cname, *argv);
233
/* NOTREACHED */
234
}
235
}
236
237
/* Send command to changer. */
238
if (ioctl(changer_fd, CHIOMOVE, &cmd))
239
err(1, "%s: CHIOMOVE", changer_name);
240
241
return (0);
242
243
usage:
244
(void) fprintf(stderr, "usage: %s %s "
245
"<from ET> <from EU> <to ET> <to EU> [inv]\n", getprogname(), cname);
246
return (1);
247
}
248
249
static int
250
do_exchange(const char *cname, int argc, char **argv)
251
{
252
struct changer_exchange cmd;
253
int val;
254
255
/*
256
* On an exchange command, we expect the following:
257
*
258
* <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2]
259
*
260
* where ET == element type and EU == element unit.
261
*/
262
263
++argv; --argc;
264
265
if (argc < 4) {
266
warnx("%s: too few arguments", cname);
267
goto usage;
268
} else if (argc > 8) {
269
warnx("%s: too many arguments", cname);
270
goto usage;
271
}
272
(void) memset(&cmd, 0, sizeof(cmd));
273
274
/* <src ET> */
275
cmd.ce_srctype = parse_element_type(*argv);
276
++argv; --argc;
277
278
/* Check for voltag virtual type */
279
if (CHET_VT == cmd.ce_srctype) {
280
find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit);
281
} else {
282
/* <from EU> */
283
cmd.ce_srcunit = parse_element_unit(*argv);
284
}
285
++argv; --argc;
286
287
/* <dst1 ET> */
288
cmd.ce_fdsttype = parse_element_type(*argv);
289
++argv; --argc;
290
291
/* Check for voltag virtual type */
292
if (CHET_VT == cmd.ce_fdsttype) {
293
find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit);
294
} else {
295
/* <from EU> */
296
cmd.ce_fdstunit = parse_element_unit(*argv);
297
}
298
++argv; --argc;
299
300
/*
301
* If the next token is a special word or there are no more
302
* arguments, then this is a case of simple exchange.
303
* dst2 == src.
304
*/
305
if ((argc == 0) || is_special(*argv)) {
306
cmd.ce_sdsttype = cmd.ce_srctype;
307
cmd.ce_sdstunit = cmd.ce_srcunit;
308
goto do_special;
309
}
310
311
/* <dst2 ET> */
312
cmd.ce_sdsttype = parse_element_type(*argv);
313
++argv; --argc;
314
315
if (CHET_VT == cmd.ce_sdsttype)
316
errx(1,"%s %s: voltag only makes sense as an element source",
317
cname, *argv);
318
319
/* <dst2 EU> */
320
cmd.ce_sdstunit = parse_element_unit(*argv);
321
++argv; --argc;
322
323
do_special:
324
/* Deal with optional command modifiers. */
325
while (argc) {
326
val = parse_special(*argv);
327
++argv; --argc;
328
switch (val) {
329
case SW_INVERT1:
330
cmd.ce_flags |= CE_INVERT1;
331
break;
332
333
case SW_INVERT2:
334
cmd.ce_flags |= CE_INVERT2;
335
break;
336
337
default:
338
errx(1, "%s: inappropriate modifier `%s'",
339
cname, *argv);
340
/* NOTREACHED */
341
}
342
}
343
344
/* Send command to changer. */
345
if (ioctl(changer_fd, CHIOEXCHANGE, &cmd))
346
err(1, "%s: CHIOEXCHANGE", changer_name);
347
348
return (0);
349
350
usage:
351
(void) fprintf(stderr,
352
"usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n"
353
" [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n",
354
getprogname(), cname);
355
return (1);
356
}
357
358
static int
359
do_position(const char *cname, int argc, char **argv)
360
{
361
struct changer_position cmd;
362
int val;
363
364
/*
365
* On a position command, we expect the following:
366
*
367
* <to ET> <to EU> [inv]
368
*
369
* where ET == element type and EU == element unit.
370
*/
371
372
++argv; --argc;
373
374
if (argc < 2) {
375
warnx("%s: too few arguments", cname);
376
goto usage;
377
} else if (argc > 3) {
378
warnx("%s: too many arguments", cname);
379
goto usage;
380
}
381
(void) memset(&cmd, 0, sizeof(cmd));
382
383
/* <to ET> */
384
cmd.cp_type = parse_element_type(*argv);
385
++argv; --argc;
386
387
/* <to EU> */
388
cmd.cp_unit = parse_element_unit(*argv);
389
++argv; --argc;
390
391
/* Deal with optional command modifier. */
392
if (argc) {
393
val = parse_special(*argv);
394
switch (val) {
395
case SW_INVERT:
396
cmd.cp_flags |= CP_INVERT;
397
break;
398
399
default:
400
errx(1, "%s: inappropriate modifier `%s'",
401
cname, *argv);
402
/* NOTREACHED */
403
}
404
}
405
406
/* Send command to changer. */
407
if (ioctl(changer_fd, CHIOPOSITION, &cmd))
408
err(1, "%s: CHIOPOSITION", changer_name);
409
410
return (0);
411
412
usage:
413
(void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n",
414
getprogname(), cname);
415
return (1);
416
}
417
418
/* ARGSUSED */
419
static int
420
do_params(const char *cname, int argc, char **argv __unused)
421
{
422
struct changer_params data;
423
int picker;
424
425
/* No arguments to this command. */
426
427
++argv; --argc;
428
429
if (argc) {
430
warnx("%s: no arguments expected", cname);
431
goto usage;
432
}
433
434
/* Get params from changer and display them. */
435
(void) memset(&data, 0, sizeof(data));
436
if (ioctl(changer_fd, CHIOGPARAMS, &data))
437
err(1, "%s: CHIOGPARAMS", changer_name);
438
439
(void) printf("%s: %d slot%s, %d drive%s, %d picker%s",
440
changer_name,
441
data.cp_nslots, (data.cp_nslots > 1) ? "s" : "",
442
data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "",
443
data.cp_npickers, (data.cp_npickers > 1) ? "s" : "");
444
if (data.cp_nportals)
445
(void) printf(", %d portal%s", data.cp_nportals,
446
(data.cp_nportals > 1) ? "s" : "");
447
448
/* Get current picker from changer and display it. */
449
if (ioctl(changer_fd, CHIOGPICKER, &picker))
450
err(1, "%s: CHIOGPICKER", changer_name);
451
452
(void) printf("\n%s: current picker: %d\n", changer_name, picker);
453
454
return (0);
455
456
usage:
457
(void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
458
return (1);
459
}
460
461
/* ARGSUSED */
462
static int
463
do_getpicker(const char *cname, int argc, char **argv __unused)
464
{
465
int picker;
466
467
/* No arguments to this command. */
468
469
++argv; --argc;
470
471
if (argc) {
472
warnx("%s: no arguments expected", cname);
473
goto usage;
474
}
475
476
/* Get current picker from changer and display it. */
477
if (ioctl(changer_fd, CHIOGPICKER, &picker))
478
err(1, "%s: CHIOGPICKER", changer_name);
479
480
(void) printf("%s: current picker: %d\n", changer_name, picker);
481
482
return (0);
483
484
usage:
485
(void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
486
return (1);
487
}
488
489
static int
490
do_setpicker(const char *cname, int argc, char **argv)
491
{
492
int picker;
493
494
++argv; --argc;
495
496
if (argc < 1) {
497
warnx("%s: too few arguments", cname);
498
goto usage;
499
} else if (argc > 1) {
500
warnx("%s: too many arguments", cname);
501
goto usage;
502
}
503
504
picker = parse_element_unit(*argv);
505
506
/* Set the changer picker. */
507
if (ioctl(changer_fd, CHIOSPICKER, &picker))
508
err(1, "%s: CHIOSPICKER", changer_name);
509
510
return (0);
511
512
usage:
513
(void) fprintf(stderr, "usage: %s %s <picker>\n", getprogname(), cname);
514
return (1);
515
}
516
517
static int
518
do_status(const char *cname, int argc, char **argv)
519
{
520
struct changer_params cp;
521
struct changer_element_status_request cesr;
522
int i;
523
u_int16_t base, count, chet, schet, echet;
524
const char *description;
525
int pvoltag = 0;
526
int avoltag = 0;
527
int sense = 0;
528
int scsi = 0;
529
int source = 0;
530
int intaddr = 0;
531
int c;
532
533
count = 0;
534
base = 0;
535
description = NULL;
536
537
optind = optreset = 1;
538
while ((c = getopt(argc, argv, "vVsSbaI")) != -1) {
539
switch (c) {
540
case 'v':
541
pvoltag = 1;
542
break;
543
case 'V':
544
avoltag = 1;
545
break;
546
case 's':
547
sense = 1;
548
break;
549
case 'S':
550
source = 1;
551
break;
552
case 'b':
553
scsi = 1;
554
break;
555
case 'I':
556
intaddr = 1;
557
break;
558
case 'a':
559
pvoltag = avoltag = source = sense = scsi = intaddr = 1;
560
break;
561
default:
562
warnx("%s: bad option", cname);
563
goto usage;
564
}
565
}
566
567
argc -= optind;
568
argv += optind;
569
570
/*
571
* On a status command, we expect the following:
572
*
573
* [<ET> [<start> [<end>] ] ]
574
*
575
* where ET == element type, start == first element to report,
576
* end == number of elements to report
577
*
578
* If we get no arguments, we get the status of all
579
* known element types.
580
*/
581
if (argc > 3) {
582
warnx("%s: too many arguments", cname);
583
goto usage;
584
}
585
586
/*
587
* Get params from changer. Specifically, we need the element
588
* counts.
589
*/
590
if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
591
err(1, "%s: CHIOGPARAMS", changer_name);
592
593
if (argc > 0)
594
schet = echet = parse_element_type(argv[0]);
595
else {
596
schet = CHET_MT;
597
echet = CHET_DT;
598
}
599
if (argc > 1) {
600
base = (u_int16_t)atol(argv[1]);
601
count = 1;
602
}
603
if (argc > 2)
604
count = (u_int16_t)atol(argv[2]) - base + 1;
605
606
for (chet = schet; chet <= echet; ++chet) {
607
switch (chet) {
608
case CHET_MT:
609
if (count == 0)
610
count = cp.cp_npickers;
611
else if (count > cp.cp_npickers)
612
errx(1, "not that many pickers in device");
613
description = "picker";
614
break;
615
616
case CHET_ST:
617
if (count == 0)
618
count = cp.cp_nslots;
619
else if (count > cp.cp_nslots)
620
errx(1, "not that many slots in device");
621
description = "slot";
622
break;
623
624
case CHET_IE:
625
if (count == 0)
626
count = cp.cp_nportals;
627
else if (count > cp.cp_nportals)
628
errx(1, "not that many portals in device");
629
description = "portal";
630
break;
631
632
case CHET_DT:
633
if (count == 0)
634
count = cp.cp_ndrives;
635
else if (count > cp.cp_ndrives)
636
errx(1, "not that many drives in device");
637
description = "drive";
638
break;
639
640
default:
641
/* To appease gcc -Wuninitialized. */
642
count = 0;
643
description = NULL;
644
}
645
646
if (count == 0) {
647
if (argc == 0)
648
continue;
649
else {
650
printf("%s: no %s elements\n",
651
changer_name, description);
652
return (0);
653
}
654
}
655
656
bzero(&cesr, sizeof(cesr));
657
cesr.cesr_element_type = chet;
658
cesr.cesr_element_base = base;
659
cesr.cesr_element_count = count;
660
/* Allocate storage for the status structures. */
661
cesr.cesr_element_status =
662
(struct changer_element_status *)
663
calloc((size_t)count, sizeof(struct changer_element_status));
664
665
if (!cesr.cesr_element_status)
666
errx(1, "can't allocate status storage");
667
668
if (avoltag || pvoltag)
669
cesr.cesr_flags |= CESR_VOLTAGS;
670
671
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) {
672
free(cesr.cesr_element_status);
673
err(1, "%s: CHIOGSTATUS", changer_name);
674
}
675
676
/* Dump the status for each reported element. */
677
for (i = 0; i < count; ++i) {
678
struct changer_element_status *ces =
679
&(cesr.cesr_element_status[i]);
680
printf("%s %d: %s", description, ces->ces_addr,
681
bits_to_string(ces->ces_flags,
682
CESTATUS_BITS));
683
if (sense)
684
printf(" sense: <0x%02x/0x%02x>",
685
ces->ces_sensecode,
686
ces->ces_sensequal);
687
if (pvoltag)
688
printf(" voltag: <%s:%d>",
689
ces->ces_pvoltag.cv_volid,
690
ces->ces_pvoltag.cv_serial);
691
if (avoltag)
692
printf(" avoltag: <%s:%d>",
693
ces->ces_avoltag.cv_volid,
694
ces->ces_avoltag.cv_serial);
695
if (source) {
696
if (ces->ces_flags & CES_SOURCE_VALID)
697
printf(" source: <%s %d>",
698
element_type_name(
699
ces->ces_source_type),
700
ces->ces_source_addr);
701
else
702
printf(" source: <>");
703
}
704
if (intaddr)
705
printf(" intaddr: <%d>", ces->ces_int_addr);
706
if (scsi) {
707
printf(" scsi: <");
708
if (ces->ces_flags & CES_SCSIID_VALID)
709
printf("%d", ces->ces_scsi_id);
710
else
711
putchar('?');
712
putchar(':');
713
if (ces->ces_flags & CES_LUN_VALID)
714
printf("%d", ces->ces_scsi_lun);
715
else
716
putchar('?');
717
putchar('>');
718
}
719
if (ces->ces_designator_length > 0)
720
print_designator(ces->ces_designator,
721
ces->ces_code_set,
722
ces->ces_designator_length);
723
putchar('\n');
724
}
725
726
free(cesr.cesr_element_status);
727
count = 0;
728
}
729
730
return (0);
731
732
usage:
733
(void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n",
734
getprogname(), cname);
735
return (1);
736
}
737
738
static int
739
do_ielem(const char *cname, int argc, char **argv)
740
{
741
int timeout = 0;
742
743
if (argc == 2) {
744
timeout = atol(argv[1]);
745
} else if (argc > 1) {
746
warnx("%s: too many arguments", cname);
747
goto usage;
748
}
749
750
if (ioctl(changer_fd, CHIOIELEM, &timeout))
751
err(1, "%s: CHIOIELEM", changer_name);
752
753
return (0);
754
755
usage:
756
(void) fprintf(stderr, "usage: %s %s [<timeout>]\n",
757
getprogname(), cname);
758
return (1);
759
}
760
761
static int
762
do_voltag(const char *cname, int argc, char **argv)
763
{
764
int force = 0;
765
int clear = 0;
766
int alternate = 0;
767
int c;
768
struct changer_set_voltag_request csvr;
769
770
bzero(&csvr, sizeof(csvr));
771
772
optind = optreset = 1;
773
while ((c = getopt(argc, argv, "fca")) != -1) {
774
switch (c) {
775
case 'f':
776
force = 1;
777
break;
778
case 'c':
779
clear = 1;
780
break;
781
case 'a':
782
alternate = 1;
783
break;
784
default:
785
warnx("%s: bad option", cname);
786
goto usage;
787
}
788
}
789
790
argc -= optind;
791
argv += optind;
792
793
if (argc < 2) {
794
warnx("%s: missing element specification", cname);
795
goto usage;
796
}
797
798
csvr.csvr_type = parse_element_type(argv[0]);
799
csvr.csvr_addr = (u_int16_t)atol(argv[1]);
800
801
if (!clear) {
802
if (argc < 3 || argc > 4) {
803
warnx("%s: missing argument", cname);
804
goto usage;
805
}
806
807
if (force)
808
csvr.csvr_flags = CSVR_MODE_REPLACE;
809
else
810
csvr.csvr_flags = CSVR_MODE_SET;
811
812
if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) {
813
warnx("%s: volume label too long", cname);
814
goto usage;
815
}
816
817
strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2],
818
sizeof(csvr.csvr_voltag.cv_volid));
819
820
if (argc == 4) {
821
csvr.csvr_voltag.cv_serial = (u_int16_t)atol(argv[3]);
822
}
823
} else {
824
if (argc != 2) {
825
warnx("%s: unexpected argument", cname);
826
goto usage;
827
}
828
csvr.csvr_flags = CSVR_MODE_CLEAR;
829
}
830
831
if (alternate) {
832
csvr.csvr_flags |= CSVR_ALTERNATE;
833
}
834
835
if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr))
836
err(1, "%s: CHIOSETVOLTAG", changer_name);
837
838
return 0;
839
usage:
840
(void) fprintf(stderr,
841
"usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n",
842
getprogname(), cname);
843
return 1;
844
}
845
846
static u_int16_t
847
parse_element_type(char *cp)
848
{
849
int i;
850
851
for (i = 0; elements[i].et_name != NULL; ++i)
852
if (strcmp(elements[i].et_name, cp) == 0)
853
return ((u_int16_t)elements[i].et_type);
854
855
errx(1, "invalid element type `%s'", cp);
856
/* NOTREACHED */
857
}
858
859
static const char *
860
element_type_name(int et)
861
{
862
int i;
863
864
for (i = 0; elements[i].et_name != NULL; i++)
865
if (elements[i].et_type == et)
866
return elements[i].et_name;
867
868
return "unknown";
869
}
870
871
static u_int16_t
872
parse_element_unit(char *cp)
873
{
874
int i;
875
char *p;
876
877
i = (int)strtol(cp, &p, 10);
878
if ((i < 0) || (*p != '\0'))
879
errx(1, "invalid unit number `%s'", cp);
880
881
return ((u_int16_t)i);
882
}
883
884
static int
885
parse_special(char *cp)
886
{
887
int val;
888
889
val = is_special(cp);
890
if (val)
891
return (val);
892
893
errx(1, "invalid modifier `%s'", cp);
894
/* NOTREACHED */
895
}
896
897
static int
898
is_special(char *cp)
899
{
900
int i;
901
902
for (i = 0; specials[i].sw_name != NULL; ++i)
903
if (strcmp(specials[i].sw_name, cp) == 0)
904
return (specials[i].sw_value);
905
906
return (0);
907
}
908
909
static const char *
910
bits_to_string(ces_status_flags v, const char *cp)
911
{
912
const char *np;
913
char f, sep, *bp;
914
static char buf[128];
915
916
bp = buf;
917
(void) memset(buf, 0, sizeof(buf));
918
919
for (sep = '<'; (f = *cp++) != 0; cp = np) {
920
for (np = cp; *np >= ' ';)
921
np++;
922
if (((int)v & (1 << (f - 1))) == 0)
923
continue;
924
(void) snprintf(bp, sizeof(buf) - (size_t)(bp - &buf[0]),
925
"%c%.*s", sep, (int)(long)(np - cp), cp);
926
bp += strlen(bp);
927
sep = ',';
928
}
929
if (sep != '<')
930
*bp = '>';
931
932
return (buf);
933
}
934
/*
935
* do_return()
936
*
937
* Given an element reference, ask the changer/picker to move that
938
* element back to its source slot.
939
*/
940
static int
941
do_return(const char *cname, int argc, char **argv)
942
{
943
struct changer_element_status *ces;
944
struct changer_move cmd;
945
uint16_t type, element;
946
947
++argv; --argc;
948
949
if (argc < 2) {
950
warnx("%s: too few arguments", cname);
951
goto usage;
952
} else if (argc > 3) {
953
warnx("%s: too many arguments", cname);
954
goto usage;
955
}
956
957
type = parse_element_type(*argv);
958
++argv; --argc;
959
960
/* Handle voltag virtual Changer Element Type */
961
if (CHET_VT == type) {
962
find_element(*argv, &type, &element);
963
} else {
964
element = parse_element_unit(*argv);
965
}
966
++argv; --argc;
967
968
/* Get the status */
969
ces = get_element_status((unsigned int)type, (unsigned int)element,
970
CHET_VT == type);
971
972
if (NULL == ces)
973
errx(1, "%s: null element status pointer", cname);
974
975
if (!(ces->ces_flags & CES_SOURCE_VALID))
976
errx(1, "%s: no source information", cname);
977
978
(void) memset(&cmd, 0, sizeof(cmd));
979
980
cmd.cm_fromtype = type;
981
cmd.cm_fromunit = element;
982
cmd.cm_totype = ces->ces_source_type;
983
cmd.cm_tounit = ces->ces_source_addr;
984
985
if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1)
986
err(1, "%s: CHIOMOVE", changer_name);
987
free(ces);
988
989
return(0);
990
991
usage:
992
(void) fprintf(stderr, "usage: %s %s "
993
"<from ET> <from EU>\n", getprogname(), cname);
994
return(1);
995
}
996
997
/*
998
* get_element_status()
999
*
1000
* return a *cesr for the specified changer element. This
1001
* routing will malloc()/calloc() the memory. The caller
1002
* should free() it when done.
1003
*/
1004
static struct changer_element_status *
1005
get_element_status(unsigned int type, unsigned int element, int use_voltags)
1006
{
1007
struct changer_element_status_request cesr;
1008
struct changer_element_status *ces;
1009
1010
ces = (struct changer_element_status *)
1011
calloc((size_t)1, sizeof(struct changer_element_status));
1012
1013
if (NULL == ces)
1014
errx(1, "can't allocate status storage");
1015
1016
(void)memset(&cesr, 0, sizeof(cesr));
1017
1018
cesr.cesr_element_type = (uint16_t)type;
1019
cesr.cesr_element_base = (uint16_t)element;
1020
cesr.cesr_element_count = 1; /* Only this one element */
1021
if (use_voltags)
1022
cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */
1023
cesr.cesr_element_status = ces;
1024
1025
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
1026
free(ces);
1027
err(1, "%s: CHIOGSTATUS", changer_name);
1028
/* NOTREACHED */
1029
}
1030
1031
return ces;
1032
}
1033
1034
1035
/*
1036
* find_element()
1037
*
1038
* Given a <voltag> find the chager element and unit, or exit
1039
* with an error if it isn't found. We grab the changer status
1040
* and iterate until we find a match, or crap out.
1041
*/
1042
static void
1043
find_element(char *voltag, uint16_t *et, uint16_t *eu)
1044
{
1045
struct changer_params cp;
1046
struct changer_element_status_request cesr;
1047
struct changer_element_status *ch_ces, *ces;
1048
int found = 0;
1049
size_t elem, total_elem;
1050
1051
/*
1052
* Get the changer parameters, we're interested in the counts
1053
* for all types of elements to perform our search.
1054
*/
1055
if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
1056
err(1, "%s: CHIOGPARAMS", changer_name);
1057
1058
/* Allocate some memory for the results */
1059
total_elem = (cp.cp_nslots + cp.cp_ndrives
1060
+ cp.cp_npickers + cp.cp_nportals);
1061
1062
ch_ces = (struct changer_element_status *)
1063
calloc(total_elem, sizeof(struct changer_element_status));
1064
1065
if (NULL == ch_ces)
1066
errx(1, "can't allocate status storage");
1067
1068
ces = ch_ces;
1069
1070
/* Read in the changer slots */
1071
if (cp.cp_nslots > 0) {
1072
(void) memset(&cesr, 0, sizeof(cesr));
1073
cesr.cesr_element_type = CHET_ST;
1074
cesr.cesr_element_base = 0;
1075
cesr.cesr_element_count = cp.cp_nslots;
1076
cesr.cesr_flags |= CESR_VOLTAGS;
1077
cesr.cesr_element_status = ces;
1078
1079
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
1080
free(ch_ces);
1081
err(1, "%s: CHIOGSTATUS", changer_name);
1082
}
1083
ces += cp.cp_nslots;
1084
}
1085
1086
/* Read in the drive information */
1087
if (cp.cp_ndrives > 0 ) {
1088
1089
(void) memset(&cesr, 0, sizeof(cesr));
1090
cesr.cesr_element_type = CHET_DT;
1091
cesr.cesr_element_base = 0;
1092
cesr.cesr_element_count = cp.cp_ndrives;
1093
cesr.cesr_flags |= CESR_VOLTAGS;
1094
cesr.cesr_element_status = ces;
1095
1096
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
1097
free(ch_ces);
1098
err(1, "%s: CHIOGSTATUS", changer_name);
1099
}
1100
ces += cp.cp_ndrives;
1101
}
1102
1103
/* Read in the portal information */
1104
if (cp.cp_nportals > 0 ) {
1105
(void) memset(&cesr, 0, sizeof(cesr));
1106
cesr.cesr_element_type = CHET_IE;
1107
cesr.cesr_element_base = 0;
1108
cesr.cesr_element_count = cp.cp_nportals;
1109
cesr.cesr_flags |= CESR_VOLTAGS;
1110
cesr.cesr_element_status = ces;
1111
1112
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
1113
free(ch_ces);
1114
err(1, "%s: CHIOGSTATUS", changer_name);
1115
}
1116
ces += cp.cp_nportals;
1117
}
1118
1119
/* Read in the picker information */
1120
if (cp.cp_npickers > 0) {
1121
(void) memset(&cesr, 0, sizeof(cesr));
1122
cesr.cesr_element_type = CHET_MT;
1123
cesr.cesr_element_base = 0;
1124
cesr.cesr_element_count = cp.cp_npickers;
1125
cesr.cesr_flags |= CESR_VOLTAGS;
1126
cesr.cesr_element_status = ces;
1127
1128
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
1129
free(ch_ces);
1130
err(1, "%s: CHIOGSTATUS", changer_name);
1131
}
1132
}
1133
1134
/*
1135
* Now search the list the specified <voltag>
1136
*/
1137
for (elem = 0; elem < total_elem; ++elem) {
1138
1139
ces = &ch_ces[elem];
1140
1141
/* Make sure we have a tape in this element */
1142
if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL))
1143
!= (CES_STATUS_ACCESS|CES_STATUS_FULL))
1144
continue;
1145
1146
/* Check to see if it is our target */
1147
if (strcasecmp(voltag,
1148
(const char *)ces->ces_pvoltag.cv_volid) == 0) {
1149
*et = ces->ces_type;
1150
*eu = ces->ces_addr;
1151
++found;
1152
break;
1153
}
1154
}
1155
if (!found) {
1156
errx(1, "%s: unable to locate voltag: %s", changer_name,
1157
voltag);
1158
}
1159
free(ch_ces);
1160
return;
1161
}
1162
1163
static void
1164
cleanup(void)
1165
{
1166
/* Simple enough... */
1167
(void)close(changer_fd);
1168
}
1169
1170
static void
1171
usage(void)
1172
{
1173
(void)fprintf(stderr, "usage: %s [-f changer] command [-<flags>] "
1174
"arg1 arg2 [arg3 [...]]\n", getprogname());
1175
exit(1);
1176
}
1177
1178
#define UTF8CODESET "UTF-8"
1179
1180
static void
1181
print_designator(const char *designator, u_int8_t code_set,
1182
u_int8_t designator_length)
1183
{
1184
printf(" serial number: <");
1185
switch (code_set) {
1186
case CES_CODE_SET_ASCII: {
1187
/*
1188
* The driver insures that the string is always NUL terminated.
1189
*/
1190
printf("%s", designator);
1191
break;
1192
}
1193
case CES_CODE_SET_UTF_8: {
1194
char *cs_native;
1195
1196
setlocale(LC_ALL, "");
1197
cs_native = nl_langinfo(CODESET);
1198
1199
/* See if we can natively print UTF-8 */
1200
if (strcmp(cs_native, UTF8CODESET) == 0)
1201
cs_native = NULL;
1202
1203
if (cs_native == NULL) {
1204
/* We can natively print UTF-8, so use printf. */
1205
printf("%s", designator);
1206
} else {
1207
int i;
1208
1209
/*
1210
* We can't natively print UTF-8. We should
1211
* convert it to the terminal's codeset, but that
1212
* requires iconv(3) and FreeBSD doesn't have
1213
* iconv(3) in the base system yet. So we use %XX
1214
* notation for non US-ASCII characters instead.
1215
*/
1216
for (i = 0; i < designator_length &&
1217
designator[i] != '\0'; i++) {
1218
if ((unsigned char)designator[i] < 0x80)
1219
printf("%c", designator[i]);
1220
else
1221
printf("%%%02x",
1222
(unsigned char)designator[i]);
1223
}
1224
}
1225
break;
1226
}
1227
case CES_CODE_SET_BINARY: {
1228
int i;
1229
1230
for (i = 0; i < designator_length; i++)
1231
printf("%02X%s", designator[i],
1232
(i == designator_length - 1) ? "" : " ");
1233
break;
1234
}
1235
default:
1236
break;
1237
}
1238
printf(">");
1239
}
1240
1241