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