metastat.c revision 22b8c3a898c468940872c5b3bdf0d3d09ce72398
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <meta.h>
#include <sdssc.h>
/*
* print metadevice status
*/
#define MD_PROBE_OPEN_T "probe open test"
/* used to keep track of the softparts on the same underlying device */
struct sp_base_list {
struct sp_base_list *next;
char *base;
};
/*
* Function prototypes
*/
md_error_t *ep);
md_error_t *ep);
int quiet_flg);
int concise_flag, int quiet_flg);
char mtype);
md_trans_t *trans);
/*
* print named hotspare pool or metadevice
*/
static int
mdsetname_t **spp,
char *uname,
char *fname,
int *meta_print_trans_msgp,
)
{
char *miscname;
/* recurse */
options |= PRINT_SUBDEVS;
/* hotspare pool */
/* get hotsparepool */
return (-1);
/* check for ownership */
return (-1);
/* print hotspare pool */
}
/* get metadevice */
return (-1);
/* check for ownership */
return (-1);
*meta_print_trans_msgp = 1;
}
}
/* print metadevice */
}
/*
* print the per set flags
*/
/*ARGSUSED*/
static int
mdsetname_t **spp,
char *fname,
)
{
int rval = -1;
/* get the canonical name */
return (-1);
}
return (0);
return (0);
goto out;
goto out;
goto out;
/* success */
rval = 0;
/* cleanup, return error */
out:
if (rval != 0)
return (rval);
}
/*
* check_replica_state:
* If the replica state is stale or the set has been halted
* this routine returns an error.
*/
static int
{
(void) memset(&c, 0, sizeof (c));
c.c_id = 0;
return (-1);
}
if (c.c_flags & MDDB_C_STALE) {
0, NULL));
} else
return (0);
}
static void
{
if (meta_print_trans_msg != 0) {
if (options & PRINT_SHORT) {
} else {
}
}
}
/*
* print usage message
*
*/
static void
int eval
)
{
usage: %s [-s setname] [-a][-c][-B][-D][-r][-i][-p] [-t] [metadevice...]\n"),
myname);
}
/*
* mainline. crack command line arguments.
*/
int
main(
int argc,
char *argv[]
)
{
char *sname = MD_LOCAL_NAME;
int c;
char *p;
int eval = 0;
int inquire = 0;
int quiet_flg = 0;
int set_flg = 0;
int error;
int all_sets_flag = 0;
int concise_flag = 0;
int devcnt = 0;
int meta_print_trans_msg = 0;
/*
* Get the locale set up before calling any other routines
* with messages to ouput. Just in case we're not in a build
* environment, make sure that TEXT_DOMAIN gets set to
* something.
*/
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (sdssc_bind_library() == SDSSC_OKAY)
&error) == SDSSC_PROXY_DONE)
/* initialize */
}
/* parse arguments */
optind = 1;
opterr = 1;
switch (c) {
case 'a':
break;
case 'c':
concise_flag++;
quiet_flg++;
break;
case 'S':
break;
case 's':
set_flg++;
break;
case 'h':
break;
case 'p':
options |= PRINT_SHORT;
options &= ~PRINT_DEVID;
break;
case 't':
options |= PRINT_TIMES;
break;
case 'i':
inquire++;
break;
case 'B':
break;
case 'D':
break;
case 'r': /* defunct option */
break;
case 'q':
quiet_flg++;
break;
case '?':
if (optopt == '?')
/*FALLTHROUGH*/
default:
break;
}
}
if (all_sets_flag && set_flg) {
"incompatible options: -a and -s\n"));
}
/* get set context */
}
/* make sure that the mddb is not stale. Else print a warning */
"****\nWARNING: Stale "
"state database replicas. Metastat output "
"may be inaccurate.\n****\n\n"));
}
}
/* if inquire is set. We probe first */
if (inquire) {
if (geteuid() != 0) {
"option requires super-user privilages\n"));
}
}
/* print debug stuff */
}
}
if (options & PRINT_SETSTAT_ONLY)
}
/* status all devices */
if (argc == 0) {
if (all_sets_flag) {
} else {
}
}
/* success */
}
/* print named device types */
/* get the canonical name */
/* already printed the error */
mdclrerror(ep);
eval = 1;
++devcnt;
continue;
}
if (concise_flag) {
mdclrerror(ep);
eval = 1;
} else {
}
} else {
mdclrerror(ep);
eval = 1;
}
}
++devcnt;
}
/* print metadevice & relocation device id */
devcnt = 0;
/* get the canonical name */
mdclrerror(ep);
++devcnt;
continue;
}
/* hotspare pools */
/* get hotsparepool */
eval = 1;
eval = 1;
for (hsi = 0;
hsi++) {
if (!(options &
(PRINT_LARGEDEVICES | PRINT_FN))) {
/* meta_getdevs populates the */
/* nlistp structure for use */
eval = 1;
}
}
} else {
/* get metadevice */
eval = 1;
if (!(options &
(PRINT_LARGEDEVICES | PRINT_FN))) {
/* meta_getdevs populates the */
/* nlistp structure for use */
!= 0)
eval = 1;
}
}
++devcnt;
}
eval = 1;
}
}
/* return success */
/*NOTREACHED*/
return (eval);
}
static void
{
int i;
return;
}
mdclrerror(&error);
return;
}
/* for each possible set number, see if we really have a diskset */
for (i = 0; i < max_sets; i++) {
/* metad rpc program not registered - no metasets */
break;
}
mdclrerror(&error);
continue;
}
mdclrerror(&error);
/* we own the set, so we can print the metadevices */
(void) printf("\n");
}
}
}
static void
int quiet_flg)
{
int meta_print_trans_msg = 0;
/* check for ownership */
}
if (concise_flag) {
} else {
/* status devices */
&meta_print_trans_msg, ep) != 0) {
}
/* print relocation device id on all dev's */
/*
* Ignore return value from meta_getalldevs since
* it will return a failure if even one device cannot
* be found - which could occur in the case of device
* failure or a device being powered off during
* upgrade. Even if meta_getalldevs fails, the
* data in nlistp is still valid.
*/
}
}
}
}
}
}
/*
* print_devid prints out cxtxdx and devid for devices passed in a
* mdnamelist_t structure
*/
static int
)
{
int retval = 0;
/* make a non-duplicate list of nlp */
}
/* cleanup */
}
return (retval);
}
/*
* probedev issues ioctls for all the metadevices
*/
/*
* Failure return's a 1
*/
int
hotspare_ok(char *bname)
{
int fd;
char buf[512];
return (0);
return (0);
}
return (1);
}
void
{
char *bname;
md_error_t e = mdnullerror;
int deleted_hs = 0;
/* print hotspare */
if (hotspare_ok(bname))
continue;
"NOTICE: Hotspare %s in %s has failed.\n"
"\tDeleting %s since it not in use\n\n",
mde_perror(&e, "");
mdclrerror(&e);
} else {
deleted_hs++;
}
}
}
}
/*
* Generic routine to issue ioctls
*/
void
{
}
int
{
mdnamelist_t *p;
int i, retval = 0;
/*
* Allocate space for all the metadevices and fill in
* the minor numbers.
*/
== 0) {
perror("md_probe_ioctl: calloc");
return (-1);
}
}
retval = -1;
return (retval);
}
/*
*
* - remove p from nlp list
* - put it on the toplp list.
* - update the p to the next element
*/
void
{
p = *curpp;
if (prevp == p) {
/* if first element reset prevp */
nlp = p;
p = prevp;
} else {
nlp = p;
}
*curpp = p;
}
/*
* Scans the given list of metadeivces and returns a list of top level
* metadevices.
* Note: The orignal list is not valid at the end and is set to NULL.
*/
int
{
int ntopmd;
md_error_t e = mdnullerror;
ntopmd = 0;
while (p) {
prevp = p;
p = p->next;
continue;
}
/* increment the top level md count. */
ntopmd++;
} else {
prevp = p;
p = p->next;
}
}
return (ntopmd);
}
int
char *dev_type)
{
md_error_t e = mdnullerror;
char *type_name;
int i = 0;
while (np) {
return (-1);
}
/* move it to the devlist */
i++;
} else {
}
}
return (i);
}
{
md_error_t e = mdnullerror;
return (np);
} else {
/* error condition below */
mde_perror(&e, "create_nlp: malloc failed\n");
}
return (0);
}
/*
* Create a list of metadevices associated with trans. top_pp points to
* this list. The number of components in the list are also returned.
*/
int
{
int ntoptrans;
md_error_t e = mdnullerror;
md_trans_t *tp;
ntoptrans = 0;
p = *lpp;
/*
* Scan the current list of trans devices. From that
* extract all the lower level metadevices and put them on
* toplp list.
*/
while (p) {
/*
* Check the master and log devices to see if they
* are metadevices
*/
/* get a mdnamelist_t. */
} else {
}
ntoptrans++;
}
} else {
}
ntoptrans++;
}
p = p->next;
}
}
return (ntoptrans);
}
void
{
int cnt;
md_error_t e = mdnullerror;
/*
* We have some mirrors to probe
* get a list of top-level mirrors
*/
perror("MD_IOCPROBE_DEV");
} else {
mdclrerror(&e);
}
}
void
{
int cnt;
md_error_t e = mdnullerror;
/*
* We have some mirrors to probe
* get a list of top-level mirrors
*/
perror("MD_IOCPROBE_DEV");
} else {
mdclrerror(&e);
}
}
/*
* Trans probes are diffenent. -- so whats new.
* we separate out the master and log device and then issue the
* probe calls.
* Since the underlying device could be disk, stripe, RAID or miror,
* we have to sort them out and then call the ioctl for each.
*/
void
{
int cnt;
md_error_t e = mdnullerror;
/*
* get a list of master and log metadevices.
*/
/* underlying RAID-5 components */
MD_RAID) < 0))
perror("MD_IOCPROBE_DEV");
/* underlying mirror components */
MD_MIRROR) < 0))
perror("MD_IOCPROBE_DEV");
/* underlying stripe components */
MD_STRIPE) < 0))
perror("MD_IOCPROBE_DEV");
} else {
mdclrerror(&e);
}
}
/*
* probe hot spares. This is differs from other approaches since
* component level and then delete it if its bad.
*/
void
{
mdhspnamelist_t *p;
md_error_t e = mdnullerror;
mdclrerror(&e);
return;
}
continue;
}
}
mdclrerror(&e);
}
static void
{
}
/*
* The following functions are used to print the concise output
* of the metastat coommand (-c option).
*
* Normally the output for metastat is performed within libmeta via
* the *_report functions within each of the metadevice specific files in
* libmeta. However, it is usually bad architecture for a library to
* perform output since there are so many different ways that an application
* can choose to do output (e.g. GUI, CLI, CIM, SNMP, etc.). So, for the
* concise output option we have moved the CLI output to the metastat
* code and just use libmeta as the source of data to be printed.
*
* This function gets all of the different top-level metadevices in the set
* and prints them. It calls the print_concise_md() function to recursively
* print the metadevices that underly the top-level metadevices. It does
* special handling for soft partitions so that all of the SPs on the
* same underlying device are grouped and then that underlying device
* is only printed once.
*/
static void
{
/*
* We do extra handling for soft parts since we want to find
* all of the SPs on the same underlying device, group them and
* print them together before printing the underlying device just
* once. This logic doesn't apply to any other metadevice type.
*/
/* keep track of the softparts on the same underlying device */
META_DEVICE, &error);
mdclrerror(&error);
0, 'p');
printf("\n");
continue;
}
mdclrerror(&error);
continue;
/* print this soft part */
/*
* keep track of the underlying device of
* this soft part
*/
/*
* now print all of the other soft parts on the same
* underlying device
*/
META_DEVICE, &error);
mdclrerror(&error);
continue;
mdclrerror(&error);
continue;
/* on the same base so print this soft part */
}
/*
* print the common metadevice hierarchy
* under these soft parts
*/
}
free_names(&nl);
}
mdclrerror(&error);
mdclrerror(&error);
mdclrerror(&error);
mdclrerror(&error);
mdclrerror(&error);
mdclrerror(&error);
int i;
char *state;
}
}
(void) printf("\n");
}
mdclrerror(&error);
}
}
/*
* Print the top-level metadevices in the name list for concise output.
*/
static void
{
md_common_t *u;
mdclrerror(&error);
printf("\n");
continue;
}
mdclrerror(&error);
}
free_names(nl);
}
/*
* Concise mirror output.
*/
static void
{
int i;
return;
for (i = 0; i < NMIRROR; i++) {
char *state;
continue;
continue;
}
(void) meta_get_tstate(
mdclrerror(&error);
}
(void) printf("\n");
indent += META_INDENT;
for (i = 0; i < NMIRROR; i++) {
continue;
}
}
/*
* Concise raid output.
*/
static void
{
int i;
return;
if (metaismeta(namep)) {
mdclrerror(&error);
} else {
if (tstate != 0)
col_state = "-";
else
}
else
}
}
(void) printf("\n");
indent += META_INDENT;
}
}
/*
* Concise stripe output.
*/
static void
{
int i;
uint_t top_tstate = 0;
return;
&error);
mdclrerror(&error);
int j;
char *comp_state = NULL;
char *hsname;
mdclrerror(&error);
} else {
if (top_tstate != 0)
comp_state = "-";
else
}
if (comp_state != NULL) {
(void) printf(" (%s-%s)",
comp_state, hsname);
else
}
}
}
(void) printf("\n");
indent += META_INDENT;
int j;
}
}
}
/*
* Concise soft partition output.
*/
static void
{
return;
}
/*
* Concise trans output.
*/
static void
{
return;
(void) printf("\n");
indent += META_INDENT;
}
/*
* Recursive function for concise metadevice nested output.
*/
static void
{
md_unit_t *u;
return;
mdclrerror(&error);
return;
}
switch (u->c.un_type) {
case MD_DEVICE:
break;
case MD_METAMIRROR:
break;
case MD_METATRANS:
break;
case MD_METARAID:
break;
case MD_METASP:
break;
default:
return;
}
mdclrerror(&error);
}
/*
* Given a name get the unit for use in concise output. We use the *_common
* routines in libmeta which allow us to specify the "fast" flag, thereby
* avoiding the DKIOCGGEOM ioctl that normally happens.
*/
static md_common_t *
{
char *miscname;
/* short circuit */
return (NULL);
/* dispatch */
return (NULL);
else {
return (NULL);
}
}
static void
{
mdnamelist_t *p;
}
}
/*
* Submirror state for concise output.
*/
static char *
{
/*
* Only return Unavailable if there is no flagged error on the
* submirror. If the mirror has received any writes since the submirror
* went into Unavailable state a resync is required. To alert the
* administrator to this we return a 'Needs maintenance' message.
*/
return (gettext("unavail"));
/* all is well */
if (state & SMS_RUNNING) {
if (!(mirror_status & MD_UN_OPT_NOT_DONE) ||
return (NULL);
}
/* resyncing, needs repair */
static char buf[MAXPATHLEN];
if (mirror_status & MD_UN_RESYNC_ACTIVE) {
gettext("resync-%2d.%1d%%"),
} else {
}
return (buf);
}
return (gettext("maint"));
}
/* needs repair */
return (gettext("maint"));
/* unknown */
return (gettext("unknown"));
}
/*
* Raid component state for concise output.
*/
static char *
{
if (tstate != 0)
return (gettext("unavail"));
}
/*
* Stripe state for concise output.
*/
static char *
{
if (tstate != 0)
return ("unavail");
return (meta_get_stripe_state(state));
}
/*
* Hostspare state for concise output.
*/
static char *
{
return (meta_get_hs_state(state));
}
/*
* Keep track of printed soft partitions for concise output.
*/
static struct sp_base_list *
{
struct sp_base_list *n;
if (n == NULL)
return (lp);
free(n);
return (lp);
}
return (n);
}
/*
* Keep track of printed soft partitions for concise output.
*/
static int
{
return (1);
}
return (0);
}
/*
* Check the first element for a match.
*/
static int
{
return (1);
return (0);
}
/*
* Free memory used for soft partition printed status in concise output.
*/
static void
{
struct sp_base_list *n;
}
}