1 /*-
2 * Copyright (c) 2013, 2014, 2015 Spectra Logic Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * substantially similar to the "NO WARRANTY" disclaimer below
13 * ("Disclaimer") and any redistribution must be conditioned upon
14 * including a substantially similar Disclaimer requirement for further
15 * binary redistribution.
16 *
17 * NO WARRANTY
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGES.
29 *
30 * Authors: Ken Merry (Spectra Logic Corporation)
31 */
32
33 #include <sys/cdefs.h>
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/mtio.h>
37 #include <sys/queue.h>
38 #include <sys/sbuf.h>
39
40 #include <ctype.h>
41 #include <err.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <stdint.h>
48 #include <errno.h>
49 #include <bsdxml.h>
50 #include <mtlib.h>
51
52 /*
53 * Called at the start of each XML element, and includes the list of
54 * attributes for the element.
55 */
56 void
mt_start_element(void * user_data,const char * name,const char ** attr)57 mt_start_element(void *user_data, const char *name, const char **attr)
58 {
59 int i;
60 struct mt_status_data *mtinfo;
61 struct mt_status_entry *entry;
62
63 mtinfo = (struct mt_status_data *)user_data;
64
65 if (mtinfo->error != 0)
66 return;
67
68 mtinfo->level++;
69 if ((u_int)mtinfo->level >= (sizeof(mtinfo->cur_sb) /
70 sizeof(mtinfo->cur_sb[0]))) {
71 mtinfo->error = 1;
72 snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
73 "%s: too many nesting levels, %zd max", __func__,
74 sizeof(mtinfo->cur_sb) / sizeof(mtinfo->cur_sb[0]));
75 return;
76 }
77
78 mtinfo->cur_sb[mtinfo->level] = sbuf_new_auto();
79 if (mtinfo->cur_sb[mtinfo->level] == NULL) {
80 mtinfo->error = 1;
81 snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
82 "%s: Unable to allocate sbuf", __func__);
83 return;
84 }
85
86 entry = malloc(sizeof(*entry));
87 if (entry == NULL) {
88 mtinfo->error = 1;
89 snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
90 "%s: unable to allocate %zd bytes", __func__,
91 sizeof(*entry));
92 return;
93 }
94 bzero(entry, sizeof(*entry));
95 STAILQ_INIT(&entry->nv_list);
96 STAILQ_INIT(&entry->child_entries);
97 entry->entry_name = strdup(name);
98 mtinfo->cur_entry[mtinfo->level] = entry;
99 if (mtinfo->cur_entry[mtinfo->level - 1] == NULL) {
100 STAILQ_INSERT_TAIL(&mtinfo->entries, entry, links);
101 } else {
102 STAILQ_INSERT_TAIL(
103 &mtinfo->cur_entry[mtinfo->level - 1]->child_entries,
104 entry, links);
105 entry->parent = mtinfo->cur_entry[mtinfo->level - 1];
106 }
107 for (i = 0; attr[i] != NULL; i+=2) {
108 struct mt_status_nv *nv;
109 int need_nv;
110
111 need_nv = 0;
112
113 if (strcmp(attr[i], "size") == 0) {
114 entry->size = strtoull(attr[i+1], NULL, 0);
115 } else if (strcmp(attr[i], "type") == 0) {
116 if (strcmp(attr[i+1], "int") == 0) {
117 entry->var_type = MT_TYPE_INT;
118 } else if (strcmp(attr[i+1], "uint") == 0) {
119 entry->var_type = MT_TYPE_UINT;
120 } else if (strcmp(attr[i+1], "str") == 0) {
121 entry->var_type = MT_TYPE_STRING;
122 } else if (strcmp(attr[i+1], "node") == 0) {
123 entry->var_type = MT_TYPE_NODE;
124 } else {
125 need_nv = 1;
126 }
127 } else if (strcmp(attr[i], "fmt") == 0) {
128 entry->fmt = strdup(attr[i+1]);
129 } else if (strcmp(attr[i], "desc") == 0) {
130 entry->desc = strdup(attr[i+1]);
131 } else {
132 need_nv = 1;
133 }
134 if (need_nv != 0) {
135 nv = malloc(sizeof(*nv));
136 if (nv == NULL) {
137 mtinfo->error = 1;
138 snprintf(mtinfo->error_str,
139 sizeof(mtinfo->error_str),
140 "%s: error allocating %zd bytes",
141 __func__, sizeof(*nv));
142 }
143 bzero(nv, sizeof(*nv));
144 nv->name = strdup(attr[i]);
145 nv->value = strdup(attr[i+1]);
146 STAILQ_INSERT_TAIL(&entry->nv_list, nv, links);
147 }
148 }
149 }
150
151 /*
152 * Called on XML element close.
153 */
154 void
mt_end_element(void * user_data,const char * name)155 mt_end_element(void *user_data, const char *name)
156 {
157 struct mt_status_data *mtinfo;
158 char *str;
159
160 mtinfo = (struct mt_status_data *)user_data;
161
162 if (mtinfo->error != 0)
163 return;
164
165 if (mtinfo->cur_sb[mtinfo->level] == NULL) {
166 mtinfo->error = 1;
167 snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
168 "%s: no valid sbuf at level %d (name %s)", __func__,
169 mtinfo->level, name);
170 return;
171 }
172 sbuf_finish(mtinfo->cur_sb[mtinfo->level]);
173 str = strdup(sbuf_data(mtinfo->cur_sb[mtinfo->level]));
174 if (str == NULL) {
175 mtinfo->error = 1;
176 snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
177 "%s can't allocate %zd bytes for string", __func__,
178 sbuf_len(mtinfo->cur_sb[mtinfo->level]));
179 return;
180 }
181
182 if (strlen(str) == 0) {
183 free(str);
184 str = NULL;
185 }
186 if (str != NULL) {
187 struct mt_status_entry *entry;
188
189 entry = mtinfo->cur_entry[mtinfo->level];
190 switch(entry->var_type) {
191 case MT_TYPE_INT:
192 entry->value_signed = strtoll(str, NULL, 0);
193 break;
194 case MT_TYPE_UINT:
195 entry->value_unsigned = strtoull(str, NULL, 0);
196 break;
197 default:
198 break;
199 }
200 }
201
202 mtinfo->cur_entry[mtinfo->level]->value = str;
203
204 sbuf_delete(mtinfo->cur_sb[mtinfo->level]);
205 mtinfo->cur_sb[mtinfo->level] = NULL;
206 mtinfo->cur_entry[mtinfo->level] = NULL;
207 mtinfo->level--;
208 }
209
210 /*
211 * Called to handle character strings in the current element.
212 */
213 void
mt_char_handler(void * user_data,const XML_Char * str,int len)214 mt_char_handler(void *user_data, const XML_Char *str, int len)
215 {
216 struct mt_status_data *mtinfo;
217
218 mtinfo = (struct mt_status_data *)user_data;
219 if (mtinfo->error != 0)
220 return;
221
222 sbuf_bcat(mtinfo->cur_sb[mtinfo->level], str, len);
223 }
224
225 void
mt_status_tree_sbuf(struct sbuf * sb,struct mt_status_entry * entry,int indent,void (* sbuf_func)(struct sbuf * sb,struct mt_status_entry * entry,void * arg),void * arg)226 mt_status_tree_sbuf(struct sbuf *sb, struct mt_status_entry *entry, int indent,
227 void (*sbuf_func)(struct sbuf *sb, struct mt_status_entry *entry,
228 void *arg), void *arg)
229 {
230 struct mt_status_nv *nv;
231 struct mt_status_entry *entry2;
232
233 if (sbuf_func != NULL) {
234 sbuf_func(sb, entry, arg);
235 } else {
236 sbuf_printf(sb, "%*sname: %s, value: %s, fmt: %s, size: %zd, "
237 "type: %d, desc: %s\n", indent, "", entry->entry_name,
238 entry->value, entry->fmt, entry->size, entry->var_type,
239 entry->desc);
240 STAILQ_FOREACH(nv, &entry->nv_list, links) {
241 sbuf_printf(sb, "%*snv: name: %s, value: %s\n",
242 indent + 1, "", nv->name, nv->value);
243 }
244 }
245
246 STAILQ_FOREACH(entry2, &entry->child_entries, links)
247 mt_status_tree_sbuf(sb, entry2, indent + 2, sbuf_func, arg);
248 }
249
250 void
mt_status_tree_print(struct mt_status_entry * entry,int indent,void (* print_func)(struct mt_status_entry * entry,void * arg),void * arg)251 mt_status_tree_print(struct mt_status_entry *entry, int indent,
252 void (*print_func)(struct mt_status_entry *entry, void *arg), void *arg)
253 {
254
255 if (print_func != NULL) {
256 struct mt_status_entry *entry2;
257
258 print_func(entry, arg);
259 STAILQ_FOREACH(entry2, &entry->child_entries, links)
260 mt_status_tree_print(entry2, indent + 2, print_func,
261 arg);
262 } else {
263 struct sbuf *sb;
264
265 sb = sbuf_new_auto();
266 if (sb == NULL)
267 return;
268 mt_status_tree_sbuf(sb, entry, indent, NULL, NULL);
269 sbuf_finish(sb);
270
271 printf("%s", sbuf_data(sb));
272 sbuf_delete(sb);
273 }
274 }
275
276 /*
277 * Given a parameter name in the form "foo" or "foo.bar.baz", traverse the
278 * tree looking for the parameter (the first case) or series of parameters
279 * (second case).
280 */
281 struct mt_status_entry *
mt_entry_find(struct mt_status_entry * entry,char * name)282 mt_entry_find(struct mt_status_entry *entry, char *name)
283 {
284 struct mt_status_entry *entry2;
285 char *tmpname = NULL, *tmpname2 = NULL, *tmpstr = NULL;
286
287 tmpname = strdup(name);
288 if (tmpname == NULL)
289 goto bailout;
290
291 /* Save a pointer so we can free this later */
292 tmpname2 = tmpname;
293
294 tmpstr = strsep(&tmpname, ".");
295
296 /*
297 * Is this the entry we're looking for? Or do we have further
298 * child entries that we need to grab?
299 */
300 if (strcmp(entry->entry_name, tmpstr) == 0) {
301 if (tmpname == NULL) {
302 /*
303 * There are no further child entries to find. We
304 * have a complete match.
305 */
306 free(tmpname2);
307 return (entry);
308 } else {
309 /*
310 * There are more child entries that we need to find.
311 * Fall through to the recursive search off of this
312 * entry, below. Use tmpname, which will contain
313 * everything after the first period.
314 */
315 name = tmpname;
316 }
317 }
318
319 /*
320 * Recursively look for further entries.
321 */
322 STAILQ_FOREACH(entry2, &entry->child_entries, links) {
323 struct mt_status_entry *entry3;
324
325 entry3 = mt_entry_find(entry2, name);
326 if (entry3 != NULL) {
327 free(tmpname2);
328 return (entry3);
329 }
330 }
331
332 bailout:
333 free(tmpname2);
334
335 return (NULL);
336 }
337
338 struct mt_status_entry *
mt_status_entry_find(struct mt_status_data * status_data,char * name)339 mt_status_entry_find(struct mt_status_data *status_data, char *name)
340 {
341 struct mt_status_entry *entry, *entry2;
342
343 STAILQ_FOREACH(entry, &status_data->entries, links) {
344 entry2 = mt_entry_find(entry, name);
345 if (entry2 != NULL)
346 return (entry2);
347 }
348
349 return (NULL);
350 }
351
352 void
mt_status_entry_free(struct mt_status_entry * entry)353 mt_status_entry_free(struct mt_status_entry *entry)
354 {
355 struct mt_status_entry *entry2, *entry3;
356 struct mt_status_nv *nv, *nv2;
357
358 STAILQ_FOREACH_SAFE(entry2, &entry->child_entries, links, entry3) {
359 STAILQ_REMOVE(&entry->child_entries, entry2, mt_status_entry,
360 links);
361 mt_status_entry_free(entry2);
362 }
363
364 free(entry->entry_name);
365 free(entry->value);
366 free(entry->fmt);
367 free(entry->desc);
368
369 STAILQ_FOREACH_SAFE(nv, &entry->nv_list, links, nv2) {
370 STAILQ_REMOVE(&entry->nv_list, nv, mt_status_nv, links);
371 free(nv->name);
372 free(nv->value);
373 free(nv);
374 }
375 free(entry);
376 }
377
378 void
mt_status_free(struct mt_status_data * status_data)379 mt_status_free(struct mt_status_data *status_data)
380 {
381 struct mt_status_entry *entry, *entry2;
382
383 STAILQ_FOREACH_SAFE(entry, &status_data->entries, links, entry2) {
384 STAILQ_REMOVE(&status_data->entries, entry, mt_status_entry,
385 links);
386 mt_status_entry_free(entry);
387 }
388 }
389
390 void
mt_entry_sbuf(struct sbuf * sb,struct mt_status_entry * entry,char * fmt)391 mt_entry_sbuf(struct sbuf *sb, struct mt_status_entry *entry, char *fmt)
392 {
393 switch(entry->var_type) {
394 case MT_TYPE_INT:
395 if (fmt != NULL)
396 sbuf_printf(sb, fmt, (intmax_t)entry->value_signed);
397 else
398 sbuf_printf(sb, "%jd",
399 (intmax_t)entry->value_signed);
400 break;
401 case MT_TYPE_UINT:
402 if (fmt != NULL)
403 sbuf_printf(sb, fmt, (uintmax_t)entry->value_unsigned);
404 else
405 sbuf_printf(sb, "%ju",
406 (uintmax_t)entry->value_unsigned);
407 break;
408 default:
409 if (fmt != NULL)
410 sbuf_printf(sb, fmt, entry->value);
411 else
412 sbuf_printf(sb, "%s", entry->value);
413 break;
414 }
415 }
416
417 void
mt_param_parent_print(struct mt_status_entry * entry,struct mt_print_params * print_params)418 mt_param_parent_print(struct mt_status_entry *entry,
419 struct mt_print_params *print_params)
420 {
421 if (entry->parent != NULL)
422 mt_param_parent_print(entry->parent, print_params);
423
424 if (((print_params->flags & MT_PF_INCLUDE_ROOT) == 0)
425 && (strcmp(entry->entry_name, print_params->root_name) == 0))
426 return;
427
428 printf("%s.", entry->entry_name);
429 }
430
431 void
mt_param_parent_sbuf(struct sbuf * sb,struct mt_status_entry * entry,struct mt_print_params * print_params)432 mt_param_parent_sbuf(struct sbuf *sb, struct mt_status_entry *entry,
433 struct mt_print_params *print_params)
434 {
435 if (entry->parent != NULL)
436 mt_param_parent_sbuf(sb, entry->parent, print_params);
437
438 if (((print_params->flags & MT_PF_INCLUDE_ROOT) == 0)
439 && (strcmp(entry->entry_name, print_params->root_name) == 0))
440 return;
441
442 sbuf_printf(sb, "%s.", entry->entry_name);
443 }
444
445 void
mt_param_entry_sbuf(struct sbuf * sb,struct mt_status_entry * entry,void * arg)446 mt_param_entry_sbuf(struct sbuf *sb, struct mt_status_entry *entry, void *arg)
447 {
448 struct mt_print_params *print_params;
449
450 print_params = (struct mt_print_params *)arg;
451
452 /*
453 * We don't want to print nodes.
454 */
455 if (entry->var_type == MT_TYPE_NODE)
456 return;
457
458 if ((print_params->flags & MT_PF_FULL_PATH)
459 && (entry->parent != NULL))
460 mt_param_parent_sbuf(sb, entry->parent, print_params);
461
462 sbuf_printf(sb, "%s: %s", entry->entry_name, entry->value);
463 if ((print_params->flags & MT_PF_VERBOSE)
464 && (entry->desc != NULL)
465 && (strlen(entry->desc) > 0))
466 sbuf_printf(sb, " (%s)", entry->desc);
467 sbuf_printf(sb, "\n");
468
469 }
470
471 void
mt_param_entry_print(struct mt_status_entry * entry,void * arg)472 mt_param_entry_print(struct mt_status_entry *entry, void *arg)
473 {
474 struct mt_print_params *print_params;
475
476 print_params = (struct mt_print_params *)arg;
477
478 /*
479 * We don't want to print nodes.
480 */
481 if (entry->var_type == MT_TYPE_NODE)
482 return;
483
484 if ((print_params->flags & MT_PF_FULL_PATH)
485 && (entry->parent != NULL))
486 mt_param_parent_print(entry->parent, print_params);
487
488 printf("%s: %s", entry->entry_name, entry->value);
489 if ((print_params->flags & MT_PF_VERBOSE)
490 && (entry->desc != NULL)
491 && (strlen(entry->desc) > 0))
492 printf(" (%s)", entry->desc);
493 printf("\n");
494 }
495
496 int
mt_protect_print(struct mt_status_data * status_data,int verbose)497 mt_protect_print(struct mt_status_data *status_data, int verbose)
498 {
499 struct mt_status_entry *entry;
500 const char *prot_name = MT_PROTECTION_NAME;
501 struct mt_print_params print_params;
502
503 snprintf(print_params.root_name, sizeof(print_params.root_name),
504 MT_PARAM_ROOT_NAME);
505 print_params.flags = MT_PF_FULL_PATH;
506 if (verbose != 0)
507 print_params.flags |= MT_PF_VERBOSE;
508
509 entry = mt_status_entry_find(status_data, __DECONST(char *,prot_name));
510 if (entry == NULL)
511 return (1);
512 mt_status_tree_print(entry, 0, mt_param_entry_print, &print_params);
513
514 return (0);
515 }
516
517 int
mt_param_list(struct mt_status_data * status_data,char * param_name,int quiet)518 mt_param_list(struct mt_status_data *status_data, char *param_name, int quiet)
519 {
520 struct mt_status_entry *entry;
521 struct mt_print_params print_params;
522 char root_name[20];
523
524 snprintf(root_name, sizeof(root_name), "mtparamget");
525 strlcpy(print_params.root_name, root_name,
526 sizeof(print_params.root_name));
527
528 print_params.flags = MT_PF_FULL_PATH;
529 if (quiet == 0)
530 print_params.flags |= MT_PF_VERBOSE;
531
532 if (param_name != NULL) {
533 entry = mt_status_entry_find(status_data, param_name);
534 if (entry == NULL)
535 return (1);
536
537 mt_param_entry_print(entry, &print_params);
538
539 return (0);
540 } else {
541 entry = mt_status_entry_find(status_data, root_name);
542
543 STAILQ_FOREACH(entry, &status_data->entries, links)
544 mt_status_tree_print(entry, 0, mt_param_entry_print,
545 &print_params);
546 }
547
548 return (0);
549 }
550
551 static struct densities {
552 int dens;
553 int bpmm;
554 int bpi;
555 const char *name;
556 } dens[] = {
557 /*
558 * Taken from T10 Project 997D
559 * SCSI-3 Stream Device Commands (SSC)
560 * Revision 11, 4-Nov-97
561 *
562 * LTO 1-6 definitions obtained from the eighth edition of the
563 * IBM TotalStorage LTO Ultrium Tape Drive SCSI Reference
564 * (July 2007) and the second edition of the IBM System Storage LTO
565 * Tape Drive SCSI Reference (February 13, 2013).
566 *
567 * IBM 3592 definitions obtained from second edition of the IBM
568 * System Storage Tape Drive 3592 SCSI Reference (May 25, 2012).
569 *
570 * DAT-72 and DAT-160 bpi values taken from "HP StorageWorks DAT160
571 * tape drive white paper", dated June 2007.
572 *
573 * DAT-160 / SDLT220 density code (0x48) conflict information
574 * found here:
575 *
576 * http://h20564.www2.hp.com/hpsc/doc/public/display?docId=emr_na-c01065117&sp4ts.oid=429311
577 * (Document ID c01065117)
578 */
579 /*Num. bpmm bpi Reference */
580 { 0x1, 32, 800, "X3.22-1983" },
581 { 0x2, 63, 1600, "X3.39-1986" },
582 { 0x3, 246, 6250, "X3.54-1986" },
583 { 0x5, 315, 8000, "X3.136-1986" },
584 { 0x6, 126, 3200, "X3.157-1987" },
585 { 0x7, 252, 6400, "X3.116-1986" },
586 { 0x8, 315, 8000, "X3.158-1987" },
587 { 0x9, 491, 37871, "X3.180" },
588 { 0xA, 262, 6667, "X3B5/86-199" },
589 { 0xB, 63, 1600, "X3.56-1986" },
590 { 0xC, 500, 12690, "HI-TC1" },
591 { 0xD, 999, 25380, "HI-TC2" },
592 { 0xF, 394, 10000, "QIC-120" },
593 { 0x10, 394, 10000, "QIC-150" },
594 { 0x11, 630, 16000, "QIC-320" },
595 { 0x12, 2034, 51667, "QIC-1350" },
596 { 0x13, 2400, 61000, "X3B5/88-185A" },
597 { 0x14, 1703, 43245, "X3.202-1991" },
598 { 0x15, 1789, 45434, "ECMA TC17" },
599 { 0x16, 394, 10000, "X3.193-1990" },
600 { 0x17, 1673, 42500, "X3B5/91-174" },
601 { 0x18, 1673, 42500, "X3B5/92-50" },
602 { 0x19, 2460, 62500, "DLTapeIII" },
603 { 0x1A, 3214, 81633, "DLTapeIV(20GB)" },
604 { 0x1B, 3383, 85937, "DLTapeIV(35GB)" },
605 { 0x1C, 1654, 42000, "QIC-385M" },
606 { 0x1D, 1512, 38400, "QIC-410M" },
607 { 0x1E, 1385, 36000, "QIC-1000C" },
608 { 0x1F, 2666, 67733, "QIC-2100C" },
609 { 0x20, 2666, 67733, "QIC-6GB(M)" },
610 { 0x21, 2666, 67733, "QIC-20GB(C)" },
611 { 0x22, 1600, 40640, "QIC-2GB(C)" },
612 { 0x23, 2666, 67733, "QIC-875M" },
613 { 0x24, 2400, 61000, "DDS-2" },
614 { 0x25, 3816, 97000, "DDS-3" },
615 { 0x26, 3816, 97000, "DDS-4" },
616 { 0x27, 3056, 77611, "Mammoth" },
617 { 0x28, 1491, 37871, "X3.224" },
618 { 0x40, 4880, 123952, "LTO-1" },
619 { 0x41, 3868, 98250, "DLTapeIV(40GB)" },
620 { 0x42, 7398, 187909, "LTO-2" },
621 { 0x44, 9638, 244805, "LTO-3" },
622 { 0x46, 12725, 323215, "LTO-4" },
623 { 0x47, 6417, 163000, "DAT-72" },
624 /*
625 * XXX KDM note that 0x48 is also the density code for DAT-160.
626 * For some reason they used overlapping density codes.
627 */
628 #if 0
629 { 0x48, 6870, 174500, "DAT-160" },
630 #endif
631 { 0x48, 5236, 133000, "SDLTapeI(110)" },
632 { 0x49, 7598, 193000, "SDLTapeI(160)" },
633 { 0x4a, 0, 0, "T10000A" },
634 { 0x4b, 0, 0, "T10000B" },
635 { 0x4c, 0, 0, "T10000C" },
636 { 0x4d, 0, 0, "T10000D" },
637 { 0x51, 11800, 299720, "3592A1 (unencrypted)" },
638 { 0x52, 11800, 299720, "3592A2 (unencrypted)" },
639 { 0x53, 13452, 341681, "3592A3 (unencrypted)" },
640 { 0x54, 19686, 500024, "3592A4 (unencrypted)" },
641 { 0x55, 20670, 525018, "3592A5 (unencrypted)" },
642 { 0x56, 20670, 525018, "3592B5 (unencrypted)" },
643 { 0x57, 21850, 554990, "3592A6 (unencrypted)" },
644 { 0x58, 15142, 384607, "LTO-5" },
645 { 0x59, 21850, 554990, "3592A7 (unencrypted)" },
646 { 0x5A, 15142, 384607, "LTO-6" },
647 { 0x5C, 19107, 485318, "LTO-7" },
648 { 0x5D, 19107, 485318, "LTO-M8" },
649 { 0x5E, 20669, 524993, "LTO-8" },
650 { 0x60, 23031, 584987, "LTO-9" },
651 { 0x71, 11800, 299720, "3592A1 (encrypted)" },
652 { 0x72, 11800, 299720, "3592A2 (encrypted)" },
653 { 0x73, 13452, 341681, "3592A3 (encrypted)" },
654 { 0x74, 19686, 500024, "3592A4 (encrypted)" },
655 { 0x75, 20670, 525018, "3592A5 (encrypted)" },
656 { 0x76, 20670, 525018, "3592B5 (encrypted)" },
657 { 0x77, 21850, 554990, "3592A6 (encrypted)" },
658 { 0x79, 21850, 554990, "3592A7 (encrypted)" },
659 { 0x8c, 1789, 45434, "EXB-8500c" },
660 { 0x90, 1703, 43245, "EXB-8200c" },
661 { 0, 0, 0, NULL }
662 };
663
664 const char *
mt_density_name(int density_num)665 mt_density_name(int density_num)
666 {
667 struct densities *sd;
668
669 /* densities 0 and 0x7f are handled as special cases */
670 if (density_num == 0)
671 return ("default");
672 if (density_num == 0x7f)
673 return ("same");
674
675 for (sd = dens; sd->dens != 0; sd++)
676 if (sd->dens == density_num)
677 break;
678 if (sd->dens == 0)
679 return ("UNKNOWN");
680 return (sd->name);
681 }
682
683 /*
684 * Given a specific density number, return either the bits per inch or bits
685 * per millimeter for the given density.
686 */
687 int
mt_density_bp(int density_num,int bpi)688 mt_density_bp(int density_num, int bpi)
689 {
690 struct densities *sd;
691
692 for (sd = dens; sd->dens; sd++)
693 if (sd->dens == density_num)
694 break;
695 if (sd->dens == 0)
696 return (0);
697 if (bpi)
698 return (sd->bpi);
699 else
700 return (sd->bpmm);
701 }
702
703 int
mt_density_num(const char * density_name)704 mt_density_num(const char *density_name)
705 {
706 struct densities *sd;
707 size_t l = strlen(density_name);
708
709 for (sd = dens; sd->dens; sd++)
710 if (strncasecmp(sd->name, density_name, l) == 0)
711 break;
712 return (sd->dens);
713 }
714
715 /*
716 * Get the current status XML string.
717 * Returns 0 on success, -1 on failure (with errno set, and *xml_str == NULL).
718 */
719 int
mt_get_xml_str(int mtfd,unsigned long cmd,char ** xml_str)720 mt_get_xml_str(int mtfd, unsigned long cmd, char **xml_str)
721 {
722 size_t alloc_len = 32768;
723 struct mtextget extget;
724 int error;
725
726 *xml_str = NULL;
727
728 for (;;) {
729 bzero(&extget, sizeof(extget));
730 *xml_str = malloc(alloc_len);
731 if (*xml_str == NULL)
732 return (-1);
733 extget.status_xml = *xml_str;
734 extget.alloc_len = alloc_len;
735
736 error = ioctl(mtfd, cmd, (caddr_t)&extget);
737 if (error == 0 && extget.status == MT_EXT_GET_OK)
738 break;
739
740 free(*xml_str);
741 *xml_str = NULL;
742
743 if (error != 0 || extget.status != MT_EXT_GET_NEED_MORE_SPACE)
744 return (-1);
745
746 /* The driver needs more space, so double and try again. */
747 alloc_len *= 2;
748 }
749 return (0);
750 }
751
752 /*
753 * Populate a struct mt_status_data from the XML string via mt_get_xml_str().
754 *
755 * Returns XML_STATUS_OK on success.
756 * If XML_STATUS_ERROR is returned, errno may be set to indicate the reason.
757 * The caller must check status_data->error.
758 */
759 int
mt_get_status(char * xml_str,struct mt_status_data * status_data)760 mt_get_status(char *xml_str, struct mt_status_data *status_data)
761 {
762 XML_Parser parser;
763 int retval;
764
765 bzero(status_data, sizeof(*status_data));
766 STAILQ_INIT(&status_data->entries);
767
768 parser = XML_ParserCreate(NULL);
769 if (parser == NULL) {
770 errno = ENOMEM;
771 return (XML_STATUS_ERROR);
772 }
773
774 XML_SetUserData(parser, status_data);
775 XML_SetElementHandler(parser, mt_start_element, mt_end_element);
776 XML_SetCharacterDataHandler(parser, mt_char_handler);
777
778 retval = XML_Parse(parser, xml_str, strlen(xml_str), 1);
779 XML_ParserFree(parser);
780 return (retval);
781 }
782