Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libmt/mtlib.c
41140 views
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
782