1279219Sken/*- 2279219Sken * Copyright (c) 2013, 2014, 2015 Spectra Logic Corporation 3279219Sken * All rights reserved. 4279219Sken * 5279219Sken * Redistribution and use in source and binary forms, with or without 6279219Sken * modification, are permitted provided that the following conditions 7279219Sken * are met: 8279219Sken * 1. Redistributions of source code must retain the above copyright 9279219Sken * notice, this list of conditions, and the following disclaimer, 10279219Sken * without modification. 11279219Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12279219Sken * substantially similar to the "NO WARRANTY" disclaimer below 13279219Sken * ("Disclaimer") and any redistribution must be conditioned upon 14279219Sken * including a substantially similar Disclaimer requirement for further 15279219Sken * binary redistribution. 16279219Sken * 17279219Sken * NO WARRANTY 18279219Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19279219Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20279219Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21279219Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22279219Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23279219Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24279219Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25279219Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26279219Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27279219Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28279219Sken * POSSIBILITY OF SUCH DAMAGES. 29279219Sken * 30279219Sken * Authors: Ken Merry (Spectra Logic Corporation) 31279219Sken */ 32279219Sken 33279219Sken#include <sys/cdefs.h> 34279219Sken__FBSDID("$FreeBSD: stable/11/lib/libmt/mtlib.c 368675 2020-12-15 20:02:40Z ken $"); 35279219Sken 36279219Sken#include <sys/types.h> 37279219Sken#include <sys/ioctl.h> 38279219Sken#include <sys/mtio.h> 39279219Sken#include <sys/queue.h> 40279219Sken#include <sys/sbuf.h> 41279219Sken 42279219Sken#include <ctype.h> 43279219Sken#include <err.h> 44279219Sken#include <fcntl.h> 45279219Sken#include <stdio.h> 46279219Sken#include <stdlib.h> 47279219Sken#include <string.h> 48279219Sken#include <unistd.h> 49279219Sken#include <stdint.h> 50279219Sken#include <errno.h> 51279219Sken#include <bsdxml.h> 52279219Sken#include <mtlib.h> 53279219Sken 54279219Sken/* 55279219Sken * Called at the start of each XML element, and includes the list of 56279219Sken * attributes for the element. 57279219Sken */ 58279219Skenvoid 59279219Skenmt_start_element(void *user_data, const char *name, const char **attr) 60279219Sken{ 61279219Sken int i; 62279219Sken struct mt_status_data *mtinfo; 63279219Sken struct mt_status_entry *entry; 64279219Sken 65279219Sken mtinfo = (struct mt_status_data *)user_data; 66279219Sken 67279219Sken if (mtinfo->error != 0) 68279219Sken return; 69279219Sken 70279219Sken mtinfo->level++; 71279261Sken if ((u_int)mtinfo->level >= (sizeof(mtinfo->cur_sb) / 72279219Sken sizeof(mtinfo->cur_sb[0]))) { 73279219Sken mtinfo->error = 1; 74279219Sken snprintf(mtinfo->error_str, sizeof(mtinfo->error_str), 75279219Sken "%s: too many nesting levels, %zd max", __func__, 76279219Sken sizeof(mtinfo->cur_sb) / sizeof(mtinfo->cur_sb[0])); 77279219Sken return; 78279219Sken } 79279219Sken 80279219Sken mtinfo->cur_sb[mtinfo->level] = sbuf_new_auto(); 81279219Sken if (mtinfo->cur_sb[mtinfo->level] == NULL) { 82279219Sken mtinfo->error = 1; 83279219Sken snprintf(mtinfo->error_str, sizeof(mtinfo->error_str), 84279219Sken "%s: Unable to allocate sbuf", __func__); 85279219Sken return; 86279219Sken } 87279219Sken 88279219Sken entry = malloc(sizeof(*entry)); 89279219Sken if (entry == NULL) { 90279219Sken mtinfo->error = 1; 91279219Sken snprintf(mtinfo->error_str, sizeof(mtinfo->error_str), 92279219Sken "%s: unable to allocate %zd bytes", __func__, 93279219Sken sizeof(*entry)); 94279219Sken return; 95279219Sken } 96279219Sken bzero(entry, sizeof(*entry)); 97279219Sken STAILQ_INIT(&entry->nv_list); 98279219Sken STAILQ_INIT(&entry->child_entries); 99279219Sken entry->entry_name = strdup(name); 100279219Sken mtinfo->cur_entry[mtinfo->level] = entry; 101279219Sken if (mtinfo->cur_entry[mtinfo->level - 1] == NULL) { 102279219Sken STAILQ_INSERT_TAIL(&mtinfo->entries, entry, links); 103279219Sken } else { 104279219Sken STAILQ_INSERT_TAIL( 105279219Sken &mtinfo->cur_entry[mtinfo->level - 1]->child_entries, 106279219Sken entry, links); 107279219Sken entry->parent = mtinfo->cur_entry[mtinfo->level - 1]; 108279219Sken } 109279219Sken for (i = 0; attr[i] != NULL; i+=2) { 110279219Sken struct mt_status_nv *nv; 111279219Sken int need_nv; 112279219Sken 113279219Sken need_nv = 0; 114279219Sken 115279219Sken if (strcmp(attr[i], "size") == 0) { 116279219Sken entry->size = strtoull(attr[i+1], NULL, 0); 117279219Sken } else if (strcmp(attr[i], "type") == 0) { 118279219Sken if (strcmp(attr[i+1], "int") == 0) { 119279219Sken entry->var_type = MT_TYPE_INT; 120279219Sken } else if (strcmp(attr[i+1], "uint") == 0) { 121279219Sken entry->var_type = MT_TYPE_UINT; 122279219Sken } else if (strcmp(attr[i+1], "str") == 0) { 123279219Sken entry->var_type = MT_TYPE_STRING; 124279219Sken } else if (strcmp(attr[i+1], "node") == 0) { 125279219Sken entry->var_type = MT_TYPE_NODE; 126279219Sken } else { 127279219Sken need_nv = 1; 128279219Sken } 129279219Sken } else if (strcmp(attr[i], "fmt") == 0) { 130279219Sken entry->fmt = strdup(attr[i+1]); 131279219Sken } else if (strcmp(attr[i], "desc") == 0) { 132279219Sken entry->desc = strdup(attr[i+1]); 133279219Sken } else { 134279219Sken need_nv = 1; 135279219Sken } 136279219Sken if (need_nv != 0) { 137279219Sken nv = malloc(sizeof(*nv)); 138279219Sken if (nv == NULL) { 139279219Sken mtinfo->error = 1; 140279219Sken snprintf(mtinfo->error_str, 141279219Sken sizeof(mtinfo->error_str), 142279219Sken "%s: error allocating %zd bytes", 143279219Sken __func__, sizeof(*nv)); 144279219Sken } 145279219Sken bzero(nv, sizeof(*nv)); 146279219Sken nv->name = strdup(attr[i]); 147279219Sken nv->value = strdup(attr[i+1]); 148279219Sken STAILQ_INSERT_TAIL(&entry->nv_list, nv, links); 149279219Sken } 150279219Sken } 151279219Sken} 152279219Sken 153279219Sken/* 154279219Sken * Called on XML element close. 155279219Sken */ 156279219Skenvoid 157279219Skenmt_end_element(void *user_data, const char *name) 158279219Sken{ 159279219Sken struct mt_status_data *mtinfo; 160279219Sken char *str; 161279219Sken 162279219Sken mtinfo = (struct mt_status_data *)user_data; 163279219Sken 164279219Sken if (mtinfo->error != 0) 165279219Sken return; 166279219Sken 167279219Sken if (mtinfo->cur_sb[mtinfo->level] == NULL) { 168279219Sken mtinfo->error = 1; 169279219Sken snprintf(mtinfo->error_str, sizeof(mtinfo->error_str), 170279219Sken "%s: no valid sbuf at level %d (name %s)", __func__, 171279219Sken mtinfo->level, name); 172279219Sken return; 173279219Sken } 174279219Sken sbuf_finish(mtinfo->cur_sb[mtinfo->level]); 175279219Sken str = strdup(sbuf_data(mtinfo->cur_sb[mtinfo->level])); 176279219Sken if (str == NULL) { 177279219Sken mtinfo->error = 1; 178279219Sken snprintf(mtinfo->error_str, sizeof(mtinfo->error_str), 179279219Sken "%s can't allocate %zd bytes for string", __func__, 180279219Sken sbuf_len(mtinfo->cur_sb[mtinfo->level])); 181279219Sken return; 182279219Sken } 183279219Sken 184279219Sken if (strlen(str) == 0) { 185279219Sken free(str); 186279219Sken str = NULL; 187279219Sken } 188279219Sken if (str != NULL) { 189279219Sken struct mt_status_entry *entry; 190279219Sken 191279219Sken entry = mtinfo->cur_entry[mtinfo->level]; 192279219Sken switch(entry->var_type) { 193279219Sken case MT_TYPE_INT: 194279219Sken entry->value_signed = strtoll(str, NULL, 0); 195279219Sken break; 196279219Sken case MT_TYPE_UINT: 197279219Sken entry->value_unsigned = strtoull(str, NULL, 0); 198279219Sken break; 199279219Sken default: 200279219Sken break; 201279219Sken } 202279219Sken } 203279219Sken 204279219Sken mtinfo->cur_entry[mtinfo->level]->value = str; 205279219Sken 206279219Sken sbuf_delete(mtinfo->cur_sb[mtinfo->level]); 207279219Sken mtinfo->cur_sb[mtinfo->level] = NULL; 208279219Sken mtinfo->cur_entry[mtinfo->level] = NULL; 209279219Sken mtinfo->level--; 210279219Sken} 211279219Sken 212279219Sken/* 213279219Sken * Called to handle character strings in the current element. 214279219Sken */ 215279219Skenvoid 216279219Skenmt_char_handler(void *user_data, const XML_Char *str, int len) 217279219Sken{ 218279219Sken struct mt_status_data *mtinfo; 219279219Sken 220279219Sken mtinfo = (struct mt_status_data *)user_data; 221279219Sken if (mtinfo->error != 0) 222279219Sken return; 223279219Sken 224279219Sken sbuf_bcat(mtinfo->cur_sb[mtinfo->level], str, len); 225279219Sken} 226279219Sken 227279219Skenvoid 228279219Skenmt_status_tree_sbuf(struct sbuf *sb, struct mt_status_entry *entry, int indent, 229279219Sken void (*sbuf_func)(struct sbuf *sb, struct mt_status_entry *entry, 230279219Sken void *arg), void *arg) 231279219Sken{ 232279219Sken struct mt_status_nv *nv; 233279219Sken struct mt_status_entry *entry2; 234279219Sken 235279219Sken if (sbuf_func != NULL) { 236279219Sken sbuf_func(sb, entry, arg); 237279219Sken } else { 238279219Sken sbuf_printf(sb, "%*sname: %s, value: %s, fmt: %s, size: %zd, " 239279219Sken "type: %d, desc: %s\n", indent, "", entry->entry_name, 240279219Sken entry->value, entry->fmt, entry->size, entry->var_type, 241279219Sken entry->desc); 242279219Sken STAILQ_FOREACH(nv, &entry->nv_list, links) { 243279219Sken sbuf_printf(sb, "%*snv: name: %s, value: %s\n", 244279219Sken indent + 1, "", nv->name, nv->value); 245279219Sken } 246279219Sken } 247279219Sken 248279219Sken STAILQ_FOREACH(entry2, &entry->child_entries, links) 249279219Sken mt_status_tree_sbuf(sb, entry2, indent + 2, sbuf_func, arg); 250279219Sken} 251279219Sken 252279219Skenvoid 253279219Skenmt_status_tree_print(struct mt_status_entry *entry, int indent, 254279219Sken void (*print_func)(struct mt_status_entry *entry, void *arg), void *arg) 255279219Sken{ 256279219Sken 257279219Sken if (print_func != NULL) { 258279219Sken struct mt_status_entry *entry2; 259279219Sken 260279219Sken print_func(entry, arg); 261279219Sken STAILQ_FOREACH(entry2, &entry->child_entries, links) 262279219Sken mt_status_tree_print(entry2, indent + 2, print_func, 263279219Sken arg); 264279219Sken } else { 265279219Sken struct sbuf *sb; 266279219Sken 267279219Sken sb = sbuf_new_auto(); 268279219Sken if (sb == NULL) 269279219Sken return; 270279219Sken mt_status_tree_sbuf(sb, entry, indent, NULL, NULL); 271279219Sken sbuf_finish(sb); 272279219Sken 273279219Sken printf("%s", sbuf_data(sb)); 274279219Sken sbuf_delete(sb); 275279219Sken } 276279219Sken} 277279219Sken 278279219Sken/* 279279219Sken * Given a parameter name in the form "foo" or "foo.bar.baz", traverse the 280279219Sken * tree looking for the parameter (the first case) or series of parameters 281279219Sken * (second case). 282279219Sken */ 283279219Skenstruct mt_status_entry * 284279219Skenmt_entry_find(struct mt_status_entry *entry, char *name) 285279219Sken{ 286279219Sken struct mt_status_entry *entry2; 287279219Sken char *tmpname = NULL, *tmpname2 = NULL, *tmpstr = NULL; 288279219Sken 289279219Sken tmpname = strdup(name); 290279219Sken if (tmpname == NULL) 291279219Sken goto bailout; 292279219Sken 293279219Sken /* Save a pointer so we can free this later */ 294279219Sken tmpname2 = tmpname; 295279219Sken 296279219Sken tmpstr = strsep(&tmpname, "."); 297279219Sken 298279219Sken /* 299279219Sken * Is this the entry we're looking for? Or do we have further 300279219Sken * child entries that we need to grab? 301279219Sken */ 302279219Sken if (strcmp(entry->entry_name, tmpstr) == 0) { 303279219Sken if (tmpname == NULL) { 304279219Sken /* 305279219Sken * There are no further child entries to find. We 306279219Sken * have a complete match. 307279219Sken */ 308279219Sken free(tmpname2); 309279219Sken return (entry); 310279219Sken } else { 311279219Sken /* 312279219Sken * There are more child entries that we need to find. 313279219Sken * Fall through to the recursive search off of this 314279219Sken * entry, below. Use tmpname, which will contain 315279219Sken * everything after the first period. 316279219Sken */ 317279219Sken name = tmpname; 318279219Sken } 319279219Sken } 320279219Sken 321279219Sken /* 322279219Sken * Recursively look for further entries. 323279219Sken */ 324279219Sken STAILQ_FOREACH(entry2, &entry->child_entries, links) { 325279219Sken struct mt_status_entry *entry3; 326279219Sken 327279219Sken entry3 = mt_entry_find(entry2, name); 328279219Sken if (entry3 != NULL) { 329279219Sken free(tmpname2); 330279219Sken return (entry3); 331279219Sken } 332279219Sken } 333279219Sken 334279219Skenbailout: 335279219Sken free(tmpname2); 336279219Sken 337279219Sken return (NULL); 338279219Sken} 339279219Sken 340279219Skenstruct mt_status_entry * 341279219Skenmt_status_entry_find(struct mt_status_data *status_data, char *name) 342279219Sken{ 343279219Sken struct mt_status_entry *entry, *entry2; 344279219Sken 345279219Sken STAILQ_FOREACH(entry, &status_data->entries, links) { 346279219Sken entry2 = mt_entry_find(entry, name); 347279219Sken if (entry2 != NULL) 348279219Sken return (entry2); 349279219Sken } 350279219Sken 351279219Sken return (NULL); 352279219Sken} 353279219Sken 354279219Skenvoid 355279219Skenmt_status_entry_free(struct mt_status_entry *entry) 356279219Sken{ 357279219Sken struct mt_status_entry *entry2, *entry3; 358279219Sken struct mt_status_nv *nv, *nv2; 359279219Sken 360279219Sken STAILQ_FOREACH_SAFE(entry2, &entry->child_entries, links, entry3) { 361279219Sken STAILQ_REMOVE(&entry->child_entries, entry2, mt_status_entry, 362279219Sken links); 363279219Sken mt_status_entry_free(entry2); 364279219Sken } 365279219Sken 366279219Sken free(entry->entry_name); 367279219Sken free(entry->value); 368279219Sken free(entry->fmt); 369279219Sken free(entry->desc); 370279219Sken 371279219Sken STAILQ_FOREACH_SAFE(nv, &entry->nv_list, links, nv2) { 372279219Sken STAILQ_REMOVE(&entry->nv_list, nv, mt_status_nv, links); 373279219Sken free(nv->name); 374279219Sken free(nv->value); 375279219Sken free(nv); 376279219Sken } 377279219Sken free(entry); 378279219Sken} 379279219Sken 380279219Skenvoid 381279219Skenmt_status_free(struct mt_status_data *status_data) 382279219Sken{ 383279219Sken struct mt_status_entry *entry, *entry2; 384279219Sken 385279219Sken STAILQ_FOREACH_SAFE(entry, &status_data->entries, links, entry2) { 386279219Sken STAILQ_REMOVE(&status_data->entries, entry, mt_status_entry, 387279219Sken links); 388279219Sken mt_status_entry_free(entry); 389279219Sken } 390279219Sken} 391279219Sken 392279219Skenvoid 393279219Skenmt_entry_sbuf(struct sbuf *sb, struct mt_status_entry *entry, char *fmt) 394279219Sken{ 395279219Sken switch(entry->var_type) { 396279219Sken case MT_TYPE_INT: 397279219Sken if (fmt != NULL) 398279219Sken sbuf_printf(sb, fmt, (intmax_t)entry->value_signed); 399279219Sken else 400279219Sken sbuf_printf(sb, "%jd", 401279219Sken (intmax_t)entry->value_signed); 402279219Sken break; 403279219Sken case MT_TYPE_UINT: 404279219Sken if (fmt != NULL) 405279219Sken sbuf_printf(sb, fmt, (uintmax_t)entry->value_unsigned); 406279219Sken else 407279219Sken sbuf_printf(sb, "%ju", 408279219Sken (uintmax_t)entry->value_unsigned); 409279219Sken break; 410279219Sken default: 411279219Sken if (fmt != NULL) 412279219Sken sbuf_printf(sb, fmt, entry->value); 413279219Sken else 414279219Sken sbuf_printf(sb, "%s", entry->value); 415279219Sken break; 416279219Sken } 417279219Sken} 418279219Sken 419279219Skenvoid 420279219Skenmt_param_parent_print(struct mt_status_entry *entry, 421279219Sken struct mt_print_params *print_params) 422279219Sken{ 423279219Sken if (entry->parent != NULL) 424279219Sken mt_param_parent_print(entry->parent, print_params); 425279219Sken 426279219Sken if (((print_params->flags & MT_PF_INCLUDE_ROOT) == 0) 427279219Sken && (strcmp(entry->entry_name, print_params->root_name) == 0)) 428279219Sken return; 429279219Sken 430279219Sken printf("%s.", entry->entry_name); 431279219Sken} 432279219Sken 433279219Skenvoid 434279219Skenmt_param_parent_sbuf(struct sbuf *sb, struct mt_status_entry *entry, 435279219Sken struct mt_print_params *print_params) 436279219Sken{ 437279219Sken if (entry->parent != NULL) 438279219Sken mt_param_parent_sbuf(sb, entry->parent, print_params); 439279219Sken 440279219Sken if (((print_params->flags & MT_PF_INCLUDE_ROOT) == 0) 441279219Sken && (strcmp(entry->entry_name, print_params->root_name) == 0)) 442279219Sken return; 443279219Sken 444279219Sken sbuf_printf(sb, "%s.", entry->entry_name); 445279219Sken} 446279219Sken 447279219Skenvoid 448279219Skenmt_param_entry_sbuf(struct sbuf *sb, struct mt_status_entry *entry, void *arg) 449279219Sken{ 450279219Sken struct mt_print_params *print_params; 451279219Sken 452279219Sken print_params = (struct mt_print_params *)arg; 453279219Sken 454279219Sken /* 455279219Sken * We don't want to print nodes. 456279219Sken */ 457279219Sken if (entry->var_type == MT_TYPE_NODE) 458279219Sken return; 459279219Sken 460279219Sken if ((print_params->flags & MT_PF_FULL_PATH) 461279219Sken && (entry->parent != NULL)) 462279219Sken mt_param_parent_sbuf(sb, entry->parent, print_params); 463279219Sken 464279219Sken sbuf_printf(sb, "%s: %s", entry->entry_name, entry->value); 465279219Sken if ((print_params->flags & MT_PF_VERBOSE) 466279219Sken && (entry->desc != NULL) 467279219Sken && (strlen(entry->desc) > 0)) 468279219Sken sbuf_printf(sb, " (%s)", entry->desc); 469279219Sken sbuf_printf(sb, "\n"); 470279219Sken 471279219Sken} 472279219Sken 473279219Skenvoid 474279219Skenmt_param_entry_print(struct mt_status_entry *entry, void *arg) 475279219Sken{ 476279219Sken struct mt_print_params *print_params; 477279219Sken 478279219Sken print_params = (struct mt_print_params *)arg; 479279219Sken 480279219Sken /* 481279219Sken * We don't want to print nodes. 482279219Sken */ 483279219Sken if (entry->var_type == MT_TYPE_NODE) 484279219Sken return; 485279219Sken 486279219Sken if ((print_params->flags & MT_PF_FULL_PATH) 487279219Sken && (entry->parent != NULL)) 488279219Sken mt_param_parent_print(entry->parent, print_params); 489279219Sken 490279219Sken printf("%s: %s", entry->entry_name, entry->value); 491279219Sken if ((print_params->flags & MT_PF_VERBOSE) 492279219Sken && (entry->desc != NULL) 493279219Sken && (strlen(entry->desc) > 0)) 494279219Sken printf(" (%s)", entry->desc); 495279219Sken printf("\n"); 496279219Sken} 497279219Sken 498279219Skenint 499279219Skenmt_protect_print(struct mt_status_data *status_data, int verbose) 500279219Sken{ 501279219Sken struct mt_status_entry *entry; 502279219Sken const char *prot_name = MT_PROTECTION_NAME; 503279219Sken struct mt_print_params print_params; 504279219Sken 505279219Sken snprintf(print_params.root_name, sizeof(print_params.root_name), 506279219Sken MT_PARAM_ROOT_NAME); 507279219Sken print_params.flags = MT_PF_FULL_PATH; 508279219Sken if (verbose != 0) 509279219Sken print_params.flags |= MT_PF_VERBOSE; 510279219Sken 511279219Sken entry = mt_status_entry_find(status_data, __DECONST(char *,prot_name)); 512279219Sken if (entry == NULL) 513279219Sken return (1); 514279219Sken mt_status_tree_print(entry, 0, mt_param_entry_print, &print_params); 515279219Sken 516279219Sken return (0); 517279219Sken} 518279219Sken 519279219Skenint 520279219Skenmt_param_list(struct mt_status_data *status_data, char *param_name, int quiet) 521279219Sken{ 522279219Sken struct mt_status_entry *entry; 523279219Sken struct mt_print_params print_params; 524279219Sken char root_name[20]; 525279219Sken 526279219Sken snprintf(root_name, sizeof(root_name), "mtparamget"); 527279219Sken strlcpy(print_params.root_name, root_name, 528279219Sken sizeof(print_params.root_name)); 529279219Sken 530279219Sken print_params.flags = MT_PF_FULL_PATH; 531279219Sken if (quiet == 0) 532279219Sken print_params.flags |= MT_PF_VERBOSE; 533279219Sken 534279219Sken if (param_name != NULL) { 535279219Sken entry = mt_status_entry_find(status_data, param_name); 536279219Sken if (entry == NULL) 537279219Sken return (1); 538279219Sken 539279219Sken mt_param_entry_print(entry, &print_params); 540279219Sken 541279219Sken return (0); 542279219Sken } else { 543279219Sken entry = mt_status_entry_find(status_data, root_name); 544279219Sken 545279219Sken STAILQ_FOREACH(entry, &status_data->entries, links) 546279219Sken mt_status_tree_print(entry, 0, mt_param_entry_print, 547279219Sken &print_params); 548279219Sken } 549279219Sken 550279219Sken return (0); 551279219Sken} 552279219Sken 553279219Skenstatic struct densities { 554279219Sken int dens; 555279219Sken int bpmm; 556279219Sken int bpi; 557279219Sken const char *name; 558279219Sken} dens[] = { 559279219Sken /* 560279219Sken * Taken from T10 Project 997D 561279219Sken * SCSI-3 Stream Device Commands (SSC) 562279219Sken * Revision 11, 4-Nov-97 563279219Sken * 564279219Sken * LTO 1-6 definitions obtained from the eighth edition of the 565279219Sken * IBM TotalStorage LTO Ultrium Tape Drive SCSI Reference 566279219Sken * (July 2007) and the second edition of the IBM System Storage LTO 567279219Sken * Tape Drive SCSI Reference (February 13, 2013). 568279219Sken * 569279219Sken * IBM 3592 definitions obtained from second edition of the IBM 570279219Sken * System Storage Tape Drive 3592 SCSI Reference (May 25, 2012). 571279570Sken * 572279570Sken * DAT-72 and DAT-160 bpi values taken from "HP StorageWorks DAT160 573279570Sken * tape drive white paper", dated June 2007. 574279570Sken * 575279570Sken * DAT-160 / SDLT220 density code (0x48) conflict information 576279570Sken * found here: 577279570Sken * 578279570Sken * http://h20564.www2.hp.com/hpsc/doc/public/display?docId=emr_na-c01065117&sp4ts.oid=429311 579279570Sken * (Document ID c01065117) 580279219Sken */ 581279219Sken /*Num. bpmm bpi Reference */ 582279219Sken { 0x1, 32, 800, "X3.22-1983" }, 583279219Sken { 0x2, 63, 1600, "X3.39-1986" }, 584279219Sken { 0x3, 246, 6250, "X3.54-1986" }, 585279219Sken { 0x5, 315, 8000, "X3.136-1986" }, 586279219Sken { 0x6, 126, 3200, "X3.157-1987" }, 587279219Sken { 0x7, 252, 6400, "X3.116-1986" }, 588279219Sken { 0x8, 315, 8000, "X3.158-1987" }, 589279219Sken { 0x9, 491, 37871, "X3.180" }, 590279219Sken { 0xA, 262, 6667, "X3B5/86-199" }, 591279219Sken { 0xB, 63, 1600, "X3.56-1986" }, 592279219Sken { 0xC, 500, 12690, "HI-TC1" }, 593279219Sken { 0xD, 999, 25380, "HI-TC2" }, 594279219Sken { 0xF, 394, 10000, "QIC-120" }, 595279219Sken { 0x10, 394, 10000, "QIC-150" }, 596279219Sken { 0x11, 630, 16000, "QIC-320" }, 597279219Sken { 0x12, 2034, 51667, "QIC-1350" }, 598279219Sken { 0x13, 2400, 61000, "X3B5/88-185A" }, 599279219Sken { 0x14, 1703, 43245, "X3.202-1991" }, 600279219Sken { 0x15, 1789, 45434, "ECMA TC17" }, 601279219Sken { 0x16, 394, 10000, "X3.193-1990" }, 602279219Sken { 0x17, 1673, 42500, "X3B5/91-174" }, 603279219Sken { 0x18, 1673, 42500, "X3B5/92-50" }, 604279219Sken { 0x19, 2460, 62500, "DLTapeIII" }, 605279219Sken { 0x1A, 3214, 81633, "DLTapeIV(20GB)" }, 606279219Sken { 0x1B, 3383, 85937, "DLTapeIV(35GB)" }, 607279219Sken { 0x1C, 1654, 42000, "QIC-385M" }, 608279219Sken { 0x1D, 1512, 38400, "QIC-410M" }, 609279219Sken { 0x1E, 1385, 36000, "QIC-1000C" }, 610279219Sken { 0x1F, 2666, 67733, "QIC-2100C" }, 611279219Sken { 0x20, 2666, 67733, "QIC-6GB(M)" }, 612279219Sken { 0x21, 2666, 67733, "QIC-20GB(C)" }, 613279219Sken { 0x22, 1600, 40640, "QIC-2GB(C)" }, 614279219Sken { 0x23, 2666, 67733, "QIC-875M" }, 615279219Sken { 0x24, 2400, 61000, "DDS-2" }, 616279219Sken { 0x25, 3816, 97000, "DDS-3" }, 617279219Sken { 0x26, 3816, 97000, "DDS-4" }, 618279219Sken { 0x27, 3056, 77611, "Mammoth" }, 619279219Sken { 0x28, 1491, 37871, "X3.224" }, 620279219Sken { 0x40, 4880, 123952, "LTO-1" }, 621279219Sken { 0x41, 3868, 98250, "DLTapeIV(40GB)" }, 622279219Sken { 0x42, 7398, 187909, "LTO-2" }, 623279219Sken { 0x44, 9638, 244805, "LTO-3" }, 624279219Sken { 0x46, 12725, 323215, "LTO-4" }, 625279570Sken { 0x47, 6417, 163000, "DAT-72" }, 626279570Sken /* 627279570Sken * XXX KDM note that 0x48 is also the density code for DAT-160. 628279570Sken * For some reason they used overlapping density codes. 629279570Sken */ 630279570Sken#if 0 631279570Sken { 0x48, 6870, 174500, "DAT-160" }, 632279570Sken#endif 633279219Sken { 0x48, 5236, 133000, "SDLTapeI(110)" }, 634279219Sken { 0x49, 7598, 193000, "SDLTapeI(160)" }, 635279219Sken { 0x4a, 0, 0, "T10000A" }, 636279219Sken { 0x4b, 0, 0, "T10000B" }, 637279219Sken { 0x4c, 0, 0, "T10000C" }, 638279219Sken { 0x4d, 0, 0, "T10000D" }, 639279219Sken { 0x51, 11800, 299720, "3592A1 (unencrypted)" }, 640279219Sken { 0x52, 11800, 299720, "3592A2 (unencrypted)" }, 641279219Sken { 0x53, 13452, 341681, "3592A3 (unencrypted)" }, 642279219Sken { 0x54, 19686, 500024, "3592A4 (unencrypted)" }, 643279219Sken { 0x55, 20670, 525018, "3592A5 (unencrypted)" }, 644322366Sken { 0x56, 20670, 525018, "3592B5 (unencrypted)" }, 645347884Sken { 0x57, 21850, 554990, "3592A6 (unencrypted)" }, 646279219Sken { 0x58, 15142, 384607, "LTO-5" }, 647279219Sken { 0x5A, 15142, 384607, "LTO-6" }, 648300327Sken { 0x5C, 19107, 485318, "LTO-7" }, 649325495Sken { 0x5D, 19107, 485318, "LTO-M8" }, 650318296Sken { 0x5E, 20669, 524993, "LTO-8" }, 651368675Sken { 0x60, 23031, 584987, "LTO-9" }, 652279219Sken { 0x71, 11800, 299720, "3592A1 (encrypted)" }, 653279219Sken { 0x72, 11800, 299720, "3592A2 (encrypted)" }, 654279219Sken { 0x73, 13452, 341681, "3592A3 (encrypted)" }, 655279219Sken { 0x74, 19686, 500024, "3592A4 (encrypted)" }, 656279219Sken { 0x75, 20670, 525018, "3592A5 (encrypted)" }, 657322366Sken { 0x76, 20670, 525018, "3592B5 (encrypted)" }, 658347884Sken { 0x77, 21850, 554990, "3592A6 (encrypted)" }, 659279219Sken { 0x8c, 1789, 45434, "EXB-8500c" }, 660279219Sken { 0x90, 1703, 43245, "EXB-8200c" }, 661279219Sken { 0, 0, 0, NULL } 662279219Sken}; 663279219Sken 664279219Skenconst char * 665279219Skenmt_density_name(int density_num) 666279219Sken{ 667279219Sken struct densities *sd; 668279219Sken 669279219Sken /* densities 0 and 0x7f are handled as special cases */ 670279219Sken if (density_num == 0) 671279219Sken return ("default"); 672279219Sken if (density_num == 0x7f) 673279219Sken return ("same"); 674279219Sken 675279219Sken for (sd = dens; sd->dens != 0; sd++) 676279219Sken if (sd->dens == density_num) 677279219Sken break; 678279219Sken if (sd->dens == 0) 679279219Sken return ("UNKNOWN"); 680279219Sken return (sd->name); 681279219Sken} 682279219Sken 683279219Sken/* 684279219Sken * Given a specific density number, return either the bits per inch or bits 685279219Sken * per millimeter for the given density. 686279219Sken */ 687279219Skenint 688279219Skenmt_density_bp(int density_num, int bpi) 689279219Sken{ 690279219Sken struct densities *sd; 691279219Sken 692279219Sken for (sd = dens; sd->dens; sd++) 693279219Sken if (sd->dens == density_num) 694279219Sken break; 695279219Sken if (sd->dens == 0) 696279219Sken return (0); 697279219Sken if (bpi) 698279219Sken return (sd->bpi); 699279219Sken else 700279219Sken return (sd->bpmm); 701279219Sken} 702279219Sken 703279219Skenint 704279219Skenmt_density_num(const char *density_name) 705279219Sken{ 706279219Sken struct densities *sd; 707279219Sken size_t l = strlen(density_name); 708279219Sken 709279219Sken for (sd = dens; sd->dens; sd++) 710279219Sken if (strncasecmp(sd->name, density_name, l) == 0) 711279219Sken break; 712279219Sken return (sd->dens); 713279219Sken} 714279219Sken 715279219Sken/* 716279219Sken * Get the current status XML string. 717279219Sken * Returns 0 on success, -1 on failure (with errno set, and *xml_str == NULL). 718279219Sken */ 719279219Skenint 720279219Skenmt_get_xml_str(int mtfd, unsigned long cmd, char **xml_str) 721279219Sken{ 722279219Sken size_t alloc_len = 32768; 723279219Sken struct mtextget extget; 724279219Sken int error; 725279219Sken 726279219Sken *xml_str = NULL; 727279219Sken 728279219Sken for (;;) { 729279219Sken bzero(&extget, sizeof(extget)); 730279219Sken *xml_str = malloc(alloc_len); 731279219Sken if (*xml_str == NULL) 732279219Sken return (-1); 733279219Sken extget.status_xml = *xml_str; 734279219Sken extget.alloc_len = alloc_len; 735279219Sken 736279219Sken error = ioctl(mtfd, cmd, (caddr_t)&extget); 737279219Sken if (error == 0 && extget.status == MT_EXT_GET_OK) 738279219Sken break; 739279219Sken 740279219Sken free(*xml_str); 741279219Sken *xml_str = NULL; 742279219Sken 743279219Sken if (error != 0 || extget.status != MT_EXT_GET_NEED_MORE_SPACE) 744279219Sken return (-1); 745279219Sken 746279219Sken /* The driver needs more space, so double and try again. */ 747279219Sken alloc_len *= 2; 748279219Sken } 749279219Sken return (0); 750279219Sken} 751279219Sken 752279219Sken/* 753279219Sken * Populate a struct mt_status_data from the XML string via mt_get_xml_str(). 754279219Sken * 755279219Sken * Returns XML_STATUS_OK on success. 756279219Sken * If XML_STATUS_ERROR is returned, errno may be set to indicate the reason. 757279219Sken * The caller must check status_data->error. 758279219Sken */ 759279219Skenint 760279219Skenmt_get_status(char *xml_str, struct mt_status_data *status_data) 761279219Sken{ 762279219Sken XML_Parser parser; 763279219Sken int retval; 764279219Sken 765279219Sken bzero(status_data, sizeof(*status_data)); 766279219Sken STAILQ_INIT(&status_data->entries); 767279219Sken 768279219Sken parser = XML_ParserCreate(NULL); 769279219Sken if (parser == NULL) { 770279219Sken errno = ENOMEM; 771279219Sken return (XML_STATUS_ERROR); 772279219Sken } 773279219Sken 774279219Sken XML_SetUserData(parser, status_data); 775279219Sken XML_SetElementHandler(parser, mt_start_element, mt_end_element); 776279219Sken XML_SetCharacterDataHandler(parser, mt_char_handler); 777279219Sken 778279219Sken retval = XML_Parse(parser, xml_str, strlen(xml_str), 1); 779279219Sken XML_ParserFree(parser); 780279219Sken return (retval); 781279219Sken} 782