xref: /freebsd/lib/libmt/mtlib.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
143518607SKenneth D. Merry /*-
243518607SKenneth D. Merry  * Copyright (c) 2013, 2014, 2015 Spectra Logic Corporation
343518607SKenneth D. Merry  * All rights reserved.
443518607SKenneth D. Merry  *
543518607SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
643518607SKenneth D. Merry  * modification, are permitted provided that the following conditions
743518607SKenneth D. Merry  * are met:
843518607SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
943518607SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
1043518607SKenneth D. Merry  *    without modification.
1143518607SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1243518607SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
1343518607SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
1443518607SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
1543518607SKenneth D. Merry  *    binary redistribution.
1643518607SKenneth D. Merry  *
1743518607SKenneth D. Merry  * NO WARRANTY
1843518607SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1943518607SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2043518607SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
2143518607SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2243518607SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2343518607SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2443518607SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2543518607SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2643518607SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2743518607SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2843518607SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
2943518607SKenneth D. Merry  *
3043518607SKenneth D. Merry  * Authors: Ken Merry           (Spectra Logic Corporation)
3143518607SKenneth D. Merry  */
3243518607SKenneth D. Merry 
3343518607SKenneth D. Merry #include <sys/types.h>
3443518607SKenneth D. Merry #include <sys/ioctl.h>
3543518607SKenneth D. Merry #include <sys/mtio.h>
3643518607SKenneth D. Merry #include <sys/queue.h>
3743518607SKenneth D. Merry #include <sys/sbuf.h>
3843518607SKenneth D. Merry 
3943518607SKenneth D. Merry #include <ctype.h>
4043518607SKenneth D. Merry #include <err.h>
4143518607SKenneth D. Merry #include <fcntl.h>
4243518607SKenneth D. Merry #include <stdio.h>
4343518607SKenneth D. Merry #include <stdlib.h>
4443518607SKenneth D. Merry #include <string.h>
4543518607SKenneth D. Merry #include <unistd.h>
4643518607SKenneth D. Merry #include <stdint.h>
4743518607SKenneth D. Merry #include <errno.h>
4843518607SKenneth D. Merry #include <bsdxml.h>
4943518607SKenneth D. Merry #include <mtlib.h>
5043518607SKenneth D. Merry 
5143518607SKenneth D. Merry /*
5243518607SKenneth D. Merry  * Called at the start of each XML element, and includes the list of
5343518607SKenneth D. Merry  * attributes for the element.
5443518607SKenneth D. Merry  */
5543518607SKenneth D. Merry void
mt_start_element(void * user_data,const char * name,const char ** attr)5643518607SKenneth D. Merry mt_start_element(void *user_data, const char *name, const char **attr)
5743518607SKenneth D. Merry {
5843518607SKenneth D. Merry 	int i;
5943518607SKenneth D. Merry 	struct mt_status_data *mtinfo;
6043518607SKenneth D. Merry 	struct mt_status_entry *entry;
6143518607SKenneth D. Merry 
6243518607SKenneth D. Merry 	mtinfo = (struct mt_status_data *)user_data;
6343518607SKenneth D. Merry 
6443518607SKenneth D. Merry 	if (mtinfo->error != 0)
6543518607SKenneth D. Merry 		return;
6643518607SKenneth D. Merry 
6743518607SKenneth D. Merry 	mtinfo->level++;
687b7c7a05SKenneth D. Merry 	if ((u_int)mtinfo->level >= (sizeof(mtinfo->cur_sb) /
6943518607SKenneth D. Merry             sizeof(mtinfo->cur_sb[0]))) {
7043518607SKenneth D. Merry 		mtinfo->error = 1;
7143518607SKenneth D. Merry                 snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
7243518607SKenneth D. Merry 		    "%s: too many nesting levels, %zd max", __func__,
7343518607SKenneth D. Merry 		    sizeof(mtinfo->cur_sb) / sizeof(mtinfo->cur_sb[0]));
7443518607SKenneth D. Merry 		return;
7543518607SKenneth D. Merry 	}
7643518607SKenneth D. Merry 
7743518607SKenneth D. Merry         mtinfo->cur_sb[mtinfo->level] = sbuf_new_auto();
7843518607SKenneth D. Merry         if (mtinfo->cur_sb[mtinfo->level] == NULL) {
7943518607SKenneth D. Merry 		mtinfo->error = 1;
8043518607SKenneth D. Merry                 snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
8143518607SKenneth D. Merry 		    "%s: Unable to allocate sbuf", __func__);
8243518607SKenneth D. Merry 		return;
8343518607SKenneth D. Merry 	}
8443518607SKenneth D. Merry 
8543518607SKenneth D. Merry 	entry = malloc(sizeof(*entry));
8643518607SKenneth D. Merry 	if (entry == NULL) {
8743518607SKenneth D. Merry 		mtinfo->error = 1;
8843518607SKenneth D. Merry 		snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
8943518607SKenneth D. Merry 		    "%s: unable to allocate %zd bytes", __func__,
9043518607SKenneth D. Merry 		    sizeof(*entry));
9143518607SKenneth D. Merry 		return;
9243518607SKenneth D. Merry 	}
9343518607SKenneth D. Merry 	bzero(entry, sizeof(*entry));
9443518607SKenneth D. Merry 	STAILQ_INIT(&entry->nv_list);
9543518607SKenneth D. Merry 	STAILQ_INIT(&entry->child_entries);
9643518607SKenneth D. Merry 	entry->entry_name = strdup(name);
9743518607SKenneth D. Merry 	mtinfo->cur_entry[mtinfo->level] = entry;
9843518607SKenneth D. Merry 	if (mtinfo->cur_entry[mtinfo->level - 1] == NULL) {
9943518607SKenneth D. Merry 		STAILQ_INSERT_TAIL(&mtinfo->entries, entry, links);
10043518607SKenneth D. Merry 	} else {
10143518607SKenneth D. Merry 		STAILQ_INSERT_TAIL(
10243518607SKenneth D. Merry 		    &mtinfo->cur_entry[mtinfo->level - 1]->child_entries,
10343518607SKenneth D. Merry 		    entry, links);
10443518607SKenneth D. Merry 		entry->parent = mtinfo->cur_entry[mtinfo->level - 1];
10543518607SKenneth D. Merry 	}
10643518607SKenneth D. Merry 	for (i = 0; attr[i] != NULL; i+=2) {
10743518607SKenneth D. Merry 		struct mt_status_nv *nv;
10843518607SKenneth D. Merry 		int need_nv;
10943518607SKenneth D. Merry 
11043518607SKenneth D. Merry 		need_nv = 0;
11143518607SKenneth D. Merry 
11243518607SKenneth D. Merry 		if (strcmp(attr[i], "size") == 0) {
11343518607SKenneth D. Merry 			entry->size = strtoull(attr[i+1], NULL, 0);
11443518607SKenneth D. Merry 		} else if (strcmp(attr[i], "type") == 0) {
11543518607SKenneth D. Merry 			if (strcmp(attr[i+1], "int") == 0) {
11643518607SKenneth D. Merry 				entry->var_type = MT_TYPE_INT;
11743518607SKenneth D. Merry 			} else if (strcmp(attr[i+1], "uint") == 0) {
11843518607SKenneth D. Merry 				entry->var_type = MT_TYPE_UINT;
11943518607SKenneth D. Merry 			} else if (strcmp(attr[i+1], "str") == 0) {
12043518607SKenneth D. Merry 				entry->var_type = MT_TYPE_STRING;
12143518607SKenneth D. Merry 			} else if (strcmp(attr[i+1], "node") == 0) {
12243518607SKenneth D. Merry 				entry->var_type = MT_TYPE_NODE;
12343518607SKenneth D. Merry 			} else {
12443518607SKenneth D. Merry 				need_nv = 1;
12543518607SKenneth D. Merry 			}
12643518607SKenneth D. Merry 		} else if (strcmp(attr[i], "fmt") == 0) {
12743518607SKenneth D. Merry 			entry->fmt = strdup(attr[i+1]);
12843518607SKenneth D. Merry 		} else if (strcmp(attr[i], "desc") == 0) {
12943518607SKenneth D. Merry 			entry->desc = strdup(attr[i+1]);
13043518607SKenneth D. Merry 		} else {
13143518607SKenneth D. Merry 			need_nv = 1;
13243518607SKenneth D. Merry 		}
13343518607SKenneth D. Merry 		if (need_nv != 0) {
13443518607SKenneth D. Merry 			nv = malloc(sizeof(*nv));
13543518607SKenneth D. Merry 			if (nv == NULL) {
13643518607SKenneth D. Merry 				mtinfo->error = 1;
13743518607SKenneth D. Merry 				snprintf(mtinfo->error_str,
13843518607SKenneth D. Merry 				    sizeof(mtinfo->error_str),
13943518607SKenneth D. Merry 				    "%s: error allocating %zd bytes",
14043518607SKenneth D. Merry 				    __func__, sizeof(*nv));
14143518607SKenneth D. Merry 			}
14243518607SKenneth D. Merry 			bzero(nv, sizeof(*nv));
14343518607SKenneth D. Merry 			nv->name = strdup(attr[i]);
14443518607SKenneth D. Merry 			nv->value = strdup(attr[i+1]);
14543518607SKenneth D. Merry 			STAILQ_INSERT_TAIL(&entry->nv_list, nv, links);
14643518607SKenneth D. Merry 		}
14743518607SKenneth D. Merry 	}
14843518607SKenneth D. Merry }
14943518607SKenneth D. Merry 
15043518607SKenneth D. Merry /*
15143518607SKenneth D. Merry  * Called on XML element close.
15243518607SKenneth D. Merry  */
15343518607SKenneth D. Merry void
mt_end_element(void * user_data,const char * name)15443518607SKenneth D. Merry mt_end_element(void *user_data, const char *name)
15543518607SKenneth D. Merry {
15643518607SKenneth D. Merry 	struct mt_status_data *mtinfo;
15743518607SKenneth D. Merry 	char *str;
15843518607SKenneth D. Merry 
15943518607SKenneth D. Merry 	mtinfo = (struct mt_status_data *)user_data;
16043518607SKenneth D. Merry 
16143518607SKenneth D. Merry 	if (mtinfo->error != 0)
16243518607SKenneth D. Merry 		return;
16343518607SKenneth D. Merry 
16443518607SKenneth D. Merry 	if (mtinfo->cur_sb[mtinfo->level] == NULL) {
16543518607SKenneth D. Merry 		mtinfo->error = 1;
16643518607SKenneth D. Merry 		snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
16743518607SKenneth D. Merry 		    "%s: no valid sbuf at level %d (name %s)", __func__,
16843518607SKenneth D. Merry 		    mtinfo->level, name);
16943518607SKenneth D. Merry 		return;
17043518607SKenneth D. Merry 	}
17143518607SKenneth D. Merry 	sbuf_finish(mtinfo->cur_sb[mtinfo->level]);
17243518607SKenneth D. Merry 	str = strdup(sbuf_data(mtinfo->cur_sb[mtinfo->level]));
17343518607SKenneth D. Merry 	if (str == NULL) {
17443518607SKenneth D. Merry 		mtinfo->error = 1;
17543518607SKenneth D. Merry 		snprintf(mtinfo->error_str, sizeof(mtinfo->error_str),
17643518607SKenneth D. Merry 		    "%s can't allocate %zd bytes for string", __func__,
17743518607SKenneth D. Merry 		    sbuf_len(mtinfo->cur_sb[mtinfo->level]));
17843518607SKenneth D. Merry 		return;
17943518607SKenneth D. Merry 	}
18043518607SKenneth D. Merry 
18143518607SKenneth D. Merry 	if (strlen(str) == 0) {
18243518607SKenneth D. Merry 		free(str);
18343518607SKenneth D. Merry 		str = NULL;
18443518607SKenneth D. Merry 	}
18543518607SKenneth D. Merry 	if (str != NULL) {
18643518607SKenneth D. Merry 		struct mt_status_entry *entry;
18743518607SKenneth D. Merry 
18843518607SKenneth D. Merry 		entry = mtinfo->cur_entry[mtinfo->level];
18943518607SKenneth D. Merry 		switch(entry->var_type) {
19043518607SKenneth D. Merry 		case MT_TYPE_INT:
19143518607SKenneth D. Merry 			entry->value_signed = strtoll(str, NULL, 0);
19243518607SKenneth D. Merry 			break;
19343518607SKenneth D. Merry 		case MT_TYPE_UINT:
19443518607SKenneth D. Merry 			entry->value_unsigned = strtoull(str, NULL, 0);
19543518607SKenneth D. Merry 			break;
19643518607SKenneth D. Merry 		default:
19743518607SKenneth D. Merry 			break;
19843518607SKenneth D. Merry 		}
19943518607SKenneth D. Merry 	}
20043518607SKenneth D. Merry 
20143518607SKenneth D. Merry 	mtinfo->cur_entry[mtinfo->level]->value = str;
20243518607SKenneth D. Merry 
20343518607SKenneth D. Merry 	sbuf_delete(mtinfo->cur_sb[mtinfo->level]);
20443518607SKenneth D. Merry 	mtinfo->cur_sb[mtinfo->level] = NULL;
20543518607SKenneth D. Merry 	mtinfo->cur_entry[mtinfo->level] = NULL;
20643518607SKenneth D. Merry 	mtinfo->level--;
20743518607SKenneth D. Merry }
20843518607SKenneth D. Merry 
20943518607SKenneth D. Merry /*
21043518607SKenneth D. Merry  * Called to handle character strings in the current element.
21143518607SKenneth D. Merry  */
21243518607SKenneth D. Merry void
mt_char_handler(void * user_data,const XML_Char * str,int len)21343518607SKenneth D. Merry mt_char_handler(void *user_data, const XML_Char *str, int len)
21443518607SKenneth D. Merry {
21543518607SKenneth D. Merry 	struct mt_status_data *mtinfo;
21643518607SKenneth D. Merry 
21743518607SKenneth D. Merry 	mtinfo = (struct mt_status_data *)user_data;
21843518607SKenneth D. Merry 	if (mtinfo->error != 0)
21943518607SKenneth D. Merry 		return;
22043518607SKenneth D. Merry 
22143518607SKenneth D. Merry 	sbuf_bcat(mtinfo->cur_sb[mtinfo->level], str, len);
22243518607SKenneth D. Merry }
22343518607SKenneth D. Merry 
22443518607SKenneth D. Merry void
mt_status_tree_sbuf(struct sbuf * sb,struct mt_status_entry * entry,int indent,void (* sbuf_func)(struct sbuf * sb,struct mt_status_entry * entry,void * arg),void * arg)22543518607SKenneth D. Merry mt_status_tree_sbuf(struct sbuf *sb, struct mt_status_entry *entry, int indent,
22643518607SKenneth D. Merry     void (*sbuf_func)(struct sbuf *sb, struct mt_status_entry *entry,
22743518607SKenneth D. Merry     void *arg), void *arg)
22843518607SKenneth D. Merry {
22943518607SKenneth D. Merry 	struct mt_status_nv *nv;
23043518607SKenneth D. Merry 	struct mt_status_entry *entry2;
23143518607SKenneth D. Merry 
23243518607SKenneth D. Merry 	if (sbuf_func != NULL) {
23343518607SKenneth D. Merry 		sbuf_func(sb, entry, arg);
23443518607SKenneth D. Merry 	} else {
23543518607SKenneth D. Merry 		sbuf_printf(sb, "%*sname: %s, value: %s, fmt: %s, size: %zd, "
23643518607SKenneth D. Merry 		    "type: %d, desc: %s\n", indent, "", entry->entry_name,
23743518607SKenneth D. Merry 		    entry->value, entry->fmt, entry->size, entry->var_type,
23843518607SKenneth D. Merry 		    entry->desc);
23943518607SKenneth D. Merry 		STAILQ_FOREACH(nv, &entry->nv_list, links) {
24043518607SKenneth D. Merry 			sbuf_printf(sb, "%*snv: name: %s, value: %s\n",
24143518607SKenneth D. Merry 			    indent + 1, "", nv->name, nv->value);
24243518607SKenneth D. Merry 		}
24343518607SKenneth D. Merry 	}
24443518607SKenneth D. Merry 
24543518607SKenneth D. Merry 	STAILQ_FOREACH(entry2, &entry->child_entries, links)
24643518607SKenneth D. Merry 		mt_status_tree_sbuf(sb, entry2, indent + 2, sbuf_func, arg);
24743518607SKenneth D. Merry }
24843518607SKenneth D. Merry 
24943518607SKenneth D. Merry void
mt_status_tree_print(struct mt_status_entry * entry,int indent,void (* print_func)(struct mt_status_entry * entry,void * arg),void * arg)25043518607SKenneth D. Merry mt_status_tree_print(struct mt_status_entry *entry, int indent,
25143518607SKenneth D. Merry     void (*print_func)(struct mt_status_entry *entry, void *arg), void *arg)
25243518607SKenneth D. Merry {
25343518607SKenneth D. Merry 
25443518607SKenneth D. Merry 	if (print_func != NULL) {
25543518607SKenneth D. Merry 		struct mt_status_entry *entry2;
25643518607SKenneth D. Merry 
25743518607SKenneth D. Merry 		print_func(entry, arg);
25843518607SKenneth D. Merry 		STAILQ_FOREACH(entry2, &entry->child_entries, links)
25943518607SKenneth D. Merry 			mt_status_tree_print(entry2, indent + 2, print_func,
26043518607SKenneth D. Merry 			    arg);
26143518607SKenneth D. Merry 	} else {
26243518607SKenneth D. Merry 		struct sbuf *sb;
26343518607SKenneth D. Merry 
26443518607SKenneth D. Merry 		sb = sbuf_new_auto();
26543518607SKenneth D. Merry 		if (sb == NULL)
26643518607SKenneth D. Merry 			return;
26743518607SKenneth D. Merry 		mt_status_tree_sbuf(sb, entry, indent, NULL, NULL);
26843518607SKenneth D. Merry 		sbuf_finish(sb);
26943518607SKenneth D. Merry 
27043518607SKenneth D. Merry 		printf("%s", sbuf_data(sb));
27143518607SKenneth D. Merry 		sbuf_delete(sb);
27243518607SKenneth D. Merry 	}
27343518607SKenneth D. Merry }
27443518607SKenneth D. Merry 
27543518607SKenneth D. Merry /*
27643518607SKenneth D. Merry  * Given a parameter name in the form "foo" or "foo.bar.baz", traverse the
27743518607SKenneth D. Merry  * tree looking for the parameter (the first case) or series of parameters
27843518607SKenneth D. Merry  * (second case).
27943518607SKenneth D. Merry  */
28043518607SKenneth D. Merry struct mt_status_entry *
mt_entry_find(struct mt_status_entry * entry,char * name)28143518607SKenneth D. Merry mt_entry_find(struct mt_status_entry *entry, char *name)
28243518607SKenneth D. Merry {
28343518607SKenneth D. Merry 	struct mt_status_entry *entry2;
28443518607SKenneth D. Merry 	char *tmpname = NULL, *tmpname2 = NULL, *tmpstr = NULL;
28543518607SKenneth D. Merry 
28643518607SKenneth D. Merry 	tmpname = strdup(name);
28743518607SKenneth D. Merry 	if (tmpname == NULL)
28843518607SKenneth D. Merry 		goto bailout;
28943518607SKenneth D. Merry 
29043518607SKenneth D. Merry 	/* Save a pointer so we can free this later */
29143518607SKenneth D. Merry 	tmpname2 = tmpname;
29243518607SKenneth D. Merry 
29343518607SKenneth D. Merry 	tmpstr = strsep(&tmpname, ".");
29443518607SKenneth D. Merry 
29543518607SKenneth D. Merry 	/*
29643518607SKenneth D. Merry 	 * Is this the entry we're looking for?  Or do we have further
29743518607SKenneth D. Merry 	 * child entries that we need to grab?
29843518607SKenneth D. Merry 	 */
29943518607SKenneth D. Merry 	if (strcmp(entry->entry_name, tmpstr) == 0) {
30043518607SKenneth D. Merry 	 	if (tmpname == NULL) {
30143518607SKenneth D. Merry 			/*
30243518607SKenneth D. Merry 			 * There are no further child entries to find.  We
30343518607SKenneth D. Merry 			 * have a complete match.
30443518607SKenneth D. Merry 			 */
30543518607SKenneth D. Merry 			free(tmpname2);
30643518607SKenneth D. Merry 			return (entry);
30743518607SKenneth D. Merry 		} else {
30843518607SKenneth D. Merry 			/*
30943518607SKenneth D. Merry 			 * There are more child entries that we need to find.
31043518607SKenneth D. Merry 			 * Fall through to the recursive search off of this
31143518607SKenneth D. Merry 			 * entry, below.  Use tmpname, which will contain
31243518607SKenneth D. Merry 			 * everything after the first period.
31343518607SKenneth D. Merry 			 */
31443518607SKenneth D. Merry 			name = tmpname;
31543518607SKenneth D. Merry 		}
31643518607SKenneth D. Merry 	}
31743518607SKenneth D. Merry 
31843518607SKenneth D. Merry 	/*
31943518607SKenneth D. Merry 	 * Recursively look for further entries.
32043518607SKenneth D. Merry 	 */
32143518607SKenneth D. Merry 	STAILQ_FOREACH(entry2, &entry->child_entries, links) {
32243518607SKenneth D. Merry 		struct mt_status_entry *entry3;
32343518607SKenneth D. Merry 
32443518607SKenneth D. Merry 		entry3 = mt_entry_find(entry2, name);
32543518607SKenneth D. Merry 		if (entry3 != NULL) {
32643518607SKenneth D. Merry 			free(tmpname2);
32743518607SKenneth D. Merry 			return (entry3);
32843518607SKenneth D. Merry 		}
32943518607SKenneth D. Merry 	}
33043518607SKenneth D. Merry 
33143518607SKenneth D. Merry bailout:
33243518607SKenneth D. Merry 	free(tmpname2);
33343518607SKenneth D. Merry 
33443518607SKenneth D. Merry 	return (NULL);
33543518607SKenneth D. Merry }
33643518607SKenneth D. Merry 
33743518607SKenneth D. Merry struct mt_status_entry *
mt_status_entry_find(struct mt_status_data * status_data,char * name)33843518607SKenneth D. Merry mt_status_entry_find(struct mt_status_data *status_data, char *name)
33943518607SKenneth D. Merry {
34043518607SKenneth D. Merry 	struct mt_status_entry *entry, *entry2;
34143518607SKenneth D. Merry 
34243518607SKenneth D. Merry 	STAILQ_FOREACH(entry, &status_data->entries, links) {
34343518607SKenneth D. Merry 		entry2 = mt_entry_find(entry, name);
34443518607SKenneth D. Merry 		if (entry2 != NULL)
34543518607SKenneth D. Merry 			return (entry2);
34643518607SKenneth D. Merry 	}
34743518607SKenneth D. Merry 
34843518607SKenneth D. Merry 	return (NULL);
34943518607SKenneth D. Merry }
35043518607SKenneth D. Merry 
35143518607SKenneth D. Merry void
mt_status_entry_free(struct mt_status_entry * entry)35243518607SKenneth D. Merry mt_status_entry_free(struct mt_status_entry *entry)
35343518607SKenneth D. Merry {
35443518607SKenneth D. Merry 	struct mt_status_entry *entry2, *entry3;
35543518607SKenneth D. Merry 	struct mt_status_nv *nv, *nv2;
35643518607SKenneth D. Merry 
35743518607SKenneth D. Merry 	STAILQ_FOREACH_SAFE(entry2, &entry->child_entries, links, entry3) {
35843518607SKenneth D. Merry 		STAILQ_REMOVE(&entry->child_entries, entry2, mt_status_entry,
35943518607SKenneth D. Merry 		    links);
36043518607SKenneth D. Merry 		mt_status_entry_free(entry2);
36143518607SKenneth D. Merry 	}
36243518607SKenneth D. Merry 
36343518607SKenneth D. Merry 	free(entry->entry_name);
36443518607SKenneth D. Merry 	free(entry->value);
36543518607SKenneth D. Merry 	free(entry->fmt);
36643518607SKenneth D. Merry 	free(entry->desc);
36743518607SKenneth D. Merry 
36843518607SKenneth D. Merry 	STAILQ_FOREACH_SAFE(nv, &entry->nv_list, links, nv2) {
36943518607SKenneth D. Merry 		STAILQ_REMOVE(&entry->nv_list, nv, mt_status_nv, links);
37043518607SKenneth D. Merry 		free(nv->name);
37143518607SKenneth D. Merry 		free(nv->value);
37243518607SKenneth D. Merry 		free(nv);
37343518607SKenneth D. Merry 	}
37443518607SKenneth D. Merry 	free(entry);
37543518607SKenneth D. Merry }
37643518607SKenneth D. Merry 
37743518607SKenneth D. Merry void
mt_status_free(struct mt_status_data * status_data)37843518607SKenneth D. Merry mt_status_free(struct mt_status_data *status_data)
37943518607SKenneth D. Merry {
38043518607SKenneth D. Merry 	struct mt_status_entry *entry, *entry2;
38143518607SKenneth D. Merry 
38243518607SKenneth D. Merry 	STAILQ_FOREACH_SAFE(entry, &status_data->entries, links, entry2) {
38343518607SKenneth D. Merry 		STAILQ_REMOVE(&status_data->entries, entry, mt_status_entry,
38443518607SKenneth D. Merry 		    links);
38543518607SKenneth D. Merry 		mt_status_entry_free(entry);
38643518607SKenneth D. Merry 	}
38743518607SKenneth D. Merry }
38843518607SKenneth D. Merry 
38943518607SKenneth D. Merry void
mt_entry_sbuf(struct sbuf * sb,struct mt_status_entry * entry,char * fmt)39043518607SKenneth D. Merry mt_entry_sbuf(struct sbuf *sb, struct mt_status_entry *entry, char *fmt)
39143518607SKenneth D. Merry {
39243518607SKenneth D. Merry 	switch(entry->var_type) {
39343518607SKenneth D. Merry 	case MT_TYPE_INT:
39443518607SKenneth D. Merry 		if (fmt != NULL)
39543518607SKenneth D. Merry 			sbuf_printf(sb, fmt, (intmax_t)entry->value_signed);
39643518607SKenneth D. Merry 		else
39743518607SKenneth D. Merry 			sbuf_printf(sb, "%jd",
39843518607SKenneth D. Merry 				    (intmax_t)entry->value_signed);
39943518607SKenneth D. Merry 		break;
40043518607SKenneth D. Merry 	case MT_TYPE_UINT:
40143518607SKenneth D. Merry 		if (fmt != NULL)
40243518607SKenneth D. Merry 			sbuf_printf(sb, fmt, (uintmax_t)entry->value_unsigned);
40343518607SKenneth D. Merry 		else
40443518607SKenneth D. Merry 			sbuf_printf(sb, "%ju",
40543518607SKenneth D. Merry 				    (uintmax_t)entry->value_unsigned);
40643518607SKenneth D. Merry 		break;
40743518607SKenneth D. Merry 	default:
40843518607SKenneth D. Merry 		if (fmt != NULL)
40943518607SKenneth D. Merry 			sbuf_printf(sb, fmt, entry->value);
41043518607SKenneth D. Merry 		else
41143518607SKenneth D. Merry 			sbuf_printf(sb, "%s", entry->value);
41243518607SKenneth D. Merry 		break;
41343518607SKenneth D. Merry 	}
41443518607SKenneth D. Merry }
41543518607SKenneth D. Merry 
41643518607SKenneth D. Merry void
mt_param_parent_print(struct mt_status_entry * entry,struct mt_print_params * print_params)41743518607SKenneth D. Merry mt_param_parent_print(struct mt_status_entry *entry,
41843518607SKenneth D. Merry     struct mt_print_params *print_params)
41943518607SKenneth D. Merry {
42043518607SKenneth D. Merry 	if (entry->parent != NULL)
42143518607SKenneth D. Merry 		mt_param_parent_print(entry->parent, print_params);
42243518607SKenneth D. Merry 
42343518607SKenneth D. Merry 	if (((print_params->flags & MT_PF_INCLUDE_ROOT) == 0)
42443518607SKenneth D. Merry 	 && (strcmp(entry->entry_name, print_params->root_name) == 0))
42543518607SKenneth D. Merry 		return;
42643518607SKenneth D. Merry 
42743518607SKenneth D. Merry 	printf("%s.", entry->entry_name);
42843518607SKenneth D. Merry }
42943518607SKenneth D. Merry 
43043518607SKenneth D. Merry void
mt_param_parent_sbuf(struct sbuf * sb,struct mt_status_entry * entry,struct mt_print_params * print_params)43143518607SKenneth D. Merry mt_param_parent_sbuf(struct sbuf *sb, struct mt_status_entry *entry,
43243518607SKenneth D. Merry     struct mt_print_params *print_params)
43343518607SKenneth D. Merry {
43443518607SKenneth D. Merry 	if (entry->parent != NULL)
43543518607SKenneth D. Merry 		mt_param_parent_sbuf(sb, entry->parent, print_params);
43643518607SKenneth D. Merry 
43743518607SKenneth D. Merry 	if (((print_params->flags & MT_PF_INCLUDE_ROOT) == 0)
43843518607SKenneth D. Merry 	 && (strcmp(entry->entry_name, print_params->root_name) == 0))
43943518607SKenneth D. Merry 		return;
44043518607SKenneth D. Merry 
44143518607SKenneth D. Merry 	sbuf_printf(sb, "%s.", entry->entry_name);
44243518607SKenneth D. Merry }
44343518607SKenneth D. Merry 
44443518607SKenneth D. Merry void
mt_param_entry_sbuf(struct sbuf * sb,struct mt_status_entry * entry,void * arg)44543518607SKenneth D. Merry mt_param_entry_sbuf(struct sbuf *sb, struct mt_status_entry *entry, void *arg)
44643518607SKenneth D. Merry {
44743518607SKenneth D. Merry 	struct mt_print_params *print_params;
44843518607SKenneth D. Merry 
44943518607SKenneth D. Merry 	print_params = (struct mt_print_params *)arg;
45043518607SKenneth D. Merry 
45143518607SKenneth D. Merry 	/*
45243518607SKenneth D. Merry 	 * We don't want to print nodes.
45343518607SKenneth D. Merry 	 */
45443518607SKenneth D. Merry 	if (entry->var_type == MT_TYPE_NODE)
45543518607SKenneth D. Merry 		return;
45643518607SKenneth D. Merry 
45743518607SKenneth D. Merry 	if ((print_params->flags & MT_PF_FULL_PATH)
45843518607SKenneth D. Merry 	 && (entry->parent != NULL))
45943518607SKenneth D. Merry 		mt_param_parent_sbuf(sb, entry->parent, print_params);
46043518607SKenneth D. Merry 
46143518607SKenneth D. Merry 	sbuf_printf(sb, "%s: %s", entry->entry_name, entry->value);
46243518607SKenneth D. Merry 	if ((print_params->flags & MT_PF_VERBOSE)
46343518607SKenneth D. Merry 	 && (entry->desc != NULL)
46443518607SKenneth D. Merry 	 && (strlen(entry->desc) > 0))
46543518607SKenneth D. Merry 		sbuf_printf(sb, " (%s)", entry->desc);
46643518607SKenneth D. Merry 	sbuf_printf(sb, "\n");
46743518607SKenneth D. Merry 
46843518607SKenneth D. Merry }
46943518607SKenneth D. Merry 
47043518607SKenneth D. Merry void
mt_param_entry_print(struct mt_status_entry * entry,void * arg)47143518607SKenneth D. Merry mt_param_entry_print(struct mt_status_entry *entry, void *arg)
47243518607SKenneth D. Merry {
47343518607SKenneth D. Merry 	struct mt_print_params *print_params;
47443518607SKenneth D. Merry 
47543518607SKenneth D. Merry 	print_params = (struct mt_print_params *)arg;
47643518607SKenneth D. Merry 
47743518607SKenneth D. Merry 	/*
47843518607SKenneth D. Merry 	 * We don't want to print nodes.
47943518607SKenneth D. Merry 	 */
48043518607SKenneth D. Merry 	if (entry->var_type == MT_TYPE_NODE)
48143518607SKenneth D. Merry 		return;
48243518607SKenneth D. Merry 
48343518607SKenneth D. Merry 	if ((print_params->flags & MT_PF_FULL_PATH)
48443518607SKenneth D. Merry 	 && (entry->parent != NULL))
48543518607SKenneth D. Merry 		mt_param_parent_print(entry->parent, print_params);
48643518607SKenneth D. Merry 
48743518607SKenneth D. Merry 	printf("%s: %s", entry->entry_name, entry->value);
48843518607SKenneth D. Merry 	if ((print_params->flags & MT_PF_VERBOSE)
48943518607SKenneth D. Merry 	 && (entry->desc != NULL)
49043518607SKenneth D. Merry 	 && (strlen(entry->desc) > 0))
49143518607SKenneth D. Merry 		printf(" (%s)", entry->desc);
49243518607SKenneth D. Merry 	printf("\n");
49343518607SKenneth D. Merry }
49443518607SKenneth D. Merry 
49543518607SKenneth D. Merry int
mt_protect_print(struct mt_status_data * status_data,int verbose)49643518607SKenneth D. Merry mt_protect_print(struct mt_status_data *status_data, int verbose)
49743518607SKenneth D. Merry {
49843518607SKenneth D. Merry 	struct mt_status_entry *entry;
49943518607SKenneth D. Merry 	const char *prot_name = MT_PROTECTION_NAME;
50043518607SKenneth D. Merry 	struct mt_print_params print_params;
50143518607SKenneth D. Merry 
50243518607SKenneth D. Merry 	snprintf(print_params.root_name, sizeof(print_params.root_name),
50343518607SKenneth D. Merry 	    MT_PARAM_ROOT_NAME);
50443518607SKenneth D. Merry 	print_params.flags = MT_PF_FULL_PATH;
50543518607SKenneth D. Merry 	if (verbose != 0)
50643518607SKenneth D. Merry 		print_params.flags |= MT_PF_VERBOSE;
50743518607SKenneth D. Merry 
50843518607SKenneth D. Merry 	entry = mt_status_entry_find(status_data, __DECONST(char *,prot_name));
50943518607SKenneth D. Merry 	if (entry == NULL)
51043518607SKenneth D. Merry 		return (1);
51143518607SKenneth D. Merry 	mt_status_tree_print(entry, 0, mt_param_entry_print, &print_params);
51243518607SKenneth D. Merry 
51343518607SKenneth D. Merry 	return (0);
51443518607SKenneth D. Merry }
51543518607SKenneth D. Merry 
51643518607SKenneth D. Merry int
mt_param_list(struct mt_status_data * status_data,char * param_name,int quiet)51743518607SKenneth D. Merry mt_param_list(struct mt_status_data *status_data, char *param_name, int quiet)
51843518607SKenneth D. Merry {
51943518607SKenneth D. Merry 	struct mt_status_entry *entry;
52043518607SKenneth D. Merry 	struct mt_print_params print_params;
52143518607SKenneth D. Merry 	char root_name[20];
52243518607SKenneth D. Merry 
52343518607SKenneth D. Merry 	snprintf(root_name, sizeof(root_name), "mtparamget");
52443518607SKenneth D. Merry 	strlcpy(print_params.root_name, root_name,
52543518607SKenneth D. Merry 	    sizeof(print_params.root_name));
52643518607SKenneth D. Merry 
52743518607SKenneth D. Merry 	print_params.flags = MT_PF_FULL_PATH;
52843518607SKenneth D. Merry 	if (quiet == 0)
52943518607SKenneth D. Merry 		print_params.flags |= MT_PF_VERBOSE;
53043518607SKenneth D. Merry 
53143518607SKenneth D. Merry 	if (param_name != NULL) {
53243518607SKenneth D. Merry 		entry = mt_status_entry_find(status_data, param_name);
53343518607SKenneth D. Merry 		if (entry == NULL)
53443518607SKenneth D. Merry 			return (1);
53543518607SKenneth D. Merry 
53643518607SKenneth D. Merry 		mt_param_entry_print(entry, &print_params);
53743518607SKenneth D. Merry 
53843518607SKenneth D. Merry 		return (0);
53943518607SKenneth D. Merry 	} else {
54043518607SKenneth D. Merry 		entry = mt_status_entry_find(status_data, root_name);
54143518607SKenneth D. Merry 
54243518607SKenneth D. Merry 		STAILQ_FOREACH(entry, &status_data->entries, links)
54343518607SKenneth D. Merry 			mt_status_tree_print(entry, 0, mt_param_entry_print,
54443518607SKenneth D. Merry 			    &print_params);
54543518607SKenneth D. Merry 	}
54643518607SKenneth D. Merry 
54743518607SKenneth D. Merry 	return (0);
54843518607SKenneth D. Merry }
54943518607SKenneth D. Merry 
55043518607SKenneth D. Merry static struct densities {
55143518607SKenneth D. Merry 	int dens;
55243518607SKenneth D. Merry 	int bpmm;
55343518607SKenneth D. Merry 	int bpi;
55443518607SKenneth D. Merry 	const char *name;
55543518607SKenneth D. Merry } dens[] = {
55643518607SKenneth D. Merry 	/*
55743518607SKenneth D. Merry 	 * Taken from T10 Project 997D
55843518607SKenneth D. Merry 	 * SCSI-3 Stream Device Commands (SSC)
55943518607SKenneth D. Merry 	 * Revision 11, 4-Nov-97
56043518607SKenneth D. Merry 	 *
56143518607SKenneth D. Merry 	 * LTO 1-6 definitions obtained from the eighth edition of the
56243518607SKenneth D. Merry 	 * IBM TotalStorage LTO Ultrium Tape Drive SCSI Reference
56343518607SKenneth D. Merry 	 * (July 2007) and the second edition of the IBM System Storage LTO
56443518607SKenneth D. Merry 	 * Tape Drive SCSI Reference (February 13, 2013).
56543518607SKenneth D. Merry 	 *
56643518607SKenneth D. Merry 	 * IBM 3592 definitions obtained from second edition of the IBM
56743518607SKenneth D. Merry 	 * System Storage Tape Drive 3592 SCSI Reference (May 25, 2012).
5685090c893SKenneth D. Merry 	 *
5695090c893SKenneth D. Merry 	 * DAT-72 and DAT-160 bpi values taken from "HP StorageWorks DAT160
5705090c893SKenneth D. Merry 	 * tape drive white paper", dated June 2007.
5715090c893SKenneth D. Merry 	 *
5725090c893SKenneth D. Merry 	 * DAT-160 / SDLT220 density code (0x48) conflict information
5735090c893SKenneth D. Merry 	 * found here:
5745090c893SKenneth D. Merry 	 *
5755090c893SKenneth D. Merry 	 * http://h20564.www2.hp.com/hpsc/doc/public/display?docId=emr_na-c01065117&sp4ts.oid=429311
5765090c893SKenneth D. Merry  	 * (Document ID c01065117)
57743518607SKenneth D. Merry 	 */
57843518607SKenneth D. Merry 	/*Num.  bpmm    bpi     Reference     */
57943518607SKenneth D. Merry 	{ 0x1,	32,	800,	"X3.22-1983" },
58043518607SKenneth D. Merry 	{ 0x2,	63,	1600,	"X3.39-1986" },
58143518607SKenneth D. Merry 	{ 0x3,	246,	6250,	"X3.54-1986" },
58243518607SKenneth D. Merry 	{ 0x5,	315,	8000,	"X3.136-1986" },
58343518607SKenneth D. Merry 	{ 0x6,	126,	3200,	"X3.157-1987" },
58443518607SKenneth D. Merry 	{ 0x7,	252,	6400,	"X3.116-1986" },
58543518607SKenneth D. Merry 	{ 0x8,	315,	8000,	"X3.158-1987" },
58643518607SKenneth D. Merry 	{ 0x9,	491,	37871,	"X3.180" },
58743518607SKenneth D. Merry 	{ 0xA,	262,	6667,	"X3B5/86-199" },
58843518607SKenneth D. Merry 	{ 0xB,	63,	1600,	"X3.56-1986" },
58943518607SKenneth D. Merry 	{ 0xC,	500,	12690,	"HI-TC1" },
59043518607SKenneth D. Merry 	{ 0xD,	999,	25380,	"HI-TC2" },
59143518607SKenneth D. Merry 	{ 0xF,	394,	10000,	"QIC-120" },
59243518607SKenneth D. Merry 	{ 0x10,	394,	10000,	"QIC-150" },
59343518607SKenneth D. Merry 	{ 0x11,	630,	16000,	"QIC-320" },
59443518607SKenneth D. Merry 	{ 0x12,	2034,	51667,	"QIC-1350" },
59543518607SKenneth D. Merry 	{ 0x13,	2400,	61000,	"X3B5/88-185A" },
59643518607SKenneth D. Merry 	{ 0x14,	1703,	43245,	"X3.202-1991" },
59743518607SKenneth D. Merry 	{ 0x15,	1789,	45434,	"ECMA TC17" },
59843518607SKenneth D. Merry 	{ 0x16,	394,	10000,	"X3.193-1990" },
59943518607SKenneth D. Merry 	{ 0x17,	1673,	42500,	"X3B5/91-174" },
60043518607SKenneth D. Merry 	{ 0x18,	1673,	42500,	"X3B5/92-50" },
60143518607SKenneth D. Merry 	{ 0x19, 2460,   62500,  "DLTapeIII" },
60243518607SKenneth D. Merry 	{ 0x1A, 3214,   81633,  "DLTapeIV(20GB)" },
60343518607SKenneth D. Merry 	{ 0x1B, 3383,   85937,  "DLTapeIV(35GB)" },
60443518607SKenneth D. Merry 	{ 0x1C, 1654,	42000,	"QIC-385M" },
60543518607SKenneth D. Merry 	{ 0x1D,	1512,	38400,	"QIC-410M" },
60643518607SKenneth D. Merry 	{ 0x1E, 1385,	36000,	"QIC-1000C" },
60743518607SKenneth D. Merry 	{ 0x1F,	2666,	67733,	"QIC-2100C" },
60843518607SKenneth D. Merry 	{ 0x20, 2666,	67733,	"QIC-6GB(M)" },
60943518607SKenneth D. Merry 	{ 0x21,	2666,	67733,	"QIC-20GB(C)" },
61043518607SKenneth D. Merry 	{ 0x22,	1600,	40640,	"QIC-2GB(C)" },
61143518607SKenneth D. Merry 	{ 0x23, 2666,	67733,	"QIC-875M" },
61243518607SKenneth D. Merry 	{ 0x24,	2400,	61000,	"DDS-2" },
61343518607SKenneth D. Merry 	{ 0x25,	3816,	97000,	"DDS-3" },
61443518607SKenneth D. Merry 	{ 0x26,	3816,	97000,	"DDS-4" },
61543518607SKenneth D. Merry 	{ 0x27,	3056,	77611,	"Mammoth" },
61643518607SKenneth D. Merry 	{ 0x28,	1491,	37871,	"X3.224" },
61743518607SKenneth D. Merry 	{ 0x40, 4880,   123952, "LTO-1" },
61843518607SKenneth D. Merry 	{ 0x41, 3868,   98250,  "DLTapeIV(40GB)" },
61943518607SKenneth D. Merry 	{ 0x42, 7398,   187909, "LTO-2" },
62043518607SKenneth D. Merry 	{ 0x44, 9638,   244805, "LTO-3" },
62143518607SKenneth D. Merry 	{ 0x46, 12725,  323215, "LTO-4" },
6225090c893SKenneth D. Merry 	{ 0x47, 6417,   163000, "DAT-72" },
6235090c893SKenneth D. Merry 	/*
6245090c893SKenneth D. Merry 	 * XXX KDM note that 0x48 is also the density code for DAT-160.
6255090c893SKenneth D. Merry 	 * For some reason they used overlapping density codes.
6265090c893SKenneth D. Merry 	 */
6275090c893SKenneth D. Merry #if 0
6285090c893SKenneth D. Merry 	{ 0x48, 6870,   174500, "DAT-160" },
6295090c893SKenneth D. Merry #endif
63043518607SKenneth D. Merry 	{ 0x48, 5236,   133000, "SDLTapeI(110)" },
63143518607SKenneth D. Merry 	{ 0x49, 7598,   193000, "SDLTapeI(160)" },
63243518607SKenneth D. Merry 	{ 0x4a,     0,       0, "T10000A" },
63343518607SKenneth D. Merry 	{ 0x4b,     0,       0, "T10000B" },
63443518607SKenneth D. Merry 	{ 0x4c,     0,       0, "T10000C" },
63543518607SKenneth D. Merry 	{ 0x4d,     0,       0, "T10000D" },
63643518607SKenneth D. Merry 	{ 0x51, 11800,  299720, "3592A1 (unencrypted)" },
63743518607SKenneth D. Merry 	{ 0x52, 11800,  299720, "3592A2 (unencrypted)" },
63843518607SKenneth D. Merry 	{ 0x53, 13452,  341681, "3592A3 (unencrypted)" },
63943518607SKenneth D. Merry 	{ 0x54, 19686,  500024, "3592A4 (unencrypted)" },
64043518607SKenneth D. Merry 	{ 0x55, 20670,  525018, "3592A5 (unencrypted)" },
641683b025aSKenneth D. Merry 	{ 0x56, 20670,  525018, "3592B5 (unencrypted)" },
6420caf9bf6SKenneth D. Merry 	{ 0x57, 21850,  554990, "3592A6 (unencrypted)" },
64343518607SKenneth D. Merry 	{ 0x58, 15142,  384607, "LTO-5" },
644*83823d06SKenneth D. Merry 	{ 0x59, 21850,  554990, "3592A7 (unencrypted)" },
64543518607SKenneth D. Merry 	{ 0x5A, 15142,  384607, "LTO-6" },
646f4bf2442SKenneth D. Merry 	{ 0x5C, 19107,  485318, "LTO-7" },
64770a83493SKenneth D. Merry 	{ 0x5D, 19107,  485318, "LTO-M8" },
6480183e015SKenneth D. Merry 	{ 0x5E, 20669,  524993, "LTO-8" },
64978adacd4SKenneth D. Merry 	{ 0x60, 23031,  584987, "LTO-9" },
65043518607SKenneth D. Merry 	{ 0x71, 11800,  299720, "3592A1 (encrypted)" },
65143518607SKenneth D. Merry 	{ 0x72, 11800,  299720, "3592A2 (encrypted)" },
65243518607SKenneth D. Merry 	{ 0x73, 13452,  341681, "3592A3 (encrypted)" },
65343518607SKenneth D. Merry 	{ 0x74, 19686,  500024, "3592A4 (encrypted)" },
65443518607SKenneth D. Merry 	{ 0x75, 20670,  525018, "3592A5 (encrypted)" },
655683b025aSKenneth D. Merry 	{ 0x76, 20670,  525018, "3592B5 (encrypted)" },
6560caf9bf6SKenneth D. Merry 	{ 0x77, 21850,  554990, "3592A6 (encrypted)" },
657*83823d06SKenneth D. Merry 	{ 0x79, 21850,  554990, "3592A7 (encrypted)" },
65843518607SKenneth D. Merry 	{ 0x8c,  1789,   45434, "EXB-8500c" },
65943518607SKenneth D. Merry 	{ 0x90,  1703,   43245, "EXB-8200c" },
66043518607SKenneth D. Merry 	{ 0, 0, 0, NULL }
66143518607SKenneth D. Merry };
66243518607SKenneth D. Merry 
66343518607SKenneth D. Merry const char *
mt_density_name(int density_num)66443518607SKenneth D. Merry mt_density_name(int density_num)
66543518607SKenneth D. Merry {
66643518607SKenneth D. Merry 	struct densities *sd;
66743518607SKenneth D. Merry 
66843518607SKenneth D. Merry 	/* densities 0 and 0x7f are handled as special cases */
66943518607SKenneth D. Merry 	if (density_num == 0)
67043518607SKenneth D. Merry 		return ("default");
67143518607SKenneth D. Merry 	if (density_num == 0x7f)
67243518607SKenneth D. Merry 		return ("same");
67343518607SKenneth D. Merry 
67443518607SKenneth D. Merry 	for (sd = dens; sd->dens != 0; sd++)
67543518607SKenneth D. Merry 		if (sd->dens == density_num)
67643518607SKenneth D. Merry 			break;
67743518607SKenneth D. Merry 	if (sd->dens == 0)
67843518607SKenneth D. Merry 		return ("UNKNOWN");
67943518607SKenneth D. Merry 	return (sd->name);
68043518607SKenneth D. Merry }
68143518607SKenneth D. Merry 
68243518607SKenneth D. Merry /*
68343518607SKenneth D. Merry  * Given a specific density number, return either the bits per inch or bits
68443518607SKenneth D. Merry  * per millimeter for the given density.
68543518607SKenneth D. Merry  */
68643518607SKenneth D. Merry int
mt_density_bp(int density_num,int bpi)68743518607SKenneth D. Merry mt_density_bp(int density_num, int bpi)
68843518607SKenneth D. Merry {
68943518607SKenneth D. Merry 	struct densities *sd;
69043518607SKenneth D. Merry 
69143518607SKenneth D. Merry 	for (sd = dens; sd->dens; sd++)
69243518607SKenneth D. Merry 		if (sd->dens == density_num)
69343518607SKenneth D. Merry 			break;
69443518607SKenneth D. Merry 	if (sd->dens == 0)
69543518607SKenneth D. Merry 		return (0);
69643518607SKenneth D. Merry 	if (bpi)
69743518607SKenneth D. Merry 		return (sd->bpi);
69843518607SKenneth D. Merry 	else
69943518607SKenneth D. Merry 		return (sd->bpmm);
70043518607SKenneth D. Merry }
70143518607SKenneth D. Merry 
70243518607SKenneth D. Merry int
mt_density_num(const char * density_name)70343518607SKenneth D. Merry mt_density_num(const char *density_name)
70443518607SKenneth D. Merry {
70543518607SKenneth D. Merry 	struct densities *sd;
70643518607SKenneth D. Merry 	size_t l = strlen(density_name);
70743518607SKenneth D. Merry 
70843518607SKenneth D. Merry 	for (sd = dens; sd->dens; sd++)
70943518607SKenneth D. Merry 		if (strncasecmp(sd->name, density_name, l) == 0)
71043518607SKenneth D. Merry 			break;
71143518607SKenneth D. Merry 	return (sd->dens);
71243518607SKenneth D. Merry }
71343518607SKenneth D. Merry 
71443518607SKenneth D. Merry /*
71543518607SKenneth D. Merry  * Get the current status XML string.
71643518607SKenneth D. Merry  * Returns 0 on success, -1 on failure (with errno set, and *xml_str == NULL).
71743518607SKenneth D. Merry  */
71843518607SKenneth D. Merry int
mt_get_xml_str(int mtfd,unsigned long cmd,char ** xml_str)71943518607SKenneth D. Merry mt_get_xml_str(int mtfd, unsigned long cmd, char **xml_str)
72043518607SKenneth D. Merry {
72143518607SKenneth D. Merry 	size_t alloc_len = 32768;
72243518607SKenneth D. Merry 	struct mtextget extget;
72343518607SKenneth D. Merry 	int error;
72443518607SKenneth D. Merry 
72543518607SKenneth D. Merry 	*xml_str = NULL;
72643518607SKenneth D. Merry 
72743518607SKenneth D. Merry 	for (;;) {
72843518607SKenneth D. Merry 		bzero(&extget, sizeof(extget));
72943518607SKenneth D. Merry 		*xml_str = malloc(alloc_len);
73043518607SKenneth D. Merry 		if (*xml_str == NULL)
73143518607SKenneth D. Merry 			return (-1);
73243518607SKenneth D. Merry 		extget.status_xml = *xml_str;
73343518607SKenneth D. Merry 		extget.alloc_len = alloc_len;
73443518607SKenneth D. Merry 
73543518607SKenneth D. Merry 		error = ioctl(mtfd, cmd, (caddr_t)&extget);
73643518607SKenneth D. Merry 		if (error == 0 && extget.status == MT_EXT_GET_OK)
73743518607SKenneth D. Merry 			break;
73843518607SKenneth D. Merry 
73943518607SKenneth D. Merry 		free(*xml_str);
74043518607SKenneth D. Merry 		*xml_str = NULL;
74143518607SKenneth D. Merry 
74243518607SKenneth D. Merry 		if (error != 0 || extget.status != MT_EXT_GET_NEED_MORE_SPACE)
74343518607SKenneth D. Merry 			return (-1);
74443518607SKenneth D. Merry 
74543518607SKenneth D. Merry 		/* The driver needs more space, so double and try again. */
74643518607SKenneth D. Merry 		alloc_len *= 2;
74743518607SKenneth D. Merry 	}
74843518607SKenneth D. Merry 	return (0);
74943518607SKenneth D. Merry }
75043518607SKenneth D. Merry 
75143518607SKenneth D. Merry /*
75243518607SKenneth D. Merry  * Populate a struct mt_status_data from the XML string via mt_get_xml_str().
75343518607SKenneth D. Merry  *
75443518607SKenneth D. Merry  * Returns XML_STATUS_OK on success.
75543518607SKenneth D. Merry  * If XML_STATUS_ERROR is returned, errno may be set to indicate the reason.
75643518607SKenneth D. Merry  * The caller must check status_data->error.
75743518607SKenneth D. Merry  */
75843518607SKenneth D. Merry int
mt_get_status(char * xml_str,struct mt_status_data * status_data)75943518607SKenneth D. Merry mt_get_status(char *xml_str, struct mt_status_data *status_data)
76043518607SKenneth D. Merry {
76143518607SKenneth D. Merry 	XML_Parser parser;
76243518607SKenneth D. Merry 	int retval;
76343518607SKenneth D. Merry 
76443518607SKenneth D. Merry 	bzero(status_data, sizeof(*status_data));
76543518607SKenneth D. Merry 	STAILQ_INIT(&status_data->entries);
76643518607SKenneth D. Merry 
76743518607SKenneth D. Merry 	parser = XML_ParserCreate(NULL);
76843518607SKenneth D. Merry 	if (parser == NULL) {
76943518607SKenneth D. Merry 		errno = ENOMEM;
77043518607SKenneth D. Merry 		return (XML_STATUS_ERROR);
77143518607SKenneth D. Merry 	}
77243518607SKenneth D. Merry 
77343518607SKenneth D. Merry 	XML_SetUserData(parser, status_data);
77443518607SKenneth D. Merry 	XML_SetElementHandler(parser, mt_start_element, mt_end_element);
77543518607SKenneth D. Merry 	XML_SetCharacterDataHandler(parser, mt_char_handler);
77643518607SKenneth D. Merry 
77743518607SKenneth D. Merry 	retval = XML_Parse(parser, xml_str, strlen(xml_str), 1);
77843518607SKenneth D. Merry 	XML_ParserFree(parser);
77943518607SKenneth D. Merry 	return (retval);
78043518607SKenneth D. Merry }
781