/bin/chio/chio.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1179 lines · 827 code · 190 blank · 162 comment · 196 complexity · 6f560a545faaab7a69baefab4f274f99 MD5 · raw file

  1. /* $NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $ */
  2. /*-
  3. * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
  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. * Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications
  36. */
  37. #if 0
  38. #ifndef lint
  39. static const char copyright[] =
  40. "@(#) Copyright (c) 1996 Jason R. Thorpe. All rights reserved.";
  41. #endif /* not lint */
  42. #endif
  43. #include <sys/cdefs.h>
  44. __FBSDID("$FreeBSD$");
  45. #include <sys/param.h>
  46. #include <sys/chio.h>
  47. #include <err.h>
  48. #include <fcntl.h>
  49. #include <stdio.h>
  50. #include <stdint.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include <unistd.h>
  54. #include "defs.h"
  55. #include "pathnames.h"
  56. static void usage(void);
  57. static void cleanup(void);
  58. static u_int16_t parse_element_type(char *);
  59. static u_int16_t parse_element_unit(char *);
  60. static const char * element_type_name(int et);
  61. static int parse_special(char *);
  62. static int is_special(char *);
  63. static const char *bits_to_string(ces_status_flags, const char *);
  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. static int do_move(const char *, int, char **);
  68. static int do_exchange(const char *, int, char **);
  69. static int do_position(const char *, int, char **);
  70. static int do_params(const char *, int, char **);
  71. static int do_getpicker(const char *, int, char **);
  72. static int do_setpicker(const char *, int, char **);
  73. static int do_status(const char *, int, char **);
  74. static int do_ielem(const char *, int, char **);
  75. static int do_return(const char *, int, char **);
  76. static int do_voltag(const char *, int, char **);
  77. #ifndef CHET_VT
  78. #define CHET_VT 10 /* Completely Arbitrary */
  79. #endif
  80. /* Valid changer element types. */
  81. static const struct element_type elements[] = {
  82. { "drive", CHET_DT },
  83. { "picker", CHET_MT },
  84. { "portal", CHET_IE },
  85. { "slot", CHET_ST },
  86. { "voltag", CHET_VT }, /* Select tapes by barcode */
  87. { NULL, 0 },
  88. };
  89. /* Valid commands. */
  90. static const struct changer_command commands[] = {
  91. { "exchange", do_exchange },
  92. { "getpicker", do_getpicker },
  93. { "ielem", do_ielem },
  94. { "move", do_move },
  95. { "params", do_params },
  96. { "position", do_position },
  97. { "setpicker", do_setpicker },
  98. { "status", do_status },
  99. { "return", do_return },
  100. { "voltag", do_voltag },
  101. { NULL, 0 },
  102. };
  103. /* Valid special words. */
  104. static const struct special_word specials[] = {
  105. { "inv", SW_INVERT },
  106. { "inv1", SW_INVERT1 },
  107. { "inv2", SW_INVERT2 },
  108. { NULL, 0 },
  109. };
  110. static int changer_fd;
  111. static const char *changer_name;
  112. int
  113. main(int argc, char **argv)
  114. {
  115. int ch, i;
  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. if (argc == 0)
  128. usage();
  129. /* Get the default changer if not already specified. */
  130. if (changer_name == NULL)
  131. if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL)
  132. changer_name = _PATH_CH;
  133. /* Open the changer device. */
  134. if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1)
  135. err(1, "%s: open", changer_name);
  136. /* Register cleanup function. */
  137. if (atexit(cleanup))
  138. err(1, "can't register cleanup function");
  139. /* Find the specified command. */
  140. for (i = 0; commands[i].cc_name != NULL; ++i)
  141. if (strcmp(*argv, commands[i].cc_name) == 0)
  142. break;
  143. if (commands[i].cc_name == NULL) {
  144. /* look for abbreviation */
  145. for (i = 0; commands[i].cc_name != NULL; ++i)
  146. if (strncmp(*argv, commands[i].cc_name,
  147. strlen(*argv)) == 0)
  148. break;
  149. }
  150. if (commands[i].cc_name == NULL)
  151. errx(1, "unknown command: %s", *argv);
  152. exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv));
  153. /* NOTREACHED */
  154. }
  155. static int
  156. do_move(const char *cname, int argc, char **argv)
  157. {
  158. struct changer_move cmd;
  159. int val;
  160. /*
  161. * On a move command, we expect the following:
  162. *
  163. * <from ET> <from EU> <to ET> <to EU> [inv]
  164. *
  165. * where ET == element type and EU == element unit.
  166. */
  167. ++argv; --argc;
  168. if (argc < 4) {
  169. warnx("%s: too few arguments", cname);
  170. goto usage;
  171. } else if (argc > 5) {
  172. warnx("%s: too many arguments", cname);
  173. goto usage;
  174. }
  175. (void) memset(&cmd, 0, sizeof(cmd));
  176. /* <from ET> */
  177. cmd.cm_fromtype = parse_element_type(*argv);
  178. ++argv; --argc;
  179. /* Check for voltag virtual type */
  180. if (CHET_VT == cmd.cm_fromtype) {
  181. find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit);
  182. } else {
  183. /* <from EU> */
  184. cmd.cm_fromunit = parse_element_unit(*argv);
  185. }
  186. ++argv; --argc;
  187. /* <to ET> */
  188. cmd.cm_totype = parse_element_type(*argv);
  189. ++argv; --argc;
  190. /* Check for voltag virtual type, and report error */
  191. if (CHET_VT == cmd.cm_totype)
  192. errx(1,"%s: voltag only makes sense as an element source",
  193. cname);
  194. /* <to EU> */
  195. cmd.cm_tounit = parse_element_unit(*argv);
  196. ++argv; --argc;
  197. /* Deal with optional command modifier. */
  198. if (argc) {
  199. val = parse_special(*argv);
  200. switch (val) {
  201. case SW_INVERT:
  202. cmd.cm_flags |= CM_INVERT;
  203. break;
  204. default:
  205. errx(1, "%s: inappropriate modifier `%s'",
  206. cname, *argv);
  207. /* NOTREACHED */
  208. }
  209. }
  210. /* Send command to changer. */
  211. if (ioctl(changer_fd, CHIOMOVE, &cmd))
  212. err(1, "%s: CHIOMOVE", changer_name);
  213. return (0);
  214. usage:
  215. (void) fprintf(stderr, "usage: %s %s "
  216. "<from ET> <from EU> <to ET> <to EU> [inv]\n", getprogname(), cname);
  217. return (1);
  218. }
  219. static int
  220. do_exchange(const char *cname, int argc, char **argv)
  221. {
  222. struct changer_exchange cmd;
  223. int val;
  224. /*
  225. * On an exchange command, we expect the following:
  226. *
  227. * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2]
  228. *
  229. * where ET == element type and EU == element unit.
  230. */
  231. ++argv; --argc;
  232. if (argc < 4) {
  233. warnx("%s: too few arguments", cname);
  234. goto usage;
  235. } else if (argc > 8) {
  236. warnx("%s: too many arguments", cname);
  237. goto usage;
  238. }
  239. (void) memset(&cmd, 0, sizeof(cmd));
  240. /* <src ET> */
  241. cmd.ce_srctype = parse_element_type(*argv);
  242. ++argv; --argc;
  243. /* Check for voltag virtual type */
  244. if (CHET_VT == cmd.ce_srctype) {
  245. find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit);
  246. } else {
  247. /* <from EU> */
  248. cmd.ce_srcunit = parse_element_unit(*argv);
  249. }
  250. ++argv; --argc;
  251. /* <dst1 ET> */
  252. cmd.ce_fdsttype = parse_element_type(*argv);
  253. ++argv; --argc;
  254. /* Check for voltag virtual type */
  255. if (CHET_VT == cmd.ce_fdsttype) {
  256. find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit);
  257. } else {
  258. /* <from EU> */
  259. cmd.ce_fdstunit = parse_element_unit(*argv);
  260. }
  261. ++argv; --argc;
  262. /*
  263. * If the next token is a special word or there are no more
  264. * arguments, then this is a case of simple exchange.
  265. * dst2 == src.
  266. */
  267. if ((argc == 0) || is_special(*argv)) {
  268. cmd.ce_sdsttype = cmd.ce_srctype;
  269. cmd.ce_sdstunit = cmd.ce_srcunit;
  270. goto do_special;
  271. }
  272. /* <dst2 ET> */
  273. cmd.ce_sdsttype = parse_element_type(*argv);
  274. ++argv; --argc;
  275. if (CHET_VT == cmd.ce_sdsttype)
  276. errx(1,"%s %s: voltag only makes sense as an element source",
  277. cname, *argv);
  278. /* <dst2 EU> */
  279. cmd.ce_sdstunit = parse_element_unit(*argv);
  280. ++argv; --argc;
  281. do_special:
  282. /* Deal with optional command modifiers. */
  283. while (argc) {
  284. val = parse_special(*argv);
  285. ++argv; --argc;
  286. switch (val) {
  287. case SW_INVERT1:
  288. cmd.ce_flags |= CE_INVERT1;
  289. break;
  290. case SW_INVERT2:
  291. cmd.ce_flags |= CE_INVERT2;
  292. break;
  293. default:
  294. errx(1, "%s: inappropriate modifier `%s'",
  295. cname, *argv);
  296. /* NOTREACHED */
  297. }
  298. }
  299. /* Send command to changer. */
  300. if (ioctl(changer_fd, CHIOEXCHANGE, &cmd))
  301. err(1, "%s: CHIOEXCHANGE", changer_name);
  302. return (0);
  303. usage:
  304. (void) fprintf(stderr,
  305. "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n"
  306. " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n",
  307. getprogname(), cname);
  308. return (1);
  309. }
  310. static int
  311. do_position(const char *cname, int argc, char **argv)
  312. {
  313. struct changer_position cmd;
  314. int val;
  315. /*
  316. * On a position command, we expect the following:
  317. *
  318. * <to ET> <to EU> [inv]
  319. *
  320. * where ET == element type and EU == element unit.
  321. */
  322. ++argv; --argc;
  323. if (argc < 2) {
  324. warnx("%s: too few arguments", cname);
  325. goto usage;
  326. } else if (argc > 3) {
  327. warnx("%s: too many arguments", cname);
  328. goto usage;
  329. }
  330. (void) memset(&cmd, 0, sizeof(cmd));
  331. /* <to ET> */
  332. cmd.cp_type = parse_element_type(*argv);
  333. ++argv; --argc;
  334. /* <to EU> */
  335. cmd.cp_unit = parse_element_unit(*argv);
  336. ++argv; --argc;
  337. /* Deal with optional command modifier. */
  338. if (argc) {
  339. val = parse_special(*argv);
  340. switch (val) {
  341. case SW_INVERT:
  342. cmd.cp_flags |= CP_INVERT;
  343. break;
  344. default:
  345. errx(1, "%s: inappropriate modifier `%s'",
  346. cname, *argv);
  347. /* NOTREACHED */
  348. }
  349. }
  350. /* Send command to changer. */
  351. if (ioctl(changer_fd, CHIOPOSITION, &cmd))
  352. err(1, "%s: CHIOPOSITION", changer_name);
  353. return (0);
  354. usage:
  355. (void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n",
  356. getprogname(), cname);
  357. return (1);
  358. }
  359. /* ARGSUSED */
  360. static int
  361. do_params(const char *cname, int argc, char **argv)
  362. {
  363. struct changer_params data;
  364. int picker;
  365. /* No arguments to this command. */
  366. ++argv; --argc;
  367. if (argc) {
  368. warnx("%s: no arguments expected", cname);
  369. goto usage;
  370. }
  371. /* Get params from changer and display them. */
  372. (void) memset(&data, 0, sizeof(data));
  373. if (ioctl(changer_fd, CHIOGPARAMS, &data))
  374. err(1, "%s: CHIOGPARAMS", changer_name);
  375. (void) printf("%s: %d slot%s, %d drive%s, %d picker%s",
  376. changer_name,
  377. data.cp_nslots, (data.cp_nslots > 1) ? "s" : "",
  378. data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "",
  379. data.cp_npickers, (data.cp_npickers > 1) ? "s" : "");
  380. if (data.cp_nportals)
  381. (void) printf(", %d portal%s", data.cp_nportals,
  382. (data.cp_nportals > 1) ? "s" : "");
  383. /* Get current picker from changer and display it. */
  384. if (ioctl(changer_fd, CHIOGPICKER, &picker))
  385. err(1, "%s: CHIOGPICKER", changer_name);
  386. (void) printf("\n%s: current picker: %d\n", changer_name, picker);
  387. return (0);
  388. usage:
  389. (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
  390. return (1);
  391. }
  392. /* ARGSUSED */
  393. static int
  394. do_getpicker(const char *cname, int argc, char **argv)
  395. {
  396. int picker;
  397. /* No arguments to this command. */
  398. ++argv; --argc;
  399. if (argc) {
  400. warnx("%s: no arguments expected", cname);
  401. goto usage;
  402. }
  403. /* Get current picker from changer and display it. */
  404. if (ioctl(changer_fd, CHIOGPICKER, &picker))
  405. err(1, "%s: CHIOGPICKER", changer_name);
  406. (void) printf("%s: current picker: %d\n", changer_name, picker);
  407. return (0);
  408. usage:
  409. (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
  410. return (1);
  411. }
  412. static int
  413. do_setpicker(const char *cname, int argc, char **argv)
  414. {
  415. int picker;
  416. ++argv; --argc;
  417. if (argc < 1) {
  418. warnx("%s: too few arguments", cname);
  419. goto usage;
  420. } else if (argc > 1) {
  421. warnx("%s: too many arguments", cname);
  422. goto usage;
  423. }
  424. picker = parse_element_unit(*argv);
  425. /* Set the changer picker. */
  426. if (ioctl(changer_fd, CHIOSPICKER, &picker))
  427. err(1, "%s: CHIOSPICKER", changer_name);
  428. return (0);
  429. usage:
  430. (void) fprintf(stderr, "usage: %s %s <picker>\n", getprogname(), cname);
  431. return (1);
  432. }
  433. static int
  434. do_status(const char *cname, int argc, char **argv)
  435. {
  436. struct changer_params cp;
  437. struct changer_element_status_request cesr;
  438. int i;
  439. u_int16_t base, count, chet, schet, echet;
  440. const char *description;
  441. int pvoltag = 0;
  442. int avoltag = 0;
  443. int sense = 0;
  444. int scsi = 0;
  445. int source = 0;
  446. int intaddr = 0;
  447. int c;
  448. count = 0;
  449. base = 0;
  450. description = NULL;
  451. optind = optreset = 1;
  452. while ((c = getopt(argc, argv, "vVsSbaI")) != -1) {
  453. switch (c) {
  454. case 'v':
  455. pvoltag = 1;
  456. break;
  457. case 'V':
  458. avoltag = 1;
  459. break;
  460. case 's':
  461. sense = 1;
  462. break;
  463. case 'S':
  464. source = 1;
  465. break;
  466. case 'b':
  467. scsi = 1;
  468. break;
  469. case 'I':
  470. intaddr = 1;
  471. break;
  472. case 'a':
  473. pvoltag = avoltag = source = sense = scsi = intaddr = 1;
  474. break;
  475. default:
  476. warnx("%s: bad option", cname);
  477. goto usage;
  478. }
  479. }
  480. argc -= optind;
  481. argv += optind;
  482. /*
  483. * On a status command, we expect the following:
  484. *
  485. * [<ET> [<start> [<end>] ] ]
  486. *
  487. * where ET == element type, start == first element to report,
  488. * end == number of elements to report
  489. *
  490. * If we get no arguments, we get the status of all
  491. * known element types.
  492. */
  493. if (argc > 3) {
  494. warnx("%s: too many arguments", cname);
  495. goto usage;
  496. }
  497. /*
  498. * Get params from changer. Specifically, we need the element
  499. * counts.
  500. */
  501. if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
  502. err(1, "%s: CHIOGPARAMS", changer_name);
  503. if (argc > 0)
  504. schet = echet = parse_element_type(argv[0]);
  505. else {
  506. schet = CHET_MT;
  507. echet = CHET_DT;
  508. }
  509. if (argc > 1) {
  510. base = (u_int16_t)atol(argv[1]);
  511. count = 1;
  512. }
  513. if (argc > 2)
  514. count = (u_int16_t)atol(argv[2]) - base + 1;
  515. for (chet = schet; chet <= echet; ++chet) {
  516. switch (chet) {
  517. case CHET_MT:
  518. if (count == 0)
  519. count = cp.cp_npickers;
  520. else if (count > cp.cp_npickers)
  521. errx(1, "not that many pickers in device");
  522. description = "picker";
  523. break;
  524. case CHET_ST:
  525. if (count == 0)
  526. count = cp.cp_nslots;
  527. else if (count > cp.cp_nslots)
  528. errx(1, "not that many slots in device");
  529. description = "slot";
  530. break;
  531. case CHET_IE:
  532. if (count == 0)
  533. count = cp.cp_nportals;
  534. else if (count > cp.cp_nportals)
  535. errx(1, "not that many portals in device");
  536. description = "portal";
  537. break;
  538. case CHET_DT:
  539. if (count == 0)
  540. count = cp.cp_ndrives;
  541. else if (count > cp.cp_ndrives)
  542. errx(1, "not that many drives in device");
  543. description = "drive";
  544. break;
  545. default:
  546. /* To appease gcc -Wuninitialized. */
  547. count = 0;
  548. description = NULL;
  549. }
  550. if (count == 0) {
  551. if (argc == 0)
  552. continue;
  553. else {
  554. printf("%s: no %s elements\n",
  555. changer_name, description);
  556. return (0);
  557. }
  558. }
  559. bzero(&cesr, sizeof(cesr));
  560. cesr.cesr_element_type = chet;
  561. cesr.cesr_element_base = base;
  562. cesr.cesr_element_count = count;
  563. /* Allocate storage for the status structures. */
  564. cesr.cesr_element_status =
  565. (struct changer_element_status *)
  566. calloc((size_t)count, sizeof(struct changer_element_status));
  567. if (!cesr.cesr_element_status)
  568. errx(1, "can't allocate status storage");
  569. if (avoltag || pvoltag)
  570. cesr.cesr_flags |= CESR_VOLTAGS;
  571. if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) {
  572. free(cesr.cesr_element_status);
  573. err(1, "%s: CHIOGSTATUS", changer_name);
  574. }
  575. /* Dump the status for each reported element. */
  576. for (i = 0; i < count; ++i) {
  577. struct changer_element_status *ces =
  578. &(cesr.cesr_element_status[i]);
  579. printf("%s %d: %s", description, ces->ces_addr,
  580. bits_to_string(ces->ces_flags,
  581. CESTATUS_BITS));
  582. if (sense)
  583. printf(" sense: <0x%02x/0x%02x>",
  584. ces->ces_sensecode,
  585. ces->ces_sensequal);
  586. if (pvoltag)
  587. printf(" voltag: <%s:%d>",
  588. ces->ces_pvoltag.cv_volid,
  589. ces->ces_pvoltag.cv_serial);
  590. if (avoltag)
  591. printf(" avoltag: <%s:%d>",
  592. ces->ces_avoltag.cv_volid,
  593. ces->ces_avoltag.cv_serial);
  594. if (source) {
  595. if (ces->ces_flags & CES_SOURCE_VALID)
  596. printf(" source: <%s %d>",
  597. element_type_name(
  598. ces->ces_source_type),
  599. ces->ces_source_addr);
  600. else
  601. printf(" source: <>");
  602. }
  603. if (intaddr)
  604. printf(" intaddr: <%d>", ces->ces_int_addr);
  605. if (scsi) {
  606. printf(" scsi: <");
  607. if (ces->ces_flags & CES_SCSIID_VALID)
  608. printf("%d", ces->ces_scsi_id);
  609. else
  610. putchar('?');
  611. putchar(':');
  612. if (ces->ces_flags & CES_LUN_VALID)
  613. printf("%d", ces->ces_scsi_lun);
  614. else
  615. putchar('?');
  616. putchar('>');
  617. }
  618. putchar('\n');
  619. }
  620. free(cesr.cesr_element_status);
  621. count = 0;
  622. }
  623. return (0);
  624. usage:
  625. (void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n",
  626. getprogname(), cname);
  627. return (1);
  628. }
  629. static int
  630. do_ielem(const char *cname, int argc, char **argv)
  631. {
  632. int timeout = 0;
  633. if (argc == 2) {
  634. timeout = atol(argv[1]);
  635. } else if (argc > 1) {
  636. warnx("%s: too many arguments", cname);
  637. goto usage;
  638. }
  639. if (ioctl(changer_fd, CHIOIELEM, &timeout))
  640. err(1, "%s: CHIOIELEM", changer_name);
  641. return (0);
  642. usage:
  643. (void) fprintf(stderr, "usage: %s %s [<timeout>]\n",
  644. getprogname(), cname);
  645. return (1);
  646. }
  647. static int
  648. do_voltag(const char *cname, int argc, char **argv)
  649. {
  650. int force = 0;
  651. int clear = 0;
  652. int alternate = 0;
  653. int c;
  654. struct changer_set_voltag_request csvr;
  655. bzero(&csvr, sizeof(csvr));
  656. optind = optreset = 1;
  657. while ((c = getopt(argc, argv, "fca")) != -1) {
  658. switch (c) {
  659. case 'f':
  660. force = 1;
  661. break;
  662. case 'c':
  663. clear = 1;
  664. break;
  665. case 'a':
  666. alternate = 1;
  667. break;
  668. default:
  669. warnx("%s: bad option", cname);
  670. goto usage;
  671. }
  672. }
  673. argc -= optind;
  674. argv += optind;
  675. if (argc < 2) {
  676. warnx("%s: missing element specification", cname);
  677. goto usage;
  678. }
  679. csvr.csvr_type = parse_element_type(argv[0]);
  680. csvr.csvr_addr = (u_int16_t)atol(argv[1]);
  681. if (!clear) {
  682. if (argc < 3 || argc > 4) {
  683. warnx("%s: missing argument", cname);
  684. goto usage;
  685. }
  686. if (force)
  687. csvr.csvr_flags = CSVR_MODE_REPLACE;
  688. else
  689. csvr.csvr_flags = CSVR_MODE_SET;
  690. if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) {
  691. warnx("%s: volume label too long", cname);
  692. goto usage;
  693. }
  694. strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2],
  695. sizeof(csvr.csvr_voltag.cv_volid));
  696. if (argc == 4) {
  697. csvr.csvr_voltag.cv_serial = (u_int16_t)atol(argv[3]);
  698. }
  699. } else {
  700. if (argc != 2) {
  701. warnx("%s: unexpected argument", cname);
  702. goto usage;
  703. }
  704. csvr.csvr_flags = CSVR_MODE_CLEAR;
  705. }
  706. if (alternate) {
  707. csvr.csvr_flags |= CSVR_ALTERNATE;
  708. }
  709. if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr))
  710. err(1, "%s: CHIOSETVOLTAG", changer_name);
  711. return 0;
  712. usage:
  713. (void) fprintf(stderr,
  714. "usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n",
  715. getprogname(), cname);
  716. return 1;
  717. }
  718. static u_int16_t
  719. parse_element_type(char *cp)
  720. {
  721. int i;
  722. for (i = 0; elements[i].et_name != NULL; ++i)
  723. if (strcmp(elements[i].et_name, cp) == 0)
  724. return ((u_int16_t)elements[i].et_type);
  725. errx(1, "invalid element type `%s'", cp);
  726. /* NOTREACHED */
  727. }
  728. static const char *
  729. element_type_name(int et)
  730. {
  731. int i;
  732. for (i = 0; elements[i].et_name != NULL; i++)
  733. if (elements[i].et_type == et)
  734. return elements[i].et_name;
  735. return "unknown";
  736. }
  737. static u_int16_t
  738. parse_element_unit(char *cp)
  739. {
  740. int i;
  741. char *p;
  742. i = (int)strtol(cp, &p, 10);
  743. if ((i < 0) || (*p != '\0'))
  744. errx(1, "invalid unit number `%s'", cp);
  745. return ((u_int16_t)i);
  746. }
  747. static int
  748. parse_special(char *cp)
  749. {
  750. int val;
  751. val = is_special(cp);
  752. if (val)
  753. return (val);
  754. errx(1, "invalid modifier `%s'", cp);
  755. /* NOTREACHED */
  756. }
  757. static int
  758. is_special(char *cp)
  759. {
  760. int i;
  761. for (i = 0; specials[i].sw_name != NULL; ++i)
  762. if (strcmp(specials[i].sw_name, cp) == 0)
  763. return (specials[i].sw_value);
  764. return (0);
  765. }
  766. static const char *
  767. bits_to_string(ces_status_flags v, const char *cp)
  768. {
  769. const char *np;
  770. char f, sep, *bp;
  771. static char buf[128];
  772. bp = buf;
  773. (void) memset(buf, 0, sizeof(buf));
  774. for (sep = '<'; (f = *cp++) != 0; cp = np) {
  775. for (np = cp; *np >= ' ';)
  776. np++;
  777. if (((int)v & (1 << (f - 1))) == 0)
  778. continue;
  779. (void) snprintf(bp, sizeof(buf) - (size_t)(bp - &buf[0]),
  780. "%c%.*s", sep, (int)(long)(np - cp), cp);
  781. bp += strlen(bp);
  782. sep = ',';
  783. }
  784. if (sep != '<')
  785. *bp = '>';
  786. return (buf);
  787. }
  788. /*
  789. * do_return()
  790. *
  791. * Given an element reference, ask the changer/picker to move that
  792. * element back to its source slot.
  793. */
  794. static int
  795. do_return(const char *cname, int argc, char **argv)
  796. {
  797. struct changer_element_status *ces;
  798. struct changer_move cmd;
  799. uint16_t type, element;
  800. ++argv; --argc;
  801. if (argc < 2) {
  802. warnx("%s: too few arguments", cname);
  803. goto usage;
  804. } else if (argc > 3) {
  805. warnx("%s: too many arguments", cname);
  806. goto usage;
  807. }
  808. type = parse_element_type(*argv);
  809. ++argv; --argc;
  810. /* Handle voltag virtual Changer Element Type */
  811. if (CHET_VT == type) {
  812. find_element(*argv, &type, &element);
  813. } else {
  814. element = parse_element_unit(*argv);
  815. }
  816. ++argv; --argc;
  817. /* Get the status */
  818. ces = get_element_status((unsigned int)type, (unsigned int)element,
  819. CHET_VT == type);
  820. if (NULL == ces)
  821. errx(1, "%s: null element status pointer", cname);
  822. if (!(ces->ces_flags & CES_SOURCE_VALID))
  823. errx(1, "%s: no source information", cname);
  824. (void) memset(&cmd, 0, sizeof(cmd));
  825. cmd.cm_fromtype = type;
  826. cmd.cm_fromunit = element;
  827. cmd.cm_totype = ces->ces_source_type;
  828. cmd.cm_tounit = ces->ces_source_addr;
  829. if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1)
  830. err(1, "%s: CHIOMOVE", changer_name);
  831. free(ces);
  832. return(0);
  833. usage:
  834. (void) fprintf(stderr, "usage: %s %s "
  835. "<from ET> <from EU>\n", getprogname(), cname);
  836. return(1);
  837. }
  838. /*
  839. * get_element_status()
  840. *
  841. * return a *cesr for the specified changer element. This
  842. * routing will malloc()/calloc() the memory. The caller
  843. * should free() it when done.
  844. */
  845. static struct changer_element_status *
  846. get_element_status(unsigned int type, unsigned int element, int use_voltags)
  847. {
  848. struct changer_element_status_request cesr;
  849. struct changer_element_status *ces;
  850. ces = (struct changer_element_status *)
  851. calloc((size_t)1, sizeof(struct changer_element_status));
  852. if (NULL == ces)
  853. errx(1, "can't allocate status storage");
  854. (void)memset(&cesr, 0, sizeof(cesr));
  855. cesr.cesr_element_type = (uint16_t)type;
  856. cesr.cesr_element_base = (uint16_t)element;
  857. cesr.cesr_element_count = 1; /* Only this one element */
  858. if (use_voltags)
  859. cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */
  860. cesr.cesr_element_status = ces;
  861. if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
  862. free(ces);
  863. err(1, "%s: CHIOGSTATUS", changer_name);
  864. /* NOTREACHED */
  865. }
  866. return ces;
  867. }
  868. /*
  869. * find_element()
  870. *
  871. * Given a <voltag> find the chager element and unit, or exit
  872. * with an error if it isn't found. We grab the changer status
  873. * and iterate until we find a match, or crap out.
  874. */
  875. static void
  876. find_element(char *voltag, uint16_t *et, uint16_t *eu)
  877. {
  878. struct changer_params cp;
  879. struct changer_element_status_request cesr;
  880. struct changer_element_status *ch_ces, *ces;
  881. int found = 0;
  882. size_t elem, total_elem;
  883. /*
  884. * Get the changer parameters, we're interested in the counts
  885. * for all types of elements to perform our search.
  886. */
  887. if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
  888. err(1, "%s: CHIOGPARAMS", changer_name);
  889. /* Allocate some memory for the results */
  890. total_elem = (cp.cp_nslots + cp.cp_ndrives
  891. + cp.cp_npickers + cp.cp_nportals);
  892. ch_ces = (struct changer_element_status *)
  893. calloc(total_elem, sizeof(struct changer_element_status));
  894. if (NULL == ch_ces)
  895. errx(1, "can't allocate status storage");
  896. ces = ch_ces;
  897. /* Read in the changer slots */
  898. if (cp.cp_nslots > 0) {
  899. (void) memset(&cesr, 0, sizeof(cesr));
  900. cesr.cesr_element_type = CHET_ST;
  901. cesr.cesr_element_base = 0;
  902. cesr.cesr_element_count = cp.cp_nslots;
  903. cesr.cesr_flags |= CESR_VOLTAGS;
  904. cesr.cesr_element_status = ces;
  905. if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
  906. free(ch_ces);
  907. err(1, "%s: CHIOGSTATUS", changer_name);
  908. }
  909. ces += cp.cp_nslots;
  910. }
  911. /* Read in the drive information */
  912. if (cp.cp_ndrives > 0 ) {
  913. (void) memset(&cesr, 0, sizeof(cesr));
  914. cesr.cesr_element_type = CHET_DT;
  915. cesr.cesr_element_base = 0;
  916. cesr.cesr_element_count = cp.cp_ndrives;
  917. cesr.cesr_flags |= CESR_VOLTAGS;
  918. cesr.cesr_element_status = ces;
  919. if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
  920. free(ch_ces);
  921. err(1, "%s: CHIOGSTATUS", changer_name);
  922. }
  923. ces += cp.cp_ndrives;
  924. }
  925. /* Read in the portal information */
  926. if (cp.cp_nportals > 0 ) {
  927. (void) memset(&cesr, 0, sizeof(cesr));
  928. cesr.cesr_element_type = CHET_IE;
  929. cesr.cesr_element_base = 0;
  930. cesr.cesr_element_count = cp.cp_nportals;
  931. cesr.cesr_flags |= CESR_VOLTAGS;
  932. cesr.cesr_element_status = ces;
  933. if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
  934. free(ch_ces);
  935. err(1, "%s: CHIOGSTATUS", changer_name);
  936. }
  937. ces += cp.cp_nportals;
  938. }
  939. /* Read in the picker information */
  940. if (cp.cp_npickers > 0) {
  941. (void) memset(&cesr, 0, sizeof(cesr));
  942. cesr.cesr_element_type = CHET_MT;
  943. cesr.cesr_element_base = 0;
  944. cesr.cesr_element_count = cp.cp_npickers;
  945. cesr.cesr_flags |= CESR_VOLTAGS;
  946. cesr.cesr_element_status = ces;
  947. if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
  948. free(ch_ces);
  949. err(1, "%s: CHIOGSTATUS", changer_name);
  950. }
  951. }
  952. /*
  953. * Now search the list the specified <voltag>
  954. */
  955. for (elem = 0; elem <= total_elem; ++elem) {
  956. ces = &ch_ces[elem];
  957. /* Make sure we have a tape in this element */
  958. if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL))
  959. != (CES_STATUS_ACCESS|CES_STATUS_FULL))
  960. continue;
  961. /* Check to see if it is our target */
  962. if (strcasecmp(voltag,
  963. (const char *)ces->ces_pvoltag.cv_volid) == 0) {
  964. *et = ces->ces_type;
  965. *eu = ces->ces_addr;
  966. ++found;
  967. break;
  968. }
  969. }
  970. if (!found) {
  971. errx(1, "%s: unable to locate voltag: %s", changer_name,
  972. voltag);
  973. }
  974. free(ch_ces);
  975. return;
  976. }
  977. static void
  978. cleanup(void)
  979. {
  980. /* Simple enough... */
  981. (void)close(changer_fd);
  982. }
  983. static void
  984. usage(void)
  985. {
  986. (void)fprintf(stderr, "usage: %s [-f changer] command [-<flags>] "
  987. "arg1 arg2 [arg3 [...]]\n", getprogname());
  988. exit(1);
  989. }