libefi: import efichar.c for ucs2 support
[unleashed.git] / usr / src / cmd / diskinfo / diskinfo.c
blobc38d52170ed2adab3b337ebccb5441d6e2af095f
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2013 Joyent Inc., All rights reserved.
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <limits.h>
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <strings.h>
29 #include <libdiskmgt.h>
30 #include <sys/nvpair.h>
31 #include <sys/param.h>
32 #include <sys/ccompile.h>
34 #include <fm/libtopo.h>
35 #include <fm/topo_hc.h>
36 #include <fm/topo_list.h>
37 #include <sys/fm/protocol.h>
38 #include <modules/common/disk/disk.h>
40 typedef struct di_opts {
41 boolean_t di_scripted;
42 boolean_t di_parseable;
43 boolean_t di_physical;
44 boolean_t di_condensed;
45 } di_opts_t;
47 typedef struct di_phys {
48 const char *dp_dev;
49 const char *dp_serial;
50 const char *dp_slotname;
51 int dp_chassis;
52 int dp_slot;
53 int dp_faulty;
54 int dp_locate;
55 } di_phys_t;
57 static void __NORETURN
58 fatal(int rv, const char *fmt, ...)
60 va_list ap;
62 va_start(ap, fmt);
63 (void) vfprintf(stderr, fmt, ap);
64 va_end(ap);
66 exit(rv);
69 static void
70 usage(const char *execname)
72 (void) fprintf(stderr, "Usage: %s [-Hp] [{-c|-P}]\n", execname);
75 static void
76 nvlist_query_string(nvlist_t *nvl, const char *label, char **val)
78 if (nvlist_lookup_string(nvl, label, val) != 0)
79 *val = "-";
82 static const char *
83 display_string(const char *label)
85 return ((label) ? label : "-");
88 static const char *
89 display_tristate(int val)
91 if (val == 0)
92 return ("no");
93 if (val == 1)
94 return ("yes");
96 return ("-");
99 static char
100 condensed_tristate(int val, char c)
102 if (val == 0)
103 return ('-');
104 if (val == 1)
105 return (c);
107 return ('?');
109 static int
110 disk_walker(topo_hdl_t *hp, tnode_t *np, void *arg)
112 di_phys_t *pp = arg;
113 tnode_t *pnp;
114 tnode_t *ppnp;
115 topo_faclist_t fl;
116 topo_faclist_t *lp;
117 int err;
118 topo_led_state_t mode;
119 topo_led_type_t type;
120 char *name, *slotname, *serial;
122 if (strcmp(topo_node_name(np), DISK) != 0)
123 return (TOPO_WALK_NEXT);
125 if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
126 TOPO_STORAGE_LOGICAL_DISK_NAME, &name, &err) != 0) {
127 return (TOPO_WALK_NEXT);
130 if (strcmp(name, pp->dp_dev) != 0)
131 return (TOPO_WALK_NEXT);
133 if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE,
134 TOPO_STORAGE_SERIAL_NUM, &serial, &err) == 0) {
135 pp->dp_serial = serial;
138 pnp = topo_node_parent(np);
139 ppnp = topo_node_parent(pnp);
140 if (strcmp(topo_node_name(pnp), BAY) == 0) {
141 if (topo_node_facility(hp, pnp, TOPO_FAC_TYPE_INDICATOR,
142 TOPO_FAC_TYPE_ANY, &fl, &err) == 0) {
143 for (lp = topo_list_next(&fl.tf_list); lp != NULL;
144 lp = topo_list_next(lp)) {
145 uint32_t prop;
147 if (topo_prop_get_uint32(lp->tf_node,
148 TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
149 &prop, &err) != 0) {
150 continue;
152 type = (topo_led_type_t)prop;
154 if (topo_prop_get_uint32(lp->tf_node,
155 TOPO_PGROUP_FACILITY, TOPO_LED_MODE,
156 &prop, &err) != 0) {
157 continue;
159 mode = (topo_led_state_t)prop;
161 switch (type) {
162 case TOPO_LED_TYPE_SERVICE:
163 pp->dp_faulty = mode ? 1 : 0;
164 break;
165 case TOPO_LED_TYPE_LOCATE:
166 pp->dp_locate = mode ? 1 : 0;
167 break;
168 default:
169 break;
174 if (topo_prop_get_string(pnp, TOPO_PGROUP_PROTOCOL,
175 TOPO_PROP_LABEL, &slotname, &err) == 0) {
176 pp->dp_slotname = slotname;
179 pp->dp_slot = topo_node_instance(pnp);
182 pp->dp_chassis = topo_node_instance(ppnp);
184 return (TOPO_WALK_TERMINATE);
187 static void
188 populate_physical(topo_hdl_t *hp, di_phys_t *pp)
190 int err;
191 topo_walk_t *wp;
193 pp->dp_faulty = pp->dp_locate = -1;
194 pp->dp_chassis = pp->dp_slot = -1;
196 err = 0;
197 wp = topo_walk_init(hp, FM_FMRI_SCHEME_HC, disk_walker, pp, &err);
198 if (wp == NULL) {
199 fatal(-1, "unable to initialise topo walker: %s",
200 topo_strerror(err));
203 while ((err = topo_walk_step(wp, TOPO_WALK_CHILD)) == TOPO_WALK_NEXT)
206 if (err == TOPO_WALK_ERR)
207 fatal(-1, "topo walk failed");
209 topo_walk_fini(wp);
212 static void
213 enumerate_disks(di_opts_t *opts)
215 topo_hdl_t *hp;
216 dm_descriptor_t *media;
217 int err, i;
218 int filter[] = { DM_DT_FIXED, -1 };
219 dm_descriptor_t *disk, *controller;
220 nvlist_t *mattrs, *dattrs, *cattrs = NULL;
222 uint64_t size, total;
223 uint32_t blocksize;
224 double total_in_GiB;
225 char sizestr[32];
226 char slotname[32];
227 char statestr[8];
229 char *vid, *pid, *opath, *c, *ctype = NULL;
230 boolean_t removable;
231 boolean_t ssd;
232 char device[MAXPATHLEN];
233 di_phys_t phys;
234 size_t len;
236 err = 0;
237 if ((media = dm_get_descriptors(DM_MEDIA, filter, &err)) == NULL) {
238 fatal(-1, "failed to obtain media descriptors: %s\n",
239 strerror(err));
242 err = 0;
243 hp = topo_open(TOPO_VERSION, NULL, &err);
244 if (hp == NULL) {
245 fatal(-1, "unable to obtain topo handle: %s",
246 topo_strerror(err));
249 err = 0;
250 (void) topo_snap_hold(hp, NULL, &err);
251 if (err != 0) {
252 fatal(-1, "unable to hold topo snapshot: %s",
253 topo_strerror(err));
256 for (i = 0; media != NULL && media[i] != 0; i++) {
257 if ((disk = dm_get_associated_descriptors(media[i],
258 DM_DRIVE, &err)) == NULL) {
259 continue;
262 mattrs = dm_get_attributes(media[i], &err);
263 err = nvlist_lookup_uint64(mattrs, DM_SIZE, &size);
264 assert(err == 0);
265 err = nvlist_lookup_uint32(mattrs, DM_BLOCKSIZE, &blocksize);
266 assert(err == 0);
267 nvlist_free(mattrs);
269 dattrs = dm_get_attributes(disk[0], &err);
271 nvlist_query_string(dattrs, DM_VENDOR_ID, &vid);
272 nvlist_query_string(dattrs, DM_PRODUCT_ID, &pid);
273 nvlist_query_string(dattrs, DM_OPATH, &opath);
275 removable = B_FALSE;
276 if (nvlist_lookup_boolean(dattrs, DM_REMOVABLE) == 0)
277 removable = B_TRUE;
279 ssd = B_FALSE;
280 if (nvlist_lookup_boolean(dattrs, DM_SOLIDSTATE) == 0)
281 ssd = B_TRUE;
283 if ((controller = dm_get_associated_descriptors(disk[0],
284 DM_CONTROLLER, &err)) != NULL) {
285 cattrs = dm_get_attributes(controller[0], &err);
286 nvlist_query_string(cattrs, DM_CTYPE, &ctype);
287 ctype = strdup(ctype);
288 for (c = ctype; *c != '\0'; c++)
289 *c = toupper(*c);
293 * Parse full device path to only show the device name,
294 * i.e. c0t1d0. Many paths will reference a particular
295 * slice (c0t1d0s0), so remove the slice if present.
297 if ((c = strrchr(opath, '/')) != NULL)
298 (void) strlcpy(device, c + 1, sizeof (device));
299 else
300 (void) strlcpy(device, opath, sizeof (device));
301 len = strlen(device);
302 if (device[len - 2] == 's' &&
303 (device[len - 1] >= '0' && device[len - 1] <= '9'))
304 device[len - 2] = '\0';
306 bzero(&phys, sizeof (phys));
307 phys.dp_dev = device;
308 populate_physical(hp, &phys);
311 * The size is given in blocks, so multiply the number
312 * of blocks by the block size to get the total size,
313 * then convert to GiB.
315 total = size * blocksize;
317 if (opts->di_parseable) {
318 (void) snprintf(sizestr, sizeof (sizestr),
319 "%llu", total);
320 } else {
321 total_in_GiB = (double)total /
322 1024.0 / 1024.0 / 1024.0;
323 (void) snprintf(sizestr, sizeof (sizestr),
324 "%7.2f GiB", total_in_GiB);
327 if (opts->di_parseable) {
328 (void) snprintf(slotname, sizeof (slotname), "%d,%d",
329 phys.dp_chassis, phys.dp_slot);
330 } else if (phys.dp_slotname != NULL) {
331 (void) snprintf(slotname, sizeof (slotname),
332 "[%d] %s", phys.dp_chassis, phys.dp_slotname);
333 } else {
334 slotname[0] = '-';
335 slotname[1] = '\0';
338 if (opts->di_condensed) {
339 (void) snprintf(statestr, sizeof (statestr), "%c%c%c%c",
340 condensed_tristate(phys.dp_faulty, 'F'),
341 condensed_tristate(phys.dp_locate, 'L'),
342 condensed_tristate(removable, 'R'),
343 condensed_tristate(ssd, 'S'));
346 if (opts->di_physical) {
347 if (opts->di_scripted) {
348 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
349 device, vid, pid,
350 display_string(phys.dp_serial),
351 display_tristate(phys.dp_faulty),
352 display_tristate(phys.dp_locate), slotname);
353 } else {
354 printf("%-22s %-8s %-16s "
355 "%-20s %-3s %-3s %s\n",
356 device, vid, pid,
357 display_string(phys.dp_serial),
358 display_tristate(phys.dp_faulty),
359 display_tristate(phys.dp_locate), slotname);
361 } else if (opts->di_condensed) {
362 if (opts->di_scripted) {
363 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
364 ctype, device, vid, pid,
365 display_string(phys.dp_serial),
366 sizestr, statestr, slotname);
367 } else {
368 printf("%-7s %-22s %-8s %-16s "
369 "%-20s\n\t%-13s %-4s %s\n",
370 ctype, device, vid, pid,
371 display_string(phys.dp_serial),
372 sizestr, statestr, slotname);
374 } else {
375 if (opts->di_scripted) {
376 printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
377 ctype, device, vid, pid, sizestr,
378 display_tristate(removable),
379 display_tristate(ssd));
380 } else {
381 printf("%-7s %-22s %-8s %-16s "
382 "%-13s %-3s %-3s\n", ctype, device,
383 vid, pid, sizestr,
384 display_tristate(removable),
385 display_tristate(ssd));
389 free(ctype);
390 nvlist_free(cattrs);
391 nvlist_free(dattrs);
392 dm_free_descriptors(controller);
393 dm_free_descriptors(disk);
396 dm_free_descriptors(media);
397 topo_snap_release(hp);
398 topo_close(hp);
402 main(int argc, char *argv[])
404 char c;
406 di_opts_t opts = {
407 .di_condensed = B_FALSE,
408 .di_scripted = B_FALSE,
409 .di_physical = B_FALSE,
410 .di_parseable = B_FALSE
413 while ((c = getopt(argc, argv, ":cHPp")) != EOF) {
414 switch (c) {
415 case 'c':
416 if (opts.di_physical) {
417 usage(argv[0]);
418 fatal(1, "-c and -P are mutually exclusive\n");
420 opts.di_condensed = B_TRUE;
421 break;
422 case 'H':
423 opts.di_scripted = B_TRUE;
424 break;
425 case 'P':
426 if (opts.di_condensed) {
427 usage(argv[0]);
428 fatal(1, "-c and -P are mutually exclusive\n");
430 opts.di_physical = B_TRUE;
431 break;
432 case 'p':
433 opts.di_parseable = B_TRUE;
434 break;
435 case '?':
436 usage(argv[0]);
437 fatal(1, "unknown option -%c\n", optopt);
438 default:
439 fatal(-1, "unexpected error on option -%c\n", optopt);
443 if (!opts.di_scripted) {
444 if (opts.di_physical) {
445 printf("DISK VID PID"
446 " SERIAL FLT LOC"
447 " LOCATION\n");
448 } else if (opts.di_condensed) {
449 printf("TYPE DISK VID PID"
450 " SERIAL\n");
451 printf("\tSIZE FLRS LOCATION\n");
452 } else {
453 printf("TYPE DISK VID PID"
454 " SIZE RMV SSD\n");
458 enumerate_disks(&opts);
460 return (0);