xref: /titanic_53/usr/src/cmd/stat/common/dsr.c (revision a08731ec17cb062d80f19791149c20e0f2f43b01)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54e78ab0bScth  * Common Development and Distribution License (the "License").
64e78ab0bScth  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
224e78ab0bScth  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/stat.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Dependent on types.h, but not including it...
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
377c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
387c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
397c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
417c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
427c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
437c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
447c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
457c478bd9Sstevel@tonic-gate #include <kstat.h>
467c478bd9Sstevel@tonic-gate #include <ctype.h>
477c478bd9Sstevel@tonic-gate #include <dirent.h>
487c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
497c478bd9Sstevel@tonic-gate #include <limits.h>
507c478bd9Sstevel@tonic-gate #include <stdlib.h>
517c478bd9Sstevel@tonic-gate #include <string.h>
527c478bd9Sstevel@tonic-gate #include <unistd.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <devid.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include "dsr.h"
577c478bd9Sstevel@tonic-gate #include "statcommon.h"
587c478bd9Sstevel@tonic-gate 
59*a08731ecScth /* disk/tape info */
60*a08731ecScth static di_node_t	di_root;	/* for devid */
61*a08731ecScth static di_dim_t		di_dim;		/* for /dev names */
62*a08731ecScth typedef struct {
63*a08731ecScth 	char		*minor_name;
64*a08731ecScth 	int		minor_isdisk;
65*a08731ecScth } minor_match_t;
66*a08731ecScth static minor_match_t	mm_disk = {"a", 1};
67*a08731ecScth static minor_match_t	mm_tape	= {"", 0};
68*a08731ecScth static char		md_minor_name[MAXPATHLEN];
69*a08731ecScth static minor_match_t	mm_md	= {md_minor_name, 0};
70*a08731ecScth static minor_match_t	*mma_disk_tape[]	= {&mm_disk, &mm_tape, NULL};
71*a08731ecScth static minor_match_t	*mma_md[]		= {&mm_md, NULL};
72*a08731ecScth static char *mdsetno2name(int setno);
73*a08731ecScth #define	DISKLIST_MOD	256		/* ^2 instunit mod hash */
74*a08731ecScth static disk_list_t	*disklist[DISKLIST_MOD];
757c478bd9Sstevel@tonic-gate 
76*a08731ecScth /* nfs info */
77*a08731ecScth extern kstat_ctl_t	*kc;
78*a08731ecScth extern mnt_t		*nfs;
79*a08731ecScth static int		nfs_tried;
807c478bd9Sstevel@tonic-gate static char		*get_nfs_by_minor(uint_t);
817c478bd9Sstevel@tonic-gate static char		*cur_hostname(uint_t, kstat_ctl_t *);
827c478bd9Sstevel@tonic-gate static char		*cur_special(char *, char *);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
85*a08731ecScth  * Clear the snapshot so a cache miss in lookup_ks_name() will cause a fresh
86*a08731ecScth  * snapshot in drvinstunit2dev().
877c478bd9Sstevel@tonic-gate  */
88*a08731ecScth void
89*a08731ecScth cleanup_iodevs_snapshot()
907c478bd9Sstevel@tonic-gate {
91*a08731ecScth 	if (di_dim) {
92*a08731ecScth 		di_dim_fini(di_dim);
93*a08731ecScth 		di_dim = NULL;
94*a08731ecScth 	}
957c478bd9Sstevel@tonic-gate 
96*a08731ecScth 	if (di_root) {
97*a08731ecScth 		di_fini(di_root);
98*a08731ecScth 		di_root = DI_NODE_NIL;
99*a08731ecScth 	}
100*a08731ecScth 
101*a08731ecScth 	nfs_tried = 0;
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
105*a08731ecScth  * Find information for (driver, instunit) device: return zero on failure.
1067c478bd9Sstevel@tonic-gate  *
107*a08731ecScth  * NOTE: Failure of drvinstunit2dev works out OK for the caller if the kstat
108*a08731ecScth  * name is the same as public name: the caller will just use kstat name.
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate static int
111*a08731ecScth drvinstunit2dev(char *driver, int instunit,
112*a08731ecScth     char **devpathp, char **adevpathp, char **devidp, int *isdiskp)
1137c478bd9Sstevel@tonic-gate {
114*a08731ecScth 	int		instance;
115*a08731ecScth 	minor_match_t	**mma;
116*a08731ecScth 	minor_match_t	*mm;
117*a08731ecScth 	char		*devpath;
118*a08731ecScth 	char		*devid;
119*a08731ecScth 	char		*a, *s;
120*a08731ecScth 	int		mdsetno;
121*a08731ecScth 	char		*mdsetname = NULL;
122*a08731ecScth 	char		amdsetname[MAXPATHLEN];
123*a08731ecScth 	char		*devicespath;
124*a08731ecScth 	di_node_t	node;
125*a08731ecScth 
126*a08731ecScth 
127*a08731ecScth 	/* setup "no result" return values */
128*a08731ecScth 	if (devpathp)
129*a08731ecScth 		*devpathp = NULL;
130*a08731ecScth 	if (adevpathp)
131*a08731ecScth 		*adevpathp = NULL;
132*a08731ecScth 	if (devidp)
133*a08731ecScth 		*devidp = NULL;
134*a08731ecScth 	if (isdiskp)
135*a08731ecScth 		*isdiskp = 0;
136*a08731ecScth 
137*a08731ecScth 	/* take <driver><instance><minor_name> snapshot if not established */
138*a08731ecScth 	if (di_dim == NULL) {
139*a08731ecScth 		di_dim = di_dim_init();
140*a08731ecScth 		if (di_dim == NULL)
1417c478bd9Sstevel@tonic-gate 			return (0);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	/*
145*a08731ecScth 	 * Determine if 'instunit' is an 'instance' or 'unit' based on the
146*a08731ecScth 	 * 'driver'.  The current code only detects 'md' metadevice 'units',
147*a08731ecScth 	 * and defaults to 'instance' for everything else.
148*a08731ecScth 	 *
149*a08731ecScth 	 * For a metadevice, 'driver' is either "md" or "<setno>/md".
1507c478bd9Sstevel@tonic-gate 	 */
151*a08731ecScth 	s = strstr(driver, "/md");
152*a08731ecScth 	if ((strcmp(driver, "md") == 0) ||
153*a08731ecScth 	    (s && isdigit(*driver) && (strcmp(s, "/md") == 0))) {
1547c478bd9Sstevel@tonic-gate 		/*
155*a08731ecScth 		 * "md" unit: Special case translation of "md" kstat names.
156*a08731ecScth 		 * For the local set the kstat name is "md<unit>", and for
157*a08731ecScth 		 * a shared set the kstat name is "<setno>/md<unit>": we map
158*a08731ecScth 		 * these to the minor paths "/pseudo/md@0:<unit>,blk" and
159*a08731ecScth 		 * "/pseudo/md@0:<set>,<unit>,blk" respectively.
1607c478bd9Sstevel@tonic-gate 		 */
161*a08731ecScth 		if (isdigit(*driver)) {
162*a08731ecScth 			mdsetno = atoi(driver);
163*a08731ecScth 
164*a08731ecScth 			/* convert setno to setname */
165*a08731ecScth 			mdsetname = mdsetno2name(mdsetno);
166*a08731ecScth 		} else
167*a08731ecScth 			mdsetno = 0;
168*a08731ecScth 
169*a08731ecScth 		driver = "md";
170*a08731ecScth 		instance = 0;
171*a08731ecScth 		mma = mma_md;			/* metadevice dynamic minor */
172*a08731ecScth 		(void) snprintf(md_minor_name, sizeof (md_minor_name),
173*a08731ecScth 		    "%d,%d,blk", mdsetno, instunit);
174*a08731ecScth 	} else {
175*a08731ecScth 		instance = instunit;
176*a08731ecScth 		mma = mma_disk_tape;		/* disk/tape minors */
177*a08731ecScth 	}
178*a08731ecScth 
179*a08731ecScth 	/* Try to find a minor_match that works */
180*a08731ecScth 	for (mm = *mma++; mm; mm = *mma++)  {
181*a08731ecScth 		if ((devpath = di_dim_path_dev(di_dim,
182*a08731ecScth 		    driver, instance, mm->minor_name)) != NULL)
183*a08731ecScth 			break;
184*a08731ecScth 	}
185*a08731ecScth 	if (devpath == NULL)
186*a08731ecScth 		return (0);
187*a08731ecScth 
188*a08731ecScth 	/*
189*a08731ecScth 	 * At this point we have a devpath result. Return the information about
190*a08731ecScth 	 * the result that the caller is asking for.
191*a08731ecScth 	 */
192*a08731ecScth 	if (devpathp)			/* devpath */
193*a08731ecScth 		*devpathp = safe_strdup(devpath);
194*a08731ecScth 
195*a08731ecScth 	if (adevpathp) {		/* abbreviated devpath */
196*a08731ecScth 		if (mm->minor_isdisk) {
197*a08731ecScth 			/*
198*a08731ecScth 			 * For disks we return the last component (with
199*a08731ecScth 			 * trailing "s#" or "p#" stripped  off for disks).
200*a08731ecScth 			 * For example for devpath of "/dev/dsk/c0t0d0s0" the
201*a08731ecScth 			 * abbreviated devpath would be "c0t0d0".
202*a08731ecScth 			 */
203*a08731ecScth 			a = strrchr(devpath, '/');
204*a08731ecScth 			if (a == NULL) {
205*a08731ecScth 				free(devpath);
206*a08731ecScth 				return (0);
207*a08731ecScth 			}
208*a08731ecScth 			a++;
209*a08731ecScth 			s = strrchr(a, 's');
210*a08731ecScth 			if (s == NULL) {
211*a08731ecScth 				s = strrchr(a, 'p');
212*a08731ecScth 				if (s == NULL) {
213*a08731ecScth 					free(devpath);
214*a08731ecScth 					return (0);
215*a08731ecScth 				}
216*a08731ecScth 			}
217*a08731ecScth 			/* don't include slice information in devpath */
218*a08731ecScth 			*s = '\0';
219*a08731ecScth 		} else {
220*a08731ecScth 			/*
221*a08731ecScth 			 * remove "/dev/", and "/dsk/", from 'devpath' (like
222*a08731ecScth 			 * "/dev/md/dsk/d0") to form the abbreviated devpath
223*a08731ecScth 			 * (like "md/d0").
224*a08731ecScth 			 */
225*a08731ecScth 			if ((s = strstr(devpath, "/dev/")) != NULL)
226*a08731ecScth 				(void) strcpy(s + 1, s + 5);
227*a08731ecScth 			if ((s = strstr(devpath, "/dsk/")) != NULL)
228*a08731ecScth 				(void) strcpy(s + 1, s + 5);
229*a08731ecScth 
230*a08731ecScth 			/*
231*a08731ecScth 			 * If we have an mdsetname, convert abbreviated setno
232*a08731ecScth 			 * notation (like "md/shared/1/d0" to abbreviated
233*a08731ecScth 			 * setname notation (like "md/red/d0").
234*a08731ecScth 			 */
235*a08731ecScth 			if (mdsetname) {
236*a08731ecScth 				a = strrchr(devpath, '/');
237*a08731ecScth 				(void) snprintf(amdsetname, sizeof (amdsetname),
238*a08731ecScth 				    "md/%s%s", mdsetname, a);
239*a08731ecScth 				free(mdsetname);
240*a08731ecScth 				a = amdsetname;
241*a08731ecScth 			} else {
242*a08731ecScth 				if (*devpath == '/')
243*a08731ecScth 					a = devpath + 1;
2447c478bd9Sstevel@tonic-gate 				else
245*a08731ecScth 					a = devpath;
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 		}
248*a08731ecScth 		*adevpathp = safe_strdup(a);
249*a08731ecScth 	}
250*a08731ecScth 
251*a08731ecScth 	if (devidp) {			/* lookup the devid */
252*a08731ecScth 		/* take snapshots if not established */
253*a08731ecScth 		if (di_root == DI_NODE_NIL) {
254*a08731ecScth 			di_root = di_init("/", DINFOCACHE);
255*a08731ecScth 		}
256*a08731ecScth 		if (di_root) {
257*a08731ecScth 			/* get path to /devices devinfo node */
258*a08731ecScth 			devicespath = di_dim_path_devices(di_dim,
259*a08731ecScth 			    driver, instance, NULL);
260*a08731ecScth 			if (devicespath) {
261*a08731ecScth 				/* find the node in the snapshot */
262*a08731ecScth 				node = di_lookup_node(di_root, devicespath);
263*a08731ecScth 				free(devicespath);
264*a08731ecScth 
265*a08731ecScth 				/* and lookup devid property on the node */
266*a08731ecScth 				if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
267*a08731ecScth 				    DEVID_PROP_NAME, &devid) != -1)
268*a08731ecScth 					*devidp = devid;
269*a08731ecScth 			}
270*a08731ecScth 		}
271*a08731ecScth 	}
272*a08731ecScth 
273*a08731ecScth 	if (isdiskp)
274*a08731ecScth 		*isdiskp = mm->minor_isdisk;
275*a08731ecScth 
276*a08731ecScth 	free(devpath);
277*a08731ecScth 	return (1);				/* success */
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
281*a08731ecScth  * Find/create a disk_list entry for "<driver><instunit>" given a kstat name.
282*a08731ecScth  * The basic format of a kstat name is "<driver><instunit>,<partition>". The
283*a08731ecScth  * <instunit> is a base10 number, and the ",<partition>" part is optional.
284*a08731ecScth  *
285*a08731ecScth  * NOTE: In the case of non-local metadevices, the format of "<driver>" in
286*a08731ecScth  * a kstat name is acutally "<setno>/md".
2877c478bd9Sstevel@tonic-gate  */
288*a08731ecScth disk_list_t *
289*a08731ecScth lookup_ks_name(char *ks_name, int want_devid)
2907c478bd9Sstevel@tonic-gate {
291*a08731ecScth 	char		*p;
292*a08731ecScth 	int		len;
293*a08731ecScth 	char		driver[MAXNAMELEN];
294*a08731ecScth 	int		instunit;
295*a08731ecScth 	disk_list_t	**dlhp;		/* disklist head */
2967c478bd9Sstevel@tonic-gate 	disk_list_t	*entry;
297*a08731ecScth 	char		*devpath;
298*a08731ecScth 	char		*adevpath = NULL;
299*a08731ecScth 	char		*devid = NULL;
300*a08731ecScth 	int		isdisk;
3017c478bd9Sstevel@tonic-gate 
302*a08731ecScth 	/*
303*a08731ecScth 	 * Extract <driver> and <instunit> from kstat name.
304*a08731ecScth 	 * Filter out illegal forms (like all digits).
305*a08731ecScth 	 */
306*a08731ecScth 	if ((ks_name == NULL) || (*ks_name == 0) ||
307*a08731ecScth 	    (strspn(ks_name, "0123456789") == strlen(ks_name)))
308*a08731ecScth 		return (NULL);
309*a08731ecScth 	p = strrchr(ks_name, ',');		/* start of ",partition" */
310*a08731ecScth 	if (p == NULL)
311*a08731ecScth 		p = &ks_name[strlen(ks_name) - 1];	/* last char */
312*a08731ecScth 	else
313*a08731ecScth 		p--;				/* before ",partition" */
314*a08731ecScth 
315*a08731ecScth 	while ((p >= ks_name) && isdigit(*p))
316*a08731ecScth 		p--;				/* backwards over digits */
317*a08731ecScth 	p++;					/* start of instunit */
318*a08731ecScth 	if ((*p == '\0') || (*p == ','))
319*a08731ecScth 		return (NULL);			/* no <instunit> */
320*a08731ecScth 	len = p - ks_name;
321*a08731ecScth 	(void) strncpy(driver, ks_name, len);
322*a08731ecScth 	driver[len] = '\0';
323*a08731ecScth 	instunit = atoi(p);
324*a08731ecScth 
325*a08731ecScth 	/* hash and search for existing disklist entry */
326*a08731ecScth 	dlhp = &disklist[instunit & (DISKLIST_MOD - 1)];
327*a08731ecScth 	for (entry = *dlhp; entry; entry = entry->next) {
328*a08731ecScth 		if ((strcmp(entry->dtype, driver) == 0) &&
329*a08731ecScth 		    (entry->dnum == instunit)) {
330*a08731ecScth 			return (entry);
331*a08731ecScth 		}
332*a08731ecScth 	}
333*a08731ecScth 
334*a08731ecScth 	/* not found, try to get dev information */
335*a08731ecScth 	if (drvinstunit2dev(driver, instunit, &devpath, &adevpath,
336*a08731ecScth 	    want_devid ? &devid : NULL, &isdisk) == 0) {
337*a08731ecScth 		return (NULL);
338*a08731ecScth 	}
339*a08731ecScth 
340*a08731ecScth 	/* and make a new disklist entry ... */
3417c478bd9Sstevel@tonic-gate 	entry = safe_alloc(sizeof (disk_list_t));
342*a08731ecScth 	entry->dtype = safe_strdup(driver);
343*a08731ecScth 	entry->dnum = instunit;
344*a08731ecScth 	entry->dname = devpath;
345*a08731ecScth 	entry->dsk = adevpath;
346*a08731ecScth 	entry->devidstr = devid;
347*a08731ecScth 	entry->flags = 0;
348*a08731ecScth 	if (isdisk) {
349*a08731ecScth 		entry->flags |= SLICES_OK;
350*a08731ecScth #if defined(__i386)
351*a08731ecScth 		entry->flags |= PARTITIONS_OK;
352*a08731ecScth #endif
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	entry->seen = 0;
355*a08731ecScth 
356*a08731ecScth 	/* add new entry to head of instunit hashed list */
357*a08731ecScth 	entry->next = *dlhp;
358*a08731ecScth 	*dlhp = entry;
3597c478bd9Sstevel@tonic-gate 	return (entry);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate /*
363*a08731ecScth  * Convert metadevice setno to setname by looking in /dev/md for symlinks
364*a08731ecScth  * that point to "shared/setno" - the name of such a symlink is the setname.
365*a08731ecScth  * The caller is responsible for freeing the returned string.
3667c478bd9Sstevel@tonic-gate  */
3677c478bd9Sstevel@tonic-gate static char *
368*a08731ecScth mdsetno2name(int setno)
3697c478bd9Sstevel@tonic-gate {
370*a08731ecScth 	char		setlink[MAXPATHLEN + 1];
371*a08731ecScth 	char		link[MAXPATHLEN + 1];
372*a08731ecScth 	char		path[MAXPATHLEN + 1];
373*a08731ecScth 	char		*p;
374*a08731ecScth 	DIR		*dirp;
375*a08731ecScth 	struct dirent	*dp;
376*a08731ecScth 	size_t		len;
377*a08731ecScth 	char		*mdsetname = NULL;
3787c478bd9Sstevel@tonic-gate 
379*a08731ecScth 	/* we are looking for a link to setlink */
380*a08731ecScth 	(void) snprintf(setlink, MAXPATHLEN, "shared/%d", setno);
3817c478bd9Sstevel@tonic-gate 
382*a08731ecScth 	/* in the directory /dev/md */
383*a08731ecScth 	(void) strcpy(path, "/dev/md/");
384*a08731ecScth 	p = path + strlen(path);
385*a08731ecScth 	dirp = opendir(path);
386*a08731ecScth 	if (dirp == NULL)
3877c478bd9Sstevel@tonic-gate 		return (NULL);
3887c478bd9Sstevel@tonic-gate 
389*a08731ecScth 	/* loop through /dev/md directory entries */
390*a08731ecScth 	while ((dp = readdir(dirp)) != NULL) {
3917c478bd9Sstevel@tonic-gate 
392*a08731ecScth 		/* doing a readlink of entry (fails for non-symlinks) */
393*a08731ecScth 		*p = '\0';
394*a08731ecScth 		(void) strcpy(p, dp->d_name);
395*a08731ecScth 		if ((len = readlink(path, link, MAXPATHLEN)) == (size_t)-1)
396*a08731ecScth 			continue;
3977c478bd9Sstevel@tonic-gate 
398*a08731ecScth 		/* and looking for a link to setlink */
399*a08731ecScth 		link[len] = '\0';
400*a08731ecScth 		if (strcmp(setlink, link))
401*a08731ecScth 			continue;
402*a08731ecScth 
403*a08731ecScth 		/* found- name of link is the setname */
404*a08731ecScth 		mdsetname = safe_strdup(dp->d_name);
4057c478bd9Sstevel@tonic-gate 		break;
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
408*a08731ecScth 	(void) closedir(dirp);
409*a08731ecScth 	return (mdsetname);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate char *
4137c478bd9Sstevel@tonic-gate lookup_nfs_name(char *ks, kstat_ctl_t *kc)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	uint_t minor;
4167c478bd9Sstevel@tonic-gate 	char *host, *path;
4177c478bd9Sstevel@tonic-gate 	char *cp;
4187c478bd9Sstevel@tonic-gate 	char *rstr = 0;
4197c478bd9Sstevel@tonic-gate 	size_t len;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	if (sscanf(ks, "nfs%u", &minor) == 1) {
4227c478bd9Sstevel@tonic-gate retry:
4237c478bd9Sstevel@tonic-gate 		cp = get_nfs_by_minor(minor);
4247c478bd9Sstevel@tonic-gate 		if (cp) {
4257c478bd9Sstevel@tonic-gate 			if (strchr(cp, ',') == NULL) {
4267c478bd9Sstevel@tonic-gate 				rstr = safe_strdup(cp);
4277c478bd9Sstevel@tonic-gate 				return (rstr);
4287c478bd9Sstevel@tonic-gate 			}
4297c478bd9Sstevel@tonic-gate 			host = cur_hostname(minor, kc);
4307c478bd9Sstevel@tonic-gate 			if (host) {
4317c478bd9Sstevel@tonic-gate 				if (*host) {
4327c478bd9Sstevel@tonic-gate 					path = cur_special(host, cp);
4337c478bd9Sstevel@tonic-gate 					if (path) {
4347c478bd9Sstevel@tonic-gate 						len = strlen(host);
4357c478bd9Sstevel@tonic-gate 						len += strlen(path);
4367c478bd9Sstevel@tonic-gate 						len += 2;
4377c478bd9Sstevel@tonic-gate 						rstr = safe_alloc(len);
4387c478bd9Sstevel@tonic-gate 						(void) snprintf(rstr, len,
4397c478bd9Sstevel@tonic-gate 						    "%s:%s", host, path);
4407c478bd9Sstevel@tonic-gate 					} else {
4417c478bd9Sstevel@tonic-gate 						rstr = safe_strdup(cp);
4427c478bd9Sstevel@tonic-gate 					}
4437c478bd9Sstevel@tonic-gate 				} else {
4447c478bd9Sstevel@tonic-gate 					rstr = safe_strdup(ks);
4457c478bd9Sstevel@tonic-gate 				}
4467c478bd9Sstevel@tonic-gate 				free(host);
4477c478bd9Sstevel@tonic-gate 			} else {
4487c478bd9Sstevel@tonic-gate 				rstr = safe_strdup(cp);
4497c478bd9Sstevel@tonic-gate 			}
450*a08731ecScth 		} else if (nfs_tried == 0) {
451*a08731ecScth 			nfs_tried = 1;
4527c478bd9Sstevel@tonic-gate 			do_mnttab();
4537c478bd9Sstevel@tonic-gate 			goto retry;
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 	return (rstr);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate static char *
4607c478bd9Sstevel@tonic-gate get_nfs_by_minor(uint_t minor)
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate 	mnt_t *localnfs;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	localnfs = nfs;
4657c478bd9Sstevel@tonic-gate 	while (localnfs) {
4667c478bd9Sstevel@tonic-gate 		if (localnfs->minor == minor) {
4677c478bd9Sstevel@tonic-gate 			return (localnfs->device_name);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 		localnfs = localnfs->next;
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 	return (0);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate  * Read the cur_hostname from the mntinfo kstat
4767c478bd9Sstevel@tonic-gate  */
4777c478bd9Sstevel@tonic-gate static char *
4787c478bd9Sstevel@tonic-gate cur_hostname(uint_t minor, kstat_ctl_t *kc)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
4817c478bd9Sstevel@tonic-gate 	static struct mntinfo_kstat mik;
4827c478bd9Sstevel@tonic-gate 	char *rstr;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
4857c478bd9Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_RAW)
4867c478bd9Sstevel@tonic-gate 			continue;
4877c478bd9Sstevel@tonic-gate 		if (ksp->ks_instance != minor)
4887c478bd9Sstevel@tonic-gate 			continue;
4897c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "nfs"))
4907c478bd9Sstevel@tonic-gate 			continue;
4917c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_name, "mntinfo"))
4927c478bd9Sstevel@tonic-gate 			continue;
4937c478bd9Sstevel@tonic-gate 		if (ksp->ks_flags & KSTAT_FLAG_INVALID)
4947c478bd9Sstevel@tonic-gate 			return (NULL);
4957c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, ksp, &mik) == -1)
4967c478bd9Sstevel@tonic-gate 			return (NULL);
4977c478bd9Sstevel@tonic-gate 		rstr = safe_strdup(mik.mik_curserver);
4987c478bd9Sstevel@tonic-gate 		return (rstr);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 	return (NULL);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate /*
5047c478bd9Sstevel@tonic-gate  * Given the hostname of the mounted server, extract the server
5057c478bd9Sstevel@tonic-gate  * mount point from the mnttab string.
5067c478bd9Sstevel@tonic-gate  *
5077c478bd9Sstevel@tonic-gate  * Common forms:
5087c478bd9Sstevel@tonic-gate  *	server1,server2,server3:/path
5097c478bd9Sstevel@tonic-gate  *	server1:/path,server2:/path
5107c478bd9Sstevel@tonic-gate  * or a hybrid of the two
5117c478bd9Sstevel@tonic-gate  */
5127c478bd9Sstevel@tonic-gate static char *
5137c478bd9Sstevel@tonic-gate cur_special(char *hostname, char *special)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	char *cp;
5167c478bd9Sstevel@tonic-gate 	char *path;
5177c478bd9Sstevel@tonic-gate 	size_t hlen = strlen(hostname);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	/*
5207c478bd9Sstevel@tonic-gate 	 * find hostname in string
5217c478bd9Sstevel@tonic-gate 	 */
5227c478bd9Sstevel@tonic-gate again:
5237c478bd9Sstevel@tonic-gate 	if ((cp = strstr(special, hostname)) == NULL)
5247c478bd9Sstevel@tonic-gate 		return (NULL);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	/*
5277c478bd9Sstevel@tonic-gate 	 * hostname must be followed by ',' or ':'
5287c478bd9Sstevel@tonic-gate 	 */
5297c478bd9Sstevel@tonic-gate 	if (cp[hlen] != ',' && cp[hlen] != ':') {
5307c478bd9Sstevel@tonic-gate 		special = &cp[hlen];
5317c478bd9Sstevel@tonic-gate 		goto again;
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/*
5357c478bd9Sstevel@tonic-gate 	 * If hostname is followed by a ',' eat all characters until a ':'
5367c478bd9Sstevel@tonic-gate 	 */
5377c478bd9Sstevel@tonic-gate 	cp = &cp[hlen];
5387c478bd9Sstevel@tonic-gate 	if (*cp == ',') {
5397c478bd9Sstevel@tonic-gate 		cp++;
5407c478bd9Sstevel@tonic-gate 		while (*cp != ':') {
5417c478bd9Sstevel@tonic-gate 			if (*cp == NULL)
5427c478bd9Sstevel@tonic-gate 				return (NULL);
5437c478bd9Sstevel@tonic-gate 			cp++;
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 	path = ++cp;			/* skip ':' */
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	/*
5497c478bd9Sstevel@tonic-gate 	 * path is terminated by either 0, or space or ','
5507c478bd9Sstevel@tonic-gate 	 */
5517c478bd9Sstevel@tonic-gate 	while (*cp) {
5527c478bd9Sstevel@tonic-gate 		if (isspace(*cp) || *cp == ',') {
5537c478bd9Sstevel@tonic-gate 			*cp = NULL;
5547c478bd9Sstevel@tonic-gate 			return (path);
5557c478bd9Sstevel@tonic-gate 		}
5567c478bd9Sstevel@tonic-gate 		cp++;
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 	return (path);
5597c478bd9Sstevel@tonic-gate }
560