]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libmt/mtlib.c
capsicum: introduce cap_rights_is_empty Function
[FreeBSD/FreeBSD.git] / lib / libmt / mtlib.c
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 }