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