xref: /onnv-gate/usr/src/cmd/stat/common/dsr.c (revision 2907:d11defc6b41b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52255Scth  * Common Development and Distribution License (the "License").
62255Scth  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
222255Scth  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/stat.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * Dependent on types.h, but not including it...
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/dkio.h>
370Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
380Sstevel@tonic-gate #include <sys/mnttab.h>
390Sstevel@tonic-gate #include <sys/mntent.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <sys/mkdev.h>
420Sstevel@tonic-gate #include <sys/vfs.h>
430Sstevel@tonic-gate #include <nfs/nfs.h>
440Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
450Sstevel@tonic-gate #include <kstat.h>
460Sstevel@tonic-gate #include <ctype.h>
470Sstevel@tonic-gate #include <dirent.h>
480Sstevel@tonic-gate #include <libdevinfo.h>
490Sstevel@tonic-gate #include <limits.h>
500Sstevel@tonic-gate #include <stdlib.h>
510Sstevel@tonic-gate #include <string.h>
52*2907Scth #include <strings.h>
530Sstevel@tonic-gate #include <unistd.h>
540Sstevel@tonic-gate #include <errno.h>
550Sstevel@tonic-gate #include <devid.h>
56*2907Scth #include <sys/scsi/adapters/scsi_vhci.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include "dsr.h"
590Sstevel@tonic-gate #include "statcommon.h"
600Sstevel@tonic-gate 
61*2907Scth /* where we get kstat name translation information from */
62*2907Scth static di_node_t	di_root;	/* from di_init: for devid */
63*2907Scth static di_dim_t		di_dim;		/* from di_dim_init: for /dev names */
64*2907Scth static int		scsi_vhci_fd = -1; /* from scsi_vhci: for mpxio path */
65*2907Scth 
66*2907Scth /* disk/tape/misc info */
672723Scth typedef struct {
682723Scth 	char		*minor_name;
692723Scth 	int		minor_isdisk;
702723Scth } minor_match_t;
712723Scth static minor_match_t	mm_disk = {"a", 1};
722723Scth static minor_match_t	mm_tape	= {"", 0};
73*2907Scth static minor_match_t	mm_misc	= {"0", 0};
742723Scth static char		md_minor_name[MAXPATHLEN];
752723Scth static minor_match_t	mm_md	= {md_minor_name, 0};
76*2907Scth static minor_match_t	*mma_disk_tape_misc[]	=
77*2907Scth 			    {&mm_disk, &mm_tape, &mm_misc, NULL};
782723Scth static minor_match_t	*mma_md[]		= {&mm_md, NULL};
792723Scth static char *mdsetno2name(int setno);
802723Scth #define	DISKLIST_MOD	256		/* ^2 instunit mod hash */
812723Scth static disk_list_t	*disklist[DISKLIST_MOD];
820Sstevel@tonic-gate 
83*2907Scth 
842723Scth /* nfs info */
852723Scth extern kstat_ctl_t	*kc;
862723Scth extern mnt_t		*nfs;
872723Scth static int		nfs_tried;
882723Scth static char		*get_nfs_by_minor(uint_t);
892723Scth static char		*cur_hostname(uint_t, kstat_ctl_t *);
902723Scth static char		*cur_special(char *, char *);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
932723Scth  * Clear the snapshot so a cache miss in lookup_ks_name() will cause a fresh
942723Scth  * snapshot in drvinstunit2dev().
950Sstevel@tonic-gate  */
962723Scth void
cleanup_iodevs_snapshot()972723Scth cleanup_iodevs_snapshot()
982723Scth {
992723Scth 	if (di_dim) {
1002723Scth 		di_dim_fini(di_dim);
1012723Scth 		di_dim = NULL;
1022723Scth 	}
1030Sstevel@tonic-gate 
1042723Scth 	if (di_root) {
1052723Scth 		di_fini(di_root);
1062723Scth 		di_root = DI_NODE_NIL;
1072723Scth 	}
1080Sstevel@tonic-gate 
1092723Scth 	nfs_tried = 0;
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1132723Scth  * Find information for (driver, instunit) device: return zero on failure.
1140Sstevel@tonic-gate  *
1152723Scth  * NOTE: Failure of drvinstunit2dev works out OK for the caller if the kstat
1162723Scth  * name is the same as public name: the caller will just use kstat name.
1170Sstevel@tonic-gate  */
1182723Scth static int
drvinstunitpart2dev(char * driver,int instunit,char * part,char ** devpathp,char ** adevpathp,char ** devidp)119*2907Scth drvinstunitpart2dev(char *driver, int instunit, char *part,
120*2907Scth     char **devpathp, char **adevpathp, char **devidp)
1210Sstevel@tonic-gate {
1222723Scth 	int		instance;
1232723Scth 	minor_match_t	**mma;
1242723Scth 	minor_match_t	*mm;
1252723Scth 	char		*devpath;
1262723Scth 	char		*devid;
1272723Scth 	char		*a, *s;
1282723Scth 	int		mdsetno;
1292723Scth 	char		*mdsetname = NULL;
1302723Scth 	char		amdsetname[MAXPATHLEN];
1312723Scth 	char		*devicespath;
1322723Scth 	di_node_t	node;
1332723Scth 
1342723Scth 	/* setup "no result" return values */
1352723Scth 	if (devpathp)
1362723Scth 		*devpathp = NULL;
1372723Scth 	if (adevpathp)
1382723Scth 		*adevpathp = NULL;
1392723Scth 	if (devidp)
1402723Scth 		*devidp = NULL;
1412723Scth 
1422723Scth 	/* take <driver><instance><minor_name> snapshot if not established */
1432723Scth 	if (di_dim == NULL) {
1442723Scth 		di_dim = di_dim_init();
1452723Scth 		if (di_dim == NULL)
1462723Scth 			return (0);
1472723Scth 	}
1482723Scth 
1492723Scth 	/*
1502723Scth 	 * Determine if 'instunit' is an 'instance' or 'unit' based on the
1512723Scth 	 * 'driver'.  The current code only detects 'md' metadevice 'units',
1522723Scth 	 * and defaults to 'instance' for everything else.
1532723Scth 	 *
1542723Scth 	 * For a metadevice, 'driver' is either "md" or "<setno>/md".
1552723Scth 	 */
1562723Scth 	s = strstr(driver, "/md");
1572723Scth 	if ((strcmp(driver, "md") == 0) ||
1582723Scth 	    (s && isdigit(*driver) && (strcmp(s, "/md") == 0))) {
1592723Scth 		/*
1602723Scth 		 * "md" unit: Special case translation of "md" kstat names.
1612723Scth 		 * For the local set the kstat name is "md<unit>", and for
1622723Scth 		 * a shared set the kstat name is "<setno>/md<unit>": we map
1632723Scth 		 * these to the minor paths "/pseudo/md@0:<unit>,blk" and
1642723Scth 		 * "/pseudo/md@0:<set>,<unit>,blk" respectively.
1652723Scth 		 */
1662723Scth 		if (isdigit(*driver)) {
1672723Scth 			mdsetno = atoi(driver);
1682723Scth 
1692723Scth 			/* convert setno to setname */
1702723Scth 			mdsetname = mdsetno2name(mdsetno);
1712723Scth 		} else
1722723Scth 			mdsetno = 0;
1732723Scth 
1742723Scth 		driver = "md";
1752723Scth 		instance = 0;
1762723Scth 		mma = mma_md;			/* metadevice dynamic minor */
1772723Scth 		(void) snprintf(md_minor_name, sizeof (md_minor_name),
1782723Scth 		    "%d,%d,blk", mdsetno, instunit);
1792723Scth 	} else {
1802723Scth 		instance = instunit;
181*2907Scth 		mma = mma_disk_tape_misc;	/* disk/tape/misc minors */
1822723Scth 	}
1830Sstevel@tonic-gate 
184*2907Scth 	if (part) {
185*2907Scth 		devpath = di_dim_path_dev(di_dim, driver, instance, part);
186*2907Scth 	} else  {
187*2907Scth 		/* Try to find a minor_match that works */
188*2907Scth 		for (mm = *mma++; mm; mm = *mma++)  {
189*2907Scth 			if ((devpath = di_dim_path_dev(di_dim,
190*2907Scth 			    driver, instance, mm->minor_name)) != NULL)
191*2907Scth 				break;
192*2907Scth 		}
1932723Scth 	}
1942723Scth 	if (devpath == NULL)
1952723Scth 		return (0);
1962723Scth 
1972723Scth 	/*
1982723Scth 	 * At this point we have a devpath result. Return the information about
1992723Scth 	 * the result that the caller is asking for.
2002723Scth 	 */
2012723Scth 	if (devpathp)			/* devpath */
2022723Scth 		*devpathp = safe_strdup(devpath);
2030Sstevel@tonic-gate 
2042723Scth 	if (adevpathp) {		/* abbreviated devpath */
205*2907Scth 		if ((part == NULL) && mm->minor_isdisk) {
2062723Scth 			/*
207*2907Scth 			 * For disk kstats without a partition we return the
208*2907Scth 			 * last component with trailing "s#" or "p#" stripped
209*2907Scth 			 * off (i.e. partition/slice information is removed).
2102723Scth 			 * For example for devpath of "/dev/dsk/c0t0d0s0" the
2112723Scth 			 * abbreviated devpath would be "c0t0d0".
2122723Scth 			 */
2132723Scth 			a = strrchr(devpath, '/');
2142723Scth 			if (a == NULL) {
2152723Scth 				free(devpath);
2162723Scth 				return (0);
2172723Scth 			}
2182723Scth 			a++;
2192723Scth 			s = strrchr(a, 's');
2202723Scth 			if (s == NULL) {
2212723Scth 				s = strrchr(a, 'p');
2222723Scth 				if (s == NULL) {
2232723Scth 					free(devpath);
2242723Scth 					return (0);
2250Sstevel@tonic-gate 				}
2262723Scth 			}
2272723Scth 			/* don't include slice information in devpath */
2282723Scth 			*s = '\0';
2292723Scth 		} else {
2302723Scth 			/*
2312723Scth 			 * remove "/dev/", and "/dsk/", from 'devpath' (like
2322723Scth 			 * "/dev/md/dsk/d0") to form the abbreviated devpath
2332723Scth 			 * (like "md/d0").
2342723Scth 			 */
2352723Scth 			if ((s = strstr(devpath, "/dev/")) != NULL)
2362723Scth 				(void) strcpy(s + 1, s + 5);
2372723Scth 			if ((s = strstr(devpath, "/dsk/")) != NULL)
2382723Scth 				(void) strcpy(s + 1, s + 5);
2392723Scth 
2402723Scth 			/*
2412723Scth 			 * If we have an mdsetname, convert abbreviated setno
2422723Scth 			 * notation (like "md/shared/1/d0" to abbreviated
2432723Scth 			 * setname notation (like "md/red/d0").
2442723Scth 			 */
2452723Scth 			if (mdsetname) {
2462723Scth 				a = strrchr(devpath, '/');
2472723Scth 				(void) snprintf(amdsetname, sizeof (amdsetname),
2482723Scth 				    "md/%s%s", mdsetname, a);
2492723Scth 				free(mdsetname);
2502723Scth 				a = amdsetname;
2512723Scth 			} else {
2522723Scth 				if (*devpath == '/')
2532723Scth 					a = devpath + 1;
2542723Scth 				else
2552723Scth 					a = devpath;
2562723Scth 			}
2572723Scth 		}
2582723Scth 		*adevpathp = safe_strdup(a);
2592723Scth 	}
2602723Scth 
2612723Scth 	if (devidp) {			/* lookup the devid */
262*2907Scth 		/* take snapshot if not established */
2632723Scth 		if (di_root == DI_NODE_NIL) {
2642723Scth 			di_root = di_init("/", DINFOCACHE);
2652723Scth 		}
2662723Scth 		if (di_root) {
2672723Scth 			/* get path to /devices devinfo node */
2682723Scth 			devicespath = di_dim_path_devices(di_dim,
2692723Scth 			    driver, instance, NULL);
2702723Scth 			if (devicespath) {
2712723Scth 				/* find the node in the snapshot */
2722723Scth 				node = di_lookup_node(di_root, devicespath);
2732723Scth 				free(devicespath);
2742723Scth 
2752723Scth 				/* and lookup devid property on the node */
2762723Scth 				if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
2772723Scth 				    DEVID_PROP_NAME, &devid) != -1)
2782723Scth 					*devidp = devid;
2790Sstevel@tonic-gate 			}
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2832723Scth 	free(devpath);
2842723Scth 	return (1);				/* success */
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
288*2907Scth  * Do <pid> to 'target-port' translation
289*2907Scth  */
290*2907Scth static int
drvpid2port(uint_t pid,char ** target_portp)291*2907Scth drvpid2port(uint_t pid, char **target_portp)
292*2907Scth {
293*2907Scth 	sv_iocdata_t	ioc;
294*2907Scth 	char		target_port[MAXNAMELEN];
295*2907Scth 
296*2907Scth 	/* setup "no result" return values */
297*2907Scth 	*target_portp = NULL;
298*2907Scth 
299*2907Scth 	/* open scsi_vhci if not already done */
300*2907Scth 	if (scsi_vhci_fd == -1) {
301*2907Scth 		scsi_vhci_fd = open("/devices/scsi_vhci:devctl", O_RDONLY);
302*2907Scth 		if (scsi_vhci_fd == -1)
303*2907Scth 			return (0);		/* failure */
304*2907Scth 	}
305*2907Scth 
306*2907Scth 	/*
307*2907Scth 	 * Perform ioctl for <pid> -> 'target-port' translation.
308*2907Scth 	 *
309*2907Scth 	 * NOTE: it is legimite for this ioctl to fail for transports
310*2907Scth 	 * that use mpxio, but don't set a 'target-port' pathinfo property.
311*2907Scth 	 * On failure we return the the "<pid>" as the target port string.
312*2907Scth 	 */
313*2907Scth 	bzero(&ioc, sizeof (sv_iocdata_t));
314*2907Scth 	ioc.buf_elem = pid;
315*2907Scth 	ioc.addr = target_port;
316*2907Scth 	if (ioctl(scsi_vhci_fd, SCSI_VHCI_GET_TARGET_LONGNAME, &ioc) < 0) {
317*2907Scth 		(void) snprintf(target_port, sizeof (target_port), "%d", pid);
318*2907Scth 	}
319*2907Scth 
320*2907Scth 	*target_portp = safe_strdup(target_port);
321*2907Scth 	return (1);				/* success */
322*2907Scth }
323*2907Scth 
324*2907Scth /*
325*2907Scth  * Find/create a disk_list entry for given a kstat name.
326*2907Scth  * The basic format of a kstat name is
327*2907Scth  *
328*2907Scth  *	"<driver><instunit>.<pid>.<phci-driver><instance>,<partition>".
329*2907Scth  *
330*2907Scth  * The <instunit> is a decimal number. The ".<pid>.<phci-driver><instance>",
331*2907Scth  * which describes mpxio path stat information, and ",<partition>" parts are
332*2907Scth  * optional. The <pid> consists of the letter 't' followed by a decimal number.
333*2907Scth  * When available, we use the <pid> to find the 'target-port' via ioctls to
334*2907Scth  * the scsi_vhci driver.
3352723Scth  *
3362723Scth  * NOTE: In the case of non-local metadevices, the format of "<driver>" in
3372723Scth  * a kstat name is acutally "<setno>/md".
3380Sstevel@tonic-gate  */
3392723Scth disk_list_t *
lookup_ks_name(char * ks_name,int want_devid)3402723Scth lookup_ks_name(char *ks_name, int want_devid)
3410Sstevel@tonic-gate {
342*2907Scth 	char		*pidp;		/* ".<pid>... */
343*2907Scth 	char		*part;		/* ",partition... */
344*2907Scth 	char		*initiator;	/* ".<phci-driver>... */
3452723Scth 	char		*p;
3462723Scth 	int		len;
347*2907Scth 	char		driver[KSTAT_STRLEN];
3482723Scth 	int		instunit;
3492723Scth 	disk_list_t	**dlhp;		/* disklist head */
3502723Scth 	disk_list_t	*entry;
351*2907Scth 	char		*devpath = NULL;
3522723Scth 	char		*adevpath = NULL;
3532723Scth 	char		*devid = NULL;
354*2907Scth 	int		pid;
355*2907Scth 	char		*target_port = NULL;
356*2907Scth 	char		portform[MAXPATHLEN];
3570Sstevel@tonic-gate 
358*2907Scth 	/* Filter out illegal forms (like all digits). */
3592723Scth 	if ((ks_name == NULL) || (*ks_name == 0) ||
3602723Scth 	    (strspn(ks_name, "0123456789") == strlen(ks_name)))
361*2907Scth 		goto fail;
362*2907Scth 
363*2907Scth 	/* parse ks_name to create new entry */
364*2907Scth 	pidp = strchr(ks_name, '.');		/* start of ".<pid>" */
365*2907Scth 	initiator = strrchr(ks_name, '.');	/* start of ".<pHCI-driver>" */
366*2907Scth 	if (pidp && (pidp == initiator))	/* can't have same start */
367*2907Scth 		goto fail;
368*2907Scth 
369*2907Scth 	part = strchr(ks_name, ',');		/* start of ",<partition>" */
370*2907Scth 	p = strchr(ks_name, ':');		/* start of ":<partition>" */
371*2907Scth 	if (part && p)
372*2907Scth 		goto fail;			/* can't have both */
373*2907Scth 	if (p)
374*2907Scth 		part = p;
375*2907Scth 	if (part && pidp)
376*2907Scth 		goto fail;			/* <pid> and partition: bad */
377*2907Scth 
378*2907Scth 	p = part ? part : pidp;
3792723Scth 	if (p == NULL)
3802723Scth 		p = &ks_name[strlen(ks_name) - 1];	/* last char */
3812723Scth 	else
382*2907Scth 		p--;				/* before ',' or '.' */
3830Sstevel@tonic-gate 
3842723Scth 	while ((p >= ks_name) && isdigit(*p))
3852723Scth 		p--;				/* backwards over digits */
3862723Scth 	p++;					/* start of instunit */
387*2907Scth 	if ((*p == '\0') || (*p == ',') || (*p == '.') || (*p == ':'))
388*2907Scth 		goto fail;			/* no <instunit> */
3892723Scth 	len = p - ks_name;
3902723Scth 	(void) strncpy(driver, ks_name, len);
3912723Scth 	driver[len] = '\0';
3922723Scth 	instunit = atoi(p);
393*2907Scth 	if (part)
394*2907Scth 		part++;				/* skip ',' */
3950Sstevel@tonic-gate 
396*2907Scth 	/* hash by instunit and search for existing entry */
3972723Scth 	dlhp = &disklist[instunit & (DISKLIST_MOD - 1)];
3982723Scth 	for (entry = *dlhp; entry; entry = entry->next) {
399*2907Scth 		if (strcmp(entry->ks_name, ks_name) == 0) {
4002723Scth 			return (entry);
4010Sstevel@tonic-gate 		}
4020Sstevel@tonic-gate 	}
4032723Scth 
404*2907Scth 	/* not found, translate kstat_name components and create new entry */
405*2907Scth 
406*2907Scth 	/* translate kstat_name dev information */
407*2907Scth 	if (drvinstunitpart2dev(driver, instunit, part,
408*2907Scth 	    &devpath, &adevpath, want_devid ? &devid : NULL) == 0) {
409*2907Scth 		goto fail;
4102723Scth 	}
4112723Scth 
412*2907Scth 	/* parse and translate path information */
413*2907Scth 	if (pidp) {
414*2907Scth 		/* parse path information: ".t#.<phci-driver><instance>" */
415*2907Scth 		pidp++;				/* skip '.' */
416*2907Scth 		initiator++;			/* skip '.' */
417*2907Scth 		if ((*pidp != 't') || !isdigit(pidp[1]))
418*2907Scth 			goto fail;		/* not ".t#" */
419*2907Scth 		pid = atoi(&pidp[1]);
420*2907Scth 
421*2907Scth 		/* translate <pid> to 'target-port' */
422*2907Scth 		if (drvpid2port(pid, &target_port) == 0)
423*2907Scth 			goto fail;
424*2907Scth 
425*2907Scth 		/* Establish 'target-port' form. */
426*2907Scth 		(void) snprintf(portform, sizeof (portform),
427*2907Scth 		    "%s.t%s.%s", adevpath, target_port, initiator);
428*2907Scth 		free(target_port);
429*2907Scth 		free(adevpath);
430*2907Scth 		adevpath = strdup(portform);
431*2907Scth 	}
432*2907Scth 
433*2907Scth 	/* make a new entry ... */
4342723Scth 	entry = safe_alloc(sizeof (disk_list_t));
435*2907Scth 	entry->ks_name = safe_strdup(ks_name);
4362723Scth 	entry->dname = devpath;
4372723Scth 	entry->dsk = adevpath;
4382723Scth 	entry->devidstr = devid;
4392723Scth 
440*2907Scth #ifdef	DEBUG
441*2907Scth 	(void) printf("lookup_ks_name:    new: %s	%s\n",
442*2907Scth 	    ks_name, entry->dsk ? entry->dsk : "NULL");
443*2907Scth #endif	/* DEBUG */
444*2907Scth 
445*2907Scth 	/* add new entry to head of hashed list */
4462723Scth 	entry->next = *dlhp;
4472723Scth 	*dlhp = entry;
4480Sstevel@tonic-gate 	return (entry);
449*2907Scth 
450*2907Scth fail:
451*2907Scth 	free(devpath);
452*2907Scth 	free(adevpath);
453*2907Scth 	free(devid);
454*2907Scth #ifdef	DEBUG
455*2907Scth 	(void) printf("lookup_ks_name: failed: %s\n", ks_name);
456*2907Scth #endif	/* DEBUG */
457*2907Scth 	return (NULL);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /*
4612723Scth  * Convert metadevice setno to setname by looking in /dev/md for symlinks
4622723Scth  * that point to "shared/setno" - the name of such a symlink is the setname.
4632723Scth  * The caller is responsible for freeing the returned string.
4640Sstevel@tonic-gate  */
4650Sstevel@tonic-gate static char *
mdsetno2name(int setno)4662723Scth mdsetno2name(int setno)
4670Sstevel@tonic-gate {
4682723Scth 	char		setlink[MAXPATHLEN + 1];
4692723Scth 	char		link[MAXPATHLEN + 1];
4702723Scth 	char		path[MAXPATHLEN + 1];
4712723Scth 	char		*p;
4722723Scth 	DIR		*dirp;
4732723Scth 	struct dirent	*dp;
4742723Scth 	size_t		len;
4752723Scth 	char		*mdsetname = NULL;
4760Sstevel@tonic-gate 
4772723Scth 	/* we are looking for a link to setlink */
4782723Scth 	(void) snprintf(setlink, MAXPATHLEN, "shared/%d", setno);
4790Sstevel@tonic-gate 
4802723Scth 	/* in the directory /dev/md */
4812723Scth 	(void) strcpy(path, "/dev/md/");
4822723Scth 	p = path + strlen(path);
4832723Scth 	dirp = opendir(path);
4842723Scth 	if (dirp == NULL)
4850Sstevel@tonic-gate 		return (NULL);
4860Sstevel@tonic-gate 
4872723Scth 	/* loop through /dev/md directory entries */
4882723Scth 	while ((dp = readdir(dirp)) != NULL) {
4890Sstevel@tonic-gate 
4902723Scth 		/* doing a readlink of entry (fails for non-symlinks) */
4912723Scth 		*p = '\0';
4922723Scth 		(void) strcpy(p, dp->d_name);
4932723Scth 		if ((len = readlink(path, link, MAXPATHLEN)) == (size_t)-1)
4942723Scth 			continue;
4950Sstevel@tonic-gate 
4962723Scth 		/* and looking for a link to setlink */
4972723Scth 		link[len] = '\0';
4982723Scth 		if (strcmp(setlink, link))
4992723Scth 			continue;
5000Sstevel@tonic-gate 
5012723Scth 		/* found- name of link is the setname */
5022723Scth 		mdsetname = safe_strdup(dp->d_name);
5032723Scth 		break;
5040Sstevel@tonic-gate 	}
5050Sstevel@tonic-gate 
5062723Scth 	(void) closedir(dirp);
5072723Scth 	return (mdsetname);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate char *
lookup_nfs_name(char * ks,kstat_ctl_t * kc)5110Sstevel@tonic-gate lookup_nfs_name(char *ks, kstat_ctl_t *kc)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate 	uint_t minor;
5140Sstevel@tonic-gate 	char *host, *path;
5150Sstevel@tonic-gate 	char *cp;
5160Sstevel@tonic-gate 	char *rstr = 0;
5170Sstevel@tonic-gate 	size_t len;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	if (sscanf(ks, "nfs%u", &minor) == 1) {
5200Sstevel@tonic-gate retry:
5210Sstevel@tonic-gate 		cp = get_nfs_by_minor(minor);
5220Sstevel@tonic-gate 		if (cp) {
5230Sstevel@tonic-gate 			if (strchr(cp, ',') == NULL) {
5240Sstevel@tonic-gate 				rstr = safe_strdup(cp);
5250Sstevel@tonic-gate 				return (rstr);
5260Sstevel@tonic-gate 			}
5270Sstevel@tonic-gate 			host = cur_hostname(minor, kc);
5280Sstevel@tonic-gate 			if (host) {
5290Sstevel@tonic-gate 				if (*host) {
5300Sstevel@tonic-gate 					path = cur_special(host, cp);
5310Sstevel@tonic-gate 					if (path) {
5320Sstevel@tonic-gate 						len = strlen(host);
5330Sstevel@tonic-gate 						len += strlen(path);
5340Sstevel@tonic-gate 						len += 2;
5350Sstevel@tonic-gate 						rstr = safe_alloc(len);
5360Sstevel@tonic-gate 						(void) snprintf(rstr, len,
5370Sstevel@tonic-gate 						    "%s:%s", host, path);
5380Sstevel@tonic-gate 					} else {
5390Sstevel@tonic-gate 						rstr = safe_strdup(cp);
5400Sstevel@tonic-gate 					}
5410Sstevel@tonic-gate 				} else {
5420Sstevel@tonic-gate 					rstr = safe_strdup(ks);
5430Sstevel@tonic-gate 				}
5440Sstevel@tonic-gate 				free(host);
5450Sstevel@tonic-gate 			} else {
5460Sstevel@tonic-gate 				rstr = safe_strdup(cp);
5470Sstevel@tonic-gate 			}
5482723Scth 		} else if (nfs_tried == 0) {
5492723Scth 			nfs_tried = 1;
5500Sstevel@tonic-gate 			do_mnttab();
5510Sstevel@tonic-gate 			goto retry;
5520Sstevel@tonic-gate 		}
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 	return (rstr);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate static char *
get_nfs_by_minor(uint_t minor)5580Sstevel@tonic-gate get_nfs_by_minor(uint_t minor)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 	mnt_t *localnfs;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	localnfs = nfs;
5630Sstevel@tonic-gate 	while (localnfs) {
5640Sstevel@tonic-gate 		if (localnfs->minor == minor) {
5650Sstevel@tonic-gate 			return (localnfs->device_name);
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 		localnfs = localnfs->next;
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 	return (0);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate /*
5730Sstevel@tonic-gate  * Read the cur_hostname from the mntinfo kstat
5740Sstevel@tonic-gate  */
5750Sstevel@tonic-gate static char *
cur_hostname(uint_t minor,kstat_ctl_t * kc)5760Sstevel@tonic-gate cur_hostname(uint_t minor, kstat_ctl_t *kc)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	kstat_t *ksp;
5790Sstevel@tonic-gate 	static struct mntinfo_kstat mik;
5800Sstevel@tonic-gate 	char *rstr;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
5830Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_RAW)
5840Sstevel@tonic-gate 			continue;
5850Sstevel@tonic-gate 		if (ksp->ks_instance != minor)
5860Sstevel@tonic-gate 			continue;
5870Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "nfs"))
5880Sstevel@tonic-gate 			continue;
5890Sstevel@tonic-gate 		if (strcmp(ksp->ks_name, "mntinfo"))
5900Sstevel@tonic-gate 			continue;
5910Sstevel@tonic-gate 		if (ksp->ks_flags & KSTAT_FLAG_INVALID)
5920Sstevel@tonic-gate 			return (NULL);
5930Sstevel@tonic-gate 		if (kstat_read(kc, ksp, &mik) == -1)
5940Sstevel@tonic-gate 			return (NULL);
5950Sstevel@tonic-gate 		rstr = safe_strdup(mik.mik_curserver);
5960Sstevel@tonic-gate 		return (rstr);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 	return (NULL);
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate /*
6020Sstevel@tonic-gate  * Given the hostname of the mounted server, extract the server
6030Sstevel@tonic-gate  * mount point from the mnttab string.
6040Sstevel@tonic-gate  *
6050Sstevel@tonic-gate  * Common forms:
6060Sstevel@tonic-gate  *	server1,server2,server3:/path
6070Sstevel@tonic-gate  *	server1:/path,server2:/path
6080Sstevel@tonic-gate  * or a hybrid of the two
6090Sstevel@tonic-gate  */
6100Sstevel@tonic-gate static char *
cur_special(char * hostname,char * special)6110Sstevel@tonic-gate cur_special(char *hostname, char *special)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate 	char *cp;
6140Sstevel@tonic-gate 	char *path;
6150Sstevel@tonic-gate 	size_t hlen = strlen(hostname);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	/*
6180Sstevel@tonic-gate 	 * find hostname in string
6190Sstevel@tonic-gate 	 */
6200Sstevel@tonic-gate again:
6210Sstevel@tonic-gate 	if ((cp = strstr(special, hostname)) == NULL)
6220Sstevel@tonic-gate 		return (NULL);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/*
6250Sstevel@tonic-gate 	 * hostname must be followed by ',' or ':'
6260Sstevel@tonic-gate 	 */
6270Sstevel@tonic-gate 	if (cp[hlen] != ',' && cp[hlen] != ':') {
6280Sstevel@tonic-gate 		special = &cp[hlen];
6290Sstevel@tonic-gate 		goto again;
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	/*
6330Sstevel@tonic-gate 	 * If hostname is followed by a ',' eat all characters until a ':'
6340Sstevel@tonic-gate 	 */
6350Sstevel@tonic-gate 	cp = &cp[hlen];
6360Sstevel@tonic-gate 	if (*cp == ',') {
6370Sstevel@tonic-gate 		cp++;
6380Sstevel@tonic-gate 		while (*cp != ':') {
6390Sstevel@tonic-gate 			if (*cp == NULL)
6400Sstevel@tonic-gate 				return (NULL);
6410Sstevel@tonic-gate 			cp++;
6420Sstevel@tonic-gate 		}
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 	path = ++cp;			/* skip ':' */
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	/*
6470Sstevel@tonic-gate 	 * path is terminated by either 0, or space or ','
6480Sstevel@tonic-gate 	 */
6490Sstevel@tonic-gate 	while (*cp) {
6500Sstevel@tonic-gate 		if (isspace(*cp) || *cp == ',') {
6510Sstevel@tonic-gate 			*cp = NULL;
6520Sstevel@tonic-gate 			return (path);
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 		cp++;
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 	return (path);
6570Sstevel@tonic-gate }
658