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
meta_print_name(mdsetname_t * sp,mdname_t * namep,mdnamelist_t ** nlpp,char * fname,FILE * fp,mdprtopts_t options,mdnamelist_t ** lognlpp,md_error_t * ep)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
meta_print_all(mdsetname_t * sp,char * fname,mdnamelist_t ** nlpp,FILE * fp,mdprtopts_t options,int * meta_print_trans_msgp,md_error_t * ep)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 *
meta_print_time(md_timeval32_t * tvp)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 *
meta_print_hrtime(hrtime_t secs)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
meta_prbits(FILE * fp,const char * fmt,...)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 *
meta_number_to_string(diskaddr_t number,u_longlong_t blk_sz)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
meta_get_tstate(md_dev64_t dev64,uint_t * tstatep,md_error_t * ep)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(¶ms, 0, sizeof (params));
356 params.id = mnum;
357 if (metaioctl(MD_IOCGET_TSTATE, ¶ms, ¶ms.mde, NULL) != 0) {
358 return (mdstealerror(ep, ¶ms.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
meta_print_devid(mdsetname_t * sp,FILE * fp,mddevid_t * mddevidp,md_error_t * ep)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