1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate #include <unistd.h> 29*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 30*7c478bd9Sstevel@tonic-gate #include <errno.h> 31*7c478bd9Sstevel@tonic-gate #include <ftw.h> 32*7c478bd9Sstevel@tonic-gate #include <string.h> 33*7c478bd9Sstevel@tonic-gate #include <thread.h> 34*7c478bd9Sstevel@tonic-gate #include <synch.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 37*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 39*7c478bd9Sstevel@tonic-gate #include <strings.h> 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h> 42*7c478bd9Sstevel@tonic-gate #include "libdevid.h" 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* 45*7c478bd9Sstevel@tonic-gate * Get Device Id from an open file descriptor 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate int 48*7c478bd9Sstevel@tonic-gate devid_get(int fd, ddi_devid_t *devidp) 49*7c478bd9Sstevel@tonic-gate { 50*7c478bd9Sstevel@tonic-gate int len = 0; 51*7c478bd9Sstevel@tonic-gate dev_t dev; 52*7c478bd9Sstevel@tonic-gate struct stat statb; 53*7c478bd9Sstevel@tonic-gate ddi_devid_t mydevid; 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate if (fstat(fd, &statb) != 0) 56*7c478bd9Sstevel@tonic-gate return (-1); 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* If not char or block device, then error */ 59*7c478bd9Sstevel@tonic-gate if (!S_ISCHR(statb.st_mode) && !S_ISBLK(statb.st_mode)) 60*7c478bd9Sstevel@tonic-gate return (-1); 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* Get the device id size */ 63*7c478bd9Sstevel@tonic-gate dev = statb.st_rdev; 64*7c478bd9Sstevel@tonic-gate if (modctl(MODSIZEOF_DEVID, dev, &len) != 0) 65*7c478bd9Sstevel@tonic-gate return (-1); 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* Allocate space to return device id */ 68*7c478bd9Sstevel@tonic-gate if ((mydevid = (ddi_devid_t)malloc(len)) == NULL) 69*7c478bd9Sstevel@tonic-gate return (-1); 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate /* Get the device id */ 72*7c478bd9Sstevel@tonic-gate if (modctl(MODGETDEVID, dev, len, mydevid) != 0) { 73*7c478bd9Sstevel@tonic-gate free(mydevid); 74*7c478bd9Sstevel@tonic-gate return (-1); 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* Return the device id copy */ 78*7c478bd9Sstevel@tonic-gate *devidp = mydevid; 79*7c478bd9Sstevel@tonic-gate return (0); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate /* 83*7c478bd9Sstevel@tonic-gate * Get the minor name 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate int 86*7c478bd9Sstevel@tonic-gate devid_get_minor_name(int fd, char **minor_namep) 87*7c478bd9Sstevel@tonic-gate { 88*7c478bd9Sstevel@tonic-gate int len = 0; 89*7c478bd9Sstevel@tonic-gate dev_t dev; 90*7c478bd9Sstevel@tonic-gate int spectype; 91*7c478bd9Sstevel@tonic-gate char *myminor_name; 92*7c478bd9Sstevel@tonic-gate struct stat statb; 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate if (fstat(fd, &statb) != 0) 95*7c478bd9Sstevel@tonic-gate return (-1); 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate /* If not a char or block device, then return an error */ 98*7c478bd9Sstevel@tonic-gate if (!S_ISCHR(statb.st_mode) && !S_ISBLK(statb.st_mode)) 99*7c478bd9Sstevel@tonic-gate return (-1); 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate spectype = statb.st_mode & S_IFMT; 102*7c478bd9Sstevel@tonic-gate dev = statb.st_rdev; 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* Get the minor name size */ 105*7c478bd9Sstevel@tonic-gate if (modctl(MODSIZEOF_MINORNAME, dev, spectype, &len) != 0) 106*7c478bd9Sstevel@tonic-gate return (-1); 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* Allocate space for the minor name */ 109*7c478bd9Sstevel@tonic-gate if ((myminor_name = (char *)malloc(len)) == NULL) 110*7c478bd9Sstevel@tonic-gate return (-1); 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* Get the minor name */ 113*7c478bd9Sstevel@tonic-gate if (modctl(MODGETMINORNAME, dev, spectype, len, myminor_name) != 0) { 114*7c478bd9Sstevel@tonic-gate free(myminor_name); 115*7c478bd9Sstevel@tonic-gate return (-1); 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* return the minor name copy */ 119*7c478bd9Sstevel@tonic-gate *minor_namep = myminor_name; 120*7c478bd9Sstevel@tonic-gate return (0); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* list element of devid_nmlist_t information */ 124*7c478bd9Sstevel@tonic-gate struct nmlist { 125*7c478bd9Sstevel@tonic-gate struct nmlist *nl_next; 126*7c478bd9Sstevel@tonic-gate char *nl_devname; 127*7c478bd9Sstevel@tonic-gate dev_t nl_dev; 128*7c478bd9Sstevel@tonic-gate }; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* add list element to end of nmlist headed by *nlhp */ 131*7c478bd9Sstevel@tonic-gate struct nmlist * 132*7c478bd9Sstevel@tonic-gate nmlist_add(struct nmlist **nlhp, char *path) 133*7c478bd9Sstevel@tonic-gate { 134*7c478bd9Sstevel@tonic-gate struct stat statb; 135*7c478bd9Sstevel@tonic-gate dev_t dev; 136*7c478bd9Sstevel@tonic-gate struct nmlist *nl; 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* stat and get the devt for char or block */ 139*7c478bd9Sstevel@tonic-gate if ((stat(path, &statb) == 0) && 140*7c478bd9Sstevel@tonic-gate (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode))) 141*7c478bd9Sstevel@tonic-gate dev = statb.st_rdev; 142*7c478bd9Sstevel@tonic-gate else 143*7c478bd9Sstevel@tonic-gate dev = NODEV; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* find the end of the list */ 146*7c478bd9Sstevel@tonic-gate for (; (nl = *nlhp) != NULL; nlhp = &nl->nl_next) 147*7c478bd9Sstevel@tonic-gate ; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* allocate and initialize new entry */ 150*7c478bd9Sstevel@tonic-gate if ((nl = malloc(sizeof (*nl))) == NULL) 151*7c478bd9Sstevel@tonic-gate return (NULL); 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate if ((nl->nl_devname = strdup(path)) == NULL) { 154*7c478bd9Sstevel@tonic-gate free(nl); 155*7c478bd9Sstevel@tonic-gate return (NULL); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate nl->nl_next = NULL; 158*7c478bd9Sstevel@tonic-gate nl->nl_dev = dev; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate /* link new entry at end */ 161*7c478bd9Sstevel@tonic-gate *nlhp = nl; 162*7c478bd9Sstevel@tonic-gate return (nl); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* information needed by devlink_callback to call nmlist_add */ 166*7c478bd9Sstevel@tonic-gate struct devlink_cbinfo { 167*7c478bd9Sstevel@tonic-gate struct nmlist **cbi_nlhp; 168*7c478bd9Sstevel@tonic-gate char *cbi_search_path; 169*7c478bd9Sstevel@tonic-gate int cbi_error; 170*7c478bd9Sstevel@tonic-gate }; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* di_devlink callback to add a /dev entry to nmlist */ 173*7c478bd9Sstevel@tonic-gate static int 174*7c478bd9Sstevel@tonic-gate devlink_callback(di_devlink_t dl, void *arg) 175*7c478bd9Sstevel@tonic-gate { 176*7c478bd9Sstevel@tonic-gate struct devlink_cbinfo *cbip = (struct devlink_cbinfo *)arg; 177*7c478bd9Sstevel@tonic-gate char *devpath = (char *)di_devlink_path(dl); 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate if (strncmp(devpath, cbip->cbi_search_path, 180*7c478bd9Sstevel@tonic-gate strlen(cbip->cbi_search_path)) == 0) { 181*7c478bd9Sstevel@tonic-gate if (nmlist_add(cbip->cbi_nlhp, devpath) == NULL) { 182*7c478bd9Sstevel@tonic-gate cbip->cbi_error = 1; 183*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate /* 190*7c478bd9Sstevel@tonic-gate * Resolve /dev names to DI_PRIMARY_LINK, DI_SECONDARY_LINK, or both. 191*7c478bd9Sstevel@tonic-gate * The default is to resolve to just the DI_PRIMARY_LINK. 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate int devid_deviceid_to_nmlist_link = DI_PRIMARY_LINK; 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * Options for the devid_deviceid_to_nmlist implementation: 197*7c478bd9Sstevel@tonic-gate * 198*7c478bd9Sstevel@tonic-gate * DEVICEID_NMLIST_SLINK - reduce overhead by reuse the previous 199*7c478bd9Sstevel@tonic-gate * di_devlink_init. 200*7c478bd9Sstevel@tonic-gate */ 201*7c478bd9Sstevel@tonic-gate #define DEVICEID_NMLIST_SLINK 1 202*7c478bd9Sstevel@tonic-gate int devid_deviceid_to_nmlist_flg = 0; 203*7c478bd9Sstevel@tonic-gate static di_devlink_handle_t devid_deviceid_to_nmlist_dlh = NULL; /* SLINK */ 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate #define DEVICEID_NMLIST_NRETRY 10 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /* 208*7c478bd9Sstevel@tonic-gate * Convert the specified devid/minor_name into a devid_nmlist_t array 209*7c478bd9Sstevel@tonic-gate * with names that resolve into /devices or /dev depending on search_path. 210*7c478bd9Sstevel@tonic-gate * 211*7c478bd9Sstevel@tonic-gate * The man page indicates that: 212*7c478bd9Sstevel@tonic-gate * 213*7c478bd9Sstevel@tonic-gate * This function traverses the file tree, starting at search_path. 214*7c478bd9Sstevel@tonic-gate * 215*7c478bd9Sstevel@tonic-gate * This is not true, we reverse engineer the paths relative to 216*7c478bd9Sstevel@tonic-gate * the specified search path to avoid attaching all devices. 217*7c478bd9Sstevel@tonic-gate */ 218*7c478bd9Sstevel@tonic-gate int 219*7c478bd9Sstevel@tonic-gate devid_deviceid_to_nmlist( 220*7c478bd9Sstevel@tonic-gate char *search_path, 221*7c478bd9Sstevel@tonic-gate ddi_devid_t devid, 222*7c478bd9Sstevel@tonic-gate char *minor_name, 223*7c478bd9Sstevel@tonic-gate devid_nmlist_t **retlist) 224*7c478bd9Sstevel@tonic-gate { 225*7c478bd9Sstevel@tonic-gate char *cp; 226*7c478bd9Sstevel@tonic-gate int dev; 227*7c478bd9Sstevel@tonic-gate char *paths = NULL; 228*7c478bd9Sstevel@tonic-gate char *path; 229*7c478bd9Sstevel@tonic-gate int lens; 230*7c478bd9Sstevel@tonic-gate di_devlink_handle_t dlh = NULL; 231*7c478bd9Sstevel@tonic-gate int ret = -1; 232*7c478bd9Sstevel@tonic-gate struct devlink_cbinfo cbi; 233*7c478bd9Sstevel@tonic-gate struct nmlist *nlh = NULL; 234*7c478bd9Sstevel@tonic-gate struct nmlist *nl; 235*7c478bd9Sstevel@tonic-gate devid_nmlist_t *rl; 236*7c478bd9Sstevel@tonic-gate int nret; 237*7c478bd9Sstevel@tonic-gate int nagain = 0; 238*7c478bd9Sstevel@tonic-gate int err = 0; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate *retlist = NULL; 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* verify valid search path starts with "/devices" or "/dev" */ 243*7c478bd9Sstevel@tonic-gate if ((strcmp(search_path, "/devices") == 0) || 244*7c478bd9Sstevel@tonic-gate (strncmp(search_path, "/devices/", 9) == 0)) 245*7c478bd9Sstevel@tonic-gate dev = 0; 246*7c478bd9Sstevel@tonic-gate else if ((strcmp(search_path, "/dev") == 0) || 247*7c478bd9Sstevel@tonic-gate (strncmp(search_path, "/dev/", 5) == 0)) 248*7c478bd9Sstevel@tonic-gate dev = 1; 249*7c478bd9Sstevel@tonic-gate else { 250*7c478bd9Sstevel@tonic-gate errno = EINVAL; 251*7c478bd9Sstevel@tonic-gate return (-1); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate /* translate devid/minor_name to /devices paths */ 256*7c478bd9Sstevel@tonic-gate again: if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, NULL) != 0) 257*7c478bd9Sstevel@tonic-gate goto out; 258*7c478bd9Sstevel@tonic-gate if ((paths = (char *)malloc(lens)) == NULL) 259*7c478bd9Sstevel@tonic-gate goto out; 260*7c478bd9Sstevel@tonic-gate if (modctl(MODDEVID2PATHS, devid, minor_name, 0, &lens, paths) != 0) { 261*7c478bd9Sstevel@tonic-gate if ((errno == EAGAIN) && (nagain++ < DEVICEID_NMLIST_NRETRY)) { 262*7c478bd9Sstevel@tonic-gate free(paths); 263*7c478bd9Sstevel@tonic-gate paths = NULL; 264*7c478bd9Sstevel@tonic-gate goto again; 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate goto out; 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * initialize for /devices path to /dev path translation. To reduce 271*7c478bd9Sstevel@tonic-gate * overhead we reuse the last snapshot if DEVICEID_NMLIST_SLINK is set. 272*7c478bd9Sstevel@tonic-gate */ 273*7c478bd9Sstevel@tonic-gate if (dev) { 274*7c478bd9Sstevel@tonic-gate dlh = devid_deviceid_to_nmlist_dlh; 275*7c478bd9Sstevel@tonic-gate if (dlh && 276*7c478bd9Sstevel@tonic-gate !(devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) { 277*7c478bd9Sstevel@tonic-gate (void) di_devlink_fini(&dlh); 278*7c478bd9Sstevel@tonic-gate dlh = devid_deviceid_to_nmlist_dlh = NULL; 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate if ((dlh == NULL) && 281*7c478bd9Sstevel@tonic-gate ((dlh = di_devlink_init(NULL, 0)) == NULL)) 282*7c478bd9Sstevel@tonic-gate goto out; 283*7c478bd9Sstevel@tonic-gate } 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate /* 286*7c478bd9Sstevel@tonic-gate * iterate over all the devtspectype resolutions of the devid and 287*7c478bd9Sstevel@tonic-gate * convert them into the appropriate path form and add items to return 288*7c478bd9Sstevel@tonic-gate * to the nmlist list; 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate for (path = paths; *path; path += strlen(path) + 1) { 291*7c478bd9Sstevel@tonic-gate if (dev) { 292*7c478bd9Sstevel@tonic-gate /* add /dev entries */ 293*7c478bd9Sstevel@tonic-gate cbi.cbi_nlhp = &nlh; 294*7c478bd9Sstevel@tonic-gate cbi.cbi_search_path = search_path; 295*7c478bd9Sstevel@tonic-gate cbi.cbi_error = 0; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate (void) di_devlink_walk(dlh, NULL, path, 298*7c478bd9Sstevel@tonic-gate devid_deviceid_to_nmlist_link, 299*7c478bd9Sstevel@tonic-gate (void *)&cbi, devlink_callback); 300*7c478bd9Sstevel@tonic-gate if (cbi.cbi_error) 301*7c478bd9Sstevel@tonic-gate goto out; 302*7c478bd9Sstevel@tonic-gate } else { 303*7c478bd9Sstevel@tonic-gate /* add /devices entry */ 304*7c478bd9Sstevel@tonic-gate cp = malloc(strlen("/devices") + strlen(path) + 1); 305*7c478bd9Sstevel@tonic-gate (void) strcpy(cp, "/devices"); 306*7c478bd9Sstevel@tonic-gate (void) strcat(cp, path); 307*7c478bd9Sstevel@tonic-gate if (strncmp(cp, search_path, 308*7c478bd9Sstevel@tonic-gate strlen(search_path)) == 0) { 309*7c478bd9Sstevel@tonic-gate if (nmlist_add(&nlh, cp) == NULL) { 310*7c478bd9Sstevel@tonic-gate free(cp); 311*7c478bd9Sstevel@tonic-gate goto out; 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate free(cp); 315*7c478bd9Sstevel@tonic-gate } 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate /* convert from nmlist to retlist array */ 319*7c478bd9Sstevel@tonic-gate for (nl = nlh, nret = 0; nl; nl = nl->nl_next) 320*7c478bd9Sstevel@tonic-gate nret++; 321*7c478bd9Sstevel@tonic-gate if (nret == 0) { 322*7c478bd9Sstevel@tonic-gate err = ENODEV; 323*7c478bd9Sstevel@tonic-gate goto out; 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate if ((*retlist = calloc(nret + 1, sizeof (devid_nmlist_t))) == NULL) { 326*7c478bd9Sstevel@tonic-gate err = ENOMEM; 327*7c478bd9Sstevel@tonic-gate goto out; 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate for (nl = nlh, rl = *retlist; nl; nl = nl->nl_next, rl++) { 330*7c478bd9Sstevel@tonic-gate rl->devname = nl->nl_devname; 331*7c478bd9Sstevel@tonic-gate rl->dev = nl->nl_dev; 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate rl->devname = NULL; 334*7c478bd9Sstevel@tonic-gate rl->dev = NODEV; 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate ret = 0; 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate out: 339*7c478bd9Sstevel@tonic-gate while ((nl = nlh) != NULL) { /* free the nmlist */ 340*7c478bd9Sstevel@tonic-gate nlh = nl->nl_next; 341*7c478bd9Sstevel@tonic-gate free(nl); 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate if (paths) 344*7c478bd9Sstevel@tonic-gate free(paths); 345*7c478bd9Sstevel@tonic-gate if (dlh) { 346*7c478bd9Sstevel@tonic-gate if ((ret == 0) && 347*7c478bd9Sstevel@tonic-gate (devid_deviceid_to_nmlist_flg & DEVICEID_NMLIST_SLINK)) 348*7c478bd9Sstevel@tonic-gate devid_deviceid_to_nmlist_dlh = dlh; 349*7c478bd9Sstevel@tonic-gate else 350*7c478bd9Sstevel@tonic-gate (void) di_devlink_fini(&dlh); 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate if (ret && *retlist) 353*7c478bd9Sstevel@tonic-gate free(*retlist); 354*7c478bd9Sstevel@tonic-gate if (ret && err != 0) 355*7c478bd9Sstevel@tonic-gate errno = err; 356*7c478bd9Sstevel@tonic-gate return (ret); 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate /* 360*7c478bd9Sstevel@tonic-gate * Free Device Id Name List 361*7c478bd9Sstevel@tonic-gate */ 362*7c478bd9Sstevel@tonic-gate void 363*7c478bd9Sstevel@tonic-gate devid_free_nmlist(devid_nmlist_t *list) 364*7c478bd9Sstevel@tonic-gate { 365*7c478bd9Sstevel@tonic-gate devid_nmlist_t *p = list; 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate if (list == NULL) 368*7c478bd9Sstevel@tonic-gate return; 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate /* Free all the device names */ 371*7c478bd9Sstevel@tonic-gate while (p->devname != NULL) { 372*7c478bd9Sstevel@tonic-gate free(p->devname); 373*7c478bd9Sstevel@tonic-gate p++; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate /* Free the array */ 377*7c478bd9Sstevel@tonic-gate free(list); 378*7c478bd9Sstevel@tonic-gate } 379