1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/stat.h> 30*0Sstevel@tonic-gate #include <sys/types.h> 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate /* 33*0Sstevel@tonic-gate * Dependent on types.h, but not including it... 34*0Sstevel@tonic-gate */ 35*0Sstevel@tonic-gate #include <stdio.h> 36*0Sstevel@tonic-gate #include <sys/types.h> 37*0Sstevel@tonic-gate #include <sys/dkio.h> 38*0Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 39*0Sstevel@tonic-gate #include <sys/mnttab.h> 40*0Sstevel@tonic-gate #include <sys/mntent.h> 41*0Sstevel@tonic-gate #include <sys/sysmacros.h> 42*0Sstevel@tonic-gate #include <sys/mkdev.h> 43*0Sstevel@tonic-gate #include <sys/vfs.h> 44*0Sstevel@tonic-gate #include <nfs/nfs.h> 45*0Sstevel@tonic-gate #include <nfs/nfs_clnt.h> 46*0Sstevel@tonic-gate #include <kstat.h> 47*0Sstevel@tonic-gate #include <ctype.h> 48*0Sstevel@tonic-gate #include <dirent.h> 49*0Sstevel@tonic-gate #include <libdevinfo.h> 50*0Sstevel@tonic-gate #include <limits.h> 51*0Sstevel@tonic-gate #include <stdlib.h> 52*0Sstevel@tonic-gate #include <string.h> 53*0Sstevel@tonic-gate #include <unistd.h> 54*0Sstevel@tonic-gate #include <errno.h> 55*0Sstevel@tonic-gate #include <devid.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #include "dsr.h" 58*0Sstevel@tonic-gate #include "statcommon.h" 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate static void rummage_dev(ldinfo_t *); 61*0Sstevel@tonic-gate static void do_snm(char *, char *); 62*0Sstevel@tonic-gate static int look_up_name(const char *, disk_list_t *); 63*0Sstevel@tonic-gate static disk_list_t *make_an_entry(char *, char *, 64*0Sstevel@tonic-gate char *, dir_info_t *, int, ldinfo_t *); 65*0Sstevel@tonic-gate static char *trim(char *, char *, int); 66*0Sstevel@tonic-gate static ldinfo_t *rummage_devinfo(void); 67*0Sstevel@tonic-gate static void pline(char *, int, char *, char *, ldinfo_t **); 68*0Sstevel@tonic-gate static void insert_dlist_ent(disk_list_t *, disk_list_t **); 69*0Sstevel@tonic-gate static int str_is_digit(char *); 70*0Sstevel@tonic-gate static ldinfo_t *find_ldinfo_match(char *, ldinfo_t *); 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate static void insert_into_dlist(dir_info_t *, disk_list_t *); 73*0Sstevel@tonic-gate static void cleanup_dlist(dir_info_t *); 74*0Sstevel@tonic-gate static void cleanup_ldinfo(ldinfo_t *); 75*0Sstevel@tonic-gate static int devinfo_ident_disks(di_node_t, void *); 76*0Sstevel@tonic-gate static int devinfo_ident_tapes(di_node_t, void *); 77*0Sstevel@tonic-gate static void process_dir_ent(char *dent, int curr_type, 78*0Sstevel@tonic-gate char *last_snm, dir_info_t *, ldinfo_t *); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate static char *get_nfs_by_minor(uint_t); 81*0Sstevel@tonic-gate static char *cur_hostname(uint_t, kstat_ctl_t *); 82*0Sstevel@tonic-gate static char *cur_special(char *, char *); 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate extern kstat_ctl_t *kc; 85*0Sstevel@tonic-gate extern mnt_t *nfs; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate /* 88*0Sstevel@tonic-gate * To do: add VXVM support: /dev/vx/dsk and ap support: /dev/ap/ 89*0Sstevel@tonic-gate * 90*0Sstevel@tonic-gate * Note: Adding support for VxVM is *not* as simple as adding another 91*0Sstevel@tonic-gate * entry in the table and magically getting to see stuff related to 92*0Sstevel@tonic-gate * VxVM. The structure is radically different *AND* they don't produce 93*0Sstevel@tonic-gate * any IO kstats. 94*0Sstevel@tonic-gate */ 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate #define OSA_DISK 0 97*0Sstevel@tonic-gate #define DISK 1 98*0Sstevel@tonic-gate #define MD_DISK 2 99*0Sstevel@tonic-gate #define TAPE 3 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate #define MAX_TYPES 4 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate #define OSA_DISK_PATH "/dev/osa/dev/dsk" 104*0Sstevel@tonic-gate #define MD_DISK_PATH "/dev/md/dsk" 105*0Sstevel@tonic-gate #define DISK_PATH "/dev/dsk" 106*0Sstevel@tonic-gate #define TAPE_PATH "/dev/rmt" 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate #define BASE_TRIM "../../devices" 109*0Sstevel@tonic-gate #define MD_TRIM "../../../devices" 110*0Sstevel@tonic-gate #define COLON ':' 111*0Sstevel@tonic-gate #define COMMA ',' 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate #define NAME_BUFLEN 256 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate static dir_info_t dlist[MAX_TYPES] = { 116*0Sstevel@tonic-gate OSA_DISK_PATH, 0, 0, 0, 0, "sd", BASE_TRIM, COLON, 117*0Sstevel@tonic-gate DISK_PATH, 0, 0, 0, 0, "sd", BASE_TRIM, COLON, 118*0Sstevel@tonic-gate MD_DISK_PATH, 0, 0, 0, 1, "md", MD_TRIM, COMMA, 119*0Sstevel@tonic-gate TAPE_PATH, 0, 0, 0, 0, "st", BASE_TRIM, COLON, 120*0Sstevel@tonic-gate }; 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* 123*0Sstevel@tonic-gate * Build a list of disks attached to the system. 124*0Sstevel@tonic-gate */ 125*0Sstevel@tonic-gate static void 126*0Sstevel@tonic-gate build_disk_list(void) 127*0Sstevel@tonic-gate { 128*0Sstevel@tonic-gate ldinfo_t *ptoi; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * Build the list of devices connected to the system. 132*0Sstevel@tonic-gate */ 133*0Sstevel@tonic-gate ptoi = rummage_devinfo(); 134*0Sstevel@tonic-gate rummage_dev(ptoi); 135*0Sstevel@tonic-gate cleanup_ldinfo(ptoi); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate /* 139*0Sstevel@tonic-gate * Walk the /dev/dsk and /dev/rmt directories building a 140*0Sstevel@tonic-gate * list of interesting devices. Interesting is everything in the 141*0Sstevel@tonic-gate * /dev/dsk directory. We skip some of the stuff in the /dev/rmt 142*0Sstevel@tonic-gate * directory. 143*0Sstevel@tonic-gate * 144*0Sstevel@tonic-gate * Note that not finding one or more of the directories is not an 145*0Sstevel@tonic-gate * error. 146*0Sstevel@tonic-gate */ 147*0Sstevel@tonic-gate static void 148*0Sstevel@tonic-gate rummage_dev(ldinfo_t *ptoi) 149*0Sstevel@tonic-gate { 150*0Sstevel@tonic-gate DIR *dskp; 151*0Sstevel@tonic-gate int i; 152*0Sstevel@tonic-gate struct stat buf; 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate for (i = 0; i < MAX_TYPES; i++) { 155*0Sstevel@tonic-gate if (stat(dlist[i].name, &buf) == 0) { 156*0Sstevel@tonic-gate if (dlist[i].mtime != buf.st_mtime) { 157*0Sstevel@tonic-gate /* 158*0Sstevel@tonic-gate * We've found a change. We need to cleanup 159*0Sstevel@tonic-gate * old information and then rebuild the list 160*0Sstevel@tonic-gate * for this device type. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate cleanup_dlist(&dlist[i]); 163*0Sstevel@tonic-gate dlist[i].mtime = buf.st_mtime; 164*0Sstevel@tonic-gate if ((dskp = opendir(dlist[i].name))) { 165*0Sstevel@tonic-gate struct dirent *bpt; 166*0Sstevel@tonic-gate char last_snm[NAME_BUFLEN]; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate last_snm[0] = NULL; 169*0Sstevel@tonic-gate while ((bpt = readdir(dskp)) != NULL) { 170*0Sstevel@tonic-gate if (bpt->d_name[0] != '.') { 171*0Sstevel@tonic-gate process_dir_ent( 172*0Sstevel@tonic-gate bpt->d_name, 173*0Sstevel@tonic-gate i, last_snm, 174*0Sstevel@tonic-gate &dlist[i], 175*0Sstevel@tonic-gate ptoi); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate (void) closedir(dskp); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Walk the list of located devices and see if we've 187*0Sstevel@tonic-gate * seen this device before. We look at the short name. 188*0Sstevel@tonic-gate */ 189*0Sstevel@tonic-gate static int 190*0Sstevel@tonic-gate look_up_name(const char *nm, disk_list_t *list) 191*0Sstevel@tonic-gate { 192*0Sstevel@tonic-gate while (list) { 193*0Sstevel@tonic-gate if (strcmp(list->dsk, nm) != 0) 194*0Sstevel@tonic-gate list = list->next; 195*0Sstevel@tonic-gate else { 196*0Sstevel@tonic-gate return (1); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate return (0); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* 203*0Sstevel@tonic-gate * Take a name of the form cNtNdNsN or cNtNdNpN 204*0Sstevel@tonic-gate * or /dev/dsk/CNtNdNsN or /dev/dsk/cNtNdNpN 205*0Sstevel@tonic-gate * remove the trailing sN or pN. Simply looking 206*0Sstevel@tonic-gate * for the first 's' or 'p' doesn't cut it. 207*0Sstevel@tonic-gate */ 208*0Sstevel@tonic-gate static void 209*0Sstevel@tonic-gate do_snm(char *orig, char *shortnm) 210*0Sstevel@tonic-gate { 211*0Sstevel@tonic-gate char *tmp; 212*0Sstevel@tonic-gate char *ptmp; 213*0Sstevel@tonic-gate int done = 0; 214*0Sstevel@tonic-gate char repl_char = 0; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate tmp = strrchr(orig, 's'); 217*0Sstevel@tonic-gate if (tmp) { 218*0Sstevel@tonic-gate ptmp = tmp; 219*0Sstevel@tonic-gate ptmp++; 220*0Sstevel@tonic-gate done = str_is_digit(ptmp); 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate if (done == 0) { 223*0Sstevel@tonic-gate /* 224*0Sstevel@tonic-gate * The string either has no 's' in it 225*0Sstevel@tonic-gate * or the stuff trailing the s has a 226*0Sstevel@tonic-gate * non-numeric in it. Look to see if 227*0Sstevel@tonic-gate * we have an ending 'p' followed by 228*0Sstevel@tonic-gate * numerics. 229*0Sstevel@tonic-gate */ 230*0Sstevel@tonic-gate tmp = strrchr(orig, 'p'); 231*0Sstevel@tonic-gate if (tmp) { 232*0Sstevel@tonic-gate ptmp = tmp; 233*0Sstevel@tonic-gate ptmp++; 234*0Sstevel@tonic-gate if (str_is_digit(ptmp)) 235*0Sstevel@tonic-gate repl_char = 'p'; 236*0Sstevel@tonic-gate else 237*0Sstevel@tonic-gate tmp = 0; 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate } else { 240*0Sstevel@tonic-gate repl_char = 's'; 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate if (tmp) 243*0Sstevel@tonic-gate *tmp = '\0'; 244*0Sstevel@tonic-gate (void) strcpy(shortnm, orig); 245*0Sstevel@tonic-gate if (repl_char) 246*0Sstevel@tonic-gate *tmp = repl_char; 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate /* 250*0Sstevel@tonic-gate * Create and insert an entry into the device list. 251*0Sstevel@tonic-gate */ 252*0Sstevel@tonic-gate static disk_list_t * 253*0Sstevel@tonic-gate make_an_entry(char *lname, char *shortnm, char *longnm, 254*0Sstevel@tonic-gate dir_info_t *drent, int devtype, ldinfo_t *ptoi) 255*0Sstevel@tonic-gate { 256*0Sstevel@tonic-gate disk_list_t *entry; 257*0Sstevel@tonic-gate char *nlnm; 258*0Sstevel@tonic-gate char snm[NAME_BUFLEN]; 259*0Sstevel@tonic-gate ldinfo_t *p; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate entry = safe_alloc(sizeof (disk_list_t)); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate nlnm = trim(lname, drent->trimstr, drent->trimchr); 264*0Sstevel@tonic-gate entry->dsk = safe_strdup(shortnm); 265*0Sstevel@tonic-gate do_snm(longnm, snm); 266*0Sstevel@tonic-gate entry->dname = safe_strdup(snm); 267*0Sstevel@tonic-gate entry->devtype = devtype; 268*0Sstevel@tonic-gate entry->devidstr = NULL; 269*0Sstevel@tonic-gate if ((p = find_ldinfo_match(nlnm, ptoi))) { 270*0Sstevel@tonic-gate entry->dnum = p->dnum; 271*0Sstevel@tonic-gate entry->dtype = safe_strdup(p->dtype); 272*0Sstevel@tonic-gate if (p->devidstr) 273*0Sstevel@tonic-gate entry->devidstr = safe_strdup(p->devidstr); 274*0Sstevel@tonic-gate } else { 275*0Sstevel@tonic-gate entry->dtype = safe_strdup(drent->dtype); 276*0Sstevel@tonic-gate entry->dnum = -1; 277*0Sstevel@tonic-gate if (drent->dtype) { 278*0Sstevel@tonic-gate if (strcmp(drent->dtype, "md") == 0) { 279*0Sstevel@tonic-gate (void) sscanf(shortnm, "d%d", &entry->dnum); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate entry->seen = 0; 284*0Sstevel@tonic-gate entry->next = 0; 285*0Sstevel@tonic-gate insert_dlist_ent(entry, &drent->list); 286*0Sstevel@tonic-gate return (entry); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* 290*0Sstevel@tonic-gate * slice stuff off beginning and end of /devices directory names derived from 291*0Sstevel@tonic-gate * device links. 292*0Sstevel@tonic-gate */ 293*0Sstevel@tonic-gate static char * 294*0Sstevel@tonic-gate trim(char *fnm, char *lname, int rchr) 295*0Sstevel@tonic-gate { 296*0Sstevel@tonic-gate char *ptr; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate while (*lname == *fnm) { 299*0Sstevel@tonic-gate lname++; 300*0Sstevel@tonic-gate fnm++; 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate if ((ptr = strrchr(fnm, rchr))) 303*0Sstevel@tonic-gate *ptr = NULL; 304*0Sstevel@tonic-gate return (fnm); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * Find an entry matching the name passed in 309*0Sstevel@tonic-gate */ 310*0Sstevel@tonic-gate static ldinfo_t * 311*0Sstevel@tonic-gate find_ldinfo_match(char *name, ldinfo_t *ptoi) 312*0Sstevel@tonic-gate { 313*0Sstevel@tonic-gate if (name) { 314*0Sstevel@tonic-gate while (ptoi) { 315*0Sstevel@tonic-gate if (strcmp(ptoi->name, name)) 316*0Sstevel@tonic-gate ptoi = ptoi->next; 317*0Sstevel@tonic-gate else 318*0Sstevel@tonic-gate return (ptoi); 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate return (NULL); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate /* 325*0Sstevel@tonic-gate * Determine if a name is already in the list of disks. If not, insert the 326*0Sstevel@tonic-gate * name in the list. 327*0Sstevel@tonic-gate */ 328*0Sstevel@tonic-gate static void 329*0Sstevel@tonic-gate insert_dlist_ent(disk_list_t *n, disk_list_t **hd) 330*0Sstevel@tonic-gate { 331*0Sstevel@tonic-gate disk_list_t *tmp_ptr; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate if (n->dtype != NULL) { 334*0Sstevel@tonic-gate tmp_ptr = *hd; 335*0Sstevel@tonic-gate while (tmp_ptr) { 336*0Sstevel@tonic-gate if (strcmp(n->dsk, tmp_ptr->dsk) != 0) 337*0Sstevel@tonic-gate tmp_ptr = tmp_ptr->next; 338*0Sstevel@tonic-gate else 339*0Sstevel@tonic-gate break; 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate if (tmp_ptr == NULL) { 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * We don't do anything with MD_DISK types here 344*0Sstevel@tonic-gate * since they don't have partitions. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate if (n->devtype == DISK || n->devtype == OSA_DISK) { 347*0Sstevel@tonic-gate n->flags = SLICES_OK; 348*0Sstevel@tonic-gate #if defined(i386) || defined(__ia64) 349*0Sstevel@tonic-gate n->flags |= PARTITIONS_OK; 350*0Sstevel@tonic-gate #endif 351*0Sstevel@tonic-gate } else { 352*0Sstevel@tonic-gate n->flags = 0; 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * Figure out where to insert the name. The list is 356*0Sstevel@tonic-gate * ostensibly in sorted order. 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate if (*hd) { 359*0Sstevel@tonic-gate disk_list_t *follw; 360*0Sstevel@tonic-gate int mv; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate tmp_ptr = *hd; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate /* 365*0Sstevel@tonic-gate * Look through the list. While the strcmp 366*0Sstevel@tonic-gate * value is less than the current value, 367*0Sstevel@tonic-gate */ 368*0Sstevel@tonic-gate while (tmp_ptr) { 369*0Sstevel@tonic-gate if ((mv = strcmp(n->dtype, 370*0Sstevel@tonic-gate tmp_ptr->dtype)) < 0) { 371*0Sstevel@tonic-gate follw = tmp_ptr; 372*0Sstevel@tonic-gate tmp_ptr = tmp_ptr->next; 373*0Sstevel@tonic-gate } else 374*0Sstevel@tonic-gate break; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate if (mv == 0) { 377*0Sstevel@tonic-gate /* 378*0Sstevel@tonic-gate * We're now in the area where the 379*0Sstevel@tonic-gate * leading chars of the kstat name 380*0Sstevel@tonic-gate * match. We need to insert in numeric 381*0Sstevel@tonic-gate * order after that. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate while (tmp_ptr) { 384*0Sstevel@tonic-gate if (strcmp(n->dtype, 385*0Sstevel@tonic-gate tmp_ptr->dtype) != 0) 386*0Sstevel@tonic-gate break; 387*0Sstevel@tonic-gate if (n->dnum > tmp_ptr->dnum) { 388*0Sstevel@tonic-gate follw = tmp_ptr; 389*0Sstevel@tonic-gate tmp_ptr = tmp_ptr->next; 390*0Sstevel@tonic-gate } else 391*0Sstevel@tonic-gate break; 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate /* 395*0Sstevel@tonic-gate * We should now be ready to insert an 396*0Sstevel@tonic-gate * entry... 397*0Sstevel@tonic-gate */ 398*0Sstevel@tonic-gate if (mv >= 0) { 399*0Sstevel@tonic-gate if (tmp_ptr == *hd) { 400*0Sstevel@tonic-gate n->next = tmp_ptr; 401*0Sstevel@tonic-gate *hd = n; 402*0Sstevel@tonic-gate } else { 403*0Sstevel@tonic-gate n->next = follw->next; 404*0Sstevel@tonic-gate follw->next = n; 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate } else { 407*0Sstevel@tonic-gate /* 408*0Sstevel@tonic-gate * insert at the end of the 409*0Sstevel@tonic-gate * list 410*0Sstevel@tonic-gate */ 411*0Sstevel@tonic-gate follw->next = n; 412*0Sstevel@tonic-gate n->next = 0; 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate } else { 415*0Sstevel@tonic-gate *hd = n; 416*0Sstevel@tonic-gate n->next = 0; 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate } 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * find an entry matching the given kstat name in the list 424*0Sstevel@tonic-gate * of disks, tapes and metadevices. 425*0Sstevel@tonic-gate */ 426*0Sstevel@tonic-gate disk_list_t * 427*0Sstevel@tonic-gate lookup_ks_name(char *dev_nm) 428*0Sstevel@tonic-gate { 429*0Sstevel@tonic-gate int tried = 0; 430*0Sstevel@tonic-gate int dv; 431*0Sstevel@tonic-gate int len; 432*0Sstevel@tonic-gate char cmpbuf[PATH_MAX + 1]; 433*0Sstevel@tonic-gate struct list_of_disks *list; 434*0Sstevel@tonic-gate char *nm; 435*0Sstevel@tonic-gate dev_name_t *tmp; 436*0Sstevel@tonic-gate uint_t i; 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate /* 439*0Sstevel@tonic-gate * extract the device type from the kstat name. We expect the 440*0Sstevel@tonic-gate * name to be one or more alphabetics followed by the device 441*0Sstevel@tonic-gate * numeric id. We do this solely for speed purposes . 442*0Sstevel@tonic-gate */ 443*0Sstevel@tonic-gate len = 0; 444*0Sstevel@tonic-gate nm = dev_nm; 445*0Sstevel@tonic-gate while (*nm) { 446*0Sstevel@tonic-gate if (isalpha(*nm)) { 447*0Sstevel@tonic-gate nm++; 448*0Sstevel@tonic-gate len++; 449*0Sstevel@tonic-gate } else 450*0Sstevel@tonic-gate break; 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate if (!*nm) 454*0Sstevel@tonic-gate return (NULL); 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate /* 457*0Sstevel@tonic-gate * For each of the elements in the dlist array we keep 458*0Sstevel@tonic-gate * an array of pointers to chains for each of the kstat 459*0Sstevel@tonic-gate * prefixes found within that directory. This is typically 460*0Sstevel@tonic-gate * 'sd' and 'ssd'. We walk the list in the directory and 461*0Sstevel@tonic-gate * match on that type. Since the same prefixes can be 462*0Sstevel@tonic-gate * in multiple places we keep checking if we don't find 463*0Sstevel@tonic-gate * it in the first place. 464*0Sstevel@tonic-gate */ 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate (void) strncpy(cmpbuf, dev_nm, len); 467*0Sstevel@tonic-gate cmpbuf[len] = NULL; 468*0Sstevel@tonic-gate dv = atoi(nm); 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate retry: 471*0Sstevel@tonic-gate for (i = 0; i < MAX_TYPES; i++) { 472*0Sstevel@tonic-gate tmp = dlist[i].nf; 473*0Sstevel@tonic-gate while (tmp) { 474*0Sstevel@tonic-gate if (strcmp(tmp->name, cmpbuf) == 0) { 475*0Sstevel@tonic-gate /* 476*0Sstevel@tonic-gate * As an optimization we keep mins 477*0Sstevel@tonic-gate * and maxes for the devices found. 478*0Sstevel@tonic-gate * This helps chop the lists up and 479*0Sstevel@tonic-gate * avoid some really long chains as 480*0Sstevel@tonic-gate * we would get if we kept only prefix 481*0Sstevel@tonic-gate * lists. 482*0Sstevel@tonic-gate */ 483*0Sstevel@tonic-gate if (dv >= tmp->min && dv <= tmp->max) { 484*0Sstevel@tonic-gate list = tmp->list_start; 485*0Sstevel@tonic-gate while (list) { 486*0Sstevel@tonic-gate if (list->dnum < dv) 487*0Sstevel@tonic-gate list = list->next; 488*0Sstevel@tonic-gate else 489*0Sstevel@tonic-gate break; 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate if (list && list->dnum == dv) { 492*0Sstevel@tonic-gate return (list); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate } 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate tmp = tmp->next; 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate if (!tried) { 501*0Sstevel@tonic-gate tried = 1; 502*0Sstevel@tonic-gate build_disk_list(); 503*0Sstevel@tonic-gate goto retry; 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate return (0); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate static int 510*0Sstevel@tonic-gate str_is_digit(char *str) 511*0Sstevel@tonic-gate { 512*0Sstevel@tonic-gate while (*str) { 513*0Sstevel@tonic-gate if (isdigit(*str)) 514*0Sstevel@tonic-gate str++; 515*0Sstevel@tonic-gate else 516*0Sstevel@tonic-gate return (0); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate return (1); 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate static void 522*0Sstevel@tonic-gate insert_into_dlist(dir_info_t *d, disk_list_t *e) 523*0Sstevel@tonic-gate { 524*0Sstevel@tonic-gate dev_name_t *tmp; 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate tmp = d->nf; 527*0Sstevel@tonic-gate while (tmp) { 528*0Sstevel@tonic-gate if (strcmp(e->dtype, tmp->name) != 0) { 529*0Sstevel@tonic-gate tmp = tmp->next; 530*0Sstevel@tonic-gate } else { 531*0Sstevel@tonic-gate if (e->dnum < tmp->min) { 532*0Sstevel@tonic-gate tmp->min = e->dnum; 533*0Sstevel@tonic-gate tmp->list_start = e; 534*0Sstevel@tonic-gate } else if (e->dnum > tmp->max) { 535*0Sstevel@tonic-gate tmp->max = e->dnum; 536*0Sstevel@tonic-gate tmp->list_end = e; 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate break; 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate if (tmp == NULL) { 542*0Sstevel@tonic-gate tmp = safe_alloc(sizeof (dev_name_t)); 543*0Sstevel@tonic-gate tmp->name = e->dtype; 544*0Sstevel@tonic-gate tmp->min = e->dnum; 545*0Sstevel@tonic-gate tmp->max = e->dnum; 546*0Sstevel@tonic-gate tmp->list_start = e; 547*0Sstevel@tonic-gate tmp->list_end = e; 548*0Sstevel@tonic-gate tmp->next = d->nf; 549*0Sstevel@tonic-gate d->nf = tmp; 550*0Sstevel@tonic-gate } 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate /* 554*0Sstevel@tonic-gate * devinfo_ident_disks() and devinfo_ident_tapes() are the callback functions we 555*0Sstevel@tonic-gate * use while walking the device tree snapshot provided by devinfo. If 556*0Sstevel@tonic-gate * devinfo_ident_disks() identifies that the device being considered has one or 557*0Sstevel@tonic-gate * more minor nodes _and_ is a block device, then it is a potential disk. 558*0Sstevel@tonic-gate * Similarly for devinfo_ident_tapes(), except that the second criterion is that 559*0Sstevel@tonic-gate * the minor_node be a character device. (This is more inclusive than only 560*0Sstevel@tonic-gate * tape devices, but will match any entries in /dev/rmt/.) 561*0Sstevel@tonic-gate * 562*0Sstevel@tonic-gate * Note: if a driver was previously loaded but is now unloaded, the kstat may 563*0Sstevel@tonic-gate * still be around (e.g., st) but no information will be found in the 564*0Sstevel@tonic-gate * libdevinfo tree. 565*0Sstevel@tonic-gate */ 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate static int 568*0Sstevel@tonic-gate devinfo_ident_disks(di_node_t node, void *arg) 569*0Sstevel@tonic-gate { 570*0Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL; 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate if ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 573*0Sstevel@tonic-gate int spectype = di_minor_spectype(minor); 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate if (S_ISBLK(spectype)) { 576*0Sstevel@tonic-gate char *physical_path = di_devfs_path(node); 577*0Sstevel@tonic-gate int instance = di_instance(node); 578*0Sstevel@tonic-gate char *driver_name = di_driver_name(node); 579*0Sstevel@tonic-gate char *devidstr; 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* lookup the devid, devt specific first */ 582*0Sstevel@tonic-gate if ((di_prop_lookup_strings(di_minor_devt(minor), node, 583*0Sstevel@tonic-gate DEVID_PROP_NAME, &devidstr) == -1) && 584*0Sstevel@tonic-gate (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 585*0Sstevel@tonic-gate DEVID_PROP_NAME, &devidstr) == -1)) 586*0Sstevel@tonic-gate devidstr = NULL; 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate if (driver_name == NULL) 589*0Sstevel@tonic-gate driver_name = "<nil>"; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate pline(physical_path, instance, 592*0Sstevel@tonic-gate driver_name, devidstr, arg); 593*0Sstevel@tonic-gate di_devfs_path_free(physical_path); 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate static int 600*0Sstevel@tonic-gate devinfo_ident_tapes(di_node_t node, void *arg) 601*0Sstevel@tonic-gate { 602*0Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL; 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate if ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 605*0Sstevel@tonic-gate int spectype = di_minor_spectype(minor); 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate if (S_ISCHR(spectype)) { 608*0Sstevel@tonic-gate char *physical_path = di_devfs_path(node); 609*0Sstevel@tonic-gate int instance = di_instance(node); 610*0Sstevel@tonic-gate char *binding_name = di_binding_name(node); 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate pline(physical_path, instance, 613*0Sstevel@tonic-gate binding_name, NULL, arg); 614*0Sstevel@tonic-gate di_devfs_path_free(physical_path); 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * rummage_devinfo() is the driver routine that walks the devinfo snapshot. 622*0Sstevel@tonic-gate */ 623*0Sstevel@tonic-gate static ldinfo_t * 624*0Sstevel@tonic-gate rummage_devinfo(void) 625*0Sstevel@tonic-gate { 626*0Sstevel@tonic-gate di_node_t root_node; 627*0Sstevel@tonic-gate ldinfo_t *rv = NULL; 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate if ((root_node = di_init("/", DINFOCPYALL)) != DI_NODE_NIL) { 630*0Sstevel@tonic-gate (void) di_walk_node(root_node, DI_WALK_CLDFIRST, (void *)&rv, 631*0Sstevel@tonic-gate devinfo_ident_disks); 632*0Sstevel@tonic-gate (void) di_walk_node(root_node, DI_WALK_CLDFIRST, (void *)&rv, 633*0Sstevel@tonic-gate devinfo_ident_tapes); 634*0Sstevel@tonic-gate di_fini(root_node); 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate return (rv); 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate /* 640*0Sstevel@tonic-gate * pline() performs the lookup of the device path in the current list of disks, 641*0Sstevel@tonic-gate * and adds the appropriate information to the nms list in the case of a match. 642*0Sstevel@tonic-gate */ 643*0Sstevel@tonic-gate static void 644*0Sstevel@tonic-gate pline(char *devfs_path, int instance, 645*0Sstevel@tonic-gate char *driver_name, char *devidstr, ldinfo_t **list) 646*0Sstevel@tonic-gate { 647*0Sstevel@tonic-gate ldinfo_t *entry; 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate entry = safe_alloc(sizeof (ldinfo_t)); 650*0Sstevel@tonic-gate entry->dnum = instance; 651*0Sstevel@tonic-gate entry->name = safe_strdup(devfs_path); 652*0Sstevel@tonic-gate entry->dtype = safe_strdup(driver_name); 653*0Sstevel@tonic-gate entry->devidstr = safe_strdup(devidstr); 654*0Sstevel@tonic-gate entry->next = *list; 655*0Sstevel@tonic-gate *list = entry; 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* 659*0Sstevel@tonic-gate * Cleanup space allocated in dlist processing. 660*0Sstevel@tonic-gate * We're only interested in cleaning up the list and nf 661*0Sstevel@tonic-gate * fields in the structure. Everything else is static 662*0Sstevel@tonic-gate * data. 663*0Sstevel@tonic-gate */ 664*0Sstevel@tonic-gate static void 665*0Sstevel@tonic-gate cleanup_dlist(dir_info_t *d) 666*0Sstevel@tonic-gate { 667*0Sstevel@tonic-gate dev_name_t *tmp; 668*0Sstevel@tonic-gate dev_name_t *t1; 669*0Sstevel@tonic-gate disk_list_t *t2; 670*0Sstevel@tonic-gate disk_list_t *t3; 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* 673*0Sstevel@tonic-gate * All of the entries in a dev_name_t use information 674*0Sstevel@tonic-gate * from a disk_list_t structure that is freed later. 675*0Sstevel@tonic-gate * All we need do here is free the dev_name_t 676*0Sstevel@tonic-gate * structure itself. 677*0Sstevel@tonic-gate */ 678*0Sstevel@tonic-gate tmp = d->nf; 679*0Sstevel@tonic-gate while (tmp) { 680*0Sstevel@tonic-gate t1 = tmp->next; 681*0Sstevel@tonic-gate free(tmp); 682*0Sstevel@tonic-gate tmp = t1; 683*0Sstevel@tonic-gate } 684*0Sstevel@tonic-gate d->nf = 0; 685*0Sstevel@tonic-gate /* 686*0Sstevel@tonic-gate * "Later". Free the disk_list_t structures and their 687*0Sstevel@tonic-gate * data attached to this portion of the dir_info 688*0Sstevel@tonic-gate * structure. 689*0Sstevel@tonic-gate */ 690*0Sstevel@tonic-gate t2 = d->list; 691*0Sstevel@tonic-gate while (t2) { 692*0Sstevel@tonic-gate if (t2->dtype) { 693*0Sstevel@tonic-gate free(t2->dtype); 694*0Sstevel@tonic-gate t2->dtype = NULL; 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate if (t2->dsk) { 697*0Sstevel@tonic-gate free(t2->dsk); 698*0Sstevel@tonic-gate t2->dsk = NULL; 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate if (t2->dname) { 701*0Sstevel@tonic-gate free(t2->dname); 702*0Sstevel@tonic-gate t2->dname = NULL; 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate t3 = t2->next; 705*0Sstevel@tonic-gate free(t2); 706*0Sstevel@tonic-gate t2 = t3; 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate d->list = 0; 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate static void 712*0Sstevel@tonic-gate process_dir_ent(char *dent, int curr_type, char *last_snm, 713*0Sstevel@tonic-gate dir_info_t *dp, ldinfo_t *ptoi) 714*0Sstevel@tonic-gate { 715*0Sstevel@tonic-gate struct stat sbuf; 716*0Sstevel@tonic-gate char dnmbuf[PATH_MAX + 1]; 717*0Sstevel@tonic-gate char lnm[NAME_BUFLEN]; 718*0Sstevel@tonic-gate char snm[NAME_BUFLEN]; 719*0Sstevel@tonic-gate char *npt; 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate snm[0] = NULL; 722*0Sstevel@tonic-gate if (curr_type == DISK || curr_type == OSA_DISK) { 723*0Sstevel@tonic-gate /* 724*0Sstevel@tonic-gate * get the short name - omitting 725*0Sstevel@tonic-gate * the trailing sN or PN 726*0Sstevel@tonic-gate */ 727*0Sstevel@tonic-gate (void) strcpy(lnm, dent); 728*0Sstevel@tonic-gate do_snm(dent, snm); 729*0Sstevel@tonic-gate } else if (curr_type == MD_DISK) { 730*0Sstevel@tonic-gate (void) strcpy(lnm, dent); 731*0Sstevel@tonic-gate (void) strcpy(snm, dent); 732*0Sstevel@tonic-gate } else { 733*0Sstevel@tonic-gate /* 734*0Sstevel@tonic-gate * don't want all rewind/etc 735*0Sstevel@tonic-gate * devices for a tape 736*0Sstevel@tonic-gate */ 737*0Sstevel@tonic-gate if (!str_is_digit(dent)) 738*0Sstevel@tonic-gate return; 739*0Sstevel@tonic-gate (void) snprintf(snm, sizeof (snm), "rmt/%s", dent); 740*0Sstevel@tonic-gate (void) snprintf(lnm, sizeof (snm), "rmt/%s", dent); 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate /* 743*0Sstevel@tonic-gate * See if we've already processed an entry for this device. 744*0Sstevel@tonic-gate * If so, we're just another partition so we get another 745*0Sstevel@tonic-gate * entry. 746*0Sstevel@tonic-gate * 747*0Sstevel@tonic-gate * last_snm is an optimization to avoid the function call 748*0Sstevel@tonic-gate * and lookup since we'll often see partition records 749*0Sstevel@tonic-gate * immediately after the disk record. 750*0Sstevel@tonic-gate */ 751*0Sstevel@tonic-gate if (dp->skip_lookup == 0) { 752*0Sstevel@tonic-gate if (strcmp(snm, last_snm) != 0) { 753*0Sstevel@tonic-gate /* 754*0Sstevel@tonic-gate * a zero return means that 755*0Sstevel@tonic-gate * no record was found. We'd 756*0Sstevel@tonic-gate * return a pointer otherwise. 757*0Sstevel@tonic-gate */ 758*0Sstevel@tonic-gate if (look_up_name(snm, 759*0Sstevel@tonic-gate dp->list) == 0) { 760*0Sstevel@tonic-gate (void) strcpy(last_snm, snm); 761*0Sstevel@tonic-gate } else 762*0Sstevel@tonic-gate return; 763*0Sstevel@tonic-gate } else 764*0Sstevel@tonic-gate return; 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate /* 767*0Sstevel@tonic-gate * Get the real device name for this beast 768*0Sstevel@tonic-gate * by following the link into /devices. 769*0Sstevel@tonic-gate */ 770*0Sstevel@tonic-gate (void) snprintf(dnmbuf, sizeof (dnmbuf), "%s/%s", dp->name, dent); 771*0Sstevel@tonic-gate if (lstat(dnmbuf, &sbuf) != -1) { 772*0Sstevel@tonic-gate if ((sbuf.st_mode & S_IFMT) == S_IFLNK) { 773*0Sstevel@tonic-gate /* 774*0Sstevel@tonic-gate * It's a link. Get the real name. 775*0Sstevel@tonic-gate */ 776*0Sstevel@tonic-gate char nmbuf[PATH_MAX + 1]; 777*0Sstevel@tonic-gate int nbyr; 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate if ((nbyr = readlink(dnmbuf, nmbuf, 780*0Sstevel@tonic-gate sizeof (nmbuf))) != 1) { 781*0Sstevel@tonic-gate npt = nmbuf; 782*0Sstevel@tonic-gate /* 783*0Sstevel@tonic-gate * readlink does not terminate 784*0Sstevel@tonic-gate * the string so we have to 785*0Sstevel@tonic-gate * do it. 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate nmbuf[nbyr] = NULL; 788*0Sstevel@tonic-gate } else 789*0Sstevel@tonic-gate npt = NULL; 790*0Sstevel@tonic-gate } else 791*0Sstevel@tonic-gate npt = lnm; 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * make an entry in the device list 794*0Sstevel@tonic-gate */ 795*0Sstevel@tonic-gate if (npt) { 796*0Sstevel@tonic-gate disk_list_t *d; 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate d = make_an_entry(npt, snm, 799*0Sstevel@tonic-gate dnmbuf, dp, 800*0Sstevel@tonic-gate curr_type, ptoi); 801*0Sstevel@tonic-gate insert_into_dlist(dp, d); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate } 805*0Sstevel@tonic-gate static void 806*0Sstevel@tonic-gate cleanup_ldinfo(ldinfo_t *list) 807*0Sstevel@tonic-gate { 808*0Sstevel@tonic-gate ldinfo_t *tmp; 809*0Sstevel@tonic-gate while (list) { 810*0Sstevel@tonic-gate tmp = list; 811*0Sstevel@tonic-gate list = list->next; 812*0Sstevel@tonic-gate free(tmp->name); 813*0Sstevel@tonic-gate free(tmp->dtype); 814*0Sstevel@tonic-gate if (tmp->devidstr) 815*0Sstevel@tonic-gate free(tmp->devidstr); 816*0Sstevel@tonic-gate free(tmp); 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate char * 821*0Sstevel@tonic-gate lookup_nfs_name(char *ks, kstat_ctl_t *kc) 822*0Sstevel@tonic-gate { 823*0Sstevel@tonic-gate int tried = 0; 824*0Sstevel@tonic-gate uint_t minor; 825*0Sstevel@tonic-gate char *host, *path; 826*0Sstevel@tonic-gate char *cp; 827*0Sstevel@tonic-gate char *rstr = 0; 828*0Sstevel@tonic-gate size_t len; 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate if (sscanf(ks, "nfs%u", &minor) == 1) { 831*0Sstevel@tonic-gate retry: 832*0Sstevel@tonic-gate cp = get_nfs_by_minor(minor); 833*0Sstevel@tonic-gate if (cp) { 834*0Sstevel@tonic-gate if (strchr(cp, ',') == NULL) { 835*0Sstevel@tonic-gate rstr = safe_strdup(cp); 836*0Sstevel@tonic-gate return (rstr); 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate host = cur_hostname(minor, kc); 839*0Sstevel@tonic-gate if (host) { 840*0Sstevel@tonic-gate if (*host) { 841*0Sstevel@tonic-gate path = cur_special(host, cp); 842*0Sstevel@tonic-gate if (path) { 843*0Sstevel@tonic-gate len = strlen(host); 844*0Sstevel@tonic-gate len += strlen(path); 845*0Sstevel@tonic-gate len += 2; 846*0Sstevel@tonic-gate rstr = safe_alloc(len); 847*0Sstevel@tonic-gate (void) snprintf(rstr, len, 848*0Sstevel@tonic-gate "%s:%s", host, path); 849*0Sstevel@tonic-gate } else { 850*0Sstevel@tonic-gate rstr = safe_strdup(cp); 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate } else { 853*0Sstevel@tonic-gate rstr = safe_strdup(ks); 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate free(host); 856*0Sstevel@tonic-gate } else { 857*0Sstevel@tonic-gate rstr = safe_strdup(cp); 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate } else if (!tried) { 860*0Sstevel@tonic-gate tried = 1; 861*0Sstevel@tonic-gate do_mnttab(); 862*0Sstevel@tonic-gate goto retry; 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate return (rstr); 866*0Sstevel@tonic-gate } 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate static char * 869*0Sstevel@tonic-gate get_nfs_by_minor(uint_t minor) 870*0Sstevel@tonic-gate { 871*0Sstevel@tonic-gate mnt_t *localnfs; 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate localnfs = nfs; 874*0Sstevel@tonic-gate while (localnfs) { 875*0Sstevel@tonic-gate if (localnfs->minor == minor) { 876*0Sstevel@tonic-gate return (localnfs->device_name); 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate localnfs = localnfs->next; 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate return (0); 881*0Sstevel@tonic-gate } 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate /* 884*0Sstevel@tonic-gate * Read the cur_hostname from the mntinfo kstat 885*0Sstevel@tonic-gate */ 886*0Sstevel@tonic-gate static char * 887*0Sstevel@tonic-gate cur_hostname(uint_t minor, kstat_ctl_t *kc) 888*0Sstevel@tonic-gate { 889*0Sstevel@tonic-gate kstat_t *ksp; 890*0Sstevel@tonic-gate static struct mntinfo_kstat mik; 891*0Sstevel@tonic-gate char *rstr; 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 894*0Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_RAW) 895*0Sstevel@tonic-gate continue; 896*0Sstevel@tonic-gate if (ksp->ks_instance != minor) 897*0Sstevel@tonic-gate continue; 898*0Sstevel@tonic-gate if (strcmp(ksp->ks_module, "nfs")) 899*0Sstevel@tonic-gate continue; 900*0Sstevel@tonic-gate if (strcmp(ksp->ks_name, "mntinfo")) 901*0Sstevel@tonic-gate continue; 902*0Sstevel@tonic-gate if (ksp->ks_flags & KSTAT_FLAG_INVALID) 903*0Sstevel@tonic-gate return (NULL); 904*0Sstevel@tonic-gate if (kstat_read(kc, ksp, &mik) == -1) 905*0Sstevel@tonic-gate return (NULL); 906*0Sstevel@tonic-gate rstr = safe_strdup(mik.mik_curserver); 907*0Sstevel@tonic-gate return (rstr); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate return (NULL); 910*0Sstevel@tonic-gate } 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate /* 913*0Sstevel@tonic-gate * Given the hostname of the mounted server, extract the server 914*0Sstevel@tonic-gate * mount point from the mnttab string. 915*0Sstevel@tonic-gate * 916*0Sstevel@tonic-gate * Common forms: 917*0Sstevel@tonic-gate * server1,server2,server3:/path 918*0Sstevel@tonic-gate * server1:/path,server2:/path 919*0Sstevel@tonic-gate * or a hybrid of the two 920*0Sstevel@tonic-gate */ 921*0Sstevel@tonic-gate static char * 922*0Sstevel@tonic-gate cur_special(char *hostname, char *special) 923*0Sstevel@tonic-gate { 924*0Sstevel@tonic-gate char *cp; 925*0Sstevel@tonic-gate char *path; 926*0Sstevel@tonic-gate size_t hlen = strlen(hostname); 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate /* 929*0Sstevel@tonic-gate * find hostname in string 930*0Sstevel@tonic-gate */ 931*0Sstevel@tonic-gate again: 932*0Sstevel@tonic-gate if ((cp = strstr(special, hostname)) == NULL) 933*0Sstevel@tonic-gate return (NULL); 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate /* 936*0Sstevel@tonic-gate * hostname must be followed by ',' or ':' 937*0Sstevel@tonic-gate */ 938*0Sstevel@tonic-gate if (cp[hlen] != ',' && cp[hlen] != ':') { 939*0Sstevel@tonic-gate special = &cp[hlen]; 940*0Sstevel@tonic-gate goto again; 941*0Sstevel@tonic-gate } 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate /* 944*0Sstevel@tonic-gate * If hostname is followed by a ',' eat all characters until a ':' 945*0Sstevel@tonic-gate */ 946*0Sstevel@tonic-gate cp = &cp[hlen]; 947*0Sstevel@tonic-gate if (*cp == ',') { 948*0Sstevel@tonic-gate cp++; 949*0Sstevel@tonic-gate while (*cp != ':') { 950*0Sstevel@tonic-gate if (*cp == NULL) 951*0Sstevel@tonic-gate return (NULL); 952*0Sstevel@tonic-gate cp++; 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate path = ++cp; /* skip ':' */ 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate /* 958*0Sstevel@tonic-gate * path is terminated by either 0, or space or ',' 959*0Sstevel@tonic-gate */ 960*0Sstevel@tonic-gate while (*cp) { 961*0Sstevel@tonic-gate if (isspace(*cp) || *cp == ',') { 962*0Sstevel@tonic-gate *cp = NULL; 963*0Sstevel@tonic-gate return (path); 964*0Sstevel@tonic-gate } 965*0Sstevel@tonic-gate cp++; 966*0Sstevel@tonic-gate } 967*0Sstevel@tonic-gate return (path); 968*0Sstevel@tonic-gate } 969