xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_print.c (revision 989f28072d20c73ae0955d6a1e3e2fc74831cb39)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Just in case we're not in a build environment, make sure that
31  * TEXT_DOMAIN gets set to something.
32  */
33 #if !defined(TEXT_DOMAIN)
34 #define	TEXT_DOMAIN "SYS_TEST"
35 #endif
36 
37 /*
38  * report metadevice status
39  */
40 
41 #include <meta.h>
42 
43 /*
44  * print named metadevice
45  */
46 int
47 meta_print_name(
48 	mdsetname_t	*sp,
49 	mdname_t	*namep,
50 	mdnamelist_t   **nlpp,
51 	char		*fname,
52 	FILE		*fp,
53 	mdprtopts_t	options,
54 	mdnamelist_t	**lognlpp,
55 	md_error_t	*ep
56 )
57 {
58 	char		*miscname;
59 
60 	/* must have set */
61 	assert(sp != NULL);
62 
63 	/* get type */
64 	if ((miscname = metagetmiscname(namep, ep)) == NULL)
65 		return (-1);
66 
67 	/* dispatch */
68 	if (strcmp(miscname, MD_TRANS) == 0) {
69 		return (meta_trans_print(sp, namep, nlpp, fname, fp,
70 		    options, NULL, lognlpp, ep));
71 	}
72 	if (strcmp(miscname, MD_MIRROR) == 0) {
73 		return (meta_mirror_print(sp, namep, nlpp, fname, fp,
74 		    options, ep));
75 	}
76 	if (strcmp(miscname, MD_RAID) == 0) {
77 		return (meta_raid_print(sp, namep, nlpp, fname, fp,
78 		    options, ep));
79 	}
80 	if (strcmp(miscname, MD_STRIPE) == 0) {
81 		return (meta_stripe_print(sp, namep, nlpp, fname, fp,
82 		    options, ep));
83 	}
84 	if (strcmp(miscname, MD_SP) == 0) {
85 		return (meta_sp_print(sp, namep, nlpp, fname, fp,
86 		    options, ep));
87 	}
88 
89 	/* unknown type */
90 	return (mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(namep->dev),
91 	    namep->cname));
92 }
93 
94 /*
95  * print all metadevices
96  */
97 int
98 meta_print_all(
99 	mdsetname_t	*sp,
100 	char		*fname,
101 	mdnamelist_t	**nlpp,
102 	FILE		*fp,
103 	mdprtopts_t	options,
104 	int		*meta_print_trans_msgp,
105 	md_error_t	*ep
106 )
107 {
108 	md_error_t	status = mdnullerror;
109 	int		rval = 0;
110 	mdnamelist_t	*lognlp = NULL;
111 
112 
113 	/* print various types (save first error) */
114 	if (meta_trans_print(sp, NULL, nlpp, fname, fp, options,
115 	    meta_print_trans_msgp, &lognlp, ep) != 0) {
116 		rval = -1;
117 		ep = &status;
118 	}
119 	if (meta_logs_print(sp, lognlp, nlpp, fname, fp, options, ep) != 0) {
120 		rval = -1;
121 		ep = &status;
122 	}
123 	metafreenamelist(lognlp);
124 	if (meta_mirror_print(sp, NULL, nlpp, fname, fp, options, ep) != 0) {
125 		rval = -1;
126 		ep = &status;
127 	}
128 	if (meta_raid_print(sp, NULL, nlpp, fname, fp, options, ep) != 0) {
129 		rval = -1;
130 		ep = &status;
131 	}
132 	if (meta_stripe_print(sp, NULL, nlpp, fname, fp, options, ep) != 0) {
133 		rval = -1;
134 		ep = &status;
135 	}
136 	if (meta_sp_print(sp, NULL, nlpp, fname, fp, options, ep) != 0) {
137 		rval = -1;
138 		ep = &status;
139 	}
140 	if (meta_hsp_print(sp, NULL, nlpp, fname, fp, options, ep) != 0) {
141 		rval = -1;
142 		ep = &status;
143 	}
144 
145 	/* discard further errors */
146 	mdclrerror(&status);
147 
148 	/* return success */
149 	return (rval);
150 }
151 
152 /*
153  * format timestamp
154  */
155 char *
156 meta_print_time(
157 	md_timeval32_t	*tvp
158 )
159 {
160 	static char	buf[128];
161 	struct tm	*tmp;
162 	char		*dcmsg;
163 
164 	if (tvp == NULL)
165 		return ("");
166 
167 	/*
168 	 * TRANSLATION_NOTE_LC_TIME
169 	 * This message is the format of file
170 	 * timestamps written with the -C and
171 	 * -c options.
172 	 * %a -- locale's abbreviated weekday name
173 	 * %b -- locale's abbreviated month name
174 	 * %e -- day of month [1,31]
175 	 * %T -- Time as %H:%M:%S
176 	 * %Y -- Year, including the century
177 	 */
178 	dcmsg = dcgettext(TEXT_DOMAIN, "%a %b %e %T %Y", LC_TIME);
179 
180 	if (((tvp->tv_sec == 0) && (tvp->tv_usec == 0)) ||
181 	    ((tmp = localtime((const time_t *)&tvp->tv_sec)) == NULL) ||
182 	    (strftime(buf, sizeof (buf), dcmsg, tmp) == 0)) {
183 		return (dgettext(TEXT_DOMAIN, "(invalid time)"));
184 	}
185 	return (buf);
186 }
187 
188 /*
189  * format high resolution time into a tuple of seconds:milliseconds:microseconds
190  */
191 char *
192 meta_print_hrtime(
193 	hrtime_t	secs
194 )
195 {
196 	long long	sec, msec, usec;
197 	static char	buf[128];
198 
199 	usec = secs / 1000;
200 	msec = usec / 1000;
201 	sec  = msec / 1000;
202 	msec %= 1000;
203 	usec %= 1000;
204 
205 	(void) snprintf(buf, sizeof (buf), "%4lld:%03lld:%03lld", sec, msec,
206 	    usec);
207 	return (buf);
208 }
209 
210 /*
211  * Routine to print 32 bit bitmasks
212  *
213  * Takes:
214  *	fp	- a file descriptor
215  *	fmt	- optional text
216  *	ul	- unsigned long bit vector
217  *	bitfmt	- special string to map bits to words.
218  *		bitfmt is layed out as follows:
219  *			byte 0 is the output base.
220  *			byte 1 a bit position less than 32
221  *			byte 2-n text for position in byte 1
222  *			byte n+1 another bit position
223  *			byte n+2-m text for position in byte n+1
224  *				.
225  *				.
226  *				.
227  *
228  *		Eg. - "\020\001DOG\002CAT\003PIG"
229  *		Print the bitmask in hex.
230  *		If bit 1 (0x0001) is set print "<DOG>"
231  *		If bit 2 (0x0002) is set print "<CAT>"
232  *		If bit 3 (0x0004) is set print "<PIG>"
233  *		If bit 4 (0x0008) is set nothing is printed.
234  *		If bit 1 and bit 2 (0x0003) are set print <DOG,CAT>
235  *
236  *	Returns 0 on OK
237  *		EOF on error
238  *
239  *	Outputs on fp
240  *
241  */
242 
243 int
244 meta_prbits(FILE *fp, const char *fmt, ...)
245 {
246 	va_list		ap;
247 	unsigned long	ul;
248 	int		set;
249 	int		n;
250 	char		*p;
251 
252 	va_start(ap, fmt);
253 
254 	if (fmt && *fmt)
255 		if (fprintf(fp, fmt) == EOF)
256 			return (EOF);
257 
258 	ul = va_arg(ap, int);
259 	p = va_arg(ap, char *);
260 
261 	switch (*p++) {
262 	    case 8:
263 		if (fprintf(fp, "0%lo", ul) == EOF)
264 			return (EOF);
265 		break;
266 
267 	    case 16:
268 		if (fprintf(fp, "0x%lx", ul) == EOF)
269 			return (EOF);
270 		break;
271 
272 	    default:
273 	    case 10:
274 		if (fprintf(fp, "%ld", ul) == EOF)
275 			return (EOF);
276 		break;
277 	}
278 
279 	if (! ul)
280 		return (0);
281 
282 	for (set = 0; (n = *p++) != '\0'; /* void */) {
283 		if (ul & (1 << (n - 1))) {
284 			if (fputc(set ? ',' : '<', fp) == EOF)
285 				return (EOF);
286 			for (/* void */; (n = *p) > ' '; ++p)
287 				if (fputc(n, fp) == EOF)
288 					return (EOF);
289 			set = 1;
290 		} else
291 			for (/* void */; *p > ' '; ++p);
292 	}
293 	if (set)
294 		if (fputc('>', fp) == EOF)
295 			return (EOF);
296 
297 	return (0);
298 }
299 
300 
301 /*
302  * Convert a number of blocks to a string representation
303  * Input:  64 bit wide number of blocks
304  * Outout: string like "199MB" or "27TB" or "3.5GB"
305  * Returns a pointer to the buffer.
306  */
307 char *
308 meta_number_to_string(diskaddr_t number, u_longlong_t blk_sz)
309 {
310 	diskaddr_t save = 0;
311 	char *M = " KMGTPE"; /* kilo, mega, giga, tera, peta, exa */
312 	char *uom = M;    /* unit of measurement, initially ' ' (=M[0]) */
313 	static char buf[64];
314 	u_longlong_t	total_bytes;
315 
316 	/* convert from blocks to bytes */
317 	total_bytes = number * blk_sz;
318 
319 	/*
320 	 * Stop scaling when we reached exa bytes, then something is
321 	 * probably wrong with our number.
322 	 */
323 	while ((total_bytes >= 1024) && (*uom != 'E')) {
324 		uom++; /* next unit of measurement */
325 		save = total_bytes;
326 		total_bytes = total_bytes / 1024;
327 	}
328 
329 	/* check if we should output a decimal place after the point */
330 	if (save && ((save / 1024) < 10)) {
331 		/* sprintf() will round for us */
332 		float fnum = (float)save / 1024;
333 		(void) sprintf(buf, "%1.1f %cB", fnum, *uom);
334 	} else {
335 		(void) sprintf(buf, "%llu %cB", total_bytes, *uom);
336 	}
337 	return (buf);
338 }
339 
340 /*
341  * meta_get_tstate: get the transient state bits from the kernel.
342  * this is for use with printing out the state field in metastat.
343  * INPUT: dev64 -- devt of the metadevice
344  *	  tstatep -- return for tstate
345  *	  ep	-- error
346  * RETURN: -1 for error
347  *	    0 for success
348  */
349 int
350 meta_get_tstate(md_dev64_t dev64, uint_t *tstatep, md_error_t *ep)
351 {
352 	md_i_get_tstate_t	params;
353 	minor_t			mnum = meta_getminor(dev64);
354 
355 	(void) memset(&params, 0, sizeof (params));
356 	params.id = mnum;
357 	if (metaioctl(MD_IOCGET_TSTATE, &params, &params.mde, NULL) != 0) {
358 		return (mdstealerror(ep, &params.mde));
359 	}
360 	*tstatep = params.tstate;
361 	return (0);
362 }
363 
364 /*
365  * meta_print_devid: print out the devid information, given a mddevid_t list.
366  * INPUT: mdsetname_t	set we're looking at
367  *	  FILE	where to print to
368  *        mddevid_t list to print from.
369  *	  md_error_t	error
370  * RETURN: -1 for error
371  *          0 for success
372  */
373 int
374 meta_print_devid(
375 	mdsetname_t	*sp,
376 	FILE		*fp,
377 	mddevid_t	*mddevidp,
378 	md_error_t	*ep
379 )
380 {
381 	int		len = 0;
382 	mddevid_t	*tmp_mddevidp = NULL;
383 	ddi_devid_t	did = NULL;
384 	char		*devid = "";
385 	int		freedevid = 0;
386 	char		*reloc = "";
387 
388 
389 	/* print header */
390 	if (fprintf(fp, gettext("Device Relocation Information:\n")) < 0)
391 		return (-1);
392 
393 	/*
394 	 * Building a format string on the fly that will
395 	 * be used in (f)printf. This allows the length
396 	 * of the ctd to vary from small to large without
397 	 * looking horrible.
398 	 */
399 
400 	tmp_mddevidp = mddevidp;
401 	while (tmp_mddevidp != NULL) {
402 		len = max(len, strlen(tmp_mddevidp->ctdname));
403 		tmp_mddevidp = tmp_mddevidp->next;
404 	}
405 
406 	if (fprintf(fp, "%-*s %-5s\t%s\n", len + 2,
407 	    gettext("Device  "),
408 	    gettext("Reloc"),
409 	    gettext("Device ID")) < 0)
410 		return (-1);
411 
412 	/* print ctd's and devids */
413 	while (mddevidp != NULL) {
414 		did = (ddi_devid_t)
415 		    meta_getdidbykey(sp->setno, getmyside(sp, ep),
416 		    mddevidp->key, ep);
417 
418 		if (did == (ddi_devid_t)NULL) {
419 			devid = "-";
420 			reloc = gettext("No ");
421 			freedevid = 0;
422 		} else {
423 			devid = devid_str_encode(did, NULL);
424 			reloc = gettext("Yes");
425 			freedevid = 1;
426 			Free(did);
427 		}
428 
429 		if (fprintf(fp, "%-*s %-5s\t%s\n", len + 2, mddevidp->ctdname,
430 		    reloc, devid) < 0)
431 			return (-1);
432 
433 		mddevidp = mddevidp->next;
434 
435 		if (freedevid == 1)
436 			devid_str_free(devid);
437 	}
438 	return (0);
439 }
440