From ed5fe2f85936728de7ab82b44e9b9742c976d436 Mon Sep 17 00:00:00 2001 From: Yuri Pankov Date: Sun, 15 Jan 2017 13:11:53 +0300 Subject: [PATCH] 7771 integrate diskinfo Reviewed by: Hans Rosenfeld Reviewed by: Toomas Soome Reviewed by: Dale Ghent Approved by: Dan McDonald --- usr/src/cmd/Makefile | 1 + usr/src/cmd/diskinfo/Makefile | 40 +++ usr/src/cmd/diskinfo/diskinfo.c | 456 +++++++++++++++++++++++++++ usr/src/man/man1m/Makefile | 1 + usr/src/man/man1m/diskinfo.1m | 191 +++++++++++ usr/src/pkg/manifests/diagnostic-diskinfo.mf | 33 ++ 6 files changed, 722 insertions(+) create mode 100644 usr/src/cmd/diskinfo/Makefile create mode 100644 usr/src/cmd/diskinfo/diskinfo.c create mode 100644 usr/src/man/man1m/diskinfo.1m create mode 100644 usr/src/pkg/manifests/diagnostic-diskinfo.mf diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index 331fc0c1f8..1c5318893d 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -127,6 +127,7 @@ COMMON_SUBDIRS= \ dircmp \ dirname \ dis \ + diskinfo \ diskmgtd \ dispadmin \ dladm \ diff --git a/usr/src/cmd/diskinfo/Makefile b/usr/src/cmd/diskinfo/Makefile new file mode 100644 index 0000000000..47d2289c90 --- /dev/null +++ b/usr/src/cmd/diskinfo/Makefile @@ -0,0 +1,40 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Nexenta Systems, Inc. +# + +PROG= diskinfo +OBJS= diskinfo.o +SRCS= $(OBJS:%.o=%.c) + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/Makefile.ctf + +CPPFLAGS += -I$(SRC)/lib/fm/topo + +LDLIBS += -L$(ROOT)/usr/lib/fm -R/usr/lib/fm -ldiskmgt -lnvpair -ltopo + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +clean: + $(RM) $(OBJS) + +install: all $(ROOTUSRSBINPROG) + +include $(SRC)/cmd/Makefile.targ diff --git a/usr/src/cmd/diskinfo/diskinfo.c b/usr/src/cmd/diskinfo/diskinfo.c new file mode 100644 index 0000000000..cf28f00889 --- /dev/null +++ b/usr/src/cmd/diskinfo/diskinfo.c @@ -0,0 +1,456 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2013 Joyent Inc., All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef struct di_opts { + boolean_t di_scripted; + boolean_t di_parseable; + boolean_t di_physical; + boolean_t di_condensed; +} di_opts_t; + +typedef struct di_phys { + const char *dp_dev; + const char *dp_serial; + const char *dp_slotname; + int dp_chassis; + int dp_slot; + int dp_faulty; + int dp_locate; +} di_phys_t; + +static void __NORETURN +fatal(int rv, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + + exit(rv); +} + +static void +usage(const char *execname) +{ + (void) fprintf(stderr, "Usage: %s [-Hp] [{-c|-P}]\n", execname); +} + +static void +nvlist_query_string(nvlist_t *nvl, const char *label, char **val) +{ + if (nvlist_lookup_string(nvl, label, val) != 0) + *val = "-"; +} + +static const char * +display_string(const char *label) +{ + return ((label) ? label : "-"); +} + +static const char * +display_tristate(int val) +{ + if (val == 0) + return ("no"); + if (val == 1) + return ("yes"); + + return ("-"); +} + +static char +condensed_tristate(int val, char c) +{ + if (val == 0) + return ('-'); + if (val == 1) + return (c); + + return ('?'); +} +static int +disk_walker(topo_hdl_t *hp, tnode_t *np, void *arg) +{ + di_phys_t *pp = arg; + tnode_t *pnp; + tnode_t *ppnp; + topo_faclist_t fl; + topo_faclist_t *lp; + int err; + topo_led_state_t mode; + topo_led_type_t type; + char *name, *slotname, *serial; + + if (strcmp(topo_node_name(np), DISK) != 0) + return (TOPO_WALK_NEXT); + + if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_LOGICAL_DISK_NAME, &name, &err) != 0) { + return (TOPO_WALK_NEXT); + } + + if (strcmp(name, pp->dp_dev) != 0) + return (TOPO_WALK_NEXT); + + if (topo_prop_get_string(np, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_SERIAL_NUM, &serial, &err) == 0) { + pp->dp_serial = serial; + } + + pnp = topo_node_parent(np); + ppnp = topo_node_parent(pnp); + if (strcmp(topo_node_name(pnp), BAY) == 0) { + if (topo_node_facility(hp, pnp, TOPO_FAC_TYPE_INDICATOR, + TOPO_FAC_TYPE_ANY, &fl, &err) == 0) { + for (lp = topo_list_next(&fl.tf_list); lp != NULL; + lp = topo_list_next(lp)) { + if (topo_prop_get_uint32(lp->tf_node, + TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE, + &type, &err) != 0) { + continue; + } + if (topo_prop_get_uint32(lp->tf_node, + TOPO_PGROUP_FACILITY, TOPO_LED_MODE, + &mode, &err) != 0) { + continue; + } + + switch (type) { + case TOPO_LED_TYPE_SERVICE: + pp->dp_faulty = mode ? 1 : 0; + break; + case TOPO_LED_TYPE_LOCATE: + pp->dp_locate = mode ? 1 : 0; + break; + default: + break; + } + } + } + + if (topo_prop_get_string(pnp, TOPO_PGROUP_PROTOCOL, + TOPO_PROP_LABEL, &slotname, &err) == 0) { + pp->dp_slotname = slotname; + } + + pp->dp_slot = topo_node_instance(pnp); + } + + pp->dp_chassis = topo_node_instance(ppnp); + + return (TOPO_WALK_TERMINATE); +} + +static void +populate_physical(topo_hdl_t *hp, di_phys_t *pp) +{ + int err; + topo_walk_t *wp; + + pp->dp_faulty = pp->dp_locate = -1; + pp->dp_chassis = pp->dp_slot = -1; + + err = 0; + wp = topo_walk_init(hp, FM_FMRI_SCHEME_HC, disk_walker, pp, &err); + if (wp == NULL) { + fatal(-1, "unable to initialise topo walker: %s", + topo_strerror(err)); + } + + while ((err = topo_walk_step(wp, TOPO_WALK_CHILD)) == TOPO_WALK_NEXT) + ; + + if (err == TOPO_WALK_ERR) + fatal(-1, "topo walk failed"); + + topo_walk_fini(wp); +} + +static void +enumerate_disks(di_opts_t *opts) +{ + topo_hdl_t *hp; + dm_descriptor_t *media; + int err, i; + int filter[] = { DM_DT_FIXED, -1 }; + dm_descriptor_t *disk, *controller; + nvlist_t *mattrs, *dattrs, *cattrs = NULL; + + uint64_t size, total; + uint32_t blocksize; + double total_in_GiB; + char sizestr[32]; + char slotname[32]; + char statestr[8]; + + char *vid, *pid, *opath, *c, *ctype = NULL; + boolean_t removable; + boolean_t ssd; + char device[MAXPATHLEN]; + di_phys_t phys; + size_t len; + + err = 0; + if ((media = dm_get_descriptors(DM_MEDIA, filter, &err)) == NULL) { + fatal(-1, "failed to obtain media descriptors: %s\n", + strerror(err)); + } + + err = 0; + hp = topo_open(TOPO_VERSION, NULL, &err); + if (hp == NULL) { + fatal(-1, "unable to obtain topo handle: %s", + topo_strerror(err)); + } + + err = 0; + (void) topo_snap_hold(hp, NULL, &err); + if (err != 0) { + fatal(-1, "unable to hold topo snapshot: %s", + topo_strerror(err)); + } + + for (i = 0; media != NULL && media[i] != NULL; i++) { + if ((disk = dm_get_associated_descriptors(media[i], + DM_DRIVE, &err)) == NULL) { + continue; + } + + mattrs = dm_get_attributes(media[i], &err); + err = nvlist_lookup_uint64(mattrs, DM_SIZE, &size); + assert(err == 0); + err = nvlist_lookup_uint32(mattrs, DM_BLOCKSIZE, &blocksize); + assert(err == 0); + nvlist_free(mattrs); + + dattrs = dm_get_attributes(disk[0], &err); + + nvlist_query_string(dattrs, DM_VENDOR_ID, &vid); + nvlist_query_string(dattrs, DM_PRODUCT_ID, &pid); + nvlist_query_string(dattrs, DM_OPATH, &opath); + + removable = B_FALSE; + if (nvlist_lookup_boolean(dattrs, DM_REMOVABLE) == 0) + removable = B_TRUE; + + ssd = B_FALSE; + if (nvlist_lookup_boolean(dattrs, DM_SOLIDSTATE) == 0) + ssd = B_TRUE; + + if ((controller = dm_get_associated_descriptors(disk[0], + DM_CONTROLLER, &err)) != NULL) { + cattrs = dm_get_attributes(controller[0], &err); + nvlist_query_string(cattrs, DM_CTYPE, &ctype); + ctype = strdup(ctype); + for (c = ctype; *c != '\0'; c++) + *c = toupper(*c); + } + + /* + * Parse full device path to only show the device name, + * i.e. c0t1d0. Many paths will reference a particular + * slice (c0t1d0s0), so remove the slice if present. + */ + if ((c = strrchr(opath, '/')) != NULL) + (void) strlcpy(device, c + 1, sizeof (device)); + else + (void) strlcpy(device, opath, sizeof (device)); + len = strlen(device); + if (device[len - 2] == 's' && + (device[len - 1] >= '0' && device[len - 1] <= '9')) + device[len - 2] = '\0'; + + bzero(&phys, sizeof (phys)); + phys.dp_dev = device; + populate_physical(hp, &phys); + + /* + * The size is given in blocks, so multiply the number + * of blocks by the block size to get the total size, + * then convert to GiB. + */ + total = size * blocksize; + + if (opts->di_parseable) { + (void) snprintf(sizestr, sizeof (sizestr), + "%llu", total); + } else { + total_in_GiB = (double)total / + 1024.0 / 1024.0 / 1024.0; + (void) snprintf(sizestr, sizeof (sizestr), + "%7.2f GiB", total_in_GiB); + } + + if (opts->di_parseable) { + (void) snprintf(slotname, sizeof (slotname), "%d,%d", + phys.dp_chassis, phys.dp_slot); + } else if (phys.dp_slotname != NULL) { + (void) snprintf(slotname, sizeof (slotname), + "[%d] %s", phys.dp_chassis, phys.dp_slotname); + } else { + slotname[0] = '-'; + slotname[1] = '\0'; + } + + if (opts->di_condensed) { + (void) snprintf(statestr, sizeof (statestr), "%c%c%c%c", + condensed_tristate(phys.dp_faulty, 'F'), + condensed_tristate(phys.dp_locate, 'L'), + condensed_tristate(removable, 'R'), + condensed_tristate(ssd, 'S')); + } + + if (opts->di_physical) { + if (opts->di_scripted) { + printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + device, vid, pid, + display_string(phys.dp_serial), + display_tristate(phys.dp_faulty), + display_tristate(phys.dp_locate), slotname); + } else { + printf("%-22s %-8s %-16s " + "%-20s %-3s %-3s %s\n", + device, vid, pid, + display_string(phys.dp_serial), + display_tristate(phys.dp_faulty), + display_tristate(phys.dp_locate), slotname); + } + } else if (opts->di_condensed) { + if (opts->di_scripted) { + printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + ctype, device, vid, pid, + display_string(phys.dp_serial), + sizestr, statestr, slotname); + } else { + printf("%-7s %-22s %-8s %-16s " + "%-20s\n\t%-13s %-4s %s\n", + ctype, device, vid, pid, + display_string(phys.dp_serial), + sizestr, statestr, slotname); + } + } else { + if (opts->di_scripted) { + printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + ctype, device, vid, pid, sizestr, + display_tristate(removable), + display_tristate(ssd)); + } else { + printf("%-7s %-22s %-8s %-16s " + "%-13s %-3s %-3s\n", ctype, device, + vid, pid, sizestr, + display_tristate(removable), + display_tristate(ssd)); + } + } + + free(ctype); + nvlist_free(cattrs); + nvlist_free(dattrs); + dm_free_descriptors(controller); + dm_free_descriptors(disk); + } + + dm_free_descriptors(media); + topo_snap_release(hp); + topo_close(hp); +} + +int +main(int argc, char *argv[]) +{ + char c; + + di_opts_t opts = { + .di_condensed = B_FALSE, + .di_scripted = B_FALSE, + .di_physical = B_FALSE, + .di_parseable = B_FALSE + }; + + while ((c = getopt(argc, argv, ":cHPp")) != EOF) { + switch (c) { + case 'c': + if (opts.di_physical) { + usage(argv[0]); + fatal(1, "-c and -P are mutually exclusive\n"); + } + opts.di_condensed = B_TRUE; + break; + case 'H': + opts.di_scripted = B_TRUE; + break; + case 'P': + if (opts.di_condensed) { + usage(argv[0]); + fatal(1, "-c and -P are mutually exclusive\n"); + } + opts.di_physical = B_TRUE; + break; + case 'p': + opts.di_parseable = B_TRUE; + break; + case '?': + usage(argv[0]); + fatal(1, "unknown option -%c\n", optopt); + default: + fatal(-1, "unexpected error on option -%c\n", optopt); + } + } + + if (!opts.di_scripted) { + if (opts.di_physical) { + printf("DISK VID PID" + " SERIAL FLT LOC" + " LOCATION\n"); + } else if (opts.di_condensed) { + printf("TYPE DISK VID PID" + " SERIAL\n"); + printf("\tSIZE FLRS LOCATION\n"); + } else { + printf("TYPE DISK VID PID" + " SIZE RMV SSD\n"); + } + } + + enumerate_disks(&opts); + + return (0); +} diff --git a/usr/src/man/man1m/Makefile b/usr/src/man/man1m/Makefile index 0d24a46bbb..b531e7abba 100644 --- a/usr/src/man/man1m/Makefile +++ b/usr/src/man/man1m/Makefile @@ -99,6 +99,7 @@ _MANFILES= 6to4relay.1m \ dfshares.1m \ dfshares_nfs.1m \ dhcpagent.1m \ + diskinfo.1m \ disks.1m \ diskscan.1m \ dispadmin.1m \ diff --git a/usr/src/man/man1m/diskinfo.1m b/usr/src/man/man1m/diskinfo.1m new file mode 100644 index 0000000000..867592fef9 --- /dev/null +++ b/usr/src/man/man1m/diskinfo.1m @@ -0,0 +1,191 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" Copyright 2014 Joyent, Inc. +.\" Copyright 2016 Nexenta Systems, Inc. +.\" +.Dd July 20, 2016 +.Dt DISKINFO 1M +.Os +.Sh NAME +.Nm diskinfo +.Nd provide disk device inventory and status +.Sh SYNOPSIS +.Nm +.Op Fl Hp +.Op Fl c Ns | Ns Fl P +.Sh DESCRIPTION +The diskinfo tool provides information about the disk devices in the system. +Because it interacts with the kernel's device management subsystem, this tool +can be used only from the global zone. +If run in any other zone, its output will be incomplete and unreliable. +.Pp +There are three main modes. +The default mode, when neither the +.Fl c +nor +.Fl P +option is specified, provides a basic inventory of the disk devices in the +system. +Each line describes a single device and contains the device's attachment bus or +fabric type, the base name of the device in the +.Pa /dev/dsk +directory, the disk's vendor and product identification strings, the size +.Pq storage capacity +of the device, whether the device is removable, and whether it is solid-state. +.Pp +The +.Fl P +option selects physical mode. +In this mode, each line of output likewise describes one disk device; however, +the fields provided indicate the base name of the device in the +.Pa /dev/dsk +directory, the disk's vendor and product identification strings, the serial number of the +device, whether the device is faulty as diagnosed by +.Xr fmd 1M , +whether the locate or identification indicator is on for the device +.Pq if one is present , +and the chassis and bay number containing the disk if known. +.Pp +The +.Fl c +option selects compact mode. +This mode provides all of the information provided by both the default mode and +physical mode in a compact format. +.Pp +See +.Sx OUTPUT FIELDS +below for a detailed description of each column. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl c +Select compact mode output. +At most one of +.Fl c +and +.Fl P +may be present on the command line. +.It Fl H +Do not print a header. +This provides output suitable for passing into text processing tools. +.It Fl P +Select physical mode output. +At most one of +.Fl P +and +.Fl c +may be present on the command line. +.It Fl p +Parsable output. +When +.Fl p +is selected, the size +.Pq storage capacity +is output in bytes instead of in human-readable units, and the device's location +.Pq if known +is provided as a comma-separated chassis and bay number instead of a +human-readable location. +This option may be used in any output mode and is intended for use by scripts or +other robotic tooling. +.El +.Sh OUTPUT FIELDS +.Bl -tag -width "LOCATION" +.It Sy DISK +The base name of the device node within the +.Pa /dev/dsk +directory. +The names of partitions and/or slices, if any, are derived from this name as +described by +.Xr prtvtoc 1M . +.Pp +This field is available in all output modes. +.It Sy FLRS +A condensed field incorporating the same information as the +.Sy FLT , LOC , RMV , +and +.Sy SSD +fields. +Each field is condensed to a single character. +If the field is true, the first letter of the field name will appear in its +position in the string; otherwise, the +.Qq Sy - +character will appear instead. +.Pp +This field is available only in compact output mode. +.It Sy FLT +A boolean field indicating whether the device is faulty; specifically, whether +the fault indicator +.Pq if one is present +is active. +.Pp +This field is available only in physical output mode. +.It Sy LOC +A boolean field indicating whether the locate or identify indicator, if any, +associated with the device's bay, is active. +.Pp +This field is available only in physical output mode. +.It Sy LOCATION +The physical chassis and bay name +.Po or chassis and bay numbers, if +.Fl p +is given +.Pc +in which the device is located. +The chassis number is identified in human-readable output within +.Bq square brackets ; +chassis 0 is the host chassis itself. +The bay name, if any, is provided by the enclosure, typically via a SCSI +Enclosure Services processor. +.Pp +This field is available in compact and physical output modes. +.It Sy PID +The product identification string reported by the device. +.Pp +This field is available in all output modes. +.It Sy RMV +A boolean field indicating whether the device is removable. +USB storage devices, most optical drives and changers, and certain other devices +that report themselves as removable will be identified as such. +.Pp +This field is available only in default output mode. +.It Sy SERIAL +The serial number of the device. The entire serial number is reported if the +device and its drivers provide it. +.Pp +This field is available in compact and physical output modes. +.It Sy SIZE +The device's storage capacity. +If the +.Fl p +option is given, this is reported in bytes; otherwise, it is reported in a +human-readable format with units specified. +All units are based on powers of 2 and are expressed in SI standard notation. +.Pp +This field is available in compact and default output modes. +.It Sy SSD +A boolean field indicating whether the device is solid-state. +.Pp +This field is available only in default output mode. +.It Sy TYPE +The transport +.Pq fabric or bus +type by which the storage device is attached to the host, if known. +Typical transports include SCSI and USB. +.Pp +This field is available in compact and default output modes. +.It Sy VID +The vendor identification string reported by the device. +.Pp +This field is available in all output modes. +.El +.Sh SEE ALSO +.Xr fmd 1M , +.Xr prtvtoc 1M , +.Xr sd 7D diff --git a/usr/src/pkg/manifests/diagnostic-diskinfo.mf b/usr/src/pkg/manifests/diagnostic-diskinfo.mf new file mode 100644 index 0000000000..a7a62def0d --- /dev/null +++ b/usr/src/pkg/manifests/diagnostic-diskinfo.mf @@ -0,0 +1,33 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Nexenta Systems, Inc. +# + +# +# The default for payload-bearing actions in this package is to appear in the +# global zone only. See the include file for greater detail, as well as +# information about overriding the defaults. +# + +set name=pkg.fmri value=pkg:/diagnostic/diskinfo@$(PKGVERS) +set name=pkg.description value=diskinfo +set name=pkg.summary value=diskinfo +set name=info.classification \ + value="org.opensolaris.category.2008:Applications/System Utilities" +set name=variant.arch value=$(ARCH) +dir path=usr group=sys +dir path=usr/sbin +dir path=usr/share/man/man1m +file path=usr/sbin/diskinfo mode=0555 +file path=usr/share/man/man1m/diskinfo.1m mode=0444 +license lic_CDDL license=lic_CDDL -- 2.11.4.GIT