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