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(¶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 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