xref: /titanic_53/usr/src/cmd/stat/common/dsr.c (revision 4e78ab0b9d0501e5cbc9350082021bed9519ec06)
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
5*4e78ab0bScth  * Common Development and Distribution License (the "License").
6*4e78ab0bScth  * 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 /*
22*4e78ab0bScth  * 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 
597c478bd9Sstevel@tonic-gate static void rummage_dev(ldinfo_t *);
607c478bd9Sstevel@tonic-gate static void do_snm(char *, char *);
617c478bd9Sstevel@tonic-gate static int look_up_name(const char *, disk_list_t *);
627c478bd9Sstevel@tonic-gate static disk_list_t *make_an_entry(char *, char *,
637c478bd9Sstevel@tonic-gate     char *, dir_info_t *, int, ldinfo_t *);
647c478bd9Sstevel@tonic-gate static char *trim(char *, char *, int);
657c478bd9Sstevel@tonic-gate static ldinfo_t	*rummage_devinfo(void);
667c478bd9Sstevel@tonic-gate static void pline(char *, int, char *, char *, ldinfo_t **);
677c478bd9Sstevel@tonic-gate static void insert_dlist_ent(disk_list_t *, disk_list_t **);
687c478bd9Sstevel@tonic-gate static int str_is_digit(char *);
697c478bd9Sstevel@tonic-gate static ldinfo_t *find_ldinfo_match(char *, ldinfo_t *);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static void insert_into_dlist(dir_info_t *, disk_list_t *);
727c478bd9Sstevel@tonic-gate static void cleanup_dlist(dir_info_t *);
737c478bd9Sstevel@tonic-gate static void cleanup_ldinfo(ldinfo_t *);
747c478bd9Sstevel@tonic-gate static int devinfo_ident_disks(di_node_t, void *);
757c478bd9Sstevel@tonic-gate static int devinfo_ident_tapes(di_node_t, void *);
767c478bd9Sstevel@tonic-gate static void process_dir_ent(char *dent, int curr_type,
777c478bd9Sstevel@tonic-gate     char *last_snm, dir_info_t *, ldinfo_t *);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static char *get_nfs_by_minor(uint_t);
807c478bd9Sstevel@tonic-gate static char *cur_hostname(uint_t, kstat_ctl_t *);
817c478bd9Sstevel@tonic-gate static char *cur_special(char *, char *);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate extern kstat_ctl_t *kc;
847c478bd9Sstevel@tonic-gate extern mnt_t *nfs;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate  * To do: add VXVM support: /dev/vx/dsk and ap support: /dev/ap/
887c478bd9Sstevel@tonic-gate  *
897c478bd9Sstevel@tonic-gate  * Note: Adding support for VxVM is *not* as simple as adding another
907c478bd9Sstevel@tonic-gate  * entry in the table and magically getting to see stuff related to
917c478bd9Sstevel@tonic-gate  * VxVM. The structure is radically different *AND* they don't produce
927c478bd9Sstevel@tonic-gate  * any IO kstats.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #define	OSA_DISK	0
967c478bd9Sstevel@tonic-gate #define	DISK		1
977c478bd9Sstevel@tonic-gate #define	MD_DISK		2
987c478bd9Sstevel@tonic-gate #define	TAPE		3
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #define	MAX_TYPES	4
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #define	OSA_DISK_PATH	"/dev/osa/dev/dsk"
1037c478bd9Sstevel@tonic-gate #define	MD_DISK_PATH	"/dev/md/dsk"
1047c478bd9Sstevel@tonic-gate #define	DISK_PATH	"/dev/dsk"
1057c478bd9Sstevel@tonic-gate #define	TAPE_PATH	"/dev/rmt"
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate #define	BASE_TRIM	"../../devices"
1087c478bd9Sstevel@tonic-gate #define	MD_TRIM		"../../../devices"
1097c478bd9Sstevel@tonic-gate #define	COLON		':'
1107c478bd9Sstevel@tonic-gate #define	COMMA		','
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate #define	NAME_BUFLEN	256
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static dir_info_t dlist[MAX_TYPES] = {
1157c478bd9Sstevel@tonic-gate 	OSA_DISK_PATH, 0, 0, 0, 0, "sd", BASE_TRIM, COLON,
1167c478bd9Sstevel@tonic-gate 	DISK_PATH, 0, 0, 0, 0, "sd", BASE_TRIM, COLON,
1177c478bd9Sstevel@tonic-gate 	MD_DISK_PATH, 0, 0, 0, 1, "md", MD_TRIM, COMMA,
1187c478bd9Sstevel@tonic-gate 	TAPE_PATH, 0, 0, 0, 0, "st", BASE_TRIM, COLON,
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Build a list of disks attached to the system.
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static void
1257c478bd9Sstevel@tonic-gate build_disk_list(void)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	ldinfo_t *ptoi;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/*
1307c478bd9Sstevel@tonic-gate 	 * Build the list of devices connected to the system.
1317c478bd9Sstevel@tonic-gate 	 */
1327c478bd9Sstevel@tonic-gate 	ptoi = rummage_devinfo();
1337c478bd9Sstevel@tonic-gate 	rummage_dev(ptoi);
1347c478bd9Sstevel@tonic-gate 	cleanup_ldinfo(ptoi);
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate  * Walk the /dev/dsk and /dev/rmt directories building a
1397c478bd9Sstevel@tonic-gate  * list of interesting devices. Interesting is everything in the
1407c478bd9Sstevel@tonic-gate  * /dev/dsk directory. We skip some of the stuff in the /dev/rmt
1417c478bd9Sstevel@tonic-gate  * directory.
1427c478bd9Sstevel@tonic-gate  *
1437c478bd9Sstevel@tonic-gate  * Note that not finding one or more of the directories is not an
1447c478bd9Sstevel@tonic-gate  * error.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate static void
1477c478bd9Sstevel@tonic-gate rummage_dev(ldinfo_t *ptoi)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	DIR		*dskp;
1507c478bd9Sstevel@tonic-gate 	int		i;
1517c478bd9Sstevel@tonic-gate 	struct stat 	buf;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_TYPES; i++) {
1547c478bd9Sstevel@tonic-gate 		if (stat(dlist[i].name, &buf) == 0) {
1557c478bd9Sstevel@tonic-gate 			if (dlist[i].mtime != buf.st_mtime) {
1567c478bd9Sstevel@tonic-gate 				/*
1577c478bd9Sstevel@tonic-gate 				 * We've found a change. We need to cleanup
1587c478bd9Sstevel@tonic-gate 				 * old information and then rebuild the list
1597c478bd9Sstevel@tonic-gate 				 * for this device type.
1607c478bd9Sstevel@tonic-gate 				 */
1617c478bd9Sstevel@tonic-gate 				cleanup_dlist(&dlist[i]);
1627c478bd9Sstevel@tonic-gate 				dlist[i].mtime = buf.st_mtime;
1637c478bd9Sstevel@tonic-gate 				if ((dskp = opendir(dlist[i].name))) {
1647c478bd9Sstevel@tonic-gate 					struct dirent 	*bpt;
1657c478bd9Sstevel@tonic-gate 					char	last_snm[NAME_BUFLEN];
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 					last_snm[0] = NULL;
1687c478bd9Sstevel@tonic-gate 					while ((bpt = readdir(dskp)) != NULL) {
1697c478bd9Sstevel@tonic-gate 						if (bpt->d_name[0] != '.') {
1707c478bd9Sstevel@tonic-gate 							process_dir_ent(
1717c478bd9Sstevel@tonic-gate 							    bpt->d_name,
1727c478bd9Sstevel@tonic-gate 							    i, last_snm,
1737c478bd9Sstevel@tonic-gate 							    &dlist[i],
1747c478bd9Sstevel@tonic-gate 							    ptoi);
1757c478bd9Sstevel@tonic-gate 						}
1767c478bd9Sstevel@tonic-gate 					}
1777c478bd9Sstevel@tonic-gate 				}
1787c478bd9Sstevel@tonic-gate 				(void) closedir(dskp);
1797c478bd9Sstevel@tonic-gate 			}
1807c478bd9Sstevel@tonic-gate 		}
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  * Walk the list of located devices and see if we've
1867c478bd9Sstevel@tonic-gate  * seen this device before. We look at the short name.
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate static int
1897c478bd9Sstevel@tonic-gate look_up_name(const char *nm, disk_list_t *list)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	while (list) {
1927c478bd9Sstevel@tonic-gate 		if (strcmp(list->dsk, nm) != 0)
1937c478bd9Sstevel@tonic-gate 			list = list->next;
1947c478bd9Sstevel@tonic-gate 		else {
1957c478bd9Sstevel@tonic-gate 			return (1);
1967c478bd9Sstevel@tonic-gate 		}
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 	return (0);
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * Take a name of the form cNtNdNsN or cNtNdNpN
2037c478bd9Sstevel@tonic-gate  * or /dev/dsk/CNtNdNsN or /dev/dsk/cNtNdNpN
2047c478bd9Sstevel@tonic-gate  * remove the trailing sN or pN. Simply looking
2057c478bd9Sstevel@tonic-gate  * for the first 's' or 'p' doesn't cut it.
2067c478bd9Sstevel@tonic-gate  */
2077c478bd9Sstevel@tonic-gate static void
2087c478bd9Sstevel@tonic-gate do_snm(char *orig, char *shortnm)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	char *tmp;
2117c478bd9Sstevel@tonic-gate 	char *ptmp;
2127c478bd9Sstevel@tonic-gate 	int done = 0;
2137c478bd9Sstevel@tonic-gate 	char repl_char = 0;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	tmp = strrchr(orig, 's');
2167c478bd9Sstevel@tonic-gate 	if (tmp) {
2177c478bd9Sstevel@tonic-gate 		ptmp = tmp;
2187c478bd9Sstevel@tonic-gate 		ptmp++;
2197c478bd9Sstevel@tonic-gate 		done = str_is_digit(ptmp);
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate 	if (done == 0) {
2227c478bd9Sstevel@tonic-gate 		/*
2237c478bd9Sstevel@tonic-gate 		 * The string either has no 's' in it
2247c478bd9Sstevel@tonic-gate 		 * or the stuff trailing the s has a
2257c478bd9Sstevel@tonic-gate 		 * non-numeric in it. Look to see if
2267c478bd9Sstevel@tonic-gate 		 * we have an ending 'p' followed by
2277c478bd9Sstevel@tonic-gate 		 * numerics.
2287c478bd9Sstevel@tonic-gate 		 */
2297c478bd9Sstevel@tonic-gate 		tmp = strrchr(orig, 'p');
2307c478bd9Sstevel@tonic-gate 		if (tmp) {
2317c478bd9Sstevel@tonic-gate 			ptmp = tmp;
2327c478bd9Sstevel@tonic-gate 			ptmp++;
2337c478bd9Sstevel@tonic-gate 			if (str_is_digit(ptmp))
2347c478bd9Sstevel@tonic-gate 				repl_char = 'p';
2357c478bd9Sstevel@tonic-gate 			else
2367c478bd9Sstevel@tonic-gate 				tmp = 0;
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 	} else {
2397c478bd9Sstevel@tonic-gate 		repl_char = 's';
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 	if (tmp)
2427c478bd9Sstevel@tonic-gate 		*tmp = '\0';
2437c478bd9Sstevel@tonic-gate 	(void) strcpy(shortnm, orig);
2447c478bd9Sstevel@tonic-gate 	if (repl_char)
2457c478bd9Sstevel@tonic-gate 		*tmp = repl_char;
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate  * Create and insert an entry into the device list.
2507c478bd9Sstevel@tonic-gate  */
2517c478bd9Sstevel@tonic-gate static disk_list_t *
2527c478bd9Sstevel@tonic-gate make_an_entry(char *lname, char *shortnm, char *longnm,
2537c478bd9Sstevel@tonic-gate 	dir_info_t *drent, int devtype, ldinfo_t *ptoi)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	disk_list_t	*entry;
2567c478bd9Sstevel@tonic-gate 	char	*nlnm;
2577c478bd9Sstevel@tonic-gate 	char 	snm[NAME_BUFLEN];
2587c478bd9Sstevel@tonic-gate 	ldinfo_t *p;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	entry = safe_alloc(sizeof (disk_list_t));
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	nlnm = trim(lname, drent->trimstr, drent->trimchr);
2637c478bd9Sstevel@tonic-gate 	entry->dsk = safe_strdup(shortnm);
2647c478bd9Sstevel@tonic-gate 	do_snm(longnm, snm);
2657c478bd9Sstevel@tonic-gate 	entry->dname = safe_strdup(snm);
2667c478bd9Sstevel@tonic-gate 	entry->devtype = devtype;
2677c478bd9Sstevel@tonic-gate 	entry->devidstr = NULL;
2687c478bd9Sstevel@tonic-gate 	if ((p = find_ldinfo_match(nlnm, ptoi))) {
2697c478bd9Sstevel@tonic-gate 		entry->dnum = p->dnum;
2707c478bd9Sstevel@tonic-gate 		entry->dtype = safe_strdup(p->dtype);
2717c478bd9Sstevel@tonic-gate 		if (p->devidstr)
2727c478bd9Sstevel@tonic-gate 			entry->devidstr = safe_strdup(p->devidstr);
2737c478bd9Sstevel@tonic-gate 	} else {
2747c478bd9Sstevel@tonic-gate 		entry->dtype = safe_strdup(drent->dtype);
2757c478bd9Sstevel@tonic-gate 		entry->dnum = -1;
2767c478bd9Sstevel@tonic-gate 		if (drent->dtype) {
2777c478bd9Sstevel@tonic-gate 			if (strcmp(drent->dtype, "md") == 0) {
2787c478bd9Sstevel@tonic-gate 				(void) sscanf(shortnm, "d%d", &entry->dnum);
2797c478bd9Sstevel@tonic-gate 			}
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	entry->seen = 0;
2837c478bd9Sstevel@tonic-gate 	entry->next = 0;
2847c478bd9Sstevel@tonic-gate 	insert_dlist_ent(entry, &drent->list);
2857c478bd9Sstevel@tonic-gate 	return (entry);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate  * slice stuff off beginning and end of /devices directory names derived from
2907c478bd9Sstevel@tonic-gate  * device links.
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate static char *
2937c478bd9Sstevel@tonic-gate trim(char *fnm, char *lname, int rchr)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	char	*ptr;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	while (*lname == *fnm) {
2987c478bd9Sstevel@tonic-gate 		lname++;
2997c478bd9Sstevel@tonic-gate 		fnm++;
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 	if ((ptr = strrchr(fnm, rchr)))
3027c478bd9Sstevel@tonic-gate 		*ptr = NULL;
3037c478bd9Sstevel@tonic-gate 	return (fnm);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate  * Find an entry matching the name passed in
3087c478bd9Sstevel@tonic-gate  */
3097c478bd9Sstevel@tonic-gate static ldinfo_t *
3107c478bd9Sstevel@tonic-gate find_ldinfo_match(char *name, ldinfo_t *ptoi)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	if (name) {
3137c478bd9Sstevel@tonic-gate 		while (ptoi) {
3147c478bd9Sstevel@tonic-gate 			if (strcmp(ptoi->name, name))
3157c478bd9Sstevel@tonic-gate 				ptoi = ptoi->next;
3167c478bd9Sstevel@tonic-gate 			else
3177c478bd9Sstevel@tonic-gate 				return (ptoi);
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 	return (NULL);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate  * Determine if a name is already in the list of disks. If not, insert the
3257c478bd9Sstevel@tonic-gate  * name in the list.
3267c478bd9Sstevel@tonic-gate  */
3277c478bd9Sstevel@tonic-gate static void
3287c478bd9Sstevel@tonic-gate insert_dlist_ent(disk_list_t *n, disk_list_t **hd)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	disk_list_t *tmp_ptr;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (n->dtype != NULL) {
3337c478bd9Sstevel@tonic-gate 		tmp_ptr = *hd;
3347c478bd9Sstevel@tonic-gate 		while (tmp_ptr) {
3357c478bd9Sstevel@tonic-gate 			if (strcmp(n->dsk, tmp_ptr->dsk) != 0)
3367c478bd9Sstevel@tonic-gate 				tmp_ptr = tmp_ptr->next;
3377c478bd9Sstevel@tonic-gate 			else
3387c478bd9Sstevel@tonic-gate 				break;
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 		if (tmp_ptr == NULL) {
3417c478bd9Sstevel@tonic-gate 			/*
3427c478bd9Sstevel@tonic-gate 			 * We don't do anything with MD_DISK types here
3437c478bd9Sstevel@tonic-gate 			 * since they don't have partitions.
3447c478bd9Sstevel@tonic-gate 			 */
3457c478bd9Sstevel@tonic-gate 			if (n->devtype == DISK || n->devtype == OSA_DISK) {
3467c478bd9Sstevel@tonic-gate 				n->flags = SLICES_OK;
347c2e7b48dSkalai #if defined(__i386)
3487c478bd9Sstevel@tonic-gate 				n->flags |= PARTITIONS_OK;
3497c478bd9Sstevel@tonic-gate #endif
3507c478bd9Sstevel@tonic-gate 			} else {
3517c478bd9Sstevel@tonic-gate 				n->flags = 0;
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 			/*
3547c478bd9Sstevel@tonic-gate 			 * Figure out where to insert the name. The list is
3557c478bd9Sstevel@tonic-gate 			 * ostensibly in sorted order.
3567c478bd9Sstevel@tonic-gate 			 */
3577c478bd9Sstevel@tonic-gate 			if (*hd) {
3587c478bd9Sstevel@tonic-gate 				disk_list_t *follw;
3597c478bd9Sstevel@tonic-gate 				int	mv;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 				tmp_ptr = *hd;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 				/*
3647c478bd9Sstevel@tonic-gate 				 * Look through the list. While the strcmp
3657c478bd9Sstevel@tonic-gate 				 * value is less than the current value,
3667c478bd9Sstevel@tonic-gate 				 */
3677c478bd9Sstevel@tonic-gate 				while (tmp_ptr) {
3687c478bd9Sstevel@tonic-gate 					if ((mv = strcmp(n->dtype,
3697c478bd9Sstevel@tonic-gate 					    tmp_ptr->dtype)) < 0) {
3707c478bd9Sstevel@tonic-gate 						follw = tmp_ptr;
3717c478bd9Sstevel@tonic-gate 						tmp_ptr = tmp_ptr->next;
3727c478bd9Sstevel@tonic-gate 					} else
3737c478bd9Sstevel@tonic-gate 						break;
3747c478bd9Sstevel@tonic-gate 				}
3757c478bd9Sstevel@tonic-gate 				if (mv == 0) {
3767c478bd9Sstevel@tonic-gate 					/*
3777c478bd9Sstevel@tonic-gate 					 * We're now in the area where the
3787c478bd9Sstevel@tonic-gate 					 * leading chars of the kstat name
3797c478bd9Sstevel@tonic-gate 					 * match. We need to insert in numeric
3807c478bd9Sstevel@tonic-gate 					 * order after that.
3817c478bd9Sstevel@tonic-gate 					 */
3827c478bd9Sstevel@tonic-gate 					while (tmp_ptr) {
3837c478bd9Sstevel@tonic-gate 						if (strcmp(n->dtype,
3847c478bd9Sstevel@tonic-gate 						    tmp_ptr->dtype) != 0)
3857c478bd9Sstevel@tonic-gate 							break;
3867c478bd9Sstevel@tonic-gate 						if (n->dnum > tmp_ptr->dnum) {
3877c478bd9Sstevel@tonic-gate 							follw = tmp_ptr;
3887c478bd9Sstevel@tonic-gate 							tmp_ptr = tmp_ptr->next;
3897c478bd9Sstevel@tonic-gate 						} else
3907c478bd9Sstevel@tonic-gate 							break;
3917c478bd9Sstevel@tonic-gate 					}
3927c478bd9Sstevel@tonic-gate 				}
3937c478bd9Sstevel@tonic-gate 				/*
3947c478bd9Sstevel@tonic-gate 				 * We should now be ready to insert an
3957c478bd9Sstevel@tonic-gate 				 * entry...
3967c478bd9Sstevel@tonic-gate 				 */
3977c478bd9Sstevel@tonic-gate 				if (mv >= 0) {
3987c478bd9Sstevel@tonic-gate 					if (tmp_ptr == *hd) {
3997c478bd9Sstevel@tonic-gate 						n->next = tmp_ptr;
4007c478bd9Sstevel@tonic-gate 						*hd = n;
4017c478bd9Sstevel@tonic-gate 					} else {
4027c478bd9Sstevel@tonic-gate 						n->next = follw->next;
4037c478bd9Sstevel@tonic-gate 						follw->next = n;
4047c478bd9Sstevel@tonic-gate 					}
4057c478bd9Sstevel@tonic-gate 				} else {
4067c478bd9Sstevel@tonic-gate 					/*
4077c478bd9Sstevel@tonic-gate 					 * insert at the end of the
4087c478bd9Sstevel@tonic-gate 					 * list
4097c478bd9Sstevel@tonic-gate 					 */
4107c478bd9Sstevel@tonic-gate 					follw->next = n;
4117c478bd9Sstevel@tonic-gate 					n->next = 0;
4127c478bd9Sstevel@tonic-gate 				}
4137c478bd9Sstevel@tonic-gate 			} else {
4147c478bd9Sstevel@tonic-gate 				*hd = n;
4157c478bd9Sstevel@tonic-gate 				n->next = 0;
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate /*
4227c478bd9Sstevel@tonic-gate  * find an entry matching the given kstat name in the list
4237c478bd9Sstevel@tonic-gate  * of disks, tapes and metadevices.
4247c478bd9Sstevel@tonic-gate  */
4257c478bd9Sstevel@tonic-gate disk_list_t *
4267c478bd9Sstevel@tonic-gate lookup_ks_name(char *dev_nm)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	int tried = 0;
4297c478bd9Sstevel@tonic-gate 	int	dv;
4307c478bd9Sstevel@tonic-gate 	int	len;
4317c478bd9Sstevel@tonic-gate 	char	cmpbuf[PATH_MAX + 1];
4327c478bd9Sstevel@tonic-gate 	struct	list_of_disks *list;
4337c478bd9Sstevel@tonic-gate 	char	*nm;
4347c478bd9Sstevel@tonic-gate 	dev_name_t *tmp;
4357c478bd9Sstevel@tonic-gate 	uint_t	i;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	/*
4387c478bd9Sstevel@tonic-gate 	 * extract the device type from the kstat name. We expect the
4397c478bd9Sstevel@tonic-gate 	 * name to be one or more alphabetics followed by the device
4407c478bd9Sstevel@tonic-gate 	 * numeric id. We do this solely for speed purposes .
4417c478bd9Sstevel@tonic-gate 	 */
4427c478bd9Sstevel@tonic-gate 	len = 0;
4437c478bd9Sstevel@tonic-gate 	nm = dev_nm;
4447c478bd9Sstevel@tonic-gate 	while (*nm) {
4457c478bd9Sstevel@tonic-gate 		if (isalpha(*nm)) {
4467c478bd9Sstevel@tonic-gate 			nm++;
4477c478bd9Sstevel@tonic-gate 			len++;
4487c478bd9Sstevel@tonic-gate 		} else
4497c478bd9Sstevel@tonic-gate 			break;
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if (!*nm)
4537c478bd9Sstevel@tonic-gate 		return (NULL);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/*
4567c478bd9Sstevel@tonic-gate 	 * For each of the elements in the dlist array we keep
4577c478bd9Sstevel@tonic-gate 	 * an array of pointers to chains for each of the kstat
4587c478bd9Sstevel@tonic-gate 	 * prefixes found within that directory. This is typically
4597c478bd9Sstevel@tonic-gate 	 * 'sd' and 'ssd'. We walk the list in the directory and
4607c478bd9Sstevel@tonic-gate 	 * match on that type. Since the same prefixes can be
4617c478bd9Sstevel@tonic-gate 	 * in multiple places we keep checking if we don't find
4627c478bd9Sstevel@tonic-gate 	 * it in the first place.
4637c478bd9Sstevel@tonic-gate 	 */
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	(void) strncpy(cmpbuf, dev_nm, len);
4667c478bd9Sstevel@tonic-gate 	cmpbuf[len] = NULL;
4677c478bd9Sstevel@tonic-gate 	dv = atoi(nm);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate retry:
4707c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_TYPES; i++) {
4717c478bd9Sstevel@tonic-gate 		tmp = dlist[i].nf;
4727c478bd9Sstevel@tonic-gate 		while (tmp) {
4737c478bd9Sstevel@tonic-gate 			if (strcmp(tmp->name, cmpbuf) == 0) {
4747c478bd9Sstevel@tonic-gate 				/*
4757c478bd9Sstevel@tonic-gate 				 * As an optimization we keep mins
4767c478bd9Sstevel@tonic-gate 				 * and maxes for the devices found.
4777c478bd9Sstevel@tonic-gate 				 * This helps chop the lists up and
4787c478bd9Sstevel@tonic-gate 				 * avoid some really long chains as
4797c478bd9Sstevel@tonic-gate 				 * we would get if we kept only prefix
4807c478bd9Sstevel@tonic-gate 				 * lists.
4817c478bd9Sstevel@tonic-gate 				 */
4827c478bd9Sstevel@tonic-gate 				if (dv >= tmp->min && dv <= tmp->max) {
4837c478bd9Sstevel@tonic-gate 					list = tmp->list_start;
4847c478bd9Sstevel@tonic-gate 					while (list) {
4857c478bd9Sstevel@tonic-gate 						if (list->dnum < dv)
4867c478bd9Sstevel@tonic-gate 							list = list->next;
4877c478bd9Sstevel@tonic-gate 						else
4887c478bd9Sstevel@tonic-gate 							break;
4897c478bd9Sstevel@tonic-gate 					}
4907c478bd9Sstevel@tonic-gate 					if (list && list->dnum == dv) {
4917c478bd9Sstevel@tonic-gate 						return (list);
4927c478bd9Sstevel@tonic-gate 					}
4937c478bd9Sstevel@tonic-gate 				}
4947c478bd9Sstevel@tonic-gate 			}
4957c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	if (!tried) {
5007c478bd9Sstevel@tonic-gate 		tried = 1;
5017c478bd9Sstevel@tonic-gate 		build_disk_list();
5027c478bd9Sstevel@tonic-gate 		goto retry;
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	return (0);
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate static int
5097c478bd9Sstevel@tonic-gate str_is_digit(char *str)
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	while (*str) {
5127c478bd9Sstevel@tonic-gate 		if (isdigit(*str))
5137c478bd9Sstevel@tonic-gate 		    str++;
5147c478bd9Sstevel@tonic-gate 		else
5157c478bd9Sstevel@tonic-gate 		    return (0);
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 	return (1);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate static void
5217c478bd9Sstevel@tonic-gate insert_into_dlist(dir_info_t *d, disk_list_t *e)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	dev_name_t *tmp;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	tmp = d->nf;
5267c478bd9Sstevel@tonic-gate 	while (tmp) {
5277c478bd9Sstevel@tonic-gate 		if (strcmp(e->dtype, tmp->name) != 0) {
5287c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
5297c478bd9Sstevel@tonic-gate 		} else {
5307c478bd9Sstevel@tonic-gate 			if (e->dnum < tmp->min) {
5317c478bd9Sstevel@tonic-gate 				tmp->min = e->dnum;
5327c478bd9Sstevel@tonic-gate 				tmp->list_start = e;
5337c478bd9Sstevel@tonic-gate 			} else if (e->dnum > tmp->max) {
5347c478bd9Sstevel@tonic-gate 				tmp->max = e->dnum;
5357c478bd9Sstevel@tonic-gate 				tmp->list_end = e;
5367c478bd9Sstevel@tonic-gate 			}
5377c478bd9Sstevel@tonic-gate 			break;
5387c478bd9Sstevel@tonic-gate 		}
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {
5417c478bd9Sstevel@tonic-gate 		tmp = safe_alloc(sizeof (dev_name_t));
5427c478bd9Sstevel@tonic-gate 		tmp->name = e->dtype;
5437c478bd9Sstevel@tonic-gate 		tmp->min = e->dnum;
5447c478bd9Sstevel@tonic-gate 		tmp->max = e->dnum;
5457c478bd9Sstevel@tonic-gate 		tmp->list_start = e;
5467c478bd9Sstevel@tonic-gate 		tmp->list_end = e;
5477c478bd9Sstevel@tonic-gate 		tmp->next = d->nf;
5487c478bd9Sstevel@tonic-gate 		d->nf = tmp;
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate  * devinfo_ident_disks() and devinfo_ident_tapes() are the callback functions we
5547c478bd9Sstevel@tonic-gate  * use while walking the device tree snapshot provided by devinfo.  If
5557c478bd9Sstevel@tonic-gate  * devinfo_ident_disks() identifies that the device being considered has one or
5567c478bd9Sstevel@tonic-gate  * more minor nodes _and_ is a block device, then it is a potential disk.
5577c478bd9Sstevel@tonic-gate  * Similarly for devinfo_ident_tapes(), except that the second criterion is that
5587c478bd9Sstevel@tonic-gate  * the minor_node be a character device.  (This is more inclusive than only
5597c478bd9Sstevel@tonic-gate  * tape devices, but will match any entries in /dev/rmt/.)
5607c478bd9Sstevel@tonic-gate  *
5617c478bd9Sstevel@tonic-gate  * Note: if a driver was previously loaded but is now unloaded, the kstat may
5627c478bd9Sstevel@tonic-gate  * still be around (e.g., st) but no information will be found in the
5637c478bd9Sstevel@tonic-gate  * libdevinfo tree.
5647c478bd9Sstevel@tonic-gate  */
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate static int
5677c478bd9Sstevel@tonic-gate devinfo_ident_disks(di_node_t node, void *arg)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	di_minor_t minor = DI_MINOR_NIL;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
5727c478bd9Sstevel@tonic-gate 		int spectype = di_minor_spectype(minor);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 		if (S_ISBLK(spectype)) {
5757c478bd9Sstevel@tonic-gate 			char *physical_path = di_devfs_path(node);
5767c478bd9Sstevel@tonic-gate 			int instance = di_instance(node);
5777c478bd9Sstevel@tonic-gate 			char *driver_name = di_driver_name(node);
5787c478bd9Sstevel@tonic-gate 			char *devidstr;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 			/* lookup the devid, devt specific first */
5817c478bd9Sstevel@tonic-gate 			if ((di_prop_lookup_strings(di_minor_devt(minor), node,
5827c478bd9Sstevel@tonic-gate 			    DEVID_PROP_NAME, &devidstr) == -1) &&
5837c478bd9Sstevel@tonic-gate 			    (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
5847c478bd9Sstevel@tonic-gate 			    DEVID_PROP_NAME, &devidstr) == -1))
5857c478bd9Sstevel@tonic-gate 				devidstr = NULL;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 			if (driver_name == NULL)
5887c478bd9Sstevel@tonic-gate 				driver_name = "<nil>";
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 			pline(physical_path, instance,
5917c478bd9Sstevel@tonic-gate 				    driver_name, devidstr, arg);
5927c478bd9Sstevel@tonic-gate 			di_devfs_path_free(physical_path);
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 	}
5957c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate static int
5997c478bd9Sstevel@tonic-gate devinfo_ident_tapes(di_node_t node, void *arg)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	di_minor_t minor = DI_MINOR_NIL;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	if ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
6047c478bd9Sstevel@tonic-gate 		int spectype = di_minor_spectype(minor);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 		if (S_ISCHR(spectype)) {
6077c478bd9Sstevel@tonic-gate 			char *physical_path = di_devfs_path(node);
6087c478bd9Sstevel@tonic-gate 			int instance = di_instance(node);
6097c478bd9Sstevel@tonic-gate 			char *binding_name = di_binding_name(node);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 			pline(physical_path, instance,
6127c478bd9Sstevel@tonic-gate 			    binding_name, NULL, arg);
6137c478bd9Sstevel@tonic-gate 			di_devfs_path_free(physical_path);
6147c478bd9Sstevel@tonic-gate 		}
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate  * rummage_devinfo() is the driver routine that walks the devinfo snapshot.
6217c478bd9Sstevel@tonic-gate  */
6227c478bd9Sstevel@tonic-gate static ldinfo_t *
6237c478bd9Sstevel@tonic-gate rummage_devinfo(void)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate 	di_node_t root_node;
6267c478bd9Sstevel@tonic-gate 	ldinfo_t *rv = NULL;
6277c478bd9Sstevel@tonic-gate 
628*4e78ab0bScth 	if ((root_node = di_init("/", DINFOCACHE)) != DI_NODE_NIL) {
6297c478bd9Sstevel@tonic-gate 		(void) di_walk_node(root_node, DI_WALK_CLDFIRST, (void *)&rv,
6307c478bd9Sstevel@tonic-gate 			devinfo_ident_disks);
6317c478bd9Sstevel@tonic-gate 		(void) di_walk_node(root_node, DI_WALK_CLDFIRST, (void *)&rv,
6327c478bd9Sstevel@tonic-gate 			devinfo_ident_tapes);
6337c478bd9Sstevel@tonic-gate 		di_fini(root_node);
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 	return (rv);
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate  * pline() performs the lookup of the device path in the current list of disks,
6407c478bd9Sstevel@tonic-gate  * and adds the appropriate information to the nms list in the case of a match.
6417c478bd9Sstevel@tonic-gate  */
6427c478bd9Sstevel@tonic-gate static void
6437c478bd9Sstevel@tonic-gate pline(char *devfs_path, int instance,
6447c478bd9Sstevel@tonic-gate 	char *driver_name, char *devidstr, ldinfo_t **list)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 	ldinfo_t *entry;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	entry = safe_alloc(sizeof (ldinfo_t));
6497c478bd9Sstevel@tonic-gate 	entry->dnum = instance;
6507c478bd9Sstevel@tonic-gate 	entry->name = safe_strdup(devfs_path);
6517c478bd9Sstevel@tonic-gate 	entry->dtype = safe_strdup(driver_name);
6527c478bd9Sstevel@tonic-gate 	entry->devidstr = safe_strdup(devidstr);
6537c478bd9Sstevel@tonic-gate 	entry->next = *list;
6547c478bd9Sstevel@tonic-gate 	*list = entry;
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate /*
6587c478bd9Sstevel@tonic-gate  * Cleanup space allocated in dlist processing.
6597c478bd9Sstevel@tonic-gate  * We're only interested in cleaning up the list and nf
6607c478bd9Sstevel@tonic-gate  * fields in the structure. Everything else is static
6617c478bd9Sstevel@tonic-gate  * data.
6627c478bd9Sstevel@tonic-gate  */
6637c478bd9Sstevel@tonic-gate static void
6647c478bd9Sstevel@tonic-gate cleanup_dlist(dir_info_t *d)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	dev_name_t *tmp;
6677c478bd9Sstevel@tonic-gate 	dev_name_t *t1;
6687c478bd9Sstevel@tonic-gate 	disk_list_t *t2;
6697c478bd9Sstevel@tonic-gate 	disk_list_t *t3;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	/*
6727c478bd9Sstevel@tonic-gate 	 * All of the entries in a dev_name_t use information
6737c478bd9Sstevel@tonic-gate 	 * from a disk_list_t structure that is freed later.
6747c478bd9Sstevel@tonic-gate 	 * All we need do here is free the dev_name_t
6757c478bd9Sstevel@tonic-gate 	 * structure itself.
6767c478bd9Sstevel@tonic-gate 	 */
6777c478bd9Sstevel@tonic-gate 	tmp = d->nf;
6787c478bd9Sstevel@tonic-gate 	while (tmp) {
6797c478bd9Sstevel@tonic-gate 		t1 = tmp->next;
6807c478bd9Sstevel@tonic-gate 		free(tmp);
6817c478bd9Sstevel@tonic-gate 		tmp = t1;
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 	d->nf = 0;
6847c478bd9Sstevel@tonic-gate 	/*
6857c478bd9Sstevel@tonic-gate 	 * "Later". Free the disk_list_t structures and their
6867c478bd9Sstevel@tonic-gate 	 * data attached to this portion of the dir_info
6877c478bd9Sstevel@tonic-gate 	 * structure.
6887c478bd9Sstevel@tonic-gate 	 */
6897c478bd9Sstevel@tonic-gate 	t2 = d->list;
6907c478bd9Sstevel@tonic-gate 	while (t2) {
6917c478bd9Sstevel@tonic-gate 		if (t2->dtype) {
6927c478bd9Sstevel@tonic-gate 			free(t2->dtype);
6937c478bd9Sstevel@tonic-gate 			t2->dtype = NULL;
6947c478bd9Sstevel@tonic-gate 		}
6957c478bd9Sstevel@tonic-gate 		if (t2->dsk) {
6967c478bd9Sstevel@tonic-gate 			free(t2->dsk);
6977c478bd9Sstevel@tonic-gate 			t2->dsk = NULL;
6987c478bd9Sstevel@tonic-gate 		}
6997c478bd9Sstevel@tonic-gate 		if (t2->dname) {
7007c478bd9Sstevel@tonic-gate 			free(t2->dname);
7017c478bd9Sstevel@tonic-gate 			t2->dname = NULL;
7027c478bd9Sstevel@tonic-gate 		}
7037c478bd9Sstevel@tonic-gate 		t3 = t2->next;
7047c478bd9Sstevel@tonic-gate 		free(t2);
7057c478bd9Sstevel@tonic-gate 		t2 = t3;
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 	d->list = 0;
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate static void
7117c478bd9Sstevel@tonic-gate process_dir_ent(char *dent, int curr_type, char *last_snm,
7127c478bd9Sstevel@tonic-gate     dir_info_t *dp, ldinfo_t *ptoi)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	struct stat	sbuf;
7157c478bd9Sstevel@tonic-gate 	char	dnmbuf[PATH_MAX + 1];
7167c478bd9Sstevel@tonic-gate 	char	lnm[NAME_BUFLEN];
7177c478bd9Sstevel@tonic-gate 	char	snm[NAME_BUFLEN];
7187c478bd9Sstevel@tonic-gate 	char	*npt;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	snm[0] = NULL;
7217c478bd9Sstevel@tonic-gate 	if (curr_type == DISK || curr_type == OSA_DISK) {
7227c478bd9Sstevel@tonic-gate 		/*
7237c478bd9Sstevel@tonic-gate 		 * get the short name - omitting
7247c478bd9Sstevel@tonic-gate 		 * the trailing sN or PN
7257c478bd9Sstevel@tonic-gate 		 */
7267c478bd9Sstevel@tonic-gate 		(void) strcpy(lnm, dent);
7277c478bd9Sstevel@tonic-gate 		do_snm(dent, snm);
7287c478bd9Sstevel@tonic-gate 	} else if (curr_type == MD_DISK) {
7297c478bd9Sstevel@tonic-gate 		(void) strcpy(lnm, dent);
7307c478bd9Sstevel@tonic-gate 		(void) strcpy(snm, dent);
7317c478bd9Sstevel@tonic-gate 	} else {
7327c478bd9Sstevel@tonic-gate 		/*
7337c478bd9Sstevel@tonic-gate 		 * don't want all rewind/etc
7347c478bd9Sstevel@tonic-gate 		 * devices for a tape
7357c478bd9Sstevel@tonic-gate 		 */
7367c478bd9Sstevel@tonic-gate 		if (!str_is_digit(dent))
7377c478bd9Sstevel@tonic-gate 			return;
7387c478bd9Sstevel@tonic-gate 		(void) snprintf(snm, sizeof (snm), "rmt/%s", dent);
7397c478bd9Sstevel@tonic-gate 		(void) snprintf(lnm, sizeof (snm), "rmt/%s", dent);
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 	/*
7427c478bd9Sstevel@tonic-gate 	 * See if we've already processed an entry for this device.
7437c478bd9Sstevel@tonic-gate 	 * If so, we're just another partition so we get another
7447c478bd9Sstevel@tonic-gate 	 * entry.
7457c478bd9Sstevel@tonic-gate 	 *
7467c478bd9Sstevel@tonic-gate 	 * last_snm is an optimization to avoid the function call
7477c478bd9Sstevel@tonic-gate 	 * and lookup since we'll often see partition records
7487c478bd9Sstevel@tonic-gate 	 * immediately after the disk record.
7497c478bd9Sstevel@tonic-gate 	 */
7507c478bd9Sstevel@tonic-gate 	if (dp->skip_lookup == 0) {
7517c478bd9Sstevel@tonic-gate 		if (strcmp(snm, last_snm) != 0) {
7527c478bd9Sstevel@tonic-gate 			/*
7537c478bd9Sstevel@tonic-gate 			 * a zero return means that
7547c478bd9Sstevel@tonic-gate 			 * no record was found. We'd
7557c478bd9Sstevel@tonic-gate 			 * return a pointer otherwise.
7567c478bd9Sstevel@tonic-gate 			 */
7577c478bd9Sstevel@tonic-gate 			if (look_up_name(snm,
7587c478bd9Sstevel@tonic-gate 				dp->list) == 0) {
7597c478bd9Sstevel@tonic-gate 				(void) strcpy(last_snm, snm);
7607c478bd9Sstevel@tonic-gate 			} else
7617c478bd9Sstevel@tonic-gate 				return;
7627c478bd9Sstevel@tonic-gate 		} else
7637c478bd9Sstevel@tonic-gate 			return;
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 	/*
7667c478bd9Sstevel@tonic-gate 	 * Get the real device name for this beast
7677c478bd9Sstevel@tonic-gate 	 * by following the link into /devices.
7687c478bd9Sstevel@tonic-gate 	 */
7697c478bd9Sstevel@tonic-gate 	(void) snprintf(dnmbuf, sizeof (dnmbuf), "%s/%s", dp->name, dent);
7707c478bd9Sstevel@tonic-gate 	if (lstat(dnmbuf, &sbuf) != -1) {
7717c478bd9Sstevel@tonic-gate 		if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
7727c478bd9Sstevel@tonic-gate 			/*
7737c478bd9Sstevel@tonic-gate 			 * It's a link. Get the real name.
7747c478bd9Sstevel@tonic-gate 			 */
7757c478bd9Sstevel@tonic-gate 			char	nmbuf[PATH_MAX + 1];
7767c478bd9Sstevel@tonic-gate 			int	nbyr;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 			if ((nbyr = readlink(dnmbuf, nmbuf,
7797c478bd9Sstevel@tonic-gate 			    sizeof (nmbuf))) != 1) {
7807c478bd9Sstevel@tonic-gate 				npt = nmbuf;
7817c478bd9Sstevel@tonic-gate 				/*
7827c478bd9Sstevel@tonic-gate 				 * readlink does not terminate
7837c478bd9Sstevel@tonic-gate 				 * the string so we have to
7847c478bd9Sstevel@tonic-gate 				 * do it.
7857c478bd9Sstevel@tonic-gate 				 */
7867c478bd9Sstevel@tonic-gate 				nmbuf[nbyr] = NULL;
7877c478bd9Sstevel@tonic-gate 			} else
7887c478bd9Sstevel@tonic-gate 				npt = NULL;
7897c478bd9Sstevel@tonic-gate 		} else
7907c478bd9Sstevel@tonic-gate 			npt = lnm;
7917c478bd9Sstevel@tonic-gate 		/*
7927c478bd9Sstevel@tonic-gate 		 * make an entry in the device list
7937c478bd9Sstevel@tonic-gate 		 */
7947c478bd9Sstevel@tonic-gate 		if (npt) {
7957c478bd9Sstevel@tonic-gate 			disk_list_t *d;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 			d = make_an_entry(npt, snm,
7987c478bd9Sstevel@tonic-gate 			    dnmbuf, dp,
7997c478bd9Sstevel@tonic-gate 			    curr_type, ptoi);
8007c478bd9Sstevel@tonic-gate 			insert_into_dlist(dp, d);
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate static void
8057c478bd9Sstevel@tonic-gate cleanup_ldinfo(ldinfo_t *list)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate 	ldinfo_t *tmp;
8087c478bd9Sstevel@tonic-gate 	while (list) {
8097c478bd9Sstevel@tonic-gate 		tmp = list;
8107c478bd9Sstevel@tonic-gate 		list = list->next;
8117c478bd9Sstevel@tonic-gate 		free(tmp->name);
8127c478bd9Sstevel@tonic-gate 		free(tmp->dtype);
8137c478bd9Sstevel@tonic-gate 		if (tmp->devidstr)
8147c478bd9Sstevel@tonic-gate 			free(tmp->devidstr);
8157c478bd9Sstevel@tonic-gate 		free(tmp);
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate char *
8207c478bd9Sstevel@tonic-gate lookup_nfs_name(char *ks, kstat_ctl_t *kc)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	int tried = 0;
8237c478bd9Sstevel@tonic-gate 	uint_t minor;
8247c478bd9Sstevel@tonic-gate 	char *host, *path;
8257c478bd9Sstevel@tonic-gate 	char *cp;
8267c478bd9Sstevel@tonic-gate 	char *rstr = 0;
8277c478bd9Sstevel@tonic-gate 	size_t len;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	if (sscanf(ks, "nfs%u", &minor) == 1) {
8307c478bd9Sstevel@tonic-gate retry:
8317c478bd9Sstevel@tonic-gate 		cp = get_nfs_by_minor(minor);
8327c478bd9Sstevel@tonic-gate 		if (cp) {
8337c478bd9Sstevel@tonic-gate 			if (strchr(cp, ',') == NULL) {
8347c478bd9Sstevel@tonic-gate 				rstr = safe_strdup(cp);
8357c478bd9Sstevel@tonic-gate 				return (rstr);
8367c478bd9Sstevel@tonic-gate 			}
8377c478bd9Sstevel@tonic-gate 			host = cur_hostname(minor, kc);
8387c478bd9Sstevel@tonic-gate 			if (host) {
8397c478bd9Sstevel@tonic-gate 				if (*host) {
8407c478bd9Sstevel@tonic-gate 					path = cur_special(host, cp);
8417c478bd9Sstevel@tonic-gate 					if (path) {
8427c478bd9Sstevel@tonic-gate 						len = strlen(host);
8437c478bd9Sstevel@tonic-gate 						len += strlen(path);
8447c478bd9Sstevel@tonic-gate 						len += 2;
8457c478bd9Sstevel@tonic-gate 						rstr = safe_alloc(len);
8467c478bd9Sstevel@tonic-gate 						(void) snprintf(rstr, len,
8477c478bd9Sstevel@tonic-gate 						    "%s:%s", host, path);
8487c478bd9Sstevel@tonic-gate 					} else {
8497c478bd9Sstevel@tonic-gate 						rstr = safe_strdup(cp);
8507c478bd9Sstevel@tonic-gate 					}
8517c478bd9Sstevel@tonic-gate 				} else {
8527c478bd9Sstevel@tonic-gate 					rstr = safe_strdup(ks);
8537c478bd9Sstevel@tonic-gate 				}
8547c478bd9Sstevel@tonic-gate 				free(host);
8557c478bd9Sstevel@tonic-gate 			} else {
8567c478bd9Sstevel@tonic-gate 				rstr = safe_strdup(cp);
8577c478bd9Sstevel@tonic-gate 			}
8587c478bd9Sstevel@tonic-gate 		} else if (!tried) {
8597c478bd9Sstevel@tonic-gate 			tried = 1;
8607c478bd9Sstevel@tonic-gate 			do_mnttab();
8617c478bd9Sstevel@tonic-gate 			goto retry;
8627c478bd9Sstevel@tonic-gate 		}
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 	return (rstr);
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate static char *
8687c478bd9Sstevel@tonic-gate get_nfs_by_minor(uint_t minor)
8697c478bd9Sstevel@tonic-gate {
8707c478bd9Sstevel@tonic-gate 	mnt_t *localnfs;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	localnfs = nfs;
8737c478bd9Sstevel@tonic-gate 	while (localnfs) {
8747c478bd9Sstevel@tonic-gate 		if (localnfs->minor == minor) {
8757c478bd9Sstevel@tonic-gate 			return (localnfs->device_name);
8767c478bd9Sstevel@tonic-gate 		}
8777c478bd9Sstevel@tonic-gate 		localnfs = localnfs->next;
8787c478bd9Sstevel@tonic-gate 	}
8797c478bd9Sstevel@tonic-gate 	return (0);
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate /*
8837c478bd9Sstevel@tonic-gate  * Read the cur_hostname from the mntinfo kstat
8847c478bd9Sstevel@tonic-gate  */
8857c478bd9Sstevel@tonic-gate static char *
8867c478bd9Sstevel@tonic-gate cur_hostname(uint_t minor, kstat_ctl_t *kc)
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
8897c478bd9Sstevel@tonic-gate 	static struct mntinfo_kstat mik;
8907c478bd9Sstevel@tonic-gate 	char *rstr;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
8937c478bd9Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_RAW)
8947c478bd9Sstevel@tonic-gate 			continue;
8957c478bd9Sstevel@tonic-gate 		if (ksp->ks_instance != minor)
8967c478bd9Sstevel@tonic-gate 			continue;
8977c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "nfs"))
8987c478bd9Sstevel@tonic-gate 			continue;
8997c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_name, "mntinfo"))
9007c478bd9Sstevel@tonic-gate 			continue;
9017c478bd9Sstevel@tonic-gate 		if (ksp->ks_flags & KSTAT_FLAG_INVALID)
9027c478bd9Sstevel@tonic-gate 			return (NULL);
9037c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, ksp, &mik) == -1)
9047c478bd9Sstevel@tonic-gate 			return (NULL);
9057c478bd9Sstevel@tonic-gate 		rstr = safe_strdup(mik.mik_curserver);
9067c478bd9Sstevel@tonic-gate 		return (rstr);
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 	return (NULL);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate  * Given the hostname of the mounted server, extract the server
9137c478bd9Sstevel@tonic-gate  * mount point from the mnttab string.
9147c478bd9Sstevel@tonic-gate  *
9157c478bd9Sstevel@tonic-gate  * Common forms:
9167c478bd9Sstevel@tonic-gate  *	server1,server2,server3:/path
9177c478bd9Sstevel@tonic-gate  *	server1:/path,server2:/path
9187c478bd9Sstevel@tonic-gate  * or a hybrid of the two
9197c478bd9Sstevel@tonic-gate  */
9207c478bd9Sstevel@tonic-gate static char *
9217c478bd9Sstevel@tonic-gate cur_special(char *hostname, char *special)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	char *cp;
9247c478bd9Sstevel@tonic-gate 	char *path;
9257c478bd9Sstevel@tonic-gate 	size_t hlen = strlen(hostname);
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/*
9287c478bd9Sstevel@tonic-gate 	 * find hostname in string
9297c478bd9Sstevel@tonic-gate 	 */
9307c478bd9Sstevel@tonic-gate again:
9317c478bd9Sstevel@tonic-gate 	if ((cp = strstr(special, hostname)) == NULL)
9327c478bd9Sstevel@tonic-gate 		return (NULL);
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	/*
9357c478bd9Sstevel@tonic-gate 	 * hostname must be followed by ',' or ':'
9367c478bd9Sstevel@tonic-gate 	 */
9377c478bd9Sstevel@tonic-gate 	if (cp[hlen] != ',' && cp[hlen] != ':') {
9387c478bd9Sstevel@tonic-gate 		special = &cp[hlen];
9397c478bd9Sstevel@tonic-gate 		goto again;
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	/*
9437c478bd9Sstevel@tonic-gate 	 * If hostname is followed by a ',' eat all characters until a ':'
9447c478bd9Sstevel@tonic-gate 	 */
9457c478bd9Sstevel@tonic-gate 	cp = &cp[hlen];
9467c478bd9Sstevel@tonic-gate 	if (*cp == ',') {
9477c478bd9Sstevel@tonic-gate 		cp++;
9487c478bd9Sstevel@tonic-gate 		while (*cp != ':') {
9497c478bd9Sstevel@tonic-gate 			if (*cp == NULL)
9507c478bd9Sstevel@tonic-gate 				return (NULL);
9517c478bd9Sstevel@tonic-gate 			cp++;
9527c478bd9Sstevel@tonic-gate 		}
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 	path = ++cp;			/* skip ':' */
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	/*
9577c478bd9Sstevel@tonic-gate 	 * path is terminated by either 0, or space or ','
9587c478bd9Sstevel@tonic-gate 	 */
9597c478bd9Sstevel@tonic-gate 	while (*cp) {
9607c478bd9Sstevel@tonic-gate 		if (isspace(*cp) || *cp == ',') {
9617c478bd9Sstevel@tonic-gate 			*cp = NULL;
9627c478bd9Sstevel@tonic-gate 			return (path);
9637c478bd9Sstevel@tonic-gate 		}
9647c478bd9Sstevel@tonic-gate 		cp++;
9657c478bd9Sstevel@tonic-gate 	}
9667c478bd9Sstevel@tonic-gate 	return (path);
9677c478bd9Sstevel@tonic-gate }
968