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 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include "devinfo_devlink.h" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #undef DEBUG 32*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 33*7c478bd9Sstevel@tonic-gate #define NDEBUG 1 34*7c478bd9Sstevel@tonic-gate #else 35*7c478bd9Sstevel@tonic-gate #undef NDEBUG 36*7c478bd9Sstevel@tonic-gate #endif 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include <assert.h> 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate static mutex_t update_mutex = DEFAULTMUTEX; /* Protects update record lock */ 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate static const size_t elem_sizes[DB_TYPES] = { 43*7c478bd9Sstevel@tonic-gate sizeof (struct db_node), 44*7c478bd9Sstevel@tonic-gate sizeof (struct db_minor), 45*7c478bd9Sstevel@tonic-gate sizeof (struct db_link), 46*7c478bd9Sstevel@tonic-gate sizeof (char) 47*7c478bd9Sstevel@tonic-gate }; 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * List of directories/files skipped while physically walking /dev 51*7c478bd9Sstevel@tonic-gate * Paths are relative to "<root>/dev/" 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate static const char *skip_dirs[] = {"fd"}; 54*7c478bd9Sstevel@tonic-gate static const char *skip_files[] = { 55*7c478bd9Sstevel@tonic-gate "stdout", 56*7c478bd9Sstevel@tonic-gate "stdin", 57*7c478bd9Sstevel@tonic-gate "stderr" 58*7c478bd9Sstevel@tonic-gate }; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #define N_SKIP_DIRS (sizeof (skip_dirs) / sizeof (skip_dirs[0])) 61*7c478bd9Sstevel@tonic-gate #define N_SKIP_FILES (sizeof (skip_files) / sizeof (skip_files[0])) 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* 64*7c478bd9Sstevel@tonic-gate * 65*7c478bd9Sstevel@tonic-gate * This file contains two sets of interfaces which operate on the reverse 66*7c478bd9Sstevel@tonic-gate * links database. One set (which includes di_devlink_open()/_close()) 67*7c478bd9Sstevel@tonic-gate * allows link generators like devfsadm(1M) and ucblinks(1B) (writers) to 68*7c478bd9Sstevel@tonic-gate * populate the database with /devices -> /dev mappings. Another set 69*7c478bd9Sstevel@tonic-gate * of interfaces (which includes di_devlink_init()/_fini()) allows 70*7c478bd9Sstevel@tonic-gate * applications (readers) to lookup the database for /dev links corresponding 71*7c478bd9Sstevel@tonic-gate * to a given minor. 72*7c478bd9Sstevel@tonic-gate * 73*7c478bd9Sstevel@tonic-gate * Writers operate on a cached version of the database. The cache is created 74*7c478bd9Sstevel@tonic-gate * when di_devlink_open() is called. As links in /dev are created and removed, 75*7c478bd9Sstevel@tonic-gate * the cache is updated to keep it in synch with /dev. When the /dev updates 76*7c478bd9Sstevel@tonic-gate * are complete, the link generator calls di_devlink_close() which writes 77*7c478bd9Sstevel@tonic-gate * out the cache to the database. 78*7c478bd9Sstevel@tonic-gate * 79*7c478bd9Sstevel@tonic-gate * Applications which need to lookup the database, call di_devlink_init(). 80*7c478bd9Sstevel@tonic-gate * di_devlink_init() checks the database file (if one exists). If the 81*7c478bd9Sstevel@tonic-gate * database is valid, it is mapped into the address space of the 82*7c478bd9Sstevel@tonic-gate * application. The database file consists of several segments. Each 83*7c478bd9Sstevel@tonic-gate * segment can be mapped in independently and is mapped on demand. 84*7c478bd9Sstevel@tonic-gate * 85*7c478bd9Sstevel@tonic-gate * Database Layout 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * --------------------- 88*7c478bd9Sstevel@tonic-gate * | Magic # | 89*7c478bd9Sstevel@tonic-gate * | ----------------- | 90*7c478bd9Sstevel@tonic-gate * | Version | HEADER 91*7c478bd9Sstevel@tonic-gate * | ----------------- | 92*7c478bd9Sstevel@tonic-gate * | ... | 93*7c478bd9Sstevel@tonic-gate * --------------------- 94*7c478bd9Sstevel@tonic-gate * | | 95*7c478bd9Sstevel@tonic-gate * | | NODES 96*7c478bd9Sstevel@tonic-gate * | | 97*7c478bd9Sstevel@tonic-gate * | | 98*7c478bd9Sstevel@tonic-gate * --------------------- 99*7c478bd9Sstevel@tonic-gate * | | 100*7c478bd9Sstevel@tonic-gate * | | MINORS 101*7c478bd9Sstevel@tonic-gate * | | 102*7c478bd9Sstevel@tonic-gate * | | 103*7c478bd9Sstevel@tonic-gate * --------------------- 104*7c478bd9Sstevel@tonic-gate * | | 105*7c478bd9Sstevel@tonic-gate * | | LINKS 106*7c478bd9Sstevel@tonic-gate * | | 107*7c478bd9Sstevel@tonic-gate * | | 108*7c478bd9Sstevel@tonic-gate * --------------------- 109*7c478bd9Sstevel@tonic-gate * | | 110*7c478bd9Sstevel@tonic-gate * | | STRINGS 111*7c478bd9Sstevel@tonic-gate * | | 112*7c478bd9Sstevel@tonic-gate * | | 113*7c478bd9Sstevel@tonic-gate * --------------------- 114*7c478bd9Sstevel@tonic-gate * 115*7c478bd9Sstevel@tonic-gate * Readers can lookup /dev links for a specific minor or 116*7c478bd9Sstevel@tonic-gate * lookup all /dev links. In the latter case, the node 117*7c478bd9Sstevel@tonic-gate * and minor segments are not mapped in and the reader 118*7c478bd9Sstevel@tonic-gate * walks through every link in the link segment. 119*7c478bd9Sstevel@tonic-gate * 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate di_devlink_handle_t 123*7c478bd9Sstevel@tonic-gate di_devlink_open(const char *root_dir, uint_t flags) 124*7c478bd9Sstevel@tonic-gate { 125*7c478bd9Sstevel@tonic-gate int err; 126*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 127*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp; 128*7c478bd9Sstevel@tonic-gate int retried = 0; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate retry: 131*7c478bd9Sstevel@tonic-gate /* 132*7c478bd9Sstevel@tonic-gate * Allocate a read-write handle but open the DB in readonly 133*7c478bd9Sstevel@tonic-gate * mode. We do writes only to a temporary copy of the database. 134*7c478bd9Sstevel@tonic-gate */ 135*7c478bd9Sstevel@tonic-gate if ((hdp = handle_alloc(root_dir, OPEN_RDWR)) == NULL) { 136*7c478bd9Sstevel@tonic-gate return (NULL); 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate err = open_db(hdp, OPEN_RDONLY); 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate /* 142*7c478bd9Sstevel@tonic-gate * Unlink the database, so that consumers don't get 143*7c478bd9Sstevel@tonic-gate * out of date information as the database is being updated. 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_FILE, path, sizeof (path)); 146*7c478bd9Sstevel@tonic-gate (void) unlink(path); 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * The flags argument is reserved for future use. 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate if (flags != 0) { 152*7c478bd9Sstevel@tonic-gate handle_free(&hdp); /* also closes the DB */ 153*7c478bd9Sstevel@tonic-gate errno = EINVAL; 154*7c478bd9Sstevel@tonic-gate return (NULL); 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate if (cache_alloc(hdp) != 0) { 158*7c478bd9Sstevel@tonic-gate handle_free(&hdp); 159*7c478bd9Sstevel@tonic-gate return (NULL); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate if (err) { 163*7c478bd9Sstevel@tonic-gate /* 164*7c478bd9Sstevel@tonic-gate * Failed to open DB. 165*7c478bd9Sstevel@tonic-gate * The most likely cause is that DB file did not exist. 166*7c478bd9Sstevel@tonic-gate * Call di_devlink_close() to recreate the DB file and 167*7c478bd9Sstevel@tonic-gate * retry di_devlink_open(). 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate if (retried == 0) { 170*7c478bd9Sstevel@tonic-gate (void) di_devlink_close(&hdp, 0); 171*7c478bd9Sstevel@tonic-gate retried = 1; 172*7c478bd9Sstevel@tonic-gate goto retry; 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* 176*7c478bd9Sstevel@tonic-gate * DB cannot be opened, just return the 177*7c478bd9Sstevel@tonic-gate * handle. We will recreate the DB later. 178*7c478bd9Sstevel@tonic-gate */ 179*7c478bd9Sstevel@tonic-gate return (hdp); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate /* Read the database into the cache */ 183*7c478bd9Sstevel@tonic-gate CACHE(hdp)->update_count = DB_HDR(hdp)->update_count; 184*7c478bd9Sstevel@tonic-gate (void) read_nodes(hdp, NULL, DB_HDR(hdp)->root_idx); 185*7c478bd9Sstevel@tonic-gate (void) read_links(hdp, NULL, DB_HDR(hdp)->dngl_idx); 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate (void) close_db(hdp); 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate return (hdp); 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate static void 193*7c478bd9Sstevel@tonic-gate get_db_path( 194*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 195*7c478bd9Sstevel@tonic-gate const char *fname, 196*7c478bd9Sstevel@tonic-gate char *buf, 197*7c478bd9Sstevel@tonic-gate size_t blen) 198*7c478bd9Sstevel@tonic-gate { 199*7c478bd9Sstevel@tonic-gate char *dir = NULL; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 202*7c478bd9Sstevel@tonic-gate if (dir = getenv(ALT_DB_DIR)) { 203*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "get_db_path: alternate db dir: %s\n", 204*7c478bd9Sstevel@tonic-gate dir); 205*7c478bd9Sstevel@tonic-gate } 206*7c478bd9Sstevel@tonic-gate #endif 207*7c478bd9Sstevel@tonic-gate if (dir == NULL) { 208*7c478bd9Sstevel@tonic-gate dir = hdp->dev_dir; 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, blen, "%s/%s", dir, fname); 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate static int 215*7c478bd9Sstevel@tonic-gate open_db(struct di_devlink_handle *hdp, int flags) 216*7c478bd9Sstevel@tonic-gate { 217*7c478bd9Sstevel@tonic-gate size_t sz; 218*7c478bd9Sstevel@tonic-gate long page_sz; 219*7c478bd9Sstevel@tonic-gate int fd, rv, flg; 220*7c478bd9Sstevel@tonic-gate struct stat sbuf; 221*7c478bd9Sstevel@tonic-gate uint32_t count[DB_TYPES] = {0}; 222*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 223*7c478bd9Sstevel@tonic-gate void *cp; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate assert(!DB_OPEN(hdp)); 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 228*7c478bd9Sstevel@tonic-gate if (getenv(SKIP_DB)) { 229*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "open_db: skipping database\n"); 230*7c478bd9Sstevel@tonic-gate return (-1); 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate #endif 233*7c478bd9Sstevel@tonic-gate if ((page_sz = sysconf(_SC_PAGE_SIZE)) == -1) { 234*7c478bd9Sstevel@tonic-gate return (-1); 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * Use O_TRUNC flag for write access, so that the subsequent ftruncate() 239*7c478bd9Sstevel@tonic-gate * call will zero-fill the entire file 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate if (IS_RDONLY(flags)) { 242*7c478bd9Sstevel@tonic-gate flg = O_RDONLY; 243*7c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_FILE, path, sizeof (path)); 244*7c478bd9Sstevel@tonic-gate } else { 245*7c478bd9Sstevel@tonic-gate flg = O_RDWR|O_CREAT|O_TRUNC; 246*7c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_TMP, path, sizeof (path)); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if ((fd = open(path, flg, DB_PERMS)) == -1) { 250*7c478bd9Sstevel@tonic-gate return (-1); 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if (IS_RDONLY(flags)) { 254*7c478bd9Sstevel@tonic-gate flg = PROT_READ; 255*7c478bd9Sstevel@tonic-gate rv = fstat(fd, &sbuf); 256*7c478bd9Sstevel@tonic-gate sz = sbuf.st_size; 257*7c478bd9Sstevel@tonic-gate } else { 258*7c478bd9Sstevel@tonic-gate flg = PROT_READ | PROT_WRITE; 259*7c478bd9Sstevel@tonic-gate sz = size_db(hdp, page_sz, count); 260*7c478bd9Sstevel@tonic-gate rv = ftruncate(fd, sz); 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate if (rv == -1 || sz < HDR_LEN) { 264*7c478bd9Sstevel@tonic-gate if (rv != -1) 265*7c478bd9Sstevel@tonic-gate errno = EINVAL; 266*7c478bd9Sstevel@tonic-gate (void) close(fd); 267*7c478bd9Sstevel@tonic-gate return (-1); 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate cp = mmap(0, HDR_LEN, flg, MAP_SHARED, fd, 0); 271*7c478bd9Sstevel@tonic-gate if (cp == MAP_FAILED) { 272*7c478bd9Sstevel@tonic-gate (void) close(fd); 273*7c478bd9Sstevel@tonic-gate return (-1); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate DB(hdp)->hdr = (struct db_hdr *)cp; 276*7c478bd9Sstevel@tonic-gate DB(hdp)->db_fd = fd; 277*7c478bd9Sstevel@tonic-gate DB(hdp)->flags = flags; 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate if (IS_RDONLY(flags)) { 280*7c478bd9Sstevel@tonic-gate rv = invalid_db(hdp, sz, page_sz); 281*7c478bd9Sstevel@tonic-gate } else { 282*7c478bd9Sstevel@tonic-gate rv = init_hdr(hdp, page_sz, count); 283*7c478bd9Sstevel@tonic-gate } 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate if (rv) { 286*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "open_db: invalid DB(%s)\n", path); 287*7c478bd9Sstevel@tonic-gate (void) close_db(hdp); 288*7c478bd9Sstevel@tonic-gate return (-1); 289*7c478bd9Sstevel@tonic-gate } else { 290*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "open_db: DB(%s): opened\n", path); 291*7c478bd9Sstevel@tonic-gate return (0); 292*7c478bd9Sstevel@tonic-gate } 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * A handle can be allocated for read-only or read-write access 297*7c478bd9Sstevel@tonic-gate */ 298*7c478bd9Sstevel@tonic-gate static struct di_devlink_handle * 299*7c478bd9Sstevel@tonic-gate handle_alloc(const char *root_dir, uint_t flags) 300*7c478bd9Sstevel@tonic-gate { 301*7c478bd9Sstevel@tonic-gate char dev_dir[PATH_MAX], path[PATH_MAX]; 302*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, proto = {0}; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate assert(flags == OPEN_RDWR || flags == OPEN_RDONLY); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate dev_dir[0] = '\0'; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* 309*7c478bd9Sstevel@tonic-gate * NULL and the empty string are equivalent to "/" 310*7c478bd9Sstevel@tonic-gate */ 311*7c478bd9Sstevel@tonic-gate if (root_dir && root_dir[0] != '\0') { 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate if (root_dir[0] != '/') { 314*7c478bd9Sstevel@tonic-gate errno = EINVAL; 315*7c478bd9Sstevel@tonic-gate return (NULL); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 319*7c478bd9Sstevel@tonic-gate /*LINTED*/ 320*7c478bd9Sstevel@tonic-gate assert(sizeof (dev_dir) >= PATH_MAX); 321*7c478bd9Sstevel@tonic-gate #endif 322*7c478bd9Sstevel@tonic-gate if (realpath(root_dir, dev_dir) == NULL) { 323*7c478bd9Sstevel@tonic-gate return (NULL); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate if (strcmp(dev_dir, "/") == 0) { 328*7c478bd9Sstevel@tonic-gate (void) strlcpy(dev_dir, DEV, sizeof (dev_dir)); 329*7c478bd9Sstevel@tonic-gate } else { 330*7c478bd9Sstevel@tonic-gate (void) strlcat(dev_dir, DEV, sizeof (dev_dir)); 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate proto.dev_dir = dev_dir; 334*7c478bd9Sstevel@tonic-gate proto.flags = flags; 335*7c478bd9Sstevel@tonic-gate proto.lock_fd = -1; 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /* 338*7c478bd9Sstevel@tonic-gate * Lock database if a read-write handle is being allocated. 339*7c478bd9Sstevel@tonic-gate * Locks are needed to protect against multiple writers. 340*7c478bd9Sstevel@tonic-gate * Readers don't need locks. 341*7c478bd9Sstevel@tonic-gate */ 342*7c478bd9Sstevel@tonic-gate if (HDL_RDWR(&proto)) { 343*7c478bd9Sstevel@tonic-gate if (enter_update_lock(&proto) != 0) { 344*7c478bd9Sstevel@tonic-gate return (NULL); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate DB(&proto)->db_fd = -1; 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate hdp = calloc(1, sizeof (struct di_devlink_handle)); 351*7c478bd9Sstevel@tonic-gate if (hdp == NULL) { 352*7c478bd9Sstevel@tonic-gate goto error; 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate *hdp = proto; 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate /* 358*7c478bd9Sstevel@tonic-gate * The handle hdp now contains a pointer to local storage 359*7c478bd9Sstevel@tonic-gate * in the dev_dir field (obtained from the proto handle). 360*7c478bd9Sstevel@tonic-gate * In the following line, a dynamically allocated version 361*7c478bd9Sstevel@tonic-gate * is substituted. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate if ((hdp->dev_dir = strdup(proto.dev_dir)) == NULL) { 365*7c478bd9Sstevel@tonic-gate free(hdp); 366*7c478bd9Sstevel@tonic-gate goto error; 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate return (hdp); 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate error: 373*7c478bd9Sstevel@tonic-gate if (HDL_RDWR(&proto)) { 374*7c478bd9Sstevel@tonic-gate /* Unlink DB file on error */ 375*7c478bd9Sstevel@tonic-gate get_db_path(&proto, DB_FILE, path, sizeof (path)); 376*7c478bd9Sstevel@tonic-gate (void) unlink(path); 377*7c478bd9Sstevel@tonic-gate exit_update_lock(&proto); 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate return (NULL); 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate static int 384*7c478bd9Sstevel@tonic-gate cache_alloc(struct di_devlink_handle *hdp) 385*7c478bd9Sstevel@tonic-gate { 386*7c478bd9Sstevel@tonic-gate size_t hash_sz = 0; 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate if (DB_OPEN(hdp)) { 391*7c478bd9Sstevel@tonic-gate hash_sz = DB_NUM(hdp, DB_LINK) / AVG_CHAIN_SIZE; 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate hash_sz = (hash_sz >= MIN_HASH_SIZE) ? hash_sz : MIN_HASH_SIZE; 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate CACHE(hdp)->hash = calloc(hash_sz, sizeof (cache_link_t *)); 396*7c478bd9Sstevel@tonic-gate if (CACHE(hdp)->hash == NULL) { 397*7c478bd9Sstevel@tonic-gate return (-1); 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate CACHE(hdp)->hash_sz = hash_sz; 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate return (0); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate static int 406*7c478bd9Sstevel@tonic-gate invalid_db(struct di_devlink_handle *hdp, size_t fsize, long page_sz) 407*7c478bd9Sstevel@tonic-gate { 408*7c478bd9Sstevel@tonic-gate int i; 409*7c478bd9Sstevel@tonic-gate char *cp; 410*7c478bd9Sstevel@tonic-gate size_t sz; 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate if (DB_HDR(hdp)->magic != DB_MAGIC || DB_HDR(hdp)->vers != DB_VERSION) { 413*7c478bd9Sstevel@tonic-gate return (1); 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate if (DB_HDR(hdp)->page_sz == 0 || DB_HDR(hdp)->page_sz != page_sz) { 417*7c478bd9Sstevel@tonic-gate return (1); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate sz = seg_size(hdp, DB_HEADER); 421*7c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) { 422*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "N[%u] = %u\n", i, DB_NUM(hdp, i)); 423*7c478bd9Sstevel@tonic-gate /* There must be at least 1 element of each type */ 424*7c478bd9Sstevel@tonic-gate if (DB_NUM(hdp, i) < 1) { 425*7c478bd9Sstevel@tonic-gate return (1); 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate sz += seg_size(hdp, i); 428*7c478bd9Sstevel@tonic-gate assert(sz % page_sz == 0); 429*7c478bd9Sstevel@tonic-gate } 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate if (sz != fsize) { 432*7c478bd9Sstevel@tonic-gate return (1); 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate if (!VALID_INDEX(hdp, DB_NODE, DB_HDR(hdp)->root_idx)) { 436*7c478bd9Sstevel@tonic-gate return (1); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate if (!VALID_INDEX(hdp, DB_LINK, DB_HDR(hdp)->dngl_idx)) { 440*7c478bd9Sstevel@tonic-gate return (1); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate if (DB_EMPTY(hdp)) { 444*7c478bd9Sstevel@tonic-gate return (1); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate * The last character in the string segment must be a NUL char. 449*7c478bd9Sstevel@tonic-gate */ 450*7c478bd9Sstevel@tonic-gate cp = get_string(hdp, DB_NUM(hdp, DB_STR) - 1); 451*7c478bd9Sstevel@tonic-gate if (cp == NULL || *cp != '\0') { 452*7c478bd9Sstevel@tonic-gate return (1); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate return (0); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate static int 459*7c478bd9Sstevel@tonic-gate read_nodes(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx) 460*7c478bd9Sstevel@tonic-gate { 461*7c478bd9Sstevel@tonic-gate char *path; 462*7c478bd9Sstevel@tonic-gate cache_node_t *cnp; 463*7c478bd9Sstevel@tonic-gate struct db_node *dnp; 464*7c478bd9Sstevel@tonic-gate const char *fcn = "read_nodes"; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate /* 469*7c478bd9Sstevel@tonic-gate * parent node should be NULL only for the root node 470*7c478bd9Sstevel@tonic-gate */ 471*7c478bd9Sstevel@tonic-gate if ((pcnp == NULL) ^ (nidx == DB_HDR(hdp)->root_idx)) { 472*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid parent or index(%u)\n", 473*7c478bd9Sstevel@tonic-gate fcn, nidx); 474*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 475*7c478bd9Sstevel@tonic-gate return (-1); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate for (; dnp = get_node(hdp, nidx); nidx = dnp->sib) { 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate path = get_string(hdp, dnp->path); 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate /* 483*7c478bd9Sstevel@tonic-gate * Insert at head of list to recreate original order 484*7c478bd9Sstevel@tonic-gate */ 485*7c478bd9Sstevel@tonic-gate cnp = node_insert(hdp, pcnp, path, INSERT_HEAD); 486*7c478bd9Sstevel@tonic-gate if (cnp == NULL) { 487*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 488*7c478bd9Sstevel@tonic-gate break; 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate assert(strcmp(path, "/") ^ (nidx == DB_HDR(hdp)->root_idx)); 492*7c478bd9Sstevel@tonic-gate assert(strcmp(path, "/") != 0 || dnp->sib == DB_NIL); 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate if (read_minors(hdp, cnp, dnp->minor) != 0 || 495*7c478bd9Sstevel@tonic-gate read_nodes(hdp, cnp, dnp->child) != 0) { 496*7c478bd9Sstevel@tonic-gate break; 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, nidx, 500*7c478bd9Sstevel@tonic-gate cnp->path); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate return (dnp ? -1 : 0); 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate static int 507*7c478bd9Sstevel@tonic-gate read_minors(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx) 508*7c478bd9Sstevel@tonic-gate { 509*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 510*7c478bd9Sstevel@tonic-gate struct db_minor *dmp; 511*7c478bd9Sstevel@tonic-gate char *name, *nodetype; 512*7c478bd9Sstevel@tonic-gate const char *fcn = "read_minors"; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate if (pcnp == NULL) { 517*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: minor[%u]: orphan minor\n", fcn, 518*7c478bd9Sstevel@tonic-gate nidx); 519*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 520*7c478bd9Sstevel@tonic-gate return (-1); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate for (; dmp = get_minor(hdp, nidx); nidx = dmp->sib) { 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate name = get_string(hdp, dmp->name); 526*7c478bd9Sstevel@tonic-gate nodetype = get_string(hdp, dmp->nodetype); 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate cmnp = minor_insert(hdp, pcnp, name, nodetype, NULL); 529*7c478bd9Sstevel@tonic-gate if (cmnp == NULL) { 530*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 531*7c478bd9Sstevel@tonic-gate break; 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, nidx, 535*7c478bd9Sstevel@tonic-gate cmnp->name); 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate if (read_links(hdp, cmnp, dmp->link) != 0) { 538*7c478bd9Sstevel@tonic-gate break; 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate return (dmp ? -1 : 0); 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * If the link is dangling the corresponding minor will be absent. 547*7c478bd9Sstevel@tonic-gate */ 548*7c478bd9Sstevel@tonic-gate static int 549*7c478bd9Sstevel@tonic-gate read_links(struct di_devlink_handle *hdp, cache_minor_t *pcmp, uint32_t nidx) 550*7c478bd9Sstevel@tonic-gate { 551*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 552*7c478bd9Sstevel@tonic-gate struct db_link *dlp; 553*7c478bd9Sstevel@tonic-gate char *path, *content; 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate if (nidx != DB_NIL && 558*7c478bd9Sstevel@tonic-gate ((pcmp == NULL) ^ (nidx == DB_HDR(hdp)->dngl_idx))) { 559*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "read_links: invalid minor or" 560*7c478bd9Sstevel@tonic-gate " index(%u)\n", nidx); 561*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 562*7c478bd9Sstevel@tonic-gate return (-1); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate for (; dlp = get_link(hdp, nidx); nidx = dlp->sib) { 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate path = get_string(hdp, dlp->path); 568*7c478bd9Sstevel@tonic-gate content = get_string(hdp, dlp->content); 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate clp = link_insert(hdp, pcmp, path, content, dlp->attr); 571*7c478bd9Sstevel@tonic-gate if (clp == NULL) { 572*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 573*7c478bd9Sstevel@tonic-gate break; 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "read_links: link[%u]: %s%s\n", 577*7c478bd9Sstevel@tonic-gate nidx, clp->path, pcmp == NULL ? "(DANGLING)" : ""); 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate return (dlp ? -1 : 0); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate int 584*7c478bd9Sstevel@tonic-gate di_devlink_close(di_devlink_handle_t *pp, int flag) 585*7c478bd9Sstevel@tonic-gate { 586*7c478bd9Sstevel@tonic-gate int i, rv; 587*7c478bd9Sstevel@tonic-gate char tmp[PATH_MAX]; 588*7c478bd9Sstevel@tonic-gate char file[PATH_MAX]; 589*7c478bd9Sstevel@tonic-gate uint32_t next[DB_TYPES] = {0}; 590*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp; 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate if (pp == NULL || *pp == NULL || !HDL_RDWR(*pp)) { 593*7c478bd9Sstevel@tonic-gate errno = EINVAL; 594*7c478bd9Sstevel@tonic-gate return (-1); 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate hdp = *pp; 598*7c478bd9Sstevel@tonic-gate *pp = NULL; 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate /* 601*7c478bd9Sstevel@tonic-gate * The caller encountered some error in their processing. 602*7c478bd9Sstevel@tonic-gate * so handle isn't valid. Discard it and return success. 603*7c478bd9Sstevel@tonic-gate */ 604*7c478bd9Sstevel@tonic-gate if (flag == DI_LINK_ERROR) { 605*7c478bd9Sstevel@tonic-gate handle_free(&hdp); 606*7c478bd9Sstevel@tonic-gate return (0); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate if (DB_ERR(hdp)) { 610*7c478bd9Sstevel@tonic-gate handle_free(&hdp); 611*7c478bd9Sstevel@tonic-gate errno = EINVAL; 612*7c478bd9Sstevel@tonic-gate return (-1); 613*7c478bd9Sstevel@tonic-gate } 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate /* 616*7c478bd9Sstevel@tonic-gate * Extract the DB path before the handle is freed. 617*7c478bd9Sstevel@tonic-gate */ 618*7c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_FILE, file, sizeof (file)); 619*7c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_TMP, tmp, sizeof (tmp)); 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate /* 622*7c478bd9Sstevel@tonic-gate * update database with actual contents of /dev 623*7c478bd9Sstevel@tonic-gate */ 624*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "di_devlink_close: update_count = %u\n", 625*7c478bd9Sstevel@tonic-gate CACHE(hdp)->update_count); 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate /* 628*7c478bd9Sstevel@tonic-gate * For performance reasons, synchronization of the database 629*7c478bd9Sstevel@tonic-gate * with /dev is turned off by default. However, applications 630*7c478bd9Sstevel@tonic-gate * with appropriate permissions can request a "sync" by 631*7c478bd9Sstevel@tonic-gate * calling di_devlink_update(). 632*7c478bd9Sstevel@tonic-gate */ 633*7c478bd9Sstevel@tonic-gate if (CACHE(hdp)->update_count == 0) { 634*7c478bd9Sstevel@tonic-gate CACHE(hdp)->update_count = 1; 635*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, 636*7c478bd9Sstevel@tonic-gate "di_devlink_close: synchronizing DB\n"); 637*7c478bd9Sstevel@tonic-gate (void) synchronize_db(hdp); 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate /* 641*7c478bd9Sstevel@tonic-gate * Resolve dangling links AFTER synchronizing DB with /dev as the 642*7c478bd9Sstevel@tonic-gate * synchronization process may create dangling links. 643*7c478bd9Sstevel@tonic-gate */ 644*7c478bd9Sstevel@tonic-gate resolve_dangling_links(hdp); 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * All changes to the cache are complete. Write out the cache 648*7c478bd9Sstevel@tonic-gate * to the database only if it is not empty. 649*7c478bd9Sstevel@tonic-gate */ 650*7c478bd9Sstevel@tonic-gate if (CACHE_EMPTY(hdp)) { 651*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "di_devlink_close: skipping write\n"); 652*7c478bd9Sstevel@tonic-gate (void) unlink(file); 653*7c478bd9Sstevel@tonic-gate handle_free(&hdp); 654*7c478bd9Sstevel@tonic-gate return (0); 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate if (open_db(hdp, OPEN_RDWR) != 0) { 658*7c478bd9Sstevel@tonic-gate handle_free(&hdp); 659*7c478bd9Sstevel@tonic-gate return (-1); 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * Keep track of array assignments. There is atleast 664*7c478bd9Sstevel@tonic-gate * 1 element (the "NIL" element) per type. 665*7c478bd9Sstevel@tonic-gate */ 666*7c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) { 667*7c478bd9Sstevel@tonic-gate next[i] = 1; 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate (void) write_nodes(hdp, NULL, CACHE_ROOT(hdp), next); 671*7c478bd9Sstevel@tonic-gate (void) write_links(hdp, NULL, CACHE(hdp)->dngl, next); 672*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->update_count = CACHE(hdp)->update_count; 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate rv = close_db(hdp); 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate if (rv != 0 || DB_ERR(hdp) || rename(tmp, file) != 0) { 677*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "di_devlink_close: %s error: %s\n", 678*7c478bd9Sstevel@tonic-gate rv ? "close_db" : "DB or rename", strerror(errno)); 679*7c478bd9Sstevel@tonic-gate (void) unlink(tmp); 680*7c478bd9Sstevel@tonic-gate (void) unlink(file); 681*7c478bd9Sstevel@tonic-gate handle_free(&hdp); 682*7c478bd9Sstevel@tonic-gate return (-1); 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate handle_free(&hdp); 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "di_devlink_close: wrote DB(%s)\n", file); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate return (0); 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* 693*7c478bd9Sstevel@tonic-gate * Inits the database header. 694*7c478bd9Sstevel@tonic-gate */ 695*7c478bd9Sstevel@tonic-gate static int 696*7c478bd9Sstevel@tonic-gate init_hdr(struct di_devlink_handle *hdp, long page_sz, uint32_t *count) 697*7c478bd9Sstevel@tonic-gate { 698*7c478bd9Sstevel@tonic-gate int i; 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->magic = DB_MAGIC; 701*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->vers = DB_VERSION; 702*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->root_idx = DB_NIL; 703*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->dngl_idx = DB_NIL; 704*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->page_sz = (uint32_t)page_sz; 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) { 707*7c478bd9Sstevel@tonic-gate assert(count[i] >= 1); 708*7c478bd9Sstevel@tonic-gate DB_NUM(hdp, i) = count[i]; 709*7c478bd9Sstevel@tonic-gate } 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate return (0); 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate static int 715*7c478bd9Sstevel@tonic-gate write_nodes( 716*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 717*7c478bd9Sstevel@tonic-gate struct db_node *pdnp, 718*7c478bd9Sstevel@tonic-gate cache_node_t *cnp, 719*7c478bd9Sstevel@tonic-gate uint32_t *next) 720*7c478bd9Sstevel@tonic-gate { 721*7c478bd9Sstevel@tonic-gate uint32_t idx; 722*7c478bd9Sstevel@tonic-gate struct db_node *dnp; 723*7c478bd9Sstevel@tonic-gate const char *fcn = "write_nodes"; 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate for (; cnp != NULL; cnp = cnp->sib) { 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate assert(cnp->path != NULL); 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate /* parent node should only be NULL for root node */ 732*7c478bd9Sstevel@tonic-gate if ((pdnp == NULL) ^ (cnp == CACHE_ROOT(hdp))) { 733*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid parent for: %s\n", 734*7c478bd9Sstevel@tonic-gate fcn, cnp->path); 735*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 736*7c478bd9Sstevel@tonic-gate break; 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate assert((strcmp(cnp->path, "/") != 0) ^ 740*7c478bd9Sstevel@tonic-gate (cnp == CACHE_ROOT(hdp))); 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate idx = next[DB_NODE]; 743*7c478bd9Sstevel@tonic-gate if ((dnp = set_node(hdp, idx)) == NULL) { 744*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 745*7c478bd9Sstevel@tonic-gate break; 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate 748*7c478bd9Sstevel@tonic-gate dnp->path = write_string(hdp, cnp->path, next); 749*7c478bd9Sstevel@tonic-gate if (dnp->path == DB_NIL) { 750*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 751*7c478bd9Sstevel@tonic-gate break; 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate /* commit write for this node */ 754*7c478bd9Sstevel@tonic-gate next[DB_NODE]++; 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate if (pdnp == NULL) { 757*7c478bd9Sstevel@tonic-gate assert(DB_HDR(hdp)->root_idx == DB_NIL); 758*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->root_idx = idx; 759*7c478bd9Sstevel@tonic-gate } else { 760*7c478bd9Sstevel@tonic-gate dnp->sib = pdnp->child; 761*7c478bd9Sstevel@tonic-gate pdnp->child = idx; 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, idx, 765*7c478bd9Sstevel@tonic-gate cnp->path); 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate if (write_minors(hdp, dnp, cnp->minor, next) != 0 || 768*7c478bd9Sstevel@tonic-gate write_nodes(hdp, dnp, cnp->child, next) != 0) { 769*7c478bd9Sstevel@tonic-gate break; 770*7c478bd9Sstevel@tonic-gate } 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate return (cnp ? -1 : 0); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate static int 777*7c478bd9Sstevel@tonic-gate write_minors( 778*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 779*7c478bd9Sstevel@tonic-gate struct db_node *pdnp, 780*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp, 781*7c478bd9Sstevel@tonic-gate uint32_t *next) 782*7c478bd9Sstevel@tonic-gate { 783*7c478bd9Sstevel@tonic-gate uint32_t idx; 784*7c478bd9Sstevel@tonic-gate struct db_minor *dmp; 785*7c478bd9Sstevel@tonic-gate const char *fcn = "write_minors"; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate if (pdnp == NULL) { 790*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: no node for minor: %s\n", fcn, 791*7c478bd9Sstevel@tonic-gate cmnp ? cmnp->name : "<NULL>"); 792*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 793*7c478bd9Sstevel@tonic-gate return (-1); 794*7c478bd9Sstevel@tonic-gate } 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate for (; cmnp != NULL; cmnp = cmnp->sib) { 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate assert(cmnp->name != NULL); 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate idx = next[DB_MINOR]; 801*7c478bd9Sstevel@tonic-gate if ((dmp = set_minor(hdp, idx)) == NULL) { 802*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 803*7c478bd9Sstevel@tonic-gate break; 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate dmp->name = write_string(hdp, cmnp->name, next); 807*7c478bd9Sstevel@tonic-gate dmp->nodetype = write_string(hdp, cmnp->nodetype, next); 808*7c478bd9Sstevel@tonic-gate if (dmp->name == DB_NIL || dmp->nodetype == DB_NIL) { 809*7c478bd9Sstevel@tonic-gate dmp->name = dmp->nodetype = DB_NIL; 810*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 811*7c478bd9Sstevel@tonic-gate break; 812*7c478bd9Sstevel@tonic-gate } 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate /* Commit writes to this minor */ 815*7c478bd9Sstevel@tonic-gate next[DB_MINOR]++; 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate dmp->sib = pdnp->minor; 818*7c478bd9Sstevel@tonic-gate pdnp->minor = idx; 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, idx, 821*7c478bd9Sstevel@tonic-gate cmnp->name); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate if (write_links(hdp, dmp, cmnp->link, next) != 0) { 824*7c478bd9Sstevel@tonic-gate break; 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate return (cmnp ? -1 : 0); 829*7c478bd9Sstevel@tonic-gate } 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate static int 832*7c478bd9Sstevel@tonic-gate write_links( 833*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 834*7c478bd9Sstevel@tonic-gate struct db_minor *pdmp, 835*7c478bd9Sstevel@tonic-gate cache_link_t *clp, 836*7c478bd9Sstevel@tonic-gate uint32_t *next) 837*7c478bd9Sstevel@tonic-gate { 838*7c478bd9Sstevel@tonic-gate uint32_t idx; 839*7c478bd9Sstevel@tonic-gate struct db_link *dlp; 840*7c478bd9Sstevel@tonic-gate const char *fcn = "write_links"; 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate /* A NULL minor if and only if the links are dangling */ 845*7c478bd9Sstevel@tonic-gate if (clp != NULL && ((pdmp == NULL) ^ (clp == CACHE(hdp)->dngl))) { 846*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid minor for link\n", fcn); 847*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 848*7c478bd9Sstevel@tonic-gate return (-1); 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate for (; clp != NULL; clp = clp->sib) { 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate assert(clp->path != NULL); 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate if ((pdmp == NULL) ^ (clp->minor == NULL)) { 856*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid minor for link" 857*7c478bd9Sstevel@tonic-gate "(%s)\n", fcn, clp->path); 858*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 859*7c478bd9Sstevel@tonic-gate break; 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate idx = next[DB_LINK]; 863*7c478bd9Sstevel@tonic-gate if ((dlp = set_link(hdp, idx)) == NULL) { 864*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 865*7c478bd9Sstevel@tonic-gate break; 866*7c478bd9Sstevel@tonic-gate } 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate dlp->path = write_string(hdp, clp->path, next); 869*7c478bd9Sstevel@tonic-gate dlp->content = write_string(hdp, clp->content, next); 870*7c478bd9Sstevel@tonic-gate if (dlp->path == DB_NIL || dlp->content == DB_NIL) { 871*7c478bd9Sstevel@tonic-gate dlp->path = dlp->content = DB_NIL; 872*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 873*7c478bd9Sstevel@tonic-gate break; 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate dlp->attr = clp->attr; 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate /* Commit writes to this link */ 879*7c478bd9Sstevel@tonic-gate next[DB_LINK]++; 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate if (pdmp != NULL) { 882*7c478bd9Sstevel@tonic-gate dlp->sib = pdmp->link; 883*7c478bd9Sstevel@tonic-gate pdmp->link = idx; 884*7c478bd9Sstevel@tonic-gate } else { 885*7c478bd9Sstevel@tonic-gate dlp->sib = DB_HDR(hdp)->dngl_idx; 886*7c478bd9Sstevel@tonic-gate DB_HDR(hdp)->dngl_idx = idx; 887*7c478bd9Sstevel@tonic-gate } 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: link[%u]: %s%s\n", fcn, idx, 890*7c478bd9Sstevel@tonic-gate clp->path, pdmp == NULL ? "(DANGLING)" : ""); 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate return (clp ? -1 : 0); 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate static uint32_t 898*7c478bd9Sstevel@tonic-gate write_string(struct di_devlink_handle *hdp, const char *str, uint32_t *next) 899*7c478bd9Sstevel@tonic-gate { 900*7c478bd9Sstevel@tonic-gate char *dstr; 901*7c478bd9Sstevel@tonic-gate uint32_t idx; 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp)); 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate if (str == NULL) { 906*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "write_string: NULL argument\n"); 907*7c478bd9Sstevel@tonic-gate return (DB_NIL); 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate idx = next[DB_STR]; 911*7c478bd9Sstevel@tonic-gate if (!VALID_STR(hdp, idx, str)) { 912*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "write_string: invalid index[%u]," 913*7c478bd9Sstevel@tonic-gate " string(%s)\n", idx, str); 914*7c478bd9Sstevel@tonic-gate return (DB_NIL); 915*7c478bd9Sstevel@tonic-gate } 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate if ((dstr = set_string(hdp, idx)) == NULL) { 918*7c478bd9Sstevel@tonic-gate return (DB_NIL); 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate (void) strcpy(dstr, str); 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate next[DB_STR] += strlen(dstr) + 1; 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate return (idx); 926*7c478bd9Sstevel@tonic-gate } 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate static int 929*7c478bd9Sstevel@tonic-gate close_db(struct di_devlink_handle *hdp) 930*7c478bd9Sstevel@tonic-gate { 931*7c478bd9Sstevel@tonic-gate int i, rv = 0; 932*7c478bd9Sstevel@tonic-gate size_t sz; 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate if (!DB_OPEN(hdp)) { 935*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 936*7c478bd9Sstevel@tonic-gate assert(DB(hdp)->db_fd == -1); 937*7c478bd9Sstevel@tonic-gate assert(DB(hdp)->flags == 0); 938*7c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) { 939*7c478bd9Sstevel@tonic-gate assert(DB_SEG(hdp, i) == NULL); 940*7c478bd9Sstevel@tonic-gate assert(DB_SEG_PROT(hdp, i) == 0); 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate #endif 943*7c478bd9Sstevel@tonic-gate return (0); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate /* Unmap header after unmapping all other mapped segments */ 947*7c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) { 948*7c478bd9Sstevel@tonic-gate if (DB_SEG(hdp, i)) { 949*7c478bd9Sstevel@tonic-gate sz = seg_size(hdp, i); 950*7c478bd9Sstevel@tonic-gate if (DB_RDWR(hdp)) 951*7c478bd9Sstevel@tonic-gate rv += msync(DB_SEG(hdp, i), sz, MS_SYNC); 952*7c478bd9Sstevel@tonic-gate (void) munmap(DB_SEG(hdp, i), sz); 953*7c478bd9Sstevel@tonic-gate DB_SEG(hdp, i) = NULL; 954*7c478bd9Sstevel@tonic-gate DB_SEG_PROT(hdp, i) = 0; 955*7c478bd9Sstevel@tonic-gate } 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate if (DB_RDWR(hdp)) 959*7c478bd9Sstevel@tonic-gate rv += msync((caddr_t)DB_HDR(hdp), HDR_LEN, MS_SYNC); 960*7c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)DB_HDR(hdp), HDR_LEN); 961*7c478bd9Sstevel@tonic-gate DB(hdp)->hdr = NULL; 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate (void) close(DB(hdp)->db_fd); 964*7c478bd9Sstevel@tonic-gate DB(hdp)->db_fd = -1; 965*7c478bd9Sstevel@tonic-gate DB(hdp)->flags = 0; 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate return (rv ? -1 : 0); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate static void 972*7c478bd9Sstevel@tonic-gate cache_free(struct di_devlink_handle *hdp) 973*7c478bd9Sstevel@tonic-gate { 974*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate subtree_free(hdp, &(CACHE_ROOT(hdp))); 977*7c478bd9Sstevel@tonic-gate assert(CACHE_LAST(hdp) == NULL); 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate /* 980*7c478bd9Sstevel@tonic-gate * Don't bother removing links from hash table chains, 981*7c478bd9Sstevel@tonic-gate * as we are freeing the hash table itself. 982*7c478bd9Sstevel@tonic-gate */ 983*7c478bd9Sstevel@tonic-gate while (CACHE(hdp)->dngl != NULL) { 984*7c478bd9Sstevel@tonic-gate clp = CACHE(hdp)->dngl; 985*7c478bd9Sstevel@tonic-gate CACHE(hdp)->dngl = clp->sib; 986*7c478bd9Sstevel@tonic-gate assert(clp->minor == NULL); 987*7c478bd9Sstevel@tonic-gate link_free(&clp); 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate assert((CACHE(hdp)->hash == NULL) ^ (CACHE(hdp)->hash_sz != 0)); 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate free(CACHE(hdp)->hash); 993*7c478bd9Sstevel@tonic-gate CACHE(hdp)->hash = NULL; 994*7c478bd9Sstevel@tonic-gate CACHE(hdp)->hash_sz = 0; 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate static void 998*7c478bd9Sstevel@tonic-gate handle_free(struct di_devlink_handle **pp) 999*7c478bd9Sstevel@tonic-gate { 1000*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp = *pp; 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate *pp = NULL; 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate if (hdp == NULL) 1005*7c478bd9Sstevel@tonic-gate return; 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate (void) close_db(hdp); 1008*7c478bd9Sstevel@tonic-gate cache_free(hdp); 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate if (HDL_RDWR(hdp)) 1011*7c478bd9Sstevel@tonic-gate exit_update_lock(hdp); 1012*7c478bd9Sstevel@tonic-gate assert(hdp->lock_fd == -1); 1013*7c478bd9Sstevel@tonic-gate 1014*7c478bd9Sstevel@tonic-gate free(hdp->dev_dir); 1015*7c478bd9Sstevel@tonic-gate free(hdp); 1016*7c478bd9Sstevel@tonic-gate } 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate /* 1019*7c478bd9Sstevel@tonic-gate * Frees the tree rooted at a node. Siblings of the subtree root 1020*7c478bd9Sstevel@tonic-gate * have to be handled by the caller. 1021*7c478bd9Sstevel@tonic-gate */ 1022*7c478bd9Sstevel@tonic-gate static void 1023*7c478bd9Sstevel@tonic-gate subtree_free(struct di_devlink_handle *hdp, cache_node_t **pp) 1024*7c478bd9Sstevel@tonic-gate { 1025*7c478bd9Sstevel@tonic-gate cache_node_t *np; 1026*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 1027*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate if (pp == NULL || *pp == NULL) 1030*7c478bd9Sstevel@tonic-gate return; 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate while ((*pp)->child != NULL) { 1033*7c478bd9Sstevel@tonic-gate np = (*pp)->child; 1034*7c478bd9Sstevel@tonic-gate (*pp)->child = np->sib; 1035*7c478bd9Sstevel@tonic-gate subtree_free(hdp, &np); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate while ((*pp)->minor != NULL) { 1039*7c478bd9Sstevel@tonic-gate cmnp = (*pp)->minor; 1040*7c478bd9Sstevel@tonic-gate (*pp)->minor = cmnp->sib; 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate while (cmnp->link != NULL) { 1043*7c478bd9Sstevel@tonic-gate clp = cmnp->link; 1044*7c478bd9Sstevel@tonic-gate cmnp->link = clp->sib; 1045*7c478bd9Sstevel@tonic-gate rm_link_from_hash(hdp, clp); 1046*7c478bd9Sstevel@tonic-gate link_free(&clp); 1047*7c478bd9Sstevel@tonic-gate } 1048*7c478bd9Sstevel@tonic-gate minor_free(hdp, &cmnp); 1049*7c478bd9Sstevel@tonic-gate } 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate node_free(pp); 1052*7c478bd9Sstevel@tonic-gate } 1053*7c478bd9Sstevel@tonic-gate 1054*7c478bd9Sstevel@tonic-gate static void 1055*7c478bd9Sstevel@tonic-gate rm_link_from_hash(struct di_devlink_handle *hdp, cache_link_t *clp) 1056*7c478bd9Sstevel@tonic-gate { 1057*7c478bd9Sstevel@tonic-gate int hval; 1058*7c478bd9Sstevel@tonic-gate cache_link_t **pp; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate if (clp == NULL) 1061*7c478bd9Sstevel@tonic-gate return; 1062*7c478bd9Sstevel@tonic-gate 1063*7c478bd9Sstevel@tonic-gate if (clp->path == NULL) 1064*7c478bd9Sstevel@tonic-gate return; 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate hval = hashfn(hdp, clp->path); 1067*7c478bd9Sstevel@tonic-gate pp = &(CACHE_HASH(hdp, hval)); 1068*7c478bd9Sstevel@tonic-gate for (; *pp != NULL; pp = &(*pp)->hash) { 1069*7c478bd9Sstevel@tonic-gate if (*pp == clp) { 1070*7c478bd9Sstevel@tonic-gate *pp = clp->hash; 1071*7c478bd9Sstevel@tonic-gate clp->hash = NULL; 1072*7c478bd9Sstevel@tonic-gate return; 1073*7c478bd9Sstevel@tonic-gate } 1074*7c478bd9Sstevel@tonic-gate } 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "rm_link_from_hash: link(%s) not found\n", clp->path); 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate static cache_link_t * 1080*7c478bd9Sstevel@tonic-gate link_hash(di_devlink_handle_t hdp, const char *link, uint_t flags) 1081*7c478bd9Sstevel@tonic-gate { 1082*7c478bd9Sstevel@tonic-gate int hval; 1083*7c478bd9Sstevel@tonic-gate cache_link_t **pp, *clp; 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate if (link == NULL) 1086*7c478bd9Sstevel@tonic-gate return (NULL); 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate hval = hashfn(hdp, link); 1089*7c478bd9Sstevel@tonic-gate pp = &(CACHE_HASH(hdp, hval)); 1090*7c478bd9Sstevel@tonic-gate for (; (clp = *pp) != NULL; pp = &clp->hash) { 1091*7c478bd9Sstevel@tonic-gate if (strcmp(clp->path, link) == 0) { 1092*7c478bd9Sstevel@tonic-gate break; 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate } 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate if (clp == NULL) 1097*7c478bd9Sstevel@tonic-gate return (NULL); 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate if ((flags & UNLINK_FROM_HASH) == UNLINK_FROM_HASH) { 1100*7c478bd9Sstevel@tonic-gate *pp = clp->hash; 1101*7c478bd9Sstevel@tonic-gate clp->hash = NULL; 1102*7c478bd9Sstevel@tonic-gate } 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate return (clp); 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate static cache_minor_t * 1108*7c478bd9Sstevel@tonic-gate link2minor(struct di_devlink_handle *hdp, cache_link_t *clp) 1109*7c478bd9Sstevel@tonic-gate { 1110*7c478bd9Sstevel@tonic-gate cache_link_t *plp; 1111*7c478bd9Sstevel@tonic-gate const char *minor_path; 1112*7c478bd9Sstevel@tonic-gate char *cp, buf[PATH_MAX], link[PATH_MAX]; 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate if (TYPE_PRI(attr2type(clp->attr))) { 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * For primary link, content should point to a /devices node. 1117*7c478bd9Sstevel@tonic-gate */ 1118*7c478bd9Sstevel@tonic-gate if (!is_minor_node(clp->content, &minor_path)) { 1119*7c478bd9Sstevel@tonic-gate return (NULL); 1120*7c478bd9Sstevel@tonic-gate } 1121*7c478bd9Sstevel@tonic-gate 1122*7c478bd9Sstevel@tonic-gate return (lookup_minor(hdp, minor_path, NULL, 1123*7c478bd9Sstevel@tonic-gate TYPE_CACHE|CREATE_FLAG)); 1124*7c478bd9Sstevel@tonic-gate 1125*7c478bd9Sstevel@tonic-gate } 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate /* 1128*7c478bd9Sstevel@tonic-gate * If secondary, the primary link is derived from the secondary 1129*7c478bd9Sstevel@tonic-gate * link contents. Secondary link contents can have two formats: 1130*7c478bd9Sstevel@tonic-gate * audio -> /dev/sound/0 1131*7c478bd9Sstevel@tonic-gate * fb0 -> fbs/afb0 1132*7c478bd9Sstevel@tonic-gate */ 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate buf[0] = '\0'; 1135*7c478bd9Sstevel@tonic-gate if (strncmp(clp->content, DEV"/", strlen(DEV"/")) == 0) { 1136*7c478bd9Sstevel@tonic-gate cp = &clp->content[strlen(DEV"/")]; 1137*7c478bd9Sstevel@tonic-gate } else if (clp->content[0] != '/') { 1138*7c478bd9Sstevel@tonic-gate if ((cp = strrchr(clp->path, '/')) != NULL) { 1139*7c478bd9Sstevel@tonic-gate char savechar = *(cp + 1); 1140*7c478bd9Sstevel@tonic-gate *(cp + 1) = '\0'; 1141*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s", clp->path); 1142*7c478bd9Sstevel@tonic-gate *(cp + 1) = savechar; 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate (void) strlcat(buf, clp->content, sizeof (buf)); 1145*7c478bd9Sstevel@tonic-gate cp = buf; 1146*7c478bd9Sstevel@tonic-gate } else { 1147*7c478bd9Sstevel@tonic-gate goto follow_link; 1148*7c478bd9Sstevel@tonic-gate } 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate /* 1151*7c478bd9Sstevel@tonic-gate * Lookup the primary link if possible and find its minor. 1152*7c478bd9Sstevel@tonic-gate */ 1153*7c478bd9Sstevel@tonic-gate if ((plp = link_hash(hdp, cp, 0)) != NULL && plp->minor != NULL) { 1154*7c478bd9Sstevel@tonic-gate return (plp->minor); 1155*7c478bd9Sstevel@tonic-gate } 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate /* realpath() used only as a last resort because it is expensive */ 1158*7c478bd9Sstevel@tonic-gate follow_link: 1159*7c478bd9Sstevel@tonic-gate (void) snprintf(link, sizeof (link), "%s/%s", hdp->dev_dir, clp->path); 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1162*7c478bd9Sstevel@tonic-gate /*LINTED*/ 1163*7c478bd9Sstevel@tonic-gate assert(sizeof (buf) >= PATH_MAX); 1164*7c478bd9Sstevel@tonic-gate #endif 1165*7c478bd9Sstevel@tonic-gate if (realpath(link, buf) == NULL || !is_minor_node(buf, &minor_path)) { 1166*7c478bd9Sstevel@tonic-gate return (NULL); 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate return (lookup_minor(hdp, minor_path, NULL, TYPE_CACHE|CREATE_FLAG)); 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate static void 1173*7c478bd9Sstevel@tonic-gate resolve_dangling_links(struct di_devlink_handle *hdp) 1174*7c478bd9Sstevel@tonic-gate { 1175*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 1176*7c478bd9Sstevel@tonic-gate cache_link_t *clp, **pp; 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate for (pp = &(CACHE(hdp)->dngl); *pp != NULL; ) { 1179*7c478bd9Sstevel@tonic-gate clp = *pp; 1180*7c478bd9Sstevel@tonic-gate if ((cmnp = link2minor(hdp, clp)) != NULL) { 1181*7c478bd9Sstevel@tonic-gate *pp = clp->sib; 1182*7c478bd9Sstevel@tonic-gate clp->sib = cmnp->link; 1183*7c478bd9Sstevel@tonic-gate cmnp->link = clp; 1184*7c478bd9Sstevel@tonic-gate assert(clp->minor == NULL); 1185*7c478bd9Sstevel@tonic-gate clp->minor = cmnp; 1186*7c478bd9Sstevel@tonic-gate } else { 1187*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "resolve_dangling_links: link(%s):" 1188*7c478bd9Sstevel@tonic-gate " unresolved\n", clp->path); 1189*7c478bd9Sstevel@tonic-gate pp = &clp->sib; 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate } 1192*7c478bd9Sstevel@tonic-gate } 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate /* 1196*7c478bd9Sstevel@tonic-gate * The elements are assumed to be detached from the cache tree. 1197*7c478bd9Sstevel@tonic-gate */ 1198*7c478bd9Sstevel@tonic-gate static void 1199*7c478bd9Sstevel@tonic-gate node_free(cache_node_t **pp) 1200*7c478bd9Sstevel@tonic-gate { 1201*7c478bd9Sstevel@tonic-gate cache_node_t *cnp = *pp; 1202*7c478bd9Sstevel@tonic-gate 1203*7c478bd9Sstevel@tonic-gate *pp = NULL; 1204*7c478bd9Sstevel@tonic-gate 1205*7c478bd9Sstevel@tonic-gate if (cnp == NULL) 1206*7c478bd9Sstevel@tonic-gate return; 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate free(cnp->path); 1209*7c478bd9Sstevel@tonic-gate free(cnp); 1210*7c478bd9Sstevel@tonic-gate } 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate static void 1213*7c478bd9Sstevel@tonic-gate minor_free(struct di_devlink_handle *hdp, cache_minor_t **pp) 1214*7c478bd9Sstevel@tonic-gate { 1215*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp = *pp; 1216*7c478bd9Sstevel@tonic-gate 1217*7c478bd9Sstevel@tonic-gate *pp = NULL; 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate if (cmnp == NULL) 1220*7c478bd9Sstevel@tonic-gate return; 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate if (CACHE_LAST(hdp) == cmnp) { 1223*7c478bd9Sstevel@tonic-gate dprintf(DBG_STEP, "minor_free: last_minor(%s)\n", cmnp->name); 1224*7c478bd9Sstevel@tonic-gate CACHE_LAST(hdp) = NULL; 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate free(cmnp->name); 1228*7c478bd9Sstevel@tonic-gate free(cmnp->nodetype); 1229*7c478bd9Sstevel@tonic-gate free(cmnp); 1230*7c478bd9Sstevel@tonic-gate } 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate static void 1233*7c478bd9Sstevel@tonic-gate link_free(cache_link_t **pp) 1234*7c478bd9Sstevel@tonic-gate { 1235*7c478bd9Sstevel@tonic-gate cache_link_t *clp = *pp; 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate *pp = NULL; 1238*7c478bd9Sstevel@tonic-gate 1239*7c478bd9Sstevel@tonic-gate if (clp == NULL) 1240*7c478bd9Sstevel@tonic-gate return; 1241*7c478bd9Sstevel@tonic-gate 1242*7c478bd9Sstevel@tonic-gate free(clp->path); 1243*7c478bd9Sstevel@tonic-gate free(clp->content); 1244*7c478bd9Sstevel@tonic-gate free(clp); 1245*7c478bd9Sstevel@tonic-gate } 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate /* 1248*7c478bd9Sstevel@tonic-gate * Returns the ':' preceding the minor name 1249*7c478bd9Sstevel@tonic-gate */ 1250*7c478bd9Sstevel@tonic-gate static char * 1251*7c478bd9Sstevel@tonic-gate minor_colon(const char *path) 1252*7c478bd9Sstevel@tonic-gate { 1253*7c478bd9Sstevel@tonic-gate char *cp; 1254*7c478bd9Sstevel@tonic-gate 1255*7c478bd9Sstevel@tonic-gate if ((cp = strrchr(path, '/')) == NULL) { 1256*7c478bd9Sstevel@tonic-gate return (NULL); 1257*7c478bd9Sstevel@tonic-gate } 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate return (strchr(cp, ':')); 1260*7c478bd9Sstevel@tonic-gate } 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate static void * 1263*7c478bd9Sstevel@tonic-gate lookup_minor( 1264*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 1265*7c478bd9Sstevel@tonic-gate const char *minor_path, 1266*7c478bd9Sstevel@tonic-gate const char *nodetype, 1267*7c478bd9Sstevel@tonic-gate const int flags) 1268*7c478bd9Sstevel@tonic-gate { 1269*7c478bd9Sstevel@tonic-gate void *vp; 1270*7c478bd9Sstevel@tonic-gate char *colon; 1271*7c478bd9Sstevel@tonic-gate char pdup[PATH_MAX]; 1272*7c478bd9Sstevel@tonic-gate const char *fcn = "lookup_minor"; 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate if (minor_path == NULL) { 1275*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1276*7c478bd9Sstevel@tonic-gate return (NULL); 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate (void) snprintf(pdup, sizeof (pdup), "%s", minor_path); 1280*7c478bd9Sstevel@tonic-gate 1281*7c478bd9Sstevel@tonic-gate if ((colon = minor_colon(pdup)) == NULL) { 1282*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid minor path(%s)\n", fcn, 1283*7c478bd9Sstevel@tonic-gate minor_path); 1284*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1285*7c478bd9Sstevel@tonic-gate return (NULL); 1286*7c478bd9Sstevel@tonic-gate } 1287*7c478bd9Sstevel@tonic-gate *colon = '\0'; 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate if ((vp = get_last_minor(hdp, pdup, colon + 1, flags)) != NULL) { 1290*7c478bd9Sstevel@tonic-gate return (vp); 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate if ((vp = lookup_node(hdp, pdup, flags)) == NULL) { 1294*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: node(%s) not found\n", fcn, pdup); 1295*7c478bd9Sstevel@tonic-gate return (NULL); 1296*7c478bd9Sstevel@tonic-gate } 1297*7c478bd9Sstevel@tonic-gate *colon = ':'; 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate if (LOOKUP_CACHE(flags)) { 1300*7c478bd9Sstevel@tonic-gate cache_minor_t **pp; 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate pp = &((cache_node_t *)vp)->minor; 1303*7c478bd9Sstevel@tonic-gate for (; *pp != NULL; pp = &(*pp)->sib) { 1304*7c478bd9Sstevel@tonic-gate if (strcmp((*pp)->name, colon + 1) == 0) 1305*7c478bd9Sstevel@tonic-gate break; 1306*7c478bd9Sstevel@tonic-gate } 1307*7c478bd9Sstevel@tonic-gate 1308*7c478bd9Sstevel@tonic-gate if (*pp == NULL && CREATE_ELEM(flags)) { 1309*7c478bd9Sstevel@tonic-gate *pp = minor_insert(hdp, vp, colon + 1, nodetype, pp); 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate set_last_minor(hdp, *pp, flags); 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate return (*pp); 1314*7c478bd9Sstevel@tonic-gate } else { 1315*7c478bd9Sstevel@tonic-gate char *cp; 1316*7c478bd9Sstevel@tonic-gate uint32_t nidx; 1317*7c478bd9Sstevel@tonic-gate struct db_minor *dmp; 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate nidx = (((struct db_node *)vp)->minor); 1320*7c478bd9Sstevel@tonic-gate for (; dmp = get_minor(hdp, nidx); nidx = dmp->sib) { 1321*7c478bd9Sstevel@tonic-gate cp = get_string(hdp, dmp->name); 1322*7c478bd9Sstevel@tonic-gate if (cp && strcmp(cp, colon + 1) == 0) 1323*7c478bd9Sstevel@tonic-gate break; 1324*7c478bd9Sstevel@tonic-gate } 1325*7c478bd9Sstevel@tonic-gate return (dmp); 1326*7c478bd9Sstevel@tonic-gate } 1327*7c478bd9Sstevel@tonic-gate } 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate static void * 1330*7c478bd9Sstevel@tonic-gate lookup_node(struct di_devlink_handle *hdp, char *path, const int flags) 1331*7c478bd9Sstevel@tonic-gate { 1332*7c478bd9Sstevel@tonic-gate struct tnode tnd = {NULL}; 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate if (tnd.node = get_last_node(hdp, path, flags)) 1335*7c478bd9Sstevel@tonic-gate return (tnd.node); 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate tnd.handle = hdp; 1338*7c478bd9Sstevel@tonic-gate tnd.flags = flags; 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate if (walk_tree(path, &tnd, visit_node) != 0) 1341*7c478bd9Sstevel@tonic-gate return (NULL); 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate return (tnd.node); 1344*7c478bd9Sstevel@tonic-gate } 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate /* 1347*7c478bd9Sstevel@tonic-gate * last_minor is used for nodes of TYPE_CACHE only. 1348*7c478bd9Sstevel@tonic-gate */ 1349*7c478bd9Sstevel@tonic-gate static void * 1350*7c478bd9Sstevel@tonic-gate get_last_node(struct di_devlink_handle *hdp, const char *path, int flags) 1351*7c478bd9Sstevel@tonic-gate { 1352*7c478bd9Sstevel@tonic-gate cache_node_t *cnp; 1353*7c478bd9Sstevel@tonic-gate 1354*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1355*7c478bd9Sstevel@tonic-gate if (getenv(SKIP_LAST_CACHE)) { 1356*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "get_last_node: SKIPPING \"last\" " 1357*7c478bd9Sstevel@tonic-gate "node cache\n"); 1358*7c478bd9Sstevel@tonic-gate return (NULL); 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate #endif 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate if (!LOOKUP_CACHE(flags) || CACHE_LAST(hdp) == NULL || 1363*7c478bd9Sstevel@tonic-gate CACHE_LAST(hdp)->node == NULL) { 1364*7c478bd9Sstevel@tonic-gate return (NULL); 1365*7c478bd9Sstevel@tonic-gate } 1366*7c478bd9Sstevel@tonic-gate 1367*7c478bd9Sstevel@tonic-gate cnp = CACHE_LAST(hdp)->node; 1368*7c478bd9Sstevel@tonic-gate if (strcmp(cnp->path, path) == 0) { 1369*7c478bd9Sstevel@tonic-gate return (cnp); 1370*7c478bd9Sstevel@tonic-gate } 1371*7c478bd9Sstevel@tonic-gate 1372*7c478bd9Sstevel@tonic-gate cnp = cnp->sib; 1373*7c478bd9Sstevel@tonic-gate if (cnp && strcmp(cnp->path, path) == 0) { 1374*7c478bd9Sstevel@tonic-gate return (cnp); 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate return (NULL); 1378*7c478bd9Sstevel@tonic-gate } 1379*7c478bd9Sstevel@tonic-gate 1380*7c478bd9Sstevel@tonic-gate static void * 1381*7c478bd9Sstevel@tonic-gate get_last_minor( 1382*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 1383*7c478bd9Sstevel@tonic-gate const char *devfs_path, 1384*7c478bd9Sstevel@tonic-gate const char *minor_name, 1385*7c478bd9Sstevel@tonic-gate int flags) 1386*7c478bd9Sstevel@tonic-gate { 1387*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1390*7c478bd9Sstevel@tonic-gate if (getenv(SKIP_LAST_CACHE)) { 1391*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "get_last_minor: SKIPPING \"last\" " 1392*7c478bd9Sstevel@tonic-gate "minor cache\n"); 1393*7c478bd9Sstevel@tonic-gate return (NULL); 1394*7c478bd9Sstevel@tonic-gate } 1395*7c478bd9Sstevel@tonic-gate #endif 1396*7c478bd9Sstevel@tonic-gate 1397*7c478bd9Sstevel@tonic-gate if (!LOOKUP_CACHE(flags) || CACHE_LAST(hdp) == NULL) { 1398*7c478bd9Sstevel@tonic-gate return (NULL); 1399*7c478bd9Sstevel@tonic-gate } 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate cmnp = CACHE_LAST(hdp); 1402*7c478bd9Sstevel@tonic-gate if (strcmp(cmnp->name, minor_name) == 0 && cmnp->node && 1403*7c478bd9Sstevel@tonic-gate strcmp(cmnp->node->path, devfs_path) == 0) { 1404*7c478bd9Sstevel@tonic-gate return (cmnp); 1405*7c478bd9Sstevel@tonic-gate } 1406*7c478bd9Sstevel@tonic-gate 1407*7c478bd9Sstevel@tonic-gate cmnp = cmnp->sib; 1408*7c478bd9Sstevel@tonic-gate if (cmnp && strcmp(cmnp->name, minor_name) == 0 && cmnp->node && 1409*7c478bd9Sstevel@tonic-gate strcmp(cmnp->node->path, devfs_path) == 0) { 1410*7c478bd9Sstevel@tonic-gate set_last_minor(hdp, cmnp, TYPE_CACHE); 1411*7c478bd9Sstevel@tonic-gate return (cmnp); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate return (NULL); 1415*7c478bd9Sstevel@tonic-gate } 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate static void 1418*7c478bd9Sstevel@tonic-gate set_last_minor(struct di_devlink_handle *hdp, cache_minor_t *cmnp, int flags) 1419*7c478bd9Sstevel@tonic-gate { 1420*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1421*7c478bd9Sstevel@tonic-gate if (getenv(SKIP_LAST_CACHE)) { 1422*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "set_last_minor: SKIPPING \"last\" " 1423*7c478bd9Sstevel@tonic-gate "minor cache\n"); 1424*7c478bd9Sstevel@tonic-gate return; 1425*7c478bd9Sstevel@tonic-gate } 1426*7c478bd9Sstevel@tonic-gate #endif 1427*7c478bd9Sstevel@tonic-gate 1428*7c478bd9Sstevel@tonic-gate if (LOOKUP_CACHE(flags) && cmnp) { 1429*7c478bd9Sstevel@tonic-gate CACHE_LAST(hdp) = cmnp; 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate } 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate 1434*7c478bd9Sstevel@tonic-gate /* 1435*7c478bd9Sstevel@tonic-gate * Returns 0 if normal return or -1 otherwise. 1436*7c478bd9Sstevel@tonic-gate */ 1437*7c478bd9Sstevel@tonic-gate static int 1438*7c478bd9Sstevel@tonic-gate walk_tree( 1439*7c478bd9Sstevel@tonic-gate char *cur, 1440*7c478bd9Sstevel@tonic-gate void *arg, 1441*7c478bd9Sstevel@tonic-gate int (*node_callback)(const char *path, void *arg)) 1442*7c478bd9Sstevel@tonic-gate { 1443*7c478bd9Sstevel@tonic-gate char *slash, buf[PATH_MAX]; 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate if (cur == NULL || cur[0] != '/' || strlen(cur) > sizeof (buf) - 1) { 1446*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1447*7c478bd9Sstevel@tonic-gate return (-1); 1448*7c478bd9Sstevel@tonic-gate } 1449*7c478bd9Sstevel@tonic-gate 1450*7c478bd9Sstevel@tonic-gate (void) strcpy(buf, "/"); 1451*7c478bd9Sstevel@tonic-gate 1452*7c478bd9Sstevel@tonic-gate for (;;) { 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate if (node_callback(buf, arg) != DI_WALK_CONTINUE) 1455*7c478bd9Sstevel@tonic-gate break; 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate while (*cur == '/') 1458*7c478bd9Sstevel@tonic-gate cur++; 1459*7c478bd9Sstevel@tonic-gate 1460*7c478bd9Sstevel@tonic-gate if (*cur == '\0') 1461*7c478bd9Sstevel@tonic-gate break; 1462*7c478bd9Sstevel@tonic-gate 1463*7c478bd9Sstevel@tonic-gate /* 1464*7c478bd9Sstevel@tonic-gate * There is a next component(s). Append a "/" separator for all 1465*7c478bd9Sstevel@tonic-gate * but the first (root) component. 1466*7c478bd9Sstevel@tonic-gate */ 1467*7c478bd9Sstevel@tonic-gate if (buf[1] != '\0') { 1468*7c478bd9Sstevel@tonic-gate (void) strlcat(buf, "/", sizeof (buf)); 1469*7c478bd9Sstevel@tonic-gate } 1470*7c478bd9Sstevel@tonic-gate 1471*7c478bd9Sstevel@tonic-gate if (slash = strchr(cur, '/')) { 1472*7c478bd9Sstevel@tonic-gate *slash = '\0'; 1473*7c478bd9Sstevel@tonic-gate (void) strlcat(buf, cur, sizeof (buf)); 1474*7c478bd9Sstevel@tonic-gate *slash = '/'; 1475*7c478bd9Sstevel@tonic-gate cur = slash; 1476*7c478bd9Sstevel@tonic-gate } else { 1477*7c478bd9Sstevel@tonic-gate (void) strlcat(buf, cur, sizeof (buf)); 1478*7c478bd9Sstevel@tonic-gate cur += strlen(cur); 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate } 1482*7c478bd9Sstevel@tonic-gate 1483*7c478bd9Sstevel@tonic-gate return (0); 1484*7c478bd9Sstevel@tonic-gate } 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate 1487*7c478bd9Sstevel@tonic-gate static int 1488*7c478bd9Sstevel@tonic-gate visit_node(const char *path, void *arg) 1489*7c478bd9Sstevel@tonic-gate { 1490*7c478bd9Sstevel@tonic-gate struct tnode *tnp = arg; 1491*7c478bd9Sstevel@tonic-gate 1492*7c478bd9Sstevel@tonic-gate if (LOOKUP_CACHE(tnp->flags)) { 1493*7c478bd9Sstevel@tonic-gate 1494*7c478bd9Sstevel@tonic-gate cache_node_t *cnp = tnp->node; 1495*7c478bd9Sstevel@tonic-gate 1496*7c478bd9Sstevel@tonic-gate cnp = (cnp) ? cnp->child : CACHE_ROOT(tnp->handle); 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate for (; cnp != NULL; cnp = cnp->sib) { 1499*7c478bd9Sstevel@tonic-gate if (strcmp(cnp->path, path) == 0) 1500*7c478bd9Sstevel@tonic-gate break; 1501*7c478bd9Sstevel@tonic-gate } 1502*7c478bd9Sstevel@tonic-gate if (cnp == NULL && CREATE_ELEM(tnp->flags)) { 1503*7c478bd9Sstevel@tonic-gate cnp = node_insert(tnp->handle, tnp->node, path, 1504*7c478bd9Sstevel@tonic-gate INSERT_TAIL); 1505*7c478bd9Sstevel@tonic-gate } 1506*7c478bd9Sstevel@tonic-gate tnp->node = cnp; 1507*7c478bd9Sstevel@tonic-gate } else { 1508*7c478bd9Sstevel@tonic-gate char *cp; 1509*7c478bd9Sstevel@tonic-gate struct db_node *dnp = tnp->node; 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate dnp = (dnp) ? get_node(tnp->handle, dnp->child) 1512*7c478bd9Sstevel@tonic-gate : get_node(tnp->handle, DB_HDR(tnp->handle)->root_idx); 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate for (; dnp != NULL; dnp = get_node(tnp->handle, dnp->sib)) { 1515*7c478bd9Sstevel@tonic-gate cp = get_string(tnp->handle, dnp->path); 1516*7c478bd9Sstevel@tonic-gate if (cp && strcmp(cp, path) == 0) { 1517*7c478bd9Sstevel@tonic-gate break; 1518*7c478bd9Sstevel@tonic-gate } 1519*7c478bd9Sstevel@tonic-gate } 1520*7c478bd9Sstevel@tonic-gate tnp->node = dnp; 1521*7c478bd9Sstevel@tonic-gate } 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate /* 1524*7c478bd9Sstevel@tonic-gate * Terminate walk if node is not found for a path component. 1525*7c478bd9Sstevel@tonic-gate */ 1526*7c478bd9Sstevel@tonic-gate return (tnp->node ? DI_WALK_CONTINUE : DI_WALK_TERMINATE); 1527*7c478bd9Sstevel@tonic-gate } 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate static void 1530*7c478bd9Sstevel@tonic-gate minor_delete(di_devlink_handle_t hdp, cache_minor_t *cmnp) 1531*7c478bd9Sstevel@tonic-gate { 1532*7c478bd9Sstevel@tonic-gate cache_link_t **lpp; 1533*7c478bd9Sstevel@tonic-gate cache_minor_t **mpp; 1534*7c478bd9Sstevel@tonic-gate const char *fcn = "minor_delete"; 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: removing minor: %s\n", fcn, cmnp->name); 1537*7c478bd9Sstevel@tonic-gate 1538*7c478bd9Sstevel@tonic-gate /* detach minor from node */ 1539*7c478bd9Sstevel@tonic-gate if (cmnp->node != NULL) { 1540*7c478bd9Sstevel@tonic-gate mpp = &cmnp->node->minor; 1541*7c478bd9Sstevel@tonic-gate for (; *mpp != NULL; mpp = &(*mpp)->sib) { 1542*7c478bd9Sstevel@tonic-gate if (*mpp == cmnp) 1543*7c478bd9Sstevel@tonic-gate break; 1544*7c478bd9Sstevel@tonic-gate } 1545*7c478bd9Sstevel@tonic-gate 1546*7c478bd9Sstevel@tonic-gate if (*mpp == NULL) { 1547*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: dangling minor: %s\n", 1548*7c478bd9Sstevel@tonic-gate fcn, cmnp->name); 1549*7c478bd9Sstevel@tonic-gate } else { 1550*7c478bd9Sstevel@tonic-gate *mpp = cmnp->sib; 1551*7c478bd9Sstevel@tonic-gate } 1552*7c478bd9Sstevel@tonic-gate } else { 1553*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: orphan minor(%s)\n", fcn, 1554*7c478bd9Sstevel@tonic-gate cmnp->name); 1555*7c478bd9Sstevel@tonic-gate } 1556*7c478bd9Sstevel@tonic-gate 1557*7c478bd9Sstevel@tonic-gate delete_unused_nodes(hdp, cmnp->node); 1558*7c478bd9Sstevel@tonic-gate 1559*7c478bd9Sstevel@tonic-gate cmnp->node = NULL; 1560*7c478bd9Sstevel@tonic-gate cmnp->sib = NULL; 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate /* Move all remaining links to dangling list */ 1563*7c478bd9Sstevel@tonic-gate for (lpp = &cmnp->link; *lpp != NULL; lpp = &(*lpp)->sib) { 1564*7c478bd9Sstevel@tonic-gate (*lpp)->minor = NULL; 1565*7c478bd9Sstevel@tonic-gate } 1566*7c478bd9Sstevel@tonic-gate *lpp = CACHE(hdp)->dngl; 1567*7c478bd9Sstevel@tonic-gate CACHE(hdp)->dngl = cmnp->link; 1568*7c478bd9Sstevel@tonic-gate cmnp->link = NULL; 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate minor_free(hdp, &cmnp); 1571*7c478bd9Sstevel@tonic-gate } 1572*7c478bd9Sstevel@tonic-gate 1573*7c478bd9Sstevel@tonic-gate static void 1574*7c478bd9Sstevel@tonic-gate delete_unused_nodes(di_devlink_handle_t hdp, cache_node_t *cnp) 1575*7c478bd9Sstevel@tonic-gate { 1576*7c478bd9Sstevel@tonic-gate cache_node_t **npp; 1577*7c478bd9Sstevel@tonic-gate const char *fcn = "delete_unused_nodes"; 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate if (cnp == NULL) 1580*7c478bd9Sstevel@tonic-gate return; 1581*7c478bd9Sstevel@tonic-gate 1582*7c478bd9Sstevel@tonic-gate if (cnp->minor != NULL || cnp->child != NULL) 1583*7c478bd9Sstevel@tonic-gate return; 1584*7c478bd9Sstevel@tonic-gate 1585*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "%s: removing unused node: %s\n", fcn, 1586*7c478bd9Sstevel@tonic-gate cnp->path); 1587*7c478bd9Sstevel@tonic-gate 1588*7c478bd9Sstevel@tonic-gate /* Unlink node from tree */ 1589*7c478bd9Sstevel@tonic-gate if (cnp->parent != NULL) { 1590*7c478bd9Sstevel@tonic-gate npp = &cnp->parent->child; 1591*7c478bd9Sstevel@tonic-gate for (; *npp != NULL; npp = &(*npp)->sib) { 1592*7c478bd9Sstevel@tonic-gate if (*npp == cnp) 1593*7c478bd9Sstevel@tonic-gate break; 1594*7c478bd9Sstevel@tonic-gate } 1595*7c478bd9Sstevel@tonic-gate 1596*7c478bd9Sstevel@tonic-gate if (*npp == NULL) { 1597*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: dangling node: %s\n", fcn, 1598*7c478bd9Sstevel@tonic-gate cnp->path); 1599*7c478bd9Sstevel@tonic-gate } else { 1600*7c478bd9Sstevel@tonic-gate *npp = cnp->sib; 1601*7c478bd9Sstevel@tonic-gate } 1602*7c478bd9Sstevel@tonic-gate } else if (cnp == CACHE_ROOT(hdp)) { 1603*7c478bd9Sstevel@tonic-gate CACHE_ROOT(hdp) = NULL; 1604*7c478bd9Sstevel@tonic-gate } else { 1605*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: orphan node (%s)\n", fcn, 1606*7c478bd9Sstevel@tonic-gate cnp->path); 1607*7c478bd9Sstevel@tonic-gate } 1608*7c478bd9Sstevel@tonic-gate 1609*7c478bd9Sstevel@tonic-gate delete_unused_nodes(hdp, cnp->parent); 1610*7c478bd9Sstevel@tonic-gate 1611*7c478bd9Sstevel@tonic-gate cnp->parent = cnp->sib = NULL; 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate node_free(&cnp); 1614*7c478bd9Sstevel@tonic-gate } 1615*7c478bd9Sstevel@tonic-gate 1616*7c478bd9Sstevel@tonic-gate static int 1617*7c478bd9Sstevel@tonic-gate rm_link(di_devlink_handle_t hdp, const char *link) 1618*7c478bd9Sstevel@tonic-gate { 1619*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 1620*7c478bd9Sstevel@tonic-gate const char *fcn = "rm_link"; 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate if (hdp == NULL || DB_ERR(hdp) || link == NULL || link[0] == '/' || 1623*7c478bd9Sstevel@tonic-gate (!HDL_RDWR(hdp) && !HDL_RDONLY(hdp))) { 1624*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "%s: %s: invalid args\n", 1625*7c478bd9Sstevel@tonic-gate fcn, link ? link : "<NULL>"); 1626*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1627*7c478bd9Sstevel@tonic-gate return (-1); 1628*7c478bd9Sstevel@tonic-gate } 1629*7c478bd9Sstevel@tonic-gate 1630*7c478bd9Sstevel@tonic-gate dprintf(DBG_STEP, "%s: link(%s)\n", fcn, link); 1631*7c478bd9Sstevel@tonic-gate 1632*7c478bd9Sstevel@tonic-gate if ((clp = link_hash(hdp, link, UNLINK_FROM_HASH)) == NULL) { 1633*7c478bd9Sstevel@tonic-gate return (0); 1634*7c478bd9Sstevel@tonic-gate } 1635*7c478bd9Sstevel@tonic-gate 1636*7c478bd9Sstevel@tonic-gate link_delete(hdp, clp); 1637*7c478bd9Sstevel@tonic-gate 1638*7c478bd9Sstevel@tonic-gate return (0); 1639*7c478bd9Sstevel@tonic-gate } 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate int 1642*7c478bd9Sstevel@tonic-gate di_devlink_rm_link(di_devlink_handle_t hdp, const char *link) 1643*7c478bd9Sstevel@tonic-gate { 1644*7c478bd9Sstevel@tonic-gate if (hdp == NULL || !HDL_RDWR(hdp)) { 1645*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1646*7c478bd9Sstevel@tonic-gate return (-1); 1647*7c478bd9Sstevel@tonic-gate } 1648*7c478bd9Sstevel@tonic-gate 1649*7c478bd9Sstevel@tonic-gate return (rm_link(hdp, link)); 1650*7c478bd9Sstevel@tonic-gate } 1651*7c478bd9Sstevel@tonic-gate 1652*7c478bd9Sstevel@tonic-gate static void 1653*7c478bd9Sstevel@tonic-gate link_delete(di_devlink_handle_t hdp, cache_link_t *clp) 1654*7c478bd9Sstevel@tonic-gate { 1655*7c478bd9Sstevel@tonic-gate cache_link_t **pp; 1656*7c478bd9Sstevel@tonic-gate const char *fcn = "link_delete"; 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: removing link: %s\n", fcn, clp->path); 1659*7c478bd9Sstevel@tonic-gate 1660*7c478bd9Sstevel@tonic-gate if (clp->minor == NULL) 1661*7c478bd9Sstevel@tonic-gate pp = &(CACHE(hdp)->dngl); 1662*7c478bd9Sstevel@tonic-gate else 1663*7c478bd9Sstevel@tonic-gate pp = &clp->minor->link; 1664*7c478bd9Sstevel@tonic-gate 1665*7c478bd9Sstevel@tonic-gate for (; *pp != NULL; pp = &(*pp)->sib) { 1666*7c478bd9Sstevel@tonic-gate if (*pp == clp) 1667*7c478bd9Sstevel@tonic-gate break; 1668*7c478bd9Sstevel@tonic-gate } 1669*7c478bd9Sstevel@tonic-gate 1670*7c478bd9Sstevel@tonic-gate if (*pp == NULL) { 1671*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: link(%s) not on list\n", 1672*7c478bd9Sstevel@tonic-gate fcn, clp->path); 1673*7c478bd9Sstevel@tonic-gate } else { 1674*7c478bd9Sstevel@tonic-gate *pp = clp->sib; 1675*7c478bd9Sstevel@tonic-gate } 1676*7c478bd9Sstevel@tonic-gate 1677*7c478bd9Sstevel@tonic-gate delete_unused_minor(hdp, clp->minor); 1678*7c478bd9Sstevel@tonic-gate 1679*7c478bd9Sstevel@tonic-gate clp->minor = NULL; 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate link_free(&clp); 1682*7c478bd9Sstevel@tonic-gate } 1683*7c478bd9Sstevel@tonic-gate 1684*7c478bd9Sstevel@tonic-gate static void 1685*7c478bd9Sstevel@tonic-gate delete_unused_minor(di_devlink_handle_t hdp, cache_minor_t *cmnp) 1686*7c478bd9Sstevel@tonic-gate { 1687*7c478bd9Sstevel@tonic-gate if (cmnp == NULL) 1688*7c478bd9Sstevel@tonic-gate return; 1689*7c478bd9Sstevel@tonic-gate 1690*7c478bd9Sstevel@tonic-gate if (cmnp->link != NULL) 1691*7c478bd9Sstevel@tonic-gate return; 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate dprintf(DBG_STEP, "delete_unused_minor: removing minor(%s)\n", 1694*7c478bd9Sstevel@tonic-gate cmnp->name); 1695*7c478bd9Sstevel@tonic-gate 1696*7c478bd9Sstevel@tonic-gate minor_delete(hdp, cmnp); 1697*7c478bd9Sstevel@tonic-gate } 1698*7c478bd9Sstevel@tonic-gate 1699*7c478bd9Sstevel@tonic-gate int 1700*7c478bd9Sstevel@tonic-gate di_devlink_add_link( 1701*7c478bd9Sstevel@tonic-gate di_devlink_handle_t hdp, 1702*7c478bd9Sstevel@tonic-gate const char *link, 1703*7c478bd9Sstevel@tonic-gate const char *content, 1704*7c478bd9Sstevel@tonic-gate int flags) 1705*7c478bd9Sstevel@tonic-gate { 1706*7c478bd9Sstevel@tonic-gate return (add_link(hdp, link, content, flags) != NULL ? 0 : -1); 1707*7c478bd9Sstevel@tonic-gate } 1708*7c478bd9Sstevel@tonic-gate 1709*7c478bd9Sstevel@tonic-gate static cache_link_t * 1710*7c478bd9Sstevel@tonic-gate add_link( 1711*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 1712*7c478bd9Sstevel@tonic-gate const char *link, 1713*7c478bd9Sstevel@tonic-gate const char *content, 1714*7c478bd9Sstevel@tonic-gate int flags) 1715*7c478bd9Sstevel@tonic-gate { 1716*7c478bd9Sstevel@tonic-gate uint32_t attr; 1717*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 1718*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 1719*7c478bd9Sstevel@tonic-gate const char *fcn = "add_link"; 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate if (hdp == NULL || DB_ERR(hdp) || link == NULL || 1722*7c478bd9Sstevel@tonic-gate link[0] == '/' || content == NULL || !link_flag(flags) || 1723*7c478bd9Sstevel@tonic-gate (!HDL_RDWR(hdp) && !HDL_RDONLY(hdp))) { 1724*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "%s: %s: invalid args\n", 1725*7c478bd9Sstevel@tonic-gate fcn, link ? link : "<NULL>"); 1726*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1727*7c478bd9Sstevel@tonic-gate return (NULL); 1728*7c478bd9Sstevel@tonic-gate } 1729*7c478bd9Sstevel@tonic-gate 1730*7c478bd9Sstevel@tonic-gate if ((clp = link_hash(hdp, link, 0)) != NULL) { 1731*7c478bd9Sstevel@tonic-gate if (link_cmp(clp, content, LINK_TYPE(flags)) != 0) { 1732*7c478bd9Sstevel@tonic-gate (void) rm_link(hdp, link); 1733*7c478bd9Sstevel@tonic-gate } else { 1734*7c478bd9Sstevel@tonic-gate return (clp); 1735*7c478bd9Sstevel@tonic-gate } 1736*7c478bd9Sstevel@tonic-gate } 1737*7c478bd9Sstevel@tonic-gate 1738*7c478bd9Sstevel@tonic-gate if (TYPE_PRI(flags)) { 1739*7c478bd9Sstevel@tonic-gate const char *minor_path = NULL; 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate if (!is_minor_node(content, &minor_path)) { 1742*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid content(%s)" 1743*7c478bd9Sstevel@tonic-gate " for primary link\n", fcn, content); 1744*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1745*7c478bd9Sstevel@tonic-gate return (NULL); 1746*7c478bd9Sstevel@tonic-gate } 1747*7c478bd9Sstevel@tonic-gate if ((cmnp = lookup_minor(hdp, minor_path, NULL, 1748*7c478bd9Sstevel@tonic-gate TYPE_CACHE|CREATE_FLAG)) == NULL) { 1749*7c478bd9Sstevel@tonic-gate return (NULL); 1750*7c478bd9Sstevel@tonic-gate } 1751*7c478bd9Sstevel@tonic-gate attr = A_PRIMARY; 1752*7c478bd9Sstevel@tonic-gate } else { 1753*7c478bd9Sstevel@tonic-gate /* 1754*7c478bd9Sstevel@tonic-gate * Defer resolving a secondary link to a minor until the 1755*7c478bd9Sstevel@tonic-gate * database is closed. This ensures that the primary link 1756*7c478bd9Sstevel@tonic-gate * (required for a successful resolve) has also been created. 1757*7c478bd9Sstevel@tonic-gate */ 1758*7c478bd9Sstevel@tonic-gate cmnp = NULL; 1759*7c478bd9Sstevel@tonic-gate attr = A_SECONDARY; 1760*7c478bd9Sstevel@tonic-gate } 1761*7c478bd9Sstevel@tonic-gate 1762*7c478bd9Sstevel@tonic-gate return (link_insert(hdp, cmnp, link, content, attr)); 1763*7c478bd9Sstevel@tonic-gate } 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate /* 1766*7c478bd9Sstevel@tonic-gate * Returns 0 on match or 1 otherwise. 1767*7c478bd9Sstevel@tonic-gate */ 1768*7c478bd9Sstevel@tonic-gate static int 1769*7c478bd9Sstevel@tonic-gate link_cmp(cache_link_t *clp, const char *content, int type) 1770*7c478bd9Sstevel@tonic-gate { 1771*7c478bd9Sstevel@tonic-gate if (strcmp(clp->content, content) != 0) 1772*7c478bd9Sstevel@tonic-gate return (1); 1773*7c478bd9Sstevel@tonic-gate 1774*7c478bd9Sstevel@tonic-gate if (attr2type(clp->attr) != type) 1775*7c478bd9Sstevel@tonic-gate return (1); 1776*7c478bd9Sstevel@tonic-gate 1777*7c478bd9Sstevel@tonic-gate return (0); 1778*7c478bd9Sstevel@tonic-gate } 1779*7c478bd9Sstevel@tonic-gate 1780*7c478bd9Sstevel@tonic-gate int 1781*7c478bd9Sstevel@tonic-gate di_devlink_update(di_devlink_handle_t hdp) 1782*7c478bd9Sstevel@tonic-gate { 1783*7c478bd9Sstevel@tonic-gate if (hdp == NULL || !HDL_RDWR(hdp) || DB_ERR(hdp)) { 1784*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1785*7c478bd9Sstevel@tonic-gate return (-1); 1786*7c478bd9Sstevel@tonic-gate } 1787*7c478bd9Sstevel@tonic-gate 1788*7c478bd9Sstevel@tonic-gate /* 1789*7c478bd9Sstevel@tonic-gate * Reset the counter to schedule a synchronization with /dev on the next 1790*7c478bd9Sstevel@tonic-gate * di_devlink_close(). 1791*7c478bd9Sstevel@tonic-gate */ 1792*7c478bd9Sstevel@tonic-gate CACHE(hdp)->update_count = 0; 1793*7c478bd9Sstevel@tonic-gate 1794*7c478bd9Sstevel@tonic-gate return (0); 1795*7c478bd9Sstevel@tonic-gate } 1796*7c478bd9Sstevel@tonic-gate 1797*7c478bd9Sstevel@tonic-gate static int 1798*7c478bd9Sstevel@tonic-gate synchronize_db(di_devlink_handle_t hdp) 1799*7c478bd9Sstevel@tonic-gate { 1800*7c478bd9Sstevel@tonic-gate int hval; 1801*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 1802*7c478bd9Sstevel@tonic-gate char pdup[PATH_MAX]; 1803*7c478bd9Sstevel@tonic-gate recurse_t rec = {NULL}; 1804*7c478bd9Sstevel@tonic-gate const char *fcn = "synchronize_db"; 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate rec.data = NULL; 1807*7c478bd9Sstevel@tonic-gate rec.fcn = cache_dev_link; 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate /* 1810*7c478bd9Sstevel@tonic-gate * Walk through $ROOT/dev, reading every link and marking the 1811*7c478bd9Sstevel@tonic-gate * corresponding cached version as valid(adding new links as needed). 1812*7c478bd9Sstevel@tonic-gate * Then walk through the cache and remove all unmarked links. 1813*7c478bd9Sstevel@tonic-gate */ 1814*7c478bd9Sstevel@tonic-gate if (recurse_dev(hdp, &rec) != 0) { 1815*7c478bd9Sstevel@tonic-gate return (-1); 1816*7c478bd9Sstevel@tonic-gate } 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate for (hval = 0; hval < CACHE(hdp)->hash_sz; hval++) { 1819*7c478bd9Sstevel@tonic-gate for (clp = CACHE_HASH(hdp, hval); clp != NULL; ) { 1820*7c478bd9Sstevel@tonic-gate if (GET_VALID_ATTR(clp->attr)) { 1821*7c478bd9Sstevel@tonic-gate CLR_VALID_ATTR(clp->attr); 1822*7c478bd9Sstevel@tonic-gate clp = clp->hash; 1823*7c478bd9Sstevel@tonic-gate continue; 1824*7c478bd9Sstevel@tonic-gate } 1825*7c478bd9Sstevel@tonic-gate 1826*7c478bd9Sstevel@tonic-gate /* 1827*7c478bd9Sstevel@tonic-gate * The link is stale, so remove it. Since the link 1828*7c478bd9Sstevel@tonic-gate * will be destroyed, use a copy of the link path to 1829*7c478bd9Sstevel@tonic-gate * invoke the remove function. 1830*7c478bd9Sstevel@tonic-gate */ 1831*7c478bd9Sstevel@tonic-gate (void) snprintf(pdup, sizeof (pdup), "%s", clp->path); 1832*7c478bd9Sstevel@tonic-gate clp = clp->hash; 1833*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: removing invalid link:" 1834*7c478bd9Sstevel@tonic-gate " %s\n", fcn, pdup); 1835*7c478bd9Sstevel@tonic-gate (void) di_devlink_rm_link(hdp, pdup); 1836*7c478bd9Sstevel@tonic-gate } 1837*7c478bd9Sstevel@tonic-gate } 1838*7c478bd9Sstevel@tonic-gate 1839*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: update completed\n", fcn); 1840*7c478bd9Sstevel@tonic-gate 1841*7c478bd9Sstevel@tonic-gate return (0); 1842*7c478bd9Sstevel@tonic-gate } 1843*7c478bd9Sstevel@tonic-gate 1844*7c478bd9Sstevel@tonic-gate static di_devlink_handle_t 1845*7c478bd9Sstevel@tonic-gate di_devlink_init_impl(const char *root, const char *name, uint_t flags) 1846*7c478bd9Sstevel@tonic-gate { 1847*7c478bd9Sstevel@tonic-gate int err = 0; 1848*7c478bd9Sstevel@tonic-gate 1849*7c478bd9Sstevel@tonic-gate if ((flags != 0 && flags != DI_MAKE_LINK) || 1850*7c478bd9Sstevel@tonic-gate (flags == 0 && name != NULL)) { 1851*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1852*7c478bd9Sstevel@tonic-gate return (NULL); 1853*7c478bd9Sstevel@tonic-gate } 1854*7c478bd9Sstevel@tonic-gate 1855*7c478bd9Sstevel@tonic-gate if (flags == DI_MAKE_LINK && (err = devlink_create(root, name))) { 1856*7c478bd9Sstevel@tonic-gate errno = err; 1857*7c478bd9Sstevel@tonic-gate return (NULL); 1858*7c478bd9Sstevel@tonic-gate } 1859*7c478bd9Sstevel@tonic-gate 1860*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "devlink_init_impl: success\n"); 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate return (devlink_snapshot(root)); 1863*7c478bd9Sstevel@tonic-gate } 1864*7c478bd9Sstevel@tonic-gate 1865*7c478bd9Sstevel@tonic-gate di_devlink_handle_t 1866*7c478bd9Sstevel@tonic-gate di_devlink_init(const char *name, uint_t flags) 1867*7c478bd9Sstevel@tonic-gate { 1868*7c478bd9Sstevel@tonic-gate return (di_devlink_init_impl("/", name, flags)); 1869*7c478bd9Sstevel@tonic-gate } 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate di_devlink_handle_t 1872*7c478bd9Sstevel@tonic-gate di_devlink_init_root(const char *root, const char *name, uint_t flags) 1873*7c478bd9Sstevel@tonic-gate { 1874*7c478bd9Sstevel@tonic-gate return (di_devlink_init_impl(root, name, flags)); 1875*7c478bd9Sstevel@tonic-gate } 1876*7c478bd9Sstevel@tonic-gate 1877*7c478bd9Sstevel@tonic-gate static di_devlink_handle_t 1878*7c478bd9Sstevel@tonic-gate devlink_snapshot(const char *root_dir) 1879*7c478bd9Sstevel@tonic-gate { 1880*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp; 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate if ((hdp = handle_alloc(root_dir, OPEN_RDONLY)) == NULL) { 1883*7c478bd9Sstevel@tonic-gate return (NULL); 1884*7c478bd9Sstevel@tonic-gate } 1885*7c478bd9Sstevel@tonic-gate 1886*7c478bd9Sstevel@tonic-gate /* 1887*7c478bd9Sstevel@tonic-gate * If we cannot open the DB below, we will walk /dev 1888*7c478bd9Sstevel@tonic-gate * in di_devlink_walk. 1889*7c478bd9Sstevel@tonic-gate */ 1890*7c478bd9Sstevel@tonic-gate (void) open_db(hdp, OPEN_RDONLY); 1891*7c478bd9Sstevel@tonic-gate 1892*7c478bd9Sstevel@tonic-gate return (hdp); 1893*7c478bd9Sstevel@tonic-gate } 1894*7c478bd9Sstevel@tonic-gate 1895*7c478bd9Sstevel@tonic-gate int 1896*7c478bd9Sstevel@tonic-gate di_devlink_fini(di_devlink_handle_t *pp) 1897*7c478bd9Sstevel@tonic-gate { 1898*7c478bd9Sstevel@tonic-gate if (pp == NULL || *pp == NULL || !HDL_RDONLY(*pp)) { 1899*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1900*7c478bd9Sstevel@tonic-gate return (-1); 1901*7c478bd9Sstevel@tonic-gate } 1902*7c478bd9Sstevel@tonic-gate 1903*7c478bd9Sstevel@tonic-gate /* Freeing the handle also closes the DB */ 1904*7c478bd9Sstevel@tonic-gate handle_free(pp); 1905*7c478bd9Sstevel@tonic-gate 1906*7c478bd9Sstevel@tonic-gate return (0); 1907*7c478bd9Sstevel@tonic-gate } 1908*7c478bd9Sstevel@tonic-gate 1909*7c478bd9Sstevel@tonic-gate int 1910*7c478bd9Sstevel@tonic-gate di_devlink_walk( 1911*7c478bd9Sstevel@tonic-gate di_devlink_handle_t hdp, 1912*7c478bd9Sstevel@tonic-gate const char *re, 1913*7c478bd9Sstevel@tonic-gate const char *minor_path, 1914*7c478bd9Sstevel@tonic-gate uint_t flags, 1915*7c478bd9Sstevel@tonic-gate void *arg, 1916*7c478bd9Sstevel@tonic-gate int (*devlink_callback)(di_devlink_t, void *)) 1917*7c478bd9Sstevel@tonic-gate { 1918*7c478bd9Sstevel@tonic-gate int rv; 1919*7c478bd9Sstevel@tonic-gate regex_t reg; 1920*7c478bd9Sstevel@tonic-gate link_desc_t linkd = {NULL}; 1921*7c478bd9Sstevel@tonic-gate 1922*7c478bd9Sstevel@tonic-gate if (hdp == NULL || !HDL_RDONLY(hdp)) { 1923*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1924*7c478bd9Sstevel@tonic-gate return (-1); 1925*7c478bd9Sstevel@tonic-gate } 1926*7c478bd9Sstevel@tonic-gate 1927*7c478bd9Sstevel@tonic-gate linkd.minor_path = minor_path; 1928*7c478bd9Sstevel@tonic-gate linkd.flags = flags; 1929*7c478bd9Sstevel@tonic-gate linkd.arg = arg; 1930*7c478bd9Sstevel@tonic-gate linkd.fcn = devlink_callback; 1931*7c478bd9Sstevel@tonic-gate 1932*7c478bd9Sstevel@tonic-gate if (re) { 1933*7c478bd9Sstevel@tonic-gate if (regcomp(®, re, REG_EXTENDED) != 0) 1934*7c478bd9Sstevel@tonic-gate return (-1); 1935*7c478bd9Sstevel@tonic-gate linkd.regp = ® 1936*7c478bd9Sstevel@tonic-gate } 1937*7c478bd9Sstevel@tonic-gate 1938*7c478bd9Sstevel@tonic-gate if (check_args(&linkd)) { 1939*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1940*7c478bd9Sstevel@tonic-gate rv = -1; 1941*7c478bd9Sstevel@tonic-gate goto out; 1942*7c478bd9Sstevel@tonic-gate } 1943*7c478bd9Sstevel@tonic-gate 1944*7c478bd9Sstevel@tonic-gate if (DB_OPEN(hdp)) { 1945*7c478bd9Sstevel@tonic-gate rv = walk_db(hdp, &linkd); 1946*7c478bd9Sstevel@tonic-gate } else { 1947*7c478bd9Sstevel@tonic-gate rv = walk_dev(hdp, &linkd); 1948*7c478bd9Sstevel@tonic-gate } 1949*7c478bd9Sstevel@tonic-gate 1950*7c478bd9Sstevel@tonic-gate out: 1951*7c478bd9Sstevel@tonic-gate if (re) { 1952*7c478bd9Sstevel@tonic-gate regfree(®); 1953*7c478bd9Sstevel@tonic-gate } 1954*7c478bd9Sstevel@tonic-gate 1955*7c478bd9Sstevel@tonic-gate return (rv ? -1 : 0); 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate static int 1959*7c478bd9Sstevel@tonic-gate link_flag(uint_t flags) 1960*7c478bd9Sstevel@tonic-gate { 1961*7c478bd9Sstevel@tonic-gate if (flags != 0 && flags != DI_PRIMARY_LINK && 1962*7c478bd9Sstevel@tonic-gate flags != DI_SECONDARY_LINK) { 1963*7c478bd9Sstevel@tonic-gate return (0); 1964*7c478bd9Sstevel@tonic-gate } 1965*7c478bd9Sstevel@tonic-gate 1966*7c478bd9Sstevel@tonic-gate return (1); 1967*7c478bd9Sstevel@tonic-gate } 1968*7c478bd9Sstevel@tonic-gate 1969*7c478bd9Sstevel@tonic-gate /* 1970*7c478bd9Sstevel@tonic-gate * Currently allowed flags are: 1971*7c478bd9Sstevel@tonic-gate * DI_PRIMARY_LINK 1972*7c478bd9Sstevel@tonic-gate * DI_SECONDARY_LINK 1973*7c478bd9Sstevel@tonic-gate */ 1974*7c478bd9Sstevel@tonic-gate static int 1975*7c478bd9Sstevel@tonic-gate check_args(link_desc_t *linkp) 1976*7c478bd9Sstevel@tonic-gate { 1977*7c478bd9Sstevel@tonic-gate if (linkp->fcn == NULL) 1978*7c478bd9Sstevel@tonic-gate return (-1); 1979*7c478bd9Sstevel@tonic-gate 1980*7c478bd9Sstevel@tonic-gate if (!link_flag(linkp->flags)) { 1981*7c478bd9Sstevel@tonic-gate return (-1); 1982*7c478bd9Sstevel@tonic-gate } 1983*7c478bd9Sstevel@tonic-gate 1984*7c478bd9Sstevel@tonic-gate /* 1985*7c478bd9Sstevel@tonic-gate * Minor path can be NULL. In that case, all links will be 1986*7c478bd9Sstevel@tonic-gate * selected. 1987*7c478bd9Sstevel@tonic-gate */ 1988*7c478bd9Sstevel@tonic-gate if (linkp->minor_path) { 1989*7c478bd9Sstevel@tonic-gate if (linkp->minor_path[0] != '/' || 1990*7c478bd9Sstevel@tonic-gate minor_colon(linkp->minor_path) == NULL) { 1991*7c478bd9Sstevel@tonic-gate return (-1); 1992*7c478bd9Sstevel@tonic-gate } 1993*7c478bd9Sstevel@tonic-gate } 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate return (0); 1996*7c478bd9Sstevel@tonic-gate } 1997*7c478bd9Sstevel@tonic-gate 1998*7c478bd9Sstevel@tonic-gate 1999*7c478bd9Sstevel@tonic-gate /* 2000*7c478bd9Sstevel@tonic-gate * Walk all links in database if no minor path is specified. 2001*7c478bd9Sstevel@tonic-gate */ 2002*7c478bd9Sstevel@tonic-gate static int 2003*7c478bd9Sstevel@tonic-gate walk_db(struct di_devlink_handle *hdp, link_desc_t *linkp) 2004*7c478bd9Sstevel@tonic-gate { 2005*7c478bd9Sstevel@tonic-gate assert(DB_OPEN(hdp)); 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate if (linkp->minor_path == NULL) { 2008*7c478bd9Sstevel@tonic-gate return (walk_all_links(hdp, linkp)); 2009*7c478bd9Sstevel@tonic-gate } else { 2010*7c478bd9Sstevel@tonic-gate return (walk_matching_links(hdp, linkp)); 2011*7c478bd9Sstevel@tonic-gate } 2012*7c478bd9Sstevel@tonic-gate } 2013*7c478bd9Sstevel@tonic-gate 2014*7c478bd9Sstevel@tonic-gate static int 2015*7c478bd9Sstevel@tonic-gate cache_dev(struct di_devlink_handle *hdp) 2016*7c478bd9Sstevel@tonic-gate { 2017*7c478bd9Sstevel@tonic-gate size_t sz; 2018*7c478bd9Sstevel@tonic-gate recurse_t rec = {NULL}; 2019*7c478bd9Sstevel@tonic-gate 2020*7c478bd9Sstevel@tonic-gate assert(hdp); 2021*7c478bd9Sstevel@tonic-gate assert(HDL_RDONLY(hdp)); 2022*7c478bd9Sstevel@tonic-gate 2023*7c478bd9Sstevel@tonic-gate if (hdp == NULL || !HDL_RDONLY(hdp)) { 2024*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "cache_dev: invalid arg\n"); 2025*7c478bd9Sstevel@tonic-gate return (-1); 2026*7c478bd9Sstevel@tonic-gate } 2027*7c478bd9Sstevel@tonic-gate 2028*7c478bd9Sstevel@tonic-gate sz = MIN_HASH_SIZE; 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate CACHE(hdp)->hash = calloc(sz, sizeof (cache_link_t *)); 2031*7c478bd9Sstevel@tonic-gate if (CACHE(hdp)->hash == NULL) { 2032*7c478bd9Sstevel@tonic-gate return (-1); 2033*7c478bd9Sstevel@tonic-gate } 2034*7c478bd9Sstevel@tonic-gate CACHE(hdp)->hash_sz = sz; 2035*7c478bd9Sstevel@tonic-gate 2036*7c478bd9Sstevel@tonic-gate rec.data = NULL; 2037*7c478bd9Sstevel@tonic-gate rec.fcn = cache_dev_link; 2038*7c478bd9Sstevel@tonic-gate 2039*7c478bd9Sstevel@tonic-gate return (recurse_dev(hdp, &rec)); 2040*7c478bd9Sstevel@tonic-gate } 2041*7c478bd9Sstevel@tonic-gate 2042*7c478bd9Sstevel@tonic-gate static int 2043*7c478bd9Sstevel@tonic-gate walk_dev(struct di_devlink_handle *hdp, link_desc_t *linkp) 2044*7c478bd9Sstevel@tonic-gate { 2045*7c478bd9Sstevel@tonic-gate assert(hdp && linkp); 2046*7c478bd9Sstevel@tonic-gate assert(!DB_OPEN(hdp)); 2047*7c478bd9Sstevel@tonic-gate assert(HDL_RDONLY(hdp)); 2048*7c478bd9Sstevel@tonic-gate 2049*7c478bd9Sstevel@tonic-gate if (hdp == NULL || !HDL_RDONLY(hdp) || DB_OPEN(hdp)) { 2050*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "walk_dev: invalid args\n"); 2051*7c478bd9Sstevel@tonic-gate return (-1); 2052*7c478bd9Sstevel@tonic-gate } 2053*7c478bd9Sstevel@tonic-gate 2054*7c478bd9Sstevel@tonic-gate if (CACHE_EMPTY(hdp) && cache_dev(hdp) != 0) { 2055*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "walk_dev: /dev caching failed\n"); 2056*7c478bd9Sstevel@tonic-gate return (-1); 2057*7c478bd9Sstevel@tonic-gate } 2058*7c478bd9Sstevel@tonic-gate 2059*7c478bd9Sstevel@tonic-gate if (linkp->minor_path) 2060*7c478bd9Sstevel@tonic-gate walk_cache_minor(hdp, linkp->minor_path, linkp); 2061*7c478bd9Sstevel@tonic-gate else 2062*7c478bd9Sstevel@tonic-gate walk_all_cache(hdp, linkp); 2063*7c478bd9Sstevel@tonic-gate 2064*7c478bd9Sstevel@tonic-gate return (linkp->retval); 2065*7c478bd9Sstevel@tonic-gate } 2066*7c478bd9Sstevel@tonic-gate 2067*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2068*7c478bd9Sstevel@tonic-gate static int 2069*7c478bd9Sstevel@tonic-gate cache_dev_link(struct di_devlink_handle *hdp, void *data, const char *link) 2070*7c478bd9Sstevel@tonic-gate { 2071*7c478bd9Sstevel@tonic-gate int flags; 2072*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 2073*7c478bd9Sstevel@tonic-gate char content[PATH_MAX]; 2074*7c478bd9Sstevel@tonic-gate 2075*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp) || HDL_RDONLY(hdp)); 2076*7c478bd9Sstevel@tonic-gate 2077*7c478bd9Sstevel@tonic-gate if (s_readlink(link, content, sizeof (content)) < 0) { 2078*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2079*7c478bd9Sstevel@tonic-gate } 2080*7c478bd9Sstevel@tonic-gate 2081*7c478bd9Sstevel@tonic-gate if (is_minor_node(content, NULL)) { 2082*7c478bd9Sstevel@tonic-gate flags = DI_PRIMARY_LINK; 2083*7c478bd9Sstevel@tonic-gate } else { 2084*7c478bd9Sstevel@tonic-gate flags = DI_SECONDARY_LINK; 2085*7c478bd9Sstevel@tonic-gate } 2086*7c478bd9Sstevel@tonic-gate 2087*7c478bd9Sstevel@tonic-gate assert(strncmp(link, hdp->dev_dir, strlen(hdp->dev_dir)) == 0); 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate /* 2090*7c478bd9Sstevel@tonic-gate * Store only the part after <root-dir>/dev/ 2091*7c478bd9Sstevel@tonic-gate */ 2092*7c478bd9Sstevel@tonic-gate link += strlen(hdp->dev_dir) + 1; 2093*7c478bd9Sstevel@tonic-gate 2094*7c478bd9Sstevel@tonic-gate if ((clp = add_link(hdp, link, content, flags)) != NULL) { 2095*7c478bd9Sstevel@tonic-gate SET_VALID_ATTR(clp->attr); 2096*7c478bd9Sstevel@tonic-gate } 2097*7c478bd9Sstevel@tonic-gate 2098*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2099*7c478bd9Sstevel@tonic-gate } 2100*7c478bd9Sstevel@tonic-gate 2101*7c478bd9Sstevel@tonic-gate 2102*7c478bd9Sstevel@tonic-gate static int 2103*7c478bd9Sstevel@tonic-gate walk_all_links(struct di_devlink_handle *hdp, link_desc_t *linkp) 2104*7c478bd9Sstevel@tonic-gate { 2105*7c478bd9Sstevel@tonic-gate struct db_link *dlp; 2106*7c478bd9Sstevel@tonic-gate uint32_t nidx, eidx; 2107*7c478bd9Sstevel@tonic-gate 2108*7c478bd9Sstevel@tonic-gate assert(DB_NUM(hdp, DB_LINK) >= 1); 2109*7c478bd9Sstevel@tonic-gate 2110*7c478bd9Sstevel@tonic-gate eidx = DB_NUM(hdp, DB_LINK); 2111*7c478bd9Sstevel@tonic-gate 2112*7c478bd9Sstevel@tonic-gate /* Skip the "NIL" (index == 0) link. */ 2113*7c478bd9Sstevel@tonic-gate for (nidx = 1; nidx < eidx; nidx++) { 2114*7c478bd9Sstevel@tonic-gate /* 2115*7c478bd9Sstevel@tonic-gate * Declare this local to the block with zero 2116*7c478bd9Sstevel@tonic-gate * initializer so that it gets rezeroed 2117*7c478bd9Sstevel@tonic-gate * for each iteration. 2118*7c478bd9Sstevel@tonic-gate */ 2119*7c478bd9Sstevel@tonic-gate struct di_devlink vlink = {NULL}; 2120*7c478bd9Sstevel@tonic-gate 2121*7c478bd9Sstevel@tonic-gate if ((dlp = get_link(hdp, nidx)) == NULL) 2122*7c478bd9Sstevel@tonic-gate continue; 2123*7c478bd9Sstevel@tonic-gate 2124*7c478bd9Sstevel@tonic-gate vlink.rel_path = get_string(hdp, dlp->path); 2125*7c478bd9Sstevel@tonic-gate vlink.content = get_string(hdp, dlp->content); 2126*7c478bd9Sstevel@tonic-gate vlink.type = attr2type(dlp->attr); 2127*7c478bd9Sstevel@tonic-gate 2128*7c478bd9Sstevel@tonic-gate if (visit_link(hdp, linkp, &vlink) != DI_WALK_CONTINUE) { 2129*7c478bd9Sstevel@tonic-gate break; 2130*7c478bd9Sstevel@tonic-gate } 2131*7c478bd9Sstevel@tonic-gate } 2132*7c478bd9Sstevel@tonic-gate 2133*7c478bd9Sstevel@tonic-gate return (linkp->retval); 2134*7c478bd9Sstevel@tonic-gate } 2135*7c478bd9Sstevel@tonic-gate 2136*7c478bd9Sstevel@tonic-gate static int 2137*7c478bd9Sstevel@tonic-gate walk_matching_links(struct di_devlink_handle *hdp, link_desc_t *linkp) 2138*7c478bd9Sstevel@tonic-gate { 2139*7c478bd9Sstevel@tonic-gate uint32_t nidx; 2140*7c478bd9Sstevel@tonic-gate struct db_link *dlp; 2141*7c478bd9Sstevel@tonic-gate struct db_minor *dmp; 2142*7c478bd9Sstevel@tonic-gate 2143*7c478bd9Sstevel@tonic-gate assert(linkp->minor_path != NULL); 2144*7c478bd9Sstevel@tonic-gate 2145*7c478bd9Sstevel@tonic-gate dmp = lookup_minor(hdp, linkp->minor_path, NULL, TYPE_DB); 2146*7c478bd9Sstevel@tonic-gate 2147*7c478bd9Sstevel@tonic-gate /* 2148*7c478bd9Sstevel@tonic-gate * If a minor matching the path exists, walk that minor's devlinks list. 2149*7c478bd9Sstevel@tonic-gate * Then walk the dangling devlinks list. Non-matching devlinks will be 2150*7c478bd9Sstevel@tonic-gate * filtered out in visit_link. 2151*7c478bd9Sstevel@tonic-gate */ 2152*7c478bd9Sstevel@tonic-gate for (;;) { 2153*7c478bd9Sstevel@tonic-gate nidx = dmp ? dmp->link : DB_HDR(hdp)->dngl_idx; 2154*7c478bd9Sstevel@tonic-gate for (; dlp = get_link(hdp, nidx); nidx = dlp->sib) { 2155*7c478bd9Sstevel@tonic-gate struct di_devlink vlink = {NULL}; 2156*7c478bd9Sstevel@tonic-gate 2157*7c478bd9Sstevel@tonic-gate vlink.rel_path = get_string(hdp, dlp->path); 2158*7c478bd9Sstevel@tonic-gate vlink.content = get_string(hdp, dlp->content); 2159*7c478bd9Sstevel@tonic-gate vlink.type = attr2type(dlp->attr); 2160*7c478bd9Sstevel@tonic-gate 2161*7c478bd9Sstevel@tonic-gate if (visit_link(hdp, linkp, &vlink) != DI_WALK_CONTINUE) 2162*7c478bd9Sstevel@tonic-gate goto out; 2163*7c478bd9Sstevel@tonic-gate } 2164*7c478bd9Sstevel@tonic-gate if (dmp == NULL) { 2165*7c478bd9Sstevel@tonic-gate break; 2166*7c478bd9Sstevel@tonic-gate } else { 2167*7c478bd9Sstevel@tonic-gate dmp = NULL; 2168*7c478bd9Sstevel@tonic-gate } 2169*7c478bd9Sstevel@tonic-gate } 2170*7c478bd9Sstevel@tonic-gate 2171*7c478bd9Sstevel@tonic-gate out: 2172*7c478bd9Sstevel@tonic-gate return (linkp->retval); 2173*7c478bd9Sstevel@tonic-gate } 2174*7c478bd9Sstevel@tonic-gate 2175*7c478bd9Sstevel@tonic-gate static int 2176*7c478bd9Sstevel@tonic-gate visit_link( 2177*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 2178*7c478bd9Sstevel@tonic-gate link_desc_t *linkp, 2179*7c478bd9Sstevel@tonic-gate struct di_devlink *vlp) 2180*7c478bd9Sstevel@tonic-gate { 2181*7c478bd9Sstevel@tonic-gate struct stat sbuf; 2182*7c478bd9Sstevel@tonic-gate const char *minor_path = NULL; 2183*7c478bd9Sstevel@tonic-gate char abs_path[PATH_MAX], cont[PATH_MAX]; 2184*7c478bd9Sstevel@tonic-gate 2185*7c478bd9Sstevel@tonic-gate /* 2186*7c478bd9Sstevel@tonic-gate * It is legal for the link's content and type to be unknown. 2187*7c478bd9Sstevel@tonic-gate * but one of absolute or relative path must be set. 2188*7c478bd9Sstevel@tonic-gate */ 2189*7c478bd9Sstevel@tonic-gate if (vlp->rel_path == NULL && vlp->abs_path == NULL) { 2190*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "visit_link: invalid arguments\n"); 2191*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2192*7c478bd9Sstevel@tonic-gate } 2193*7c478bd9Sstevel@tonic-gate 2194*7c478bd9Sstevel@tonic-gate if (vlp->rel_path == NULL) { 2195*7c478bd9Sstevel@tonic-gate vlp->rel_path = (char *)rel_path(hdp, vlp->abs_path); 2196*7c478bd9Sstevel@tonic-gate if (vlp->rel_path == NULL || vlp->rel_path[0] == '\0') 2197*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2198*7c478bd9Sstevel@tonic-gate } 2199*7c478bd9Sstevel@tonic-gate 2200*7c478bd9Sstevel@tonic-gate if (linkp->regp) { 2201*7c478bd9Sstevel@tonic-gate if (regexec(linkp->regp, vlp->rel_path, 0, NULL, 0) != 0) 2202*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2203*7c478bd9Sstevel@tonic-gate } 2204*7c478bd9Sstevel@tonic-gate 2205*7c478bd9Sstevel@tonic-gate if (vlp->abs_path == NULL) { 2206*7c478bd9Sstevel@tonic-gate assert(vlp->rel_path[0] != '/'); 2207*7c478bd9Sstevel@tonic-gate (void) snprintf(abs_path, sizeof (abs_path), "%s/%s", 2208*7c478bd9Sstevel@tonic-gate hdp->dev_dir, vlp->rel_path); 2209*7c478bd9Sstevel@tonic-gate vlp->abs_path = abs_path; 2210*7c478bd9Sstevel@tonic-gate } 2211*7c478bd9Sstevel@tonic-gate 2212*7c478bd9Sstevel@tonic-gate if (vlp->content == NULL) { 2213*7c478bd9Sstevel@tonic-gate if (s_readlink(vlp->abs_path, cont, sizeof (cont)) < 0) { 2214*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2215*7c478bd9Sstevel@tonic-gate } 2216*7c478bd9Sstevel@tonic-gate vlp->content = cont; 2217*7c478bd9Sstevel@tonic-gate } 2218*7c478bd9Sstevel@tonic-gate 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate if (vlp->type == 0) { 2221*7c478bd9Sstevel@tonic-gate if (is_minor_node(vlp->content, &minor_path)) { 2222*7c478bd9Sstevel@tonic-gate vlp->type = DI_PRIMARY_LINK; 2223*7c478bd9Sstevel@tonic-gate } else { 2224*7c478bd9Sstevel@tonic-gate vlp->type = DI_SECONDARY_LINK; 2225*7c478bd9Sstevel@tonic-gate } 2226*7c478bd9Sstevel@tonic-gate } 2227*7c478bd9Sstevel@tonic-gate 2228*7c478bd9Sstevel@tonic-gate /* 2229*7c478bd9Sstevel@tonic-gate * Filter based on minor path 2230*7c478bd9Sstevel@tonic-gate */ 2231*7c478bd9Sstevel@tonic-gate if (linkp->minor_path) { 2232*7c478bd9Sstevel@tonic-gate char tmp[PATH_MAX]; 2233*7c478bd9Sstevel@tonic-gate 2234*7c478bd9Sstevel@tonic-gate /* 2235*7c478bd9Sstevel@tonic-gate * derive minor path 2236*7c478bd9Sstevel@tonic-gate */ 2237*7c478bd9Sstevel@tonic-gate if (vlp->type == DI_SECONDARY_LINK) { 2238*7c478bd9Sstevel@tonic-gate 2239*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2240*7c478bd9Sstevel@tonic-gate /*LINTED*/ 2241*7c478bd9Sstevel@tonic-gate assert(sizeof (tmp) >= PATH_MAX); 2242*7c478bd9Sstevel@tonic-gate #endif 2243*7c478bd9Sstevel@tonic-gate if (realpath(vlp->abs_path, tmp) == NULL) 2244*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2245*7c478bd9Sstevel@tonic-gate 2246*7c478bd9Sstevel@tonic-gate if (!is_minor_node(tmp, &minor_path)) 2247*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2248*7c478bd9Sstevel@tonic-gate 2249*7c478bd9Sstevel@tonic-gate } else if (minor_path == NULL) { 2250*7c478bd9Sstevel@tonic-gate if (!is_minor_node(vlp->content, &minor_path)) 2251*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2252*7c478bd9Sstevel@tonic-gate } 2253*7c478bd9Sstevel@tonic-gate 2254*7c478bd9Sstevel@tonic-gate assert(minor_path != NULL); 2255*7c478bd9Sstevel@tonic-gate 2256*7c478bd9Sstevel@tonic-gate if (strcmp(linkp->minor_path, minor_path) != 0) 2257*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2258*7c478bd9Sstevel@tonic-gate } 2259*7c478bd9Sstevel@tonic-gate 2260*7c478bd9Sstevel@tonic-gate /* 2261*7c478bd9Sstevel@tonic-gate * Filter based on link type 2262*7c478bd9Sstevel@tonic-gate */ 2263*7c478bd9Sstevel@tonic-gate if (!TYPE_NONE(linkp->flags) && LINK_TYPE(linkp->flags) != vlp->type) { 2264*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2265*7c478bd9Sstevel@tonic-gate } 2266*7c478bd9Sstevel@tonic-gate 2267*7c478bd9Sstevel@tonic-gate if (lstat(vlp->abs_path, &sbuf) < 0) { 2268*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "visit_link: %s: lstat failed: %s\n", 2269*7c478bd9Sstevel@tonic-gate vlp->abs_path, strerror(errno)); 2270*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2271*7c478bd9Sstevel@tonic-gate } 2272*7c478bd9Sstevel@tonic-gate 2273*7c478bd9Sstevel@tonic-gate return (linkp->fcn(vlp, linkp->arg)); 2274*7c478bd9Sstevel@tonic-gate } 2275*7c478bd9Sstevel@tonic-gate 2276*7c478bd9Sstevel@tonic-gate static int 2277*7c478bd9Sstevel@tonic-gate devlink_valid(di_devlink_t devlink) 2278*7c478bd9Sstevel@tonic-gate { 2279*7c478bd9Sstevel@tonic-gate if (devlink == NULL || devlink->rel_path == NULL || 2280*7c478bd9Sstevel@tonic-gate devlink->abs_path == NULL || devlink->content == NULL || 2281*7c478bd9Sstevel@tonic-gate TYPE_NONE(devlink->type)) { 2282*7c478bd9Sstevel@tonic-gate return (0); 2283*7c478bd9Sstevel@tonic-gate } 2284*7c478bd9Sstevel@tonic-gate 2285*7c478bd9Sstevel@tonic-gate return (1); 2286*7c478bd9Sstevel@tonic-gate } 2287*7c478bd9Sstevel@tonic-gate 2288*7c478bd9Sstevel@tonic-gate const char * 2289*7c478bd9Sstevel@tonic-gate di_devlink_path(di_devlink_t devlink) 2290*7c478bd9Sstevel@tonic-gate { 2291*7c478bd9Sstevel@tonic-gate if (!devlink_valid(devlink)) { 2292*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2293*7c478bd9Sstevel@tonic-gate return (NULL); 2294*7c478bd9Sstevel@tonic-gate } 2295*7c478bd9Sstevel@tonic-gate 2296*7c478bd9Sstevel@tonic-gate return (devlink->abs_path); 2297*7c478bd9Sstevel@tonic-gate } 2298*7c478bd9Sstevel@tonic-gate 2299*7c478bd9Sstevel@tonic-gate const char * 2300*7c478bd9Sstevel@tonic-gate di_devlink_content(di_devlink_t devlink) 2301*7c478bd9Sstevel@tonic-gate { 2302*7c478bd9Sstevel@tonic-gate if (!devlink_valid(devlink)) { 2303*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2304*7c478bd9Sstevel@tonic-gate return (NULL); 2305*7c478bd9Sstevel@tonic-gate } 2306*7c478bd9Sstevel@tonic-gate 2307*7c478bd9Sstevel@tonic-gate return (devlink->content); 2308*7c478bd9Sstevel@tonic-gate } 2309*7c478bd9Sstevel@tonic-gate 2310*7c478bd9Sstevel@tonic-gate int 2311*7c478bd9Sstevel@tonic-gate di_devlink_type(di_devlink_t devlink) 2312*7c478bd9Sstevel@tonic-gate { 2313*7c478bd9Sstevel@tonic-gate if (!devlink_valid(devlink)) { 2314*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2315*7c478bd9Sstevel@tonic-gate return (-1); 2316*7c478bd9Sstevel@tonic-gate } 2317*7c478bd9Sstevel@tonic-gate 2318*7c478bd9Sstevel@tonic-gate return (devlink->type); 2319*7c478bd9Sstevel@tonic-gate } 2320*7c478bd9Sstevel@tonic-gate 2321*7c478bd9Sstevel@tonic-gate di_devlink_t 2322*7c478bd9Sstevel@tonic-gate di_devlink_dup(di_devlink_t devlink) 2323*7c478bd9Sstevel@tonic-gate { 2324*7c478bd9Sstevel@tonic-gate struct di_devlink *duplink; 2325*7c478bd9Sstevel@tonic-gate 2326*7c478bd9Sstevel@tonic-gate if (!devlink_valid(devlink)) { 2327*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2328*7c478bd9Sstevel@tonic-gate return (NULL); 2329*7c478bd9Sstevel@tonic-gate } 2330*7c478bd9Sstevel@tonic-gate 2331*7c478bd9Sstevel@tonic-gate if ((duplink = calloc(1, sizeof (struct di_devlink))) == NULL) { 2332*7c478bd9Sstevel@tonic-gate return (NULL); 2333*7c478bd9Sstevel@tonic-gate } 2334*7c478bd9Sstevel@tonic-gate 2335*7c478bd9Sstevel@tonic-gate duplink->rel_path = strdup(devlink->rel_path); 2336*7c478bd9Sstevel@tonic-gate duplink->abs_path = strdup(devlink->abs_path); 2337*7c478bd9Sstevel@tonic-gate duplink->content = strdup(devlink->content); 2338*7c478bd9Sstevel@tonic-gate duplink->type = devlink->type; 2339*7c478bd9Sstevel@tonic-gate 2340*7c478bd9Sstevel@tonic-gate if (!devlink_valid(duplink)) { 2341*7c478bd9Sstevel@tonic-gate (void) di_devlink_free(duplink); 2342*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 2343*7c478bd9Sstevel@tonic-gate return (NULL); 2344*7c478bd9Sstevel@tonic-gate } 2345*7c478bd9Sstevel@tonic-gate 2346*7c478bd9Sstevel@tonic-gate return (duplink); 2347*7c478bd9Sstevel@tonic-gate } 2348*7c478bd9Sstevel@tonic-gate 2349*7c478bd9Sstevel@tonic-gate int 2350*7c478bd9Sstevel@tonic-gate di_devlink_free(di_devlink_t devlink) 2351*7c478bd9Sstevel@tonic-gate { 2352*7c478bd9Sstevel@tonic-gate if (devlink == NULL) { 2353*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2354*7c478bd9Sstevel@tonic-gate return (-1); 2355*7c478bd9Sstevel@tonic-gate } 2356*7c478bd9Sstevel@tonic-gate 2357*7c478bd9Sstevel@tonic-gate free(devlink->rel_path); 2358*7c478bd9Sstevel@tonic-gate free(devlink->abs_path); 2359*7c478bd9Sstevel@tonic-gate free(devlink->content); 2360*7c478bd9Sstevel@tonic-gate free(devlink); 2361*7c478bd9Sstevel@tonic-gate 2362*7c478bd9Sstevel@tonic-gate return (0); 2363*7c478bd9Sstevel@tonic-gate } 2364*7c478bd9Sstevel@tonic-gate 2365*7c478bd9Sstevel@tonic-gate /* 2366*7c478bd9Sstevel@tonic-gate * Obtain path relative to dev_dir 2367*7c478bd9Sstevel@tonic-gate */ 2368*7c478bd9Sstevel@tonic-gate static const char * 2369*7c478bd9Sstevel@tonic-gate rel_path(struct di_devlink_handle *hdp, const char *path) 2370*7c478bd9Sstevel@tonic-gate { 2371*7c478bd9Sstevel@tonic-gate const size_t len = strlen(hdp->dev_dir); 2372*7c478bd9Sstevel@tonic-gate 2373*7c478bd9Sstevel@tonic-gate if (strncmp(path, hdp->dev_dir, len) != 0) 2374*7c478bd9Sstevel@tonic-gate return (NULL); 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate if (path[len] == '\0') 2377*7c478bd9Sstevel@tonic-gate return (&path[len]); 2378*7c478bd9Sstevel@tonic-gate 2379*7c478bd9Sstevel@tonic-gate if (path[len] != '/') 2380*7c478bd9Sstevel@tonic-gate return (NULL); 2381*7c478bd9Sstevel@tonic-gate 2382*7c478bd9Sstevel@tonic-gate return (&path[len+1]); 2383*7c478bd9Sstevel@tonic-gate } 2384*7c478bd9Sstevel@tonic-gate 2385*7c478bd9Sstevel@tonic-gate static int 2386*7c478bd9Sstevel@tonic-gate recurse_dev(struct di_devlink_handle *hdp, recurse_t *rp) 2387*7c478bd9Sstevel@tonic-gate { 2388*7c478bd9Sstevel@tonic-gate int ret = 0; 2389*7c478bd9Sstevel@tonic-gate 2390*7c478bd9Sstevel@tonic-gate (void) do_recurse(hdp->dev_dir, hdp, rp, &ret); 2391*7c478bd9Sstevel@tonic-gate 2392*7c478bd9Sstevel@tonic-gate return (ret); 2393*7c478bd9Sstevel@tonic-gate } 2394*7c478bd9Sstevel@tonic-gate 2395*7c478bd9Sstevel@tonic-gate static int 2396*7c478bd9Sstevel@tonic-gate do_recurse( 2397*7c478bd9Sstevel@tonic-gate const char *dir, 2398*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 2399*7c478bd9Sstevel@tonic-gate recurse_t *rp, 2400*7c478bd9Sstevel@tonic-gate int *retp) 2401*7c478bd9Sstevel@tonic-gate { 2402*7c478bd9Sstevel@tonic-gate DIR *dp; 2403*7c478bd9Sstevel@tonic-gate size_t len; 2404*7c478bd9Sstevel@tonic-gate const char *rel; 2405*7c478bd9Sstevel@tonic-gate struct stat sbuf; 2406*7c478bd9Sstevel@tonic-gate char cur[PATH_MAX], *cp; 2407*7c478bd9Sstevel@tonic-gate int i, rv = DI_WALK_CONTINUE; 2408*7c478bd9Sstevel@tonic-gate struct dirent *entp, *result; 2409*7c478bd9Sstevel@tonic-gate 2410*7c478bd9Sstevel@tonic-gate 2411*7c478bd9Sstevel@tonic-gate if ((rel = rel_path(hdp, dir)) == NULL) 2412*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2413*7c478bd9Sstevel@tonic-gate 2414*7c478bd9Sstevel@tonic-gate /* 2415*7c478bd9Sstevel@tonic-gate * Skip directories we are not interested in. 2416*7c478bd9Sstevel@tonic-gate */ 2417*7c478bd9Sstevel@tonic-gate for (i = 0; i < N_SKIP_DIRS; i++) { 2418*7c478bd9Sstevel@tonic-gate if (strcmp(rel, skip_dirs[i]) == 0) { 2419*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "do_recurse: skipping %s\n", 2420*7c478bd9Sstevel@tonic-gate dir); 2421*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2422*7c478bd9Sstevel@tonic-gate } 2423*7c478bd9Sstevel@tonic-gate } 2424*7c478bd9Sstevel@tonic-gate 2425*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "do_recurse: dir = %s\n", dir); 2426*7c478bd9Sstevel@tonic-gate 2427*7c478bd9Sstevel@tonic-gate if ((dp = opendir(dir)) == NULL) 2428*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2429*7c478bd9Sstevel@tonic-gate 2430*7c478bd9Sstevel@tonic-gate entp = malloc(sizeof (struct dirent) + PATH_MAX + 1); 2431*7c478bd9Sstevel@tonic-gate if (entp == NULL) { 2432*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2433*7c478bd9Sstevel@tonic-gate (void) closedir(dp); 2434*7c478bd9Sstevel@tonic-gate *retp = -1; 2435*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 2436*7c478bd9Sstevel@tonic-gate } 2437*7c478bd9Sstevel@tonic-gate 2438*7c478bd9Sstevel@tonic-gate (void) snprintf(cur, sizeof (cur), "%s/", dir); 2439*7c478bd9Sstevel@tonic-gate len = strlen(cur); 2440*7c478bd9Sstevel@tonic-gate cp = cur + len; 2441*7c478bd9Sstevel@tonic-gate len = sizeof (cur) - len; 2442*7c478bd9Sstevel@tonic-gate 2443*7c478bd9Sstevel@tonic-gate while (readdir_r(dp, entp, &result) == 0) { 2444*7c478bd9Sstevel@tonic-gate 2445*7c478bd9Sstevel@tonic-gate if (result == NULL) 2446*7c478bd9Sstevel@tonic-gate break; 2447*7c478bd9Sstevel@tonic-gate 2448*7c478bd9Sstevel@tonic-gate if (strcmp(entp->d_name, ".") == 0 || 2449*7c478bd9Sstevel@tonic-gate strcmp(entp->d_name, "..") == 0) { 2450*7c478bd9Sstevel@tonic-gate continue; 2451*7c478bd9Sstevel@tonic-gate } 2452*7c478bd9Sstevel@tonic-gate 2453*7c478bd9Sstevel@tonic-gate (void) snprintf(cp, len, "%s", entp->d_name); 2454*7c478bd9Sstevel@tonic-gate 2455*7c478bd9Sstevel@tonic-gate /* 2456*7c478bd9Sstevel@tonic-gate * Skip files we are not interested in. 2457*7c478bd9Sstevel@tonic-gate */ 2458*7c478bd9Sstevel@tonic-gate for (i = 0; i < N_SKIP_FILES; i++) { 2459*7c478bd9Sstevel@tonic-gate 2460*7c478bd9Sstevel@tonic-gate rel = rel_path(hdp, cur); 2461*7c478bd9Sstevel@tonic-gate if (rel == NULL || strcmp(rel, skip_files[i]) == 0) { 2462*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, 2463*7c478bd9Sstevel@tonic-gate "do_recurse: skipping %s\n", cur); 2464*7c478bd9Sstevel@tonic-gate goto next_entry; 2465*7c478bd9Sstevel@tonic-gate } 2466*7c478bd9Sstevel@tonic-gate } 2467*7c478bd9Sstevel@tonic-gate 2468*7c478bd9Sstevel@tonic-gate if (lstat(cur, &sbuf) == 0) { 2469*7c478bd9Sstevel@tonic-gate if (S_ISDIR(sbuf.st_mode)) { 2470*7c478bd9Sstevel@tonic-gate rv = do_recurse(cur, hdp, rp, retp); 2471*7c478bd9Sstevel@tonic-gate } else if (S_ISLNK(sbuf.st_mode)) { 2472*7c478bd9Sstevel@tonic-gate rv = rp->fcn(hdp, rp->data, cur); 2473*7c478bd9Sstevel@tonic-gate } else { 2474*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, 2475*7c478bd9Sstevel@tonic-gate "do_recurse: Skipping entry: %s\n", cur); 2476*7c478bd9Sstevel@tonic-gate } 2477*7c478bd9Sstevel@tonic-gate } else { 2478*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "do_recurse: cur(%s): lstat" 2479*7c478bd9Sstevel@tonic-gate " failed: %s\n", cur, strerror(errno)); 2480*7c478bd9Sstevel@tonic-gate } 2481*7c478bd9Sstevel@tonic-gate 2482*7c478bd9Sstevel@tonic-gate next_entry: 2483*7c478bd9Sstevel@tonic-gate *cp = '\0'; 2484*7c478bd9Sstevel@tonic-gate 2485*7c478bd9Sstevel@tonic-gate if (rv != DI_WALK_CONTINUE) 2486*7c478bd9Sstevel@tonic-gate break; 2487*7c478bd9Sstevel@tonic-gate } 2488*7c478bd9Sstevel@tonic-gate 2489*7c478bd9Sstevel@tonic-gate free(entp); 2490*7c478bd9Sstevel@tonic-gate (void) closedir(dp); 2491*7c478bd9Sstevel@tonic-gate 2492*7c478bd9Sstevel@tonic-gate return (rv); 2493*7c478bd9Sstevel@tonic-gate } 2494*7c478bd9Sstevel@tonic-gate 2495*7c478bd9Sstevel@tonic-gate 2496*7c478bd9Sstevel@tonic-gate static int 2497*7c478bd9Sstevel@tonic-gate check_attr(uint32_t attr) 2498*7c478bd9Sstevel@tonic-gate { 2499*7c478bd9Sstevel@tonic-gate switch (attr & A_LINK_TYPES) { 2500*7c478bd9Sstevel@tonic-gate case A_PRIMARY: 2501*7c478bd9Sstevel@tonic-gate case A_SECONDARY: 2502*7c478bd9Sstevel@tonic-gate return (1); 2503*7c478bd9Sstevel@tonic-gate default: 2504*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "check_attr: incorrect attr(%u)\n", 2505*7c478bd9Sstevel@tonic-gate attr); 2506*7c478bd9Sstevel@tonic-gate return (0); 2507*7c478bd9Sstevel@tonic-gate } 2508*7c478bd9Sstevel@tonic-gate } 2509*7c478bd9Sstevel@tonic-gate 2510*7c478bd9Sstevel@tonic-gate static int 2511*7c478bd9Sstevel@tonic-gate attr2type(uint32_t attr) 2512*7c478bd9Sstevel@tonic-gate { 2513*7c478bd9Sstevel@tonic-gate switch (attr & A_LINK_TYPES) { 2514*7c478bd9Sstevel@tonic-gate case A_PRIMARY: 2515*7c478bd9Sstevel@tonic-gate return (DI_PRIMARY_LINK); 2516*7c478bd9Sstevel@tonic-gate case A_SECONDARY: 2517*7c478bd9Sstevel@tonic-gate return (DI_SECONDARY_LINK); 2518*7c478bd9Sstevel@tonic-gate default: 2519*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "attr2type: incorrect attr(%u)\n", 2520*7c478bd9Sstevel@tonic-gate attr); 2521*7c478bd9Sstevel@tonic-gate return (0); 2522*7c478bd9Sstevel@tonic-gate } 2523*7c478bd9Sstevel@tonic-gate } 2524*7c478bd9Sstevel@tonic-gate 2525*7c478bd9Sstevel@tonic-gate /* Allocate new node and link it in */ 2526*7c478bd9Sstevel@tonic-gate static cache_node_t * 2527*7c478bd9Sstevel@tonic-gate node_insert( 2528*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 2529*7c478bd9Sstevel@tonic-gate cache_node_t *pcnp, 2530*7c478bd9Sstevel@tonic-gate const char *path, 2531*7c478bd9Sstevel@tonic-gate int insert) 2532*7c478bd9Sstevel@tonic-gate { 2533*7c478bd9Sstevel@tonic-gate cache_node_t *cnp; 2534*7c478bd9Sstevel@tonic-gate 2535*7c478bd9Sstevel@tonic-gate if (path == NULL) { 2536*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2537*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2538*7c478bd9Sstevel@tonic-gate return (NULL); 2539*7c478bd9Sstevel@tonic-gate } 2540*7c478bd9Sstevel@tonic-gate 2541*7c478bd9Sstevel@tonic-gate if ((cnp = calloc(1, sizeof (cache_node_t))) == NULL) { 2542*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2543*7c478bd9Sstevel@tonic-gate return (NULL); 2544*7c478bd9Sstevel@tonic-gate } 2545*7c478bd9Sstevel@tonic-gate 2546*7c478bd9Sstevel@tonic-gate if ((cnp->path = strdup(path)) == NULL) { 2547*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2548*7c478bd9Sstevel@tonic-gate free(cnp); 2549*7c478bd9Sstevel@tonic-gate return (NULL); 2550*7c478bd9Sstevel@tonic-gate } 2551*7c478bd9Sstevel@tonic-gate 2552*7c478bd9Sstevel@tonic-gate cnp->parent = pcnp; 2553*7c478bd9Sstevel@tonic-gate 2554*7c478bd9Sstevel@tonic-gate if (pcnp == NULL) { 2555*7c478bd9Sstevel@tonic-gate assert(strcmp(path, "/") == 0); 2556*7c478bd9Sstevel@tonic-gate assert(CACHE(hdp)->root == NULL); 2557*7c478bd9Sstevel@tonic-gate CACHE(hdp)->root = cnp; 2558*7c478bd9Sstevel@tonic-gate } else if (insert == INSERT_HEAD) { 2559*7c478bd9Sstevel@tonic-gate cnp->sib = pcnp->child; 2560*7c478bd9Sstevel@tonic-gate pcnp->child = cnp; 2561*7c478bd9Sstevel@tonic-gate } else if (CACHE_LAST(hdp) && CACHE_LAST(hdp)->node && 2562*7c478bd9Sstevel@tonic-gate CACHE_LAST(hdp)->node->parent == pcnp && 2563*7c478bd9Sstevel@tonic-gate CACHE_LAST(hdp)->node->sib == NULL) { 2564*7c478bd9Sstevel@tonic-gate 2565*7c478bd9Sstevel@tonic-gate CACHE_LAST(hdp)->node->sib = cnp; 2566*7c478bd9Sstevel@tonic-gate 2567*7c478bd9Sstevel@tonic-gate } else { 2568*7c478bd9Sstevel@tonic-gate cache_node_t **pp; 2569*7c478bd9Sstevel@tonic-gate 2570*7c478bd9Sstevel@tonic-gate for (pp = &pcnp->child; *pp != NULL; pp = &(*pp)->sib) 2571*7c478bd9Sstevel@tonic-gate ; 2572*7c478bd9Sstevel@tonic-gate *pp = cnp; 2573*7c478bd9Sstevel@tonic-gate } 2574*7c478bd9Sstevel@tonic-gate 2575*7c478bd9Sstevel@tonic-gate return (cnp); 2576*7c478bd9Sstevel@tonic-gate } 2577*7c478bd9Sstevel@tonic-gate 2578*7c478bd9Sstevel@tonic-gate /* 2579*7c478bd9Sstevel@tonic-gate * Allocate a new minor and link it in either at the tail or head 2580*7c478bd9Sstevel@tonic-gate * of the minor list depending on the value of "prev". 2581*7c478bd9Sstevel@tonic-gate */ 2582*7c478bd9Sstevel@tonic-gate static cache_minor_t * 2583*7c478bd9Sstevel@tonic-gate minor_insert( 2584*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 2585*7c478bd9Sstevel@tonic-gate cache_node_t *pcnp, 2586*7c478bd9Sstevel@tonic-gate const char *name, 2587*7c478bd9Sstevel@tonic-gate const char *nodetype, 2588*7c478bd9Sstevel@tonic-gate cache_minor_t **prev) 2589*7c478bd9Sstevel@tonic-gate { 2590*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 2591*7c478bd9Sstevel@tonic-gate 2592*7c478bd9Sstevel@tonic-gate if (pcnp == NULL || name == NULL) { 2593*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2594*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2595*7c478bd9Sstevel@tonic-gate return (NULL); 2596*7c478bd9Sstevel@tonic-gate } 2597*7c478bd9Sstevel@tonic-gate 2598*7c478bd9Sstevel@tonic-gate /* 2599*7c478bd9Sstevel@tonic-gate * Some pseudo drivers don't specify nodetype. Assume pseudo if 2600*7c478bd9Sstevel@tonic-gate * nodetype is not specified. 2601*7c478bd9Sstevel@tonic-gate */ 2602*7c478bd9Sstevel@tonic-gate if (nodetype == NULL) 2603*7c478bd9Sstevel@tonic-gate nodetype = DDI_PSEUDO; 2604*7c478bd9Sstevel@tonic-gate 2605*7c478bd9Sstevel@tonic-gate if ((cmnp = calloc(1, sizeof (cache_minor_t))) == NULL) { 2606*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2607*7c478bd9Sstevel@tonic-gate return (NULL); 2608*7c478bd9Sstevel@tonic-gate } 2609*7c478bd9Sstevel@tonic-gate 2610*7c478bd9Sstevel@tonic-gate cmnp->name = strdup(name); 2611*7c478bd9Sstevel@tonic-gate cmnp->nodetype = strdup(nodetype); 2612*7c478bd9Sstevel@tonic-gate if (cmnp->name == NULL || cmnp->nodetype == NULL) { 2613*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2614*7c478bd9Sstevel@tonic-gate free(cmnp->name); 2615*7c478bd9Sstevel@tonic-gate free(cmnp->nodetype); 2616*7c478bd9Sstevel@tonic-gate free(cmnp); 2617*7c478bd9Sstevel@tonic-gate return (NULL); 2618*7c478bd9Sstevel@tonic-gate } 2619*7c478bd9Sstevel@tonic-gate 2620*7c478bd9Sstevel@tonic-gate cmnp->node = pcnp; 2621*7c478bd9Sstevel@tonic-gate 2622*7c478bd9Sstevel@tonic-gate /* Add to node's minor list */ 2623*7c478bd9Sstevel@tonic-gate if (prev == NULL) { 2624*7c478bd9Sstevel@tonic-gate cmnp->sib = pcnp->minor; 2625*7c478bd9Sstevel@tonic-gate pcnp->minor = cmnp; 2626*7c478bd9Sstevel@tonic-gate } else { 2627*7c478bd9Sstevel@tonic-gate assert(*prev == NULL); 2628*7c478bd9Sstevel@tonic-gate *prev = cmnp; 2629*7c478bd9Sstevel@tonic-gate } 2630*7c478bd9Sstevel@tonic-gate 2631*7c478bd9Sstevel@tonic-gate return (cmnp); 2632*7c478bd9Sstevel@tonic-gate } 2633*7c478bd9Sstevel@tonic-gate 2634*7c478bd9Sstevel@tonic-gate static cache_link_t * 2635*7c478bd9Sstevel@tonic-gate link_insert( 2636*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 2637*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp, 2638*7c478bd9Sstevel@tonic-gate const char *path, 2639*7c478bd9Sstevel@tonic-gate const char *content, 2640*7c478bd9Sstevel@tonic-gate uint32_t attr) 2641*7c478bd9Sstevel@tonic-gate { 2642*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 2643*7c478bd9Sstevel@tonic-gate 2644*7c478bd9Sstevel@tonic-gate if (path == NULL || content == NULL || !check_attr(attr)) { 2645*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2646*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2647*7c478bd9Sstevel@tonic-gate return (NULL); 2648*7c478bd9Sstevel@tonic-gate } 2649*7c478bd9Sstevel@tonic-gate 2650*7c478bd9Sstevel@tonic-gate if ((clp = calloc(1, sizeof (cache_link_t))) == NULL) { 2651*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2652*7c478bd9Sstevel@tonic-gate return (NULL); 2653*7c478bd9Sstevel@tonic-gate } 2654*7c478bd9Sstevel@tonic-gate 2655*7c478bd9Sstevel@tonic-gate clp->path = strdup(path); 2656*7c478bd9Sstevel@tonic-gate clp->content = strdup(content); 2657*7c478bd9Sstevel@tonic-gate if (clp->path == NULL || clp->content == NULL) { 2658*7c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp); 2659*7c478bd9Sstevel@tonic-gate link_free(&clp); 2660*7c478bd9Sstevel@tonic-gate return (NULL); 2661*7c478bd9Sstevel@tonic-gate } 2662*7c478bd9Sstevel@tonic-gate 2663*7c478bd9Sstevel@tonic-gate clp->attr = attr; 2664*7c478bd9Sstevel@tonic-gate hash_insert(hdp, clp); 2665*7c478bd9Sstevel@tonic-gate clp->minor = cmnp; 2666*7c478bd9Sstevel@tonic-gate 2667*7c478bd9Sstevel@tonic-gate /* Add to minor's link list */ 2668*7c478bd9Sstevel@tonic-gate if (cmnp != NULL) { 2669*7c478bd9Sstevel@tonic-gate clp->sib = cmnp->link; 2670*7c478bd9Sstevel@tonic-gate cmnp->link = clp; 2671*7c478bd9Sstevel@tonic-gate } else { 2672*7c478bd9Sstevel@tonic-gate clp->sib = CACHE(hdp)->dngl; 2673*7c478bd9Sstevel@tonic-gate CACHE(hdp)->dngl = clp; 2674*7c478bd9Sstevel@tonic-gate } 2675*7c478bd9Sstevel@tonic-gate 2676*7c478bd9Sstevel@tonic-gate return (clp); 2677*7c478bd9Sstevel@tonic-gate } 2678*7c478bd9Sstevel@tonic-gate 2679*7c478bd9Sstevel@tonic-gate static void 2680*7c478bd9Sstevel@tonic-gate hash_insert(struct di_devlink_handle *hdp, cache_link_t *clp) 2681*7c478bd9Sstevel@tonic-gate { 2682*7c478bd9Sstevel@tonic-gate uint_t hval; 2683*7c478bd9Sstevel@tonic-gate 2684*7c478bd9Sstevel@tonic-gate hval = hashfn(hdp, clp->path); 2685*7c478bd9Sstevel@tonic-gate clp->hash = CACHE_HASH(hdp, hval); 2686*7c478bd9Sstevel@tonic-gate CACHE_HASH(hdp, hval) = clp; 2687*7c478bd9Sstevel@tonic-gate } 2688*7c478bd9Sstevel@tonic-gate 2689*7c478bd9Sstevel@tonic-gate 2690*7c478bd9Sstevel@tonic-gate static struct db_node * 2691*7c478bd9Sstevel@tonic-gate get_node(struct di_devlink_handle *hdp, uint32_t idx) 2692*7c478bd9Sstevel@tonic-gate { 2693*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ, DB_NODE)); 2694*7c478bd9Sstevel@tonic-gate } 2695*7c478bd9Sstevel@tonic-gate 2696*7c478bd9Sstevel@tonic-gate static struct db_node * 2697*7c478bd9Sstevel@tonic-gate set_node(struct di_devlink_handle *hdp, uint32_t idx) 2698*7c478bd9Sstevel@tonic-gate { 2699*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_NODE)); 2700*7c478bd9Sstevel@tonic-gate } 2701*7c478bd9Sstevel@tonic-gate 2702*7c478bd9Sstevel@tonic-gate static struct db_minor * 2703*7c478bd9Sstevel@tonic-gate get_minor(struct di_devlink_handle *hdp, uint32_t idx) 2704*7c478bd9Sstevel@tonic-gate { 2705*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ, DB_MINOR)); 2706*7c478bd9Sstevel@tonic-gate } 2707*7c478bd9Sstevel@tonic-gate 2708*7c478bd9Sstevel@tonic-gate static struct db_minor * 2709*7c478bd9Sstevel@tonic-gate set_minor(struct di_devlink_handle *hdp, uint32_t idx) 2710*7c478bd9Sstevel@tonic-gate { 2711*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_MINOR)); 2712*7c478bd9Sstevel@tonic-gate } 2713*7c478bd9Sstevel@tonic-gate 2714*7c478bd9Sstevel@tonic-gate static struct db_link * 2715*7c478bd9Sstevel@tonic-gate get_link(struct di_devlink_handle *hdp, uint32_t idx) 2716*7c478bd9Sstevel@tonic-gate { 2717*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ, DB_LINK)); 2718*7c478bd9Sstevel@tonic-gate } 2719*7c478bd9Sstevel@tonic-gate 2720*7c478bd9Sstevel@tonic-gate static struct db_link * 2721*7c478bd9Sstevel@tonic-gate set_link(struct di_devlink_handle *hdp, uint32_t idx) 2722*7c478bd9Sstevel@tonic-gate { 2723*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_LINK)); 2724*7c478bd9Sstevel@tonic-gate } 2725*7c478bd9Sstevel@tonic-gate 2726*7c478bd9Sstevel@tonic-gate static char * 2727*7c478bd9Sstevel@tonic-gate get_string(struct di_devlink_handle *hdp, uint32_t idx) 2728*7c478bd9Sstevel@tonic-gate { 2729*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ, DB_STR)); 2730*7c478bd9Sstevel@tonic-gate } 2731*7c478bd9Sstevel@tonic-gate 2732*7c478bd9Sstevel@tonic-gate static char * 2733*7c478bd9Sstevel@tonic-gate set_string(struct di_devlink_handle *hdp, uint32_t idx) 2734*7c478bd9Sstevel@tonic-gate { 2735*7c478bd9Sstevel@tonic-gate return (map_seg(hdp, idx, PROT_READ | PROT_WRITE, DB_STR)); 2736*7c478bd9Sstevel@tonic-gate } 2737*7c478bd9Sstevel@tonic-gate 2738*7c478bd9Sstevel@tonic-gate 2739*7c478bd9Sstevel@tonic-gate /* 2740*7c478bd9Sstevel@tonic-gate * Returns the element corresponding to idx. If the portion of file involved 2741*7c478bd9Sstevel@tonic-gate * is not yet mapped, does an mmap() as well. Existing mappings are not changed. 2742*7c478bd9Sstevel@tonic-gate */ 2743*7c478bd9Sstevel@tonic-gate static void * 2744*7c478bd9Sstevel@tonic-gate map_seg( 2745*7c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, 2746*7c478bd9Sstevel@tonic-gate uint32_t idx, 2747*7c478bd9Sstevel@tonic-gate int prot, 2748*7c478bd9Sstevel@tonic-gate db_seg_t seg) 2749*7c478bd9Sstevel@tonic-gate { 2750*7c478bd9Sstevel@tonic-gate int s; 2751*7c478bd9Sstevel@tonic-gate off_t off; 2752*7c478bd9Sstevel@tonic-gate size_t slen; 2753*7c478bd9Sstevel@tonic-gate caddr_t addr; 2754*7c478bd9Sstevel@tonic-gate 2755*7c478bd9Sstevel@tonic-gate if (idx == DB_NIL) { 2756*7c478bd9Sstevel@tonic-gate return (NULL); 2757*7c478bd9Sstevel@tonic-gate } 2758*7c478bd9Sstevel@tonic-gate 2759*7c478bd9Sstevel@tonic-gate if (!VALID_INDEX(hdp, seg, idx)) { 2760*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "map_seg: seg(%d): invalid idx(%u)\n", 2761*7c478bd9Sstevel@tonic-gate seg, idx); 2762*7c478bd9Sstevel@tonic-gate return (NULL); 2763*7c478bd9Sstevel@tonic-gate } 2764*7c478bd9Sstevel@tonic-gate 2765*7c478bd9Sstevel@tonic-gate /* 2766*7c478bd9Sstevel@tonic-gate * If the seg is already mapped in, use it if the access type is 2767*7c478bd9Sstevel@tonic-gate * valid. 2768*7c478bd9Sstevel@tonic-gate */ 2769*7c478bd9Sstevel@tonic-gate if (DB_SEG(hdp, seg) != NULL) { 2770*7c478bd9Sstevel@tonic-gate if (DB_SEG_PROT(hdp, seg) != prot) { 2771*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "map_seg: illegal access: " 2772*7c478bd9Sstevel@tonic-gate "seg[%d]: idx=%u, seg_prot=%d, access=%d\n", 2773*7c478bd9Sstevel@tonic-gate seg, idx, DB_SEG_PROT(hdp, seg), prot); 2774*7c478bd9Sstevel@tonic-gate return (NULL); 2775*7c478bd9Sstevel@tonic-gate } 2776*7c478bd9Sstevel@tonic-gate return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]); 2777*7c478bd9Sstevel@tonic-gate } 2778*7c478bd9Sstevel@tonic-gate 2779*7c478bd9Sstevel@tonic-gate /* 2780*7c478bd9Sstevel@tonic-gate * Segment is not mapped. Mmap() the segment. 2781*7c478bd9Sstevel@tonic-gate */ 2782*7c478bd9Sstevel@tonic-gate off = seg_size(hdp, DB_HEADER); 2783*7c478bd9Sstevel@tonic-gate for (s = 0; s < seg; s++) { 2784*7c478bd9Sstevel@tonic-gate off += seg_size(hdp, s); 2785*7c478bd9Sstevel@tonic-gate } 2786*7c478bd9Sstevel@tonic-gate slen = seg_size(hdp, seg); 2787*7c478bd9Sstevel@tonic-gate 2788*7c478bd9Sstevel@tonic-gate addr = mmap(0, slen, prot, MAP_SHARED, DB(hdp)->db_fd, off); 2789*7c478bd9Sstevel@tonic-gate if (addr == MAP_FAILED) { 2790*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "map_seg: seg[%d]: mmap failed: %s\n", 2791*7c478bd9Sstevel@tonic-gate seg, strerror(errno)); 2792*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "map_seg: args: len=%lu, prot=%d," 2793*7c478bd9Sstevel@tonic-gate " fd=%d, off=%ld\n", (ulong_t)slen, prot, DB(hdp)->db_fd, 2794*7c478bd9Sstevel@tonic-gate off); 2795*7c478bd9Sstevel@tonic-gate return (NULL); 2796*7c478bd9Sstevel@tonic-gate } 2797*7c478bd9Sstevel@tonic-gate 2798*7c478bd9Sstevel@tonic-gate DB_SEG(hdp, seg) = addr; 2799*7c478bd9Sstevel@tonic-gate DB_SEG_PROT(hdp, seg) = prot; 2800*7c478bd9Sstevel@tonic-gate 2801*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "map_seg: seg[%d]: len=%lu, prot=%d, fd=%d, " 2802*7c478bd9Sstevel@tonic-gate "off=%ld, seg_base=%p\n", seg, (ulong_t)slen, prot, DB(hdp)->db_fd, 2803*7c478bd9Sstevel@tonic-gate off, (void *)addr); 2804*7c478bd9Sstevel@tonic-gate 2805*7c478bd9Sstevel@tonic-gate return (DB_SEG(hdp, seg) + idx * elem_sizes[seg]); 2806*7c478bd9Sstevel@tonic-gate } 2807*7c478bd9Sstevel@tonic-gate 2808*7c478bd9Sstevel@tonic-gate /* 2809*7c478bd9Sstevel@tonic-gate * Computes the size of a segment rounded up to the nearest page boundary. 2810*7c478bd9Sstevel@tonic-gate */ 2811*7c478bd9Sstevel@tonic-gate static size_t 2812*7c478bd9Sstevel@tonic-gate seg_size(struct di_devlink_handle *hdp, int seg) 2813*7c478bd9Sstevel@tonic-gate { 2814*7c478bd9Sstevel@tonic-gate size_t sz; 2815*7c478bd9Sstevel@tonic-gate 2816*7c478bd9Sstevel@tonic-gate assert(DB_HDR(hdp)->page_sz); 2817*7c478bd9Sstevel@tonic-gate 2818*7c478bd9Sstevel@tonic-gate if (seg == DB_HEADER) { 2819*7c478bd9Sstevel@tonic-gate sz = HDR_LEN; 2820*7c478bd9Sstevel@tonic-gate } else { 2821*7c478bd9Sstevel@tonic-gate assert(DB_NUM(hdp, seg) >= 1); 2822*7c478bd9Sstevel@tonic-gate sz = DB_NUM(hdp, seg) * elem_sizes[seg]; 2823*7c478bd9Sstevel@tonic-gate } 2824*7c478bd9Sstevel@tonic-gate 2825*7c478bd9Sstevel@tonic-gate sz = (sz / DB_HDR(hdp)->page_sz) + 1; 2826*7c478bd9Sstevel@tonic-gate 2827*7c478bd9Sstevel@tonic-gate sz *= DB_HDR(hdp)->page_sz; 2828*7c478bd9Sstevel@tonic-gate 2829*7c478bd9Sstevel@tonic-gate return (sz); 2830*7c478bd9Sstevel@tonic-gate } 2831*7c478bd9Sstevel@tonic-gate 2832*7c478bd9Sstevel@tonic-gate static size_t 2833*7c478bd9Sstevel@tonic-gate size_db(struct di_devlink_handle *hdp, long page_sz, uint32_t *count) 2834*7c478bd9Sstevel@tonic-gate { 2835*7c478bd9Sstevel@tonic-gate int i; 2836*7c478bd9Sstevel@tonic-gate size_t sz; 2837*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 2838*7c478bd9Sstevel@tonic-gate 2839*7c478bd9Sstevel@tonic-gate assert(page_sz > 0); 2840*7c478bd9Sstevel@tonic-gate 2841*7c478bd9Sstevel@tonic-gate /* Take "NIL" element into account */ 2842*7c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) { 2843*7c478bd9Sstevel@tonic-gate count[i] = 1; 2844*7c478bd9Sstevel@tonic-gate } 2845*7c478bd9Sstevel@tonic-gate 2846*7c478bd9Sstevel@tonic-gate count_node(CACHE(hdp)->root, count); 2847*7c478bd9Sstevel@tonic-gate 2848*7c478bd9Sstevel@tonic-gate for (clp = CACHE(hdp)->dngl; clp != NULL; clp = clp->sib) { 2849*7c478bd9Sstevel@tonic-gate count_link(clp, count); 2850*7c478bd9Sstevel@tonic-gate } 2851*7c478bd9Sstevel@tonic-gate 2852*7c478bd9Sstevel@tonic-gate sz = ((HDR_LEN / page_sz) + 1) * page_sz; 2853*7c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) { 2854*7c478bd9Sstevel@tonic-gate assert(count[i] >= 1); 2855*7c478bd9Sstevel@tonic-gate sz += (((count[i] * elem_sizes[i]) / page_sz) + 1) * page_sz; 2856*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "N[%u]=%u\n", i, count[i]); 2857*7c478bd9Sstevel@tonic-gate } 2858*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "DB size=%lu\n", (ulong_t)sz); 2859*7c478bd9Sstevel@tonic-gate 2860*7c478bd9Sstevel@tonic-gate return (sz); 2861*7c478bd9Sstevel@tonic-gate } 2862*7c478bd9Sstevel@tonic-gate 2863*7c478bd9Sstevel@tonic-gate 2864*7c478bd9Sstevel@tonic-gate static void 2865*7c478bd9Sstevel@tonic-gate count_node(cache_node_t *cnp, uint32_t *count) 2866*7c478bd9Sstevel@tonic-gate { 2867*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 2868*7c478bd9Sstevel@tonic-gate 2869*7c478bd9Sstevel@tonic-gate if (cnp == NULL) 2870*7c478bd9Sstevel@tonic-gate return; 2871*7c478bd9Sstevel@tonic-gate 2872*7c478bd9Sstevel@tonic-gate count[DB_NODE]++; 2873*7c478bd9Sstevel@tonic-gate count_string(cnp->path, count); 2874*7c478bd9Sstevel@tonic-gate 2875*7c478bd9Sstevel@tonic-gate for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) { 2876*7c478bd9Sstevel@tonic-gate count_minor(cmnp, count); 2877*7c478bd9Sstevel@tonic-gate } 2878*7c478bd9Sstevel@tonic-gate 2879*7c478bd9Sstevel@tonic-gate for (cnp = cnp->child; cnp != NULL; cnp = cnp->sib) { 2880*7c478bd9Sstevel@tonic-gate count_node(cnp, count); 2881*7c478bd9Sstevel@tonic-gate } 2882*7c478bd9Sstevel@tonic-gate 2883*7c478bd9Sstevel@tonic-gate } 2884*7c478bd9Sstevel@tonic-gate 2885*7c478bd9Sstevel@tonic-gate static void 2886*7c478bd9Sstevel@tonic-gate count_minor(cache_minor_t *cmnp, uint32_t *count) 2887*7c478bd9Sstevel@tonic-gate { 2888*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 2889*7c478bd9Sstevel@tonic-gate 2890*7c478bd9Sstevel@tonic-gate if (cmnp == NULL) 2891*7c478bd9Sstevel@tonic-gate return; 2892*7c478bd9Sstevel@tonic-gate 2893*7c478bd9Sstevel@tonic-gate count[DB_MINOR]++; 2894*7c478bd9Sstevel@tonic-gate count_string(cmnp->name, count); 2895*7c478bd9Sstevel@tonic-gate count_string(cmnp->nodetype, count); 2896*7c478bd9Sstevel@tonic-gate 2897*7c478bd9Sstevel@tonic-gate for (clp = cmnp->link; clp != NULL; clp = clp->sib) { 2898*7c478bd9Sstevel@tonic-gate count_link(clp, count); 2899*7c478bd9Sstevel@tonic-gate } 2900*7c478bd9Sstevel@tonic-gate } 2901*7c478bd9Sstevel@tonic-gate 2902*7c478bd9Sstevel@tonic-gate static void 2903*7c478bd9Sstevel@tonic-gate count_link(cache_link_t *clp, uint32_t *count) 2904*7c478bd9Sstevel@tonic-gate { 2905*7c478bd9Sstevel@tonic-gate if (clp == NULL) 2906*7c478bd9Sstevel@tonic-gate return; 2907*7c478bd9Sstevel@tonic-gate 2908*7c478bd9Sstevel@tonic-gate count[DB_LINK]++; 2909*7c478bd9Sstevel@tonic-gate count_string(clp->path, count); 2910*7c478bd9Sstevel@tonic-gate count_string(clp->content, count); 2911*7c478bd9Sstevel@tonic-gate } 2912*7c478bd9Sstevel@tonic-gate 2913*7c478bd9Sstevel@tonic-gate 2914*7c478bd9Sstevel@tonic-gate static void 2915*7c478bd9Sstevel@tonic-gate count_string(const char *str, uint32_t *count) 2916*7c478bd9Sstevel@tonic-gate { 2917*7c478bd9Sstevel@tonic-gate if (str == NULL) { 2918*7c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "count_string: NULL argument\n"); 2919*7c478bd9Sstevel@tonic-gate return; 2920*7c478bd9Sstevel@tonic-gate } 2921*7c478bd9Sstevel@tonic-gate 2922*7c478bd9Sstevel@tonic-gate count[DB_STR] += strlen(str) + 1; 2923*7c478bd9Sstevel@tonic-gate } 2924*7c478bd9Sstevel@tonic-gate 2925*7c478bd9Sstevel@tonic-gate static uint_t 2926*7c478bd9Sstevel@tonic-gate hashfn(struct di_devlink_handle *hdp, const char *str) 2927*7c478bd9Sstevel@tonic-gate { 2928*7c478bd9Sstevel@tonic-gate const char *cp; 2929*7c478bd9Sstevel@tonic-gate ulong_t hval = 0; 2930*7c478bd9Sstevel@tonic-gate 2931*7c478bd9Sstevel@tonic-gate if (str == NULL) { 2932*7c478bd9Sstevel@tonic-gate return (0); 2933*7c478bd9Sstevel@tonic-gate } 2934*7c478bd9Sstevel@tonic-gate 2935*7c478bd9Sstevel@tonic-gate assert(CACHE(hdp)->hash_sz >= MIN_HASH_SIZE); 2936*7c478bd9Sstevel@tonic-gate 2937*7c478bd9Sstevel@tonic-gate for (cp = str; *cp != '\0'; cp++) { 2938*7c478bd9Sstevel@tonic-gate hval += *cp; 2939*7c478bd9Sstevel@tonic-gate } 2940*7c478bd9Sstevel@tonic-gate 2941*7c478bd9Sstevel@tonic-gate return (hval % CACHE(hdp)->hash_sz); 2942*7c478bd9Sstevel@tonic-gate } 2943*7c478bd9Sstevel@tonic-gate 2944*7c478bd9Sstevel@tonic-gate static int 2945*7c478bd9Sstevel@tonic-gate enter_update_lock(struct di_devlink_handle *hdp) 2946*7c478bd9Sstevel@tonic-gate { 2947*7c478bd9Sstevel@tonic-gate int i, fd, rv; 2948*7c478bd9Sstevel@tonic-gate struct flock lock; 2949*7c478bd9Sstevel@tonic-gate char lockfile[PATH_MAX]; 2950*7c478bd9Sstevel@tonic-gate 2951*7c478bd9Sstevel@tonic-gate assert(hdp->lock_fd < 0); 2952*7c478bd9Sstevel@tonic-gate 2953*7c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_LOCK, lockfile, sizeof (lockfile)); 2954*7c478bd9Sstevel@tonic-gate 2955*7c478bd9Sstevel@tonic-gate /* 2956*7c478bd9Sstevel@tonic-gate * Record locks are per-process. Protect against multiple threads. 2957*7c478bd9Sstevel@tonic-gate */ 2958*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&update_mutex); 2959*7c478bd9Sstevel@tonic-gate 2960*7c478bd9Sstevel@tonic-gate if ((fd = open(lockfile, O_RDWR|O_CREAT, DB_LOCK_PERMS)) < 0) { 2961*7c478bd9Sstevel@tonic-gate goto error; 2962*7c478bd9Sstevel@tonic-gate } 2963*7c478bd9Sstevel@tonic-gate 2964*7c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 2965*7c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 2966*7c478bd9Sstevel@tonic-gate lock.l_start = 0; 2967*7c478bd9Sstevel@tonic-gate lock.l_len = 0; 2968*7c478bd9Sstevel@tonic-gate 2969*7c478bd9Sstevel@tonic-gate i = 1; 2970*7c478bd9Sstevel@tonic-gate while ((rv = fcntl(fd, F_SETLKW, &lock)) == -1 && errno == EINTR) { 2971*7c478bd9Sstevel@tonic-gate if (i < MAX_LOCK_RETRY) { 2972*7c478bd9Sstevel@tonic-gate i++; 2973*7c478bd9Sstevel@tonic-gate } else { 2974*7c478bd9Sstevel@tonic-gate break; 2975*7c478bd9Sstevel@tonic-gate } 2976*7c478bd9Sstevel@tonic-gate } 2977*7c478bd9Sstevel@tonic-gate 2978*7c478bd9Sstevel@tonic-gate if (rv == 0) { 2979*7c478bd9Sstevel@tonic-gate hdp->lock_fd = fd; 2980*7c478bd9Sstevel@tonic-gate return (0); 2981*7c478bd9Sstevel@tonic-gate } else { 2982*7c478bd9Sstevel@tonic-gate (void) close(fd); 2983*7c478bd9Sstevel@tonic-gate } 2984*7c478bd9Sstevel@tonic-gate 2985*7c478bd9Sstevel@tonic-gate error: 2986*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&update_mutex); 2987*7c478bd9Sstevel@tonic-gate 2988*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "lockfile(%s): lock failed: %s\n", lockfile, 2989*7c478bd9Sstevel@tonic-gate strerror(errno)); 2990*7c478bd9Sstevel@tonic-gate return (-1); 2991*7c478bd9Sstevel@tonic-gate } 2992*7c478bd9Sstevel@tonic-gate 2993*7c478bd9Sstevel@tonic-gate /* 2994*7c478bd9Sstevel@tonic-gate * Close and re-open lock file every time so that it is recreated if deleted. 2995*7c478bd9Sstevel@tonic-gate */ 2996*7c478bd9Sstevel@tonic-gate static void 2997*7c478bd9Sstevel@tonic-gate exit_update_lock(struct di_devlink_handle *hdp) 2998*7c478bd9Sstevel@tonic-gate { 2999*7c478bd9Sstevel@tonic-gate struct flock unlock; 3000*7c478bd9Sstevel@tonic-gate 3001*7c478bd9Sstevel@tonic-gate if (hdp->lock_fd < 0) { 3002*7c478bd9Sstevel@tonic-gate return; 3003*7c478bd9Sstevel@tonic-gate } 3004*7c478bd9Sstevel@tonic-gate 3005*7c478bd9Sstevel@tonic-gate unlock.l_type = F_UNLCK; 3006*7c478bd9Sstevel@tonic-gate unlock.l_whence = SEEK_SET; 3007*7c478bd9Sstevel@tonic-gate unlock.l_start = 0; 3008*7c478bd9Sstevel@tonic-gate unlock.l_len = 0; 3009*7c478bd9Sstevel@tonic-gate 3010*7c478bd9Sstevel@tonic-gate if (fcntl(hdp->lock_fd, F_SETLK, &unlock) == -1) { 3011*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "update lockfile: unlock failed: %s\n", 3012*7c478bd9Sstevel@tonic-gate strerror(errno)); 3013*7c478bd9Sstevel@tonic-gate } 3014*7c478bd9Sstevel@tonic-gate 3015*7c478bd9Sstevel@tonic-gate (void) close(hdp->lock_fd); 3016*7c478bd9Sstevel@tonic-gate 3017*7c478bd9Sstevel@tonic-gate hdp->lock_fd = -1; 3018*7c478bd9Sstevel@tonic-gate 3019*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&update_mutex); 3020*7c478bd9Sstevel@tonic-gate } 3021*7c478bd9Sstevel@tonic-gate 3022*7c478bd9Sstevel@tonic-gate /* 3023*7c478bd9Sstevel@tonic-gate * returns 1 if contents is a minor node in /devices. 3024*7c478bd9Sstevel@tonic-gate * If mn_root is not NULL, mn_root is set to: 3025*7c478bd9Sstevel@tonic-gate * if contents is a /dev node, mn_root = contents 3026*7c478bd9Sstevel@tonic-gate * OR 3027*7c478bd9Sstevel@tonic-gate * if contents is a /devices node, mn_root set to the '/' 3028*7c478bd9Sstevel@tonic-gate * following /devices. 3029*7c478bd9Sstevel@tonic-gate */ 3030*7c478bd9Sstevel@tonic-gate int 3031*7c478bd9Sstevel@tonic-gate is_minor_node(const char *contents, const char **mn_root) 3032*7c478bd9Sstevel@tonic-gate { 3033*7c478bd9Sstevel@tonic-gate char *ptr, *prefix; 3034*7c478bd9Sstevel@tonic-gate 3035*7c478bd9Sstevel@tonic-gate prefix = "../devices/"; 3036*7c478bd9Sstevel@tonic-gate 3037*7c478bd9Sstevel@tonic-gate if ((ptr = strstr(contents, prefix)) != NULL) { 3038*7c478bd9Sstevel@tonic-gate 3039*7c478bd9Sstevel@tonic-gate /* mn_root should point to the / following /devices */ 3040*7c478bd9Sstevel@tonic-gate if (mn_root != NULL) { 3041*7c478bd9Sstevel@tonic-gate *mn_root = ptr += strlen(prefix) - 1; 3042*7c478bd9Sstevel@tonic-gate } 3043*7c478bd9Sstevel@tonic-gate return (1); 3044*7c478bd9Sstevel@tonic-gate } 3045*7c478bd9Sstevel@tonic-gate 3046*7c478bd9Sstevel@tonic-gate prefix = "/devices/"; 3047*7c478bd9Sstevel@tonic-gate 3048*7c478bd9Sstevel@tonic-gate if (strncmp(contents, prefix, strlen(prefix)) == 0) { 3049*7c478bd9Sstevel@tonic-gate 3050*7c478bd9Sstevel@tonic-gate /* mn_root should point to the / following /devices/ */ 3051*7c478bd9Sstevel@tonic-gate if (mn_root != NULL) { 3052*7c478bd9Sstevel@tonic-gate *mn_root = contents + strlen(prefix) - 1; 3053*7c478bd9Sstevel@tonic-gate } 3054*7c478bd9Sstevel@tonic-gate return (1); 3055*7c478bd9Sstevel@tonic-gate } 3056*7c478bd9Sstevel@tonic-gate 3057*7c478bd9Sstevel@tonic-gate if (mn_root != NULL) { 3058*7c478bd9Sstevel@tonic-gate *mn_root = contents; 3059*7c478bd9Sstevel@tonic-gate } 3060*7c478bd9Sstevel@tonic-gate return (0); 3061*7c478bd9Sstevel@tonic-gate } 3062*7c478bd9Sstevel@tonic-gate 3063*7c478bd9Sstevel@tonic-gate static int 3064*7c478bd9Sstevel@tonic-gate s_readlink(const char *link, char *buf, size_t blen) 3065*7c478bd9Sstevel@tonic-gate { 3066*7c478bd9Sstevel@tonic-gate int rv; 3067*7c478bd9Sstevel@tonic-gate 3068*7c478bd9Sstevel@tonic-gate if ((rv = readlink(link, buf, blen)) == -1) 3069*7c478bd9Sstevel@tonic-gate goto bad; 3070*7c478bd9Sstevel@tonic-gate 3071*7c478bd9Sstevel@tonic-gate if (rv >= blen && buf[blen - 1] != '\0') { 3072*7c478bd9Sstevel@tonic-gate errno = ENAMETOOLONG; 3073*7c478bd9Sstevel@tonic-gate goto bad; 3074*7c478bd9Sstevel@tonic-gate } else if (rv < blen) { 3075*7c478bd9Sstevel@tonic-gate buf[rv] = '\0'; 3076*7c478bd9Sstevel@tonic-gate } 3077*7c478bd9Sstevel@tonic-gate 3078*7c478bd9Sstevel@tonic-gate return (0); 3079*7c478bd9Sstevel@tonic-gate bad: 3080*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "s_readlink: %s: failed: %s\n", 3081*7c478bd9Sstevel@tonic-gate link, strerror(errno)); 3082*7c478bd9Sstevel@tonic-gate return (-1); 3083*7c478bd9Sstevel@tonic-gate } 3084*7c478bd9Sstevel@tonic-gate 3085*7c478bd9Sstevel@tonic-gate /* 3086*7c478bd9Sstevel@tonic-gate * Synchronous link creation interface routines 3087*7c478bd9Sstevel@tonic-gate * The scope of the operation is determined by the "name" arg. 3088*7c478bd9Sstevel@tonic-gate * "name" can be NULL, a driver name or a devfs pathname (without /devices) 3089*7c478bd9Sstevel@tonic-gate * 3090*7c478bd9Sstevel@tonic-gate * "name" creates 3091*7c478bd9Sstevel@tonic-gate * ====== ======= 3092*7c478bd9Sstevel@tonic-gate * 3093*7c478bd9Sstevel@tonic-gate * NULL => All devlinks in system 3094*7c478bd9Sstevel@tonic-gate * <driver> => devlinks for named driver 3095*7c478bd9Sstevel@tonic-gate * /pci@1 => devlinks for subtree rooted at pci@1 3096*7c478bd9Sstevel@tonic-gate * /pseudo/foo@0:X => devlinks for minor X 3097*7c478bd9Sstevel@tonic-gate * 3098*7c478bd9Sstevel@tonic-gate * devlink_create() returns 0 on success or an errno value on failure 3099*7c478bd9Sstevel@tonic-gate */ 3100*7c478bd9Sstevel@tonic-gate 3101*7c478bd9Sstevel@tonic-gate #define MAX_DAEMON_ATTEMPTS 2 3102*7c478bd9Sstevel@tonic-gate 3103*7c478bd9Sstevel@tonic-gate static int 3104*7c478bd9Sstevel@tonic-gate devlink_create(const char *root, const char *name) 3105*7c478bd9Sstevel@tonic-gate { 3106*7c478bd9Sstevel@tonic-gate int i; 3107*7c478bd9Sstevel@tonic-gate struct dca_off dca; 3108*7c478bd9Sstevel@tonic-gate 3109*7c478bd9Sstevel@tonic-gate assert(root); 3110*7c478bd9Sstevel@tonic-gate 3111*7c478bd9Sstevel@tonic-gate /* 3112*7c478bd9Sstevel@tonic-gate * Convert name into arg for door_call 3113*7c478bd9Sstevel@tonic-gate */ 3114*7c478bd9Sstevel@tonic-gate if (dca_init(name, &dca) != 0) 3115*7c478bd9Sstevel@tonic-gate return (EINVAL); 3116*7c478bd9Sstevel@tonic-gate 3117*7c478bd9Sstevel@tonic-gate /* 3118*7c478bd9Sstevel@tonic-gate * Attempt to use the daemon first 3119*7c478bd9Sstevel@tonic-gate */ 3120*7c478bd9Sstevel@tonic-gate i = 0; 3121*7c478bd9Sstevel@tonic-gate do { 3122*7c478bd9Sstevel@tonic-gate daemon_call(root, &dca); 3123*7c478bd9Sstevel@tonic-gate 3124*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "daemon_call() retval=%d\n", dca.dca_error); 3125*7c478bd9Sstevel@tonic-gate 3126*7c478bd9Sstevel@tonic-gate /* 3127*7c478bd9Sstevel@tonic-gate * Retry only if door server isn't running 3128*7c478bd9Sstevel@tonic-gate */ 3129*7c478bd9Sstevel@tonic-gate if (dca.dca_error != ENOENT && dca.dca_error != EBADF) { 3130*7c478bd9Sstevel@tonic-gate return (dca.dca_error); 3131*7c478bd9Sstevel@tonic-gate } 3132*7c478bd9Sstevel@tonic-gate 3133*7c478bd9Sstevel@tonic-gate dca.dca_error = 0; 3134*7c478bd9Sstevel@tonic-gate 3135*7c478bd9Sstevel@tonic-gate /* 3136*7c478bd9Sstevel@tonic-gate * To improve performance defer this check until the first 3137*7c478bd9Sstevel@tonic-gate * failure. Safe to defer as door server checks perms. 3138*7c478bd9Sstevel@tonic-gate */ 3139*7c478bd9Sstevel@tonic-gate if (geteuid() != 0) 3140*7c478bd9Sstevel@tonic-gate return (EPERM); 3141*7c478bd9Sstevel@tonic-gate /* 3142*7c478bd9Sstevel@tonic-gate * Daemon may not be running. Try to start it. 3143*7c478bd9Sstevel@tonic-gate */ 3144*7c478bd9Sstevel@tonic-gate } while ((++i < MAX_DAEMON_ATTEMPTS) && start_daemon(root) == 0); 3145*7c478bd9Sstevel@tonic-gate 3146*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "devlink_create: can't start daemon\n"); 3147*7c478bd9Sstevel@tonic-gate 3148*7c478bd9Sstevel@tonic-gate assert(dca.dca_error == 0); 3149*7c478bd9Sstevel@tonic-gate 3150*7c478bd9Sstevel@tonic-gate /* 3151*7c478bd9Sstevel@tonic-gate * If the daemon cannot be started execute the devfsadm command. 3152*7c478bd9Sstevel@tonic-gate */ 3153*7c478bd9Sstevel@tonic-gate exec_cmd(root, &dca); 3154*7c478bd9Sstevel@tonic-gate 3155*7c478bd9Sstevel@tonic-gate return (dca.dca_error); 3156*7c478bd9Sstevel@tonic-gate } 3157*7c478bd9Sstevel@tonic-gate 3158*7c478bd9Sstevel@tonic-gate /* 3159*7c478bd9Sstevel@tonic-gate * The "name" member of "struct dca" contains data in the following order 3160*7c478bd9Sstevel@tonic-gate * root'\0'minor'\0'driver'\0' 3161*7c478bd9Sstevel@tonic-gate * The root component is always present at offset 0 in the "name" field. 3162*7c478bd9Sstevel@tonic-gate * The driver and minor are optional. If present they have a non-zero 3163*7c478bd9Sstevel@tonic-gate * offset in the "name" member. 3164*7c478bd9Sstevel@tonic-gate */ 3165*7c478bd9Sstevel@tonic-gate static int 3166*7c478bd9Sstevel@tonic-gate dca_init(const char *name, struct dca_off *dcp) 3167*7c478bd9Sstevel@tonic-gate { 3168*7c478bd9Sstevel@tonic-gate char *cp; 3169*7c478bd9Sstevel@tonic-gate 3170*7c478bd9Sstevel@tonic-gate dcp->dca_root = 0; 3171*7c478bd9Sstevel@tonic-gate dcp->dca_minor = 0; 3172*7c478bd9Sstevel@tonic-gate dcp->dca_driver = 0; 3173*7c478bd9Sstevel@tonic-gate dcp->dca_error = 0; 3174*7c478bd9Sstevel@tonic-gate dcp->dca_flags = 0; 3175*7c478bd9Sstevel@tonic-gate dcp->dca_name[0] = '\0'; 3176*7c478bd9Sstevel@tonic-gate 3177*7c478bd9Sstevel@tonic-gate name = name ? name : "/"; 3178*7c478bd9Sstevel@tonic-gate 3179*7c478bd9Sstevel@tonic-gate /* 3180*7c478bd9Sstevel@tonic-gate * Check if name is a driver name 3181*7c478bd9Sstevel@tonic-gate */ 3182*7c478bd9Sstevel@tonic-gate if (*name != '/') { 3183*7c478bd9Sstevel@tonic-gate (void) snprintf(dcp->dca_name, sizeof (dcp->dca_name), 3184*7c478bd9Sstevel@tonic-gate "/ %s", name); 3185*7c478bd9Sstevel@tonic-gate dcp->dca_root = 0; 3186*7c478bd9Sstevel@tonic-gate *(dcp->dca_name + 1) = '\0'; 3187*7c478bd9Sstevel@tonic-gate dcp->dca_driver = 2; 3188*7c478bd9Sstevel@tonic-gate return (0); 3189*7c478bd9Sstevel@tonic-gate } 3190*7c478bd9Sstevel@tonic-gate 3191*7c478bd9Sstevel@tonic-gate (void) snprintf(dcp->dca_name, sizeof (dcp->dca_name), "%s", name); 3192*7c478bd9Sstevel@tonic-gate 3193*7c478bd9Sstevel@tonic-gate /* 3194*7c478bd9Sstevel@tonic-gate * "/devices" not allowed in devfs pathname 3195*7c478bd9Sstevel@tonic-gate */ 3196*7c478bd9Sstevel@tonic-gate if (is_minor_node(name, NULL)) 3197*7c478bd9Sstevel@tonic-gate return (-1); 3198*7c478bd9Sstevel@tonic-gate 3199*7c478bd9Sstevel@tonic-gate dcp->dca_root = 0; 3200*7c478bd9Sstevel@tonic-gate if (cp = strrchr(dcp->dca_name, ':')) { 3201*7c478bd9Sstevel@tonic-gate *cp++ = '\0'; 3202*7c478bd9Sstevel@tonic-gate dcp->dca_minor = cp - dcp->dca_name; 3203*7c478bd9Sstevel@tonic-gate } 3204*7c478bd9Sstevel@tonic-gate 3205*7c478bd9Sstevel@tonic-gate return (0); 3206*7c478bd9Sstevel@tonic-gate } 3207*7c478bd9Sstevel@tonic-gate 3208*7c478bd9Sstevel@tonic-gate 3209*7c478bd9Sstevel@tonic-gate #define DAEMON_STARTUP_TIME 1 /* 1 second. This may need to be adjusted */ 3210*7c478bd9Sstevel@tonic-gate 3211*7c478bd9Sstevel@tonic-gate static void 3212*7c478bd9Sstevel@tonic-gate daemon_call(const char *root, struct dca_off *dcp) 3213*7c478bd9Sstevel@tonic-gate { 3214*7c478bd9Sstevel@tonic-gate door_arg_t arg; 3215*7c478bd9Sstevel@tonic-gate int fd, door_error; 3216*7c478bd9Sstevel@tonic-gate sigset_t oset, nset; 3217*7c478bd9Sstevel@tonic-gate char synch_door[PATH_MAX]; 3218*7c478bd9Sstevel@tonic-gate 3219*7c478bd9Sstevel@tonic-gate (void) snprintf(synch_door, sizeof (synch_door), 3220*7c478bd9Sstevel@tonic-gate "%s/dev/%s", root, DEVFSADM_SYNCH_DOOR); 3221*7c478bd9Sstevel@tonic-gate 3222*7c478bd9Sstevel@tonic-gate if ((fd = open(synch_door, O_RDONLY)) == -1) { 3223*7c478bd9Sstevel@tonic-gate dcp->dca_error = errno; 3224*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "open of %s failed: %s\n", 3225*7c478bd9Sstevel@tonic-gate synch_door, strerror(errno)); 3226*7c478bd9Sstevel@tonic-gate return; 3227*7c478bd9Sstevel@tonic-gate } 3228*7c478bd9Sstevel@tonic-gate 3229*7c478bd9Sstevel@tonic-gate arg.data_ptr = (char *)dcp; 3230*7c478bd9Sstevel@tonic-gate arg.data_size = sizeof (*dcp); 3231*7c478bd9Sstevel@tonic-gate arg.desc_ptr = NULL; 3232*7c478bd9Sstevel@tonic-gate arg.desc_num = 0; 3233*7c478bd9Sstevel@tonic-gate arg.rbuf = (char *)dcp; 3234*7c478bd9Sstevel@tonic-gate arg.rsize = sizeof (*dcp); 3235*7c478bd9Sstevel@tonic-gate 3236*7c478bd9Sstevel@tonic-gate /* 3237*7c478bd9Sstevel@tonic-gate * Block signals to this thread until door call 3238*7c478bd9Sstevel@tonic-gate * completes. 3239*7c478bd9Sstevel@tonic-gate */ 3240*7c478bd9Sstevel@tonic-gate (void) sigfillset(&nset); 3241*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&oset); 3242*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &nset, &oset); 3243*7c478bd9Sstevel@tonic-gate if (door_call(fd, &arg)) { 3244*7c478bd9Sstevel@tonic-gate door_error = 1; 3245*7c478bd9Sstevel@tonic-gate dcp->dca_error = errno; 3246*7c478bd9Sstevel@tonic-gate } 3247*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oset, NULL); 3248*7c478bd9Sstevel@tonic-gate 3249*7c478bd9Sstevel@tonic-gate (void) close(fd); 3250*7c478bd9Sstevel@tonic-gate 3251*7c478bd9Sstevel@tonic-gate if (door_error) 3252*7c478bd9Sstevel@tonic-gate return; 3253*7c478bd9Sstevel@tonic-gate 3254*7c478bd9Sstevel@tonic-gate assert(arg.data_ptr); 3255*7c478bd9Sstevel@tonic-gate 3256*7c478bd9Sstevel@tonic-gate /*LINTED*/ 3257*7c478bd9Sstevel@tonic-gate dcp->dca_error = ((struct dca_off *)arg.data_ptr)->dca_error; 3258*7c478bd9Sstevel@tonic-gate 3259*7c478bd9Sstevel@tonic-gate /* 3260*7c478bd9Sstevel@tonic-gate * The doors interface may return data in a different buffer 3261*7c478bd9Sstevel@tonic-gate * If that happens, deallocate buffer via munmap() 3262*7c478bd9Sstevel@tonic-gate */ 3263*7c478bd9Sstevel@tonic-gate if (arg.rbuf != (char *)dcp) 3264*7c478bd9Sstevel@tonic-gate (void) munmap(arg.rbuf, arg.rsize); 3265*7c478bd9Sstevel@tonic-gate } 3266*7c478bd9Sstevel@tonic-gate 3267*7c478bd9Sstevel@tonic-gate #define DEVFSADM_PATH "/usr/sbin/devfsadm" 3268*7c478bd9Sstevel@tonic-gate #define DEVFSADM "devfsadm" 3269*7c478bd9Sstevel@tonic-gate 3270*7c478bd9Sstevel@tonic-gate #define DEVFSADMD_PATH "/usr/lib/devfsadm/devfsadmd" 3271*7c478bd9Sstevel@tonic-gate #define DEVFSADM_DAEMON "devfsadmd" 3272*7c478bd9Sstevel@tonic-gate 3273*7c478bd9Sstevel@tonic-gate static int 3274*7c478bd9Sstevel@tonic-gate start_daemon(const char *root) 3275*7c478bd9Sstevel@tonic-gate { 3276*7c478bd9Sstevel@tonic-gate int rv, i = 0; 3277*7c478bd9Sstevel@tonic-gate char *argv[20]; 3278*7c478bd9Sstevel@tonic-gate 3279*7c478bd9Sstevel@tonic-gate argv[i++] = DEVFSADM_DAEMON; 3280*7c478bd9Sstevel@tonic-gate if (strcmp(root, "/")) { 3281*7c478bd9Sstevel@tonic-gate argv[i++] = "-r"; 3282*7c478bd9Sstevel@tonic-gate argv[i++] = (char *)root; 3283*7c478bd9Sstevel@tonic-gate } 3284*7c478bd9Sstevel@tonic-gate argv[i++] = NULL; 3285*7c478bd9Sstevel@tonic-gate 3286*7c478bd9Sstevel@tonic-gate rv = do_exec(DEVFSADMD_PATH, argv); 3287*7c478bd9Sstevel@tonic-gate 3288*7c478bd9Sstevel@tonic-gate (void) sleep(DAEMON_STARTUP_TIME); 3289*7c478bd9Sstevel@tonic-gate 3290*7c478bd9Sstevel@tonic-gate return (rv); 3291*7c478bd9Sstevel@tonic-gate } 3292*7c478bd9Sstevel@tonic-gate 3293*7c478bd9Sstevel@tonic-gate static void 3294*7c478bd9Sstevel@tonic-gate exec_cmd(const char *root, struct dca_off *dcp) 3295*7c478bd9Sstevel@tonic-gate { 3296*7c478bd9Sstevel@tonic-gate int i; 3297*7c478bd9Sstevel@tonic-gate char *argv[20]; 3298*7c478bd9Sstevel@tonic-gate 3299*7c478bd9Sstevel@tonic-gate i = 0; 3300*7c478bd9Sstevel@tonic-gate argv[i++] = DEVFSADM; 3301*7c478bd9Sstevel@tonic-gate 3302*7c478bd9Sstevel@tonic-gate /* 3303*7c478bd9Sstevel@tonic-gate * Load drivers only if -i is specified 3304*7c478bd9Sstevel@tonic-gate */ 3305*7c478bd9Sstevel@tonic-gate if (dcp->dca_driver) { 3306*7c478bd9Sstevel@tonic-gate argv[i++] = "-i"; 3307*7c478bd9Sstevel@tonic-gate argv[i++] = &dcp->dca_name[dcp->dca_driver]; 3308*7c478bd9Sstevel@tonic-gate } else { 3309*7c478bd9Sstevel@tonic-gate argv[i++] = "-n"; 3310*7c478bd9Sstevel@tonic-gate } 3311*7c478bd9Sstevel@tonic-gate 3312*7c478bd9Sstevel@tonic-gate if (root != NULL && strcmp(root, "/") != 0) { 3313*7c478bd9Sstevel@tonic-gate argv[i++] = "-r"; 3314*7c478bd9Sstevel@tonic-gate argv[i++] = (char *)root; 3315*7c478bd9Sstevel@tonic-gate } 3316*7c478bd9Sstevel@tonic-gate 3317*7c478bd9Sstevel@tonic-gate argv[i] = NULL; 3318*7c478bd9Sstevel@tonic-gate 3319*7c478bd9Sstevel@tonic-gate if (do_exec(DEVFSADM_PATH, argv)) 3320*7c478bd9Sstevel@tonic-gate dcp->dca_error = errno; 3321*7c478bd9Sstevel@tonic-gate } 3322*7c478bd9Sstevel@tonic-gate 3323*7c478bd9Sstevel@tonic-gate static int 3324*7c478bd9Sstevel@tonic-gate do_exec(const char *path, char *const argv[]) 3325*7c478bd9Sstevel@tonic-gate { 3326*7c478bd9Sstevel@tonic-gate int i; 3327*7c478bd9Sstevel@tonic-gate pid_t cpid; 3328*7c478bd9Sstevel@tonic-gate 3329*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 3330*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "Executing %s\n\tArgument list:", path); 3331*7c478bd9Sstevel@tonic-gate for (i = 0; argv[i] != NULL; i++) { 3332*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, " %s", argv[i]); 3333*7c478bd9Sstevel@tonic-gate } 3334*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "\n"); 3335*7c478bd9Sstevel@tonic-gate #endif 3336*7c478bd9Sstevel@tonic-gate 3337*7c478bd9Sstevel@tonic-gate if ((cpid = fork1()) == -1) { 3338*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "fork1 failed: %s\n", strerror(errno)); 3339*7c478bd9Sstevel@tonic-gate return (-1); 3340*7c478bd9Sstevel@tonic-gate } 3341*7c478bd9Sstevel@tonic-gate 3342*7c478bd9Sstevel@tonic-gate if (cpid == 0) { /* child process */ 3343*7c478bd9Sstevel@tonic-gate int fd; 3344*7c478bd9Sstevel@tonic-gate 3345*7c478bd9Sstevel@tonic-gate if ((fd = open("/dev/null", O_RDWR)) >= 0) { 3346*7c478bd9Sstevel@tonic-gate (void) dup2(fd, fileno(stdout)); 3347*7c478bd9Sstevel@tonic-gate (void) dup2(fd, fileno(stderr)); 3348*7c478bd9Sstevel@tonic-gate (void) close(fd); 3349*7c478bd9Sstevel@tonic-gate 3350*7c478bd9Sstevel@tonic-gate (void) execv(path, argv); 3351*7c478bd9Sstevel@tonic-gate } else { 3352*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "open of /dev/null failed: %s\n", 3353*7c478bd9Sstevel@tonic-gate strerror(errno)); 3354*7c478bd9Sstevel@tonic-gate } 3355*7c478bd9Sstevel@tonic-gate 3356*7c478bd9Sstevel@tonic-gate _exit(-1); 3357*7c478bd9Sstevel@tonic-gate } 3358*7c478bd9Sstevel@tonic-gate 3359*7c478bd9Sstevel@tonic-gate /* Parent process */ 3360*7c478bd9Sstevel@tonic-gate if (waitpid(cpid, &i, 0) == cpid) { 3361*7c478bd9Sstevel@tonic-gate if (WIFEXITED(i)) { 3362*7c478bd9Sstevel@tonic-gate if (WEXITSTATUS(i) == 0) { 3363*7c478bd9Sstevel@tonic-gate dprintf(DBG_STEP, 3364*7c478bd9Sstevel@tonic-gate "do_exec: child exited normally\n"); 3365*7c478bd9Sstevel@tonic-gate return (0); 3366*7c478bd9Sstevel@tonic-gate } else 3367*7c478bd9Sstevel@tonic-gate errno = EINVAL; 3368*7c478bd9Sstevel@tonic-gate } else { 3369*7c478bd9Sstevel@tonic-gate /* 3370*7c478bd9Sstevel@tonic-gate * The child was interrupted by a signal 3371*7c478bd9Sstevel@tonic-gate */ 3372*7c478bd9Sstevel@tonic-gate errno = EINTR; 3373*7c478bd9Sstevel@tonic-gate } 3374*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "child terminated abnormally: %s\n", 3375*7c478bd9Sstevel@tonic-gate strerror(errno)); 3376*7c478bd9Sstevel@tonic-gate } else { 3377*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "waitpid failed: %s\n", strerror(errno)); 3378*7c478bd9Sstevel@tonic-gate } 3379*7c478bd9Sstevel@tonic-gate 3380*7c478bd9Sstevel@tonic-gate return (-1); 3381*7c478bd9Sstevel@tonic-gate } 3382*7c478bd9Sstevel@tonic-gate 3383*7c478bd9Sstevel@tonic-gate static int 3384*7c478bd9Sstevel@tonic-gate walk_cache_links(di_devlink_handle_t hdp, cache_link_t *clp, link_desc_t *linkp) 3385*7c478bd9Sstevel@tonic-gate { 3386*7c478bd9Sstevel@tonic-gate int i; 3387*7c478bd9Sstevel@tonic-gate 3388*7c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp) || HDL_RDONLY(hdp)); 3389*7c478bd9Sstevel@tonic-gate 3390*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "walk_cache_links: initial link: %s\n", 3391*7c478bd9Sstevel@tonic-gate clp ? clp->path : "<NULL>"); 3392*7c478bd9Sstevel@tonic-gate 3393*7c478bd9Sstevel@tonic-gate /* 3394*7c478bd9Sstevel@tonic-gate * First search the links under the specified minor. On the 3395*7c478bd9Sstevel@tonic-gate * 2nd pass, search the dangling list - secondary links may 3396*7c478bd9Sstevel@tonic-gate * exist on this list since they are not resolved during the 3397*7c478bd9Sstevel@tonic-gate * /dev walk. 3398*7c478bd9Sstevel@tonic-gate */ 3399*7c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 3400*7c478bd9Sstevel@tonic-gate for (; clp != NULL; clp = clp->sib) { 3401*7c478bd9Sstevel@tonic-gate struct di_devlink vlink = {NULL}; 3402*7c478bd9Sstevel@tonic-gate 3403*7c478bd9Sstevel@tonic-gate assert(clp->path[0] != '/'); 3404*7c478bd9Sstevel@tonic-gate 3405*7c478bd9Sstevel@tonic-gate vlink.rel_path = clp->path; 3406*7c478bd9Sstevel@tonic-gate vlink.content = clp->content; 3407*7c478bd9Sstevel@tonic-gate vlink.type = attr2type(clp->attr); 3408*7c478bd9Sstevel@tonic-gate 3409*7c478bd9Sstevel@tonic-gate if (visit_link(hdp, linkp, &vlink) 3410*7c478bd9Sstevel@tonic-gate != DI_WALK_CONTINUE) { 3411*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "walk_cache_links: " 3412*7c478bd9Sstevel@tonic-gate "terminating at link: %s\n", clp->path); 3413*7c478bd9Sstevel@tonic-gate goto out; 3414*7c478bd9Sstevel@tonic-gate } 3415*7c478bd9Sstevel@tonic-gate } 3416*7c478bd9Sstevel@tonic-gate 3417*7c478bd9Sstevel@tonic-gate clp = CACHE(hdp)->dngl; 3418*7c478bd9Sstevel@tonic-gate } 3419*7c478bd9Sstevel@tonic-gate 3420*7c478bd9Sstevel@tonic-gate out: 3421*7c478bd9Sstevel@tonic-gate 3422*7c478bd9Sstevel@tonic-gate /* If i < 2, we terminated the walk prematurely */ 3423*7c478bd9Sstevel@tonic-gate return (i < 2 ? DI_WALK_TERMINATE : DI_WALK_CONTINUE); 3424*7c478bd9Sstevel@tonic-gate } 3425*7c478bd9Sstevel@tonic-gate 3426*7c478bd9Sstevel@tonic-gate static void 3427*7c478bd9Sstevel@tonic-gate walk_all_cache(di_devlink_handle_t hdp, link_desc_t *linkp) 3428*7c478bd9Sstevel@tonic-gate { 3429*7c478bd9Sstevel@tonic-gate int i; 3430*7c478bd9Sstevel@tonic-gate cache_link_t *clp; 3431*7c478bd9Sstevel@tonic-gate 3432*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "walk_all_cache: entered\n"); 3433*7c478bd9Sstevel@tonic-gate 3434*7c478bd9Sstevel@tonic-gate for (i = 0; i < CACHE(hdp)->hash_sz; i++) { 3435*7c478bd9Sstevel@tonic-gate clp = CACHE_HASH(hdp, i); 3436*7c478bd9Sstevel@tonic-gate for (; clp; clp = clp->hash) { 3437*7c478bd9Sstevel@tonic-gate struct di_devlink vlink = {NULL}; 3438*7c478bd9Sstevel@tonic-gate 3439*7c478bd9Sstevel@tonic-gate assert(clp->path[0] != '/'); 3440*7c478bd9Sstevel@tonic-gate 3441*7c478bd9Sstevel@tonic-gate vlink.rel_path = clp->path; 3442*7c478bd9Sstevel@tonic-gate vlink.content = clp->content; 3443*7c478bd9Sstevel@tonic-gate vlink.type = attr2type(clp->attr); 3444*7c478bd9Sstevel@tonic-gate if (visit_link(hdp, linkp, &vlink) != 3445*7c478bd9Sstevel@tonic-gate DI_WALK_CONTINUE) { 3446*7c478bd9Sstevel@tonic-gate dprintf(DBG_INFO, "walk_all_cache: terminating " 3447*7c478bd9Sstevel@tonic-gate "walk at link: %s\n", clp->path); 3448*7c478bd9Sstevel@tonic-gate return; 3449*7c478bd9Sstevel@tonic-gate } 3450*7c478bd9Sstevel@tonic-gate } 3451*7c478bd9Sstevel@tonic-gate } 3452*7c478bd9Sstevel@tonic-gate } 3453*7c478bd9Sstevel@tonic-gate 3454*7c478bd9Sstevel@tonic-gate static void 3455*7c478bd9Sstevel@tonic-gate walk_cache_minor(di_devlink_handle_t hdp, const char *mpath, link_desc_t *linkp) 3456*7c478bd9Sstevel@tonic-gate { 3457*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 3458*7c478bd9Sstevel@tonic-gate 3459*7c478bd9Sstevel@tonic-gate assert(mpath); 3460*7c478bd9Sstevel@tonic-gate 3461*7c478bd9Sstevel@tonic-gate if ((cmnp = lookup_minor(hdp, mpath, NULL, TYPE_CACHE)) != NULL) { 3462*7c478bd9Sstevel@tonic-gate (void) walk_cache_links(hdp, cmnp->link, linkp); 3463*7c478bd9Sstevel@tonic-gate } else { 3464*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "lookup minor failed: %s\n", mpath); 3465*7c478bd9Sstevel@tonic-gate } 3466*7c478bd9Sstevel@tonic-gate } 3467*7c478bd9Sstevel@tonic-gate 3468*7c478bd9Sstevel@tonic-gate static void 3469*7c478bd9Sstevel@tonic-gate walk_cache_node(di_devlink_handle_t hdp, const char *path, link_desc_t *linkp) 3470*7c478bd9Sstevel@tonic-gate { 3471*7c478bd9Sstevel@tonic-gate cache_minor_t *cmnp; 3472*7c478bd9Sstevel@tonic-gate cache_node_t *cnp; 3473*7c478bd9Sstevel@tonic-gate 3474*7c478bd9Sstevel@tonic-gate assert(path); 3475*7c478bd9Sstevel@tonic-gate 3476*7c478bd9Sstevel@tonic-gate if ((cnp = lookup_node(hdp, (char *)path, TYPE_CACHE)) == NULL) { 3477*7c478bd9Sstevel@tonic-gate dprintf(DBG_ERR, "lookup node failed: %s\n", path); 3478*7c478bd9Sstevel@tonic-gate return; 3479*7c478bd9Sstevel@tonic-gate } 3480*7c478bd9Sstevel@tonic-gate 3481*7c478bd9Sstevel@tonic-gate for (cmnp = cnp->minor; cmnp != NULL; cmnp = cmnp->sib) { 3482*7c478bd9Sstevel@tonic-gate if (walk_cache_links(hdp, cmnp->link, linkp) 3483*7c478bd9Sstevel@tonic-gate == DI_WALK_TERMINATE) 3484*7c478bd9Sstevel@tonic-gate break; 3485*7c478bd9Sstevel@tonic-gate } 3486*7c478bd9Sstevel@tonic-gate } 3487*7c478bd9Sstevel@tonic-gate 3488*7c478bd9Sstevel@tonic-gate /* 3489*7c478bd9Sstevel@tonic-gate * Private function 3490*7c478bd9Sstevel@tonic-gate * 3491*7c478bd9Sstevel@tonic-gate * Walk cached links corresponding to the given path. 3492*7c478bd9Sstevel@tonic-gate * 3493*7c478bd9Sstevel@tonic-gate * path path to a node or minor node. 3494*7c478bd9Sstevel@tonic-gate * 3495*7c478bd9Sstevel@tonic-gate * flags specifies the type of devlinks to be selected. 3496*7c478bd9Sstevel@tonic-gate * If DI_PRIMARY_LINK is used, only primary links are selected. 3497*7c478bd9Sstevel@tonic-gate * If DI_SECONDARY_LINK is specified, only secondary links 3498*7c478bd9Sstevel@tonic-gate * are selected. 3499*7c478bd9Sstevel@tonic-gate * If neither flag is specified, all devlinks are selected. 3500*7c478bd9Sstevel@tonic-gate * 3501*7c478bd9Sstevel@tonic-gate * re An extended regular expression in regex(5) format which 3502*7c478bd9Sstevel@tonic-gate * selects the /dev links to be returned. The regular 3503*7c478bd9Sstevel@tonic-gate * expression should use link pathnames relative to 3504*7c478bd9Sstevel@tonic-gate * /dev. i.e. without the leading "/dev/" prefix. 3505*7c478bd9Sstevel@tonic-gate * A NULL value matches all devlinks. 3506*7c478bd9Sstevel@tonic-gate */ 3507*7c478bd9Sstevel@tonic-gate int 3508*7c478bd9Sstevel@tonic-gate di_devlink_cache_walk(di_devlink_handle_t hdp, 3509*7c478bd9Sstevel@tonic-gate const char *re, 3510*7c478bd9Sstevel@tonic-gate const char *path, 3511*7c478bd9Sstevel@tonic-gate uint_t flags, 3512*7c478bd9Sstevel@tonic-gate void *arg, 3513*7c478bd9Sstevel@tonic-gate int (*devlink_callback)(di_devlink_t, void *)) 3514*7c478bd9Sstevel@tonic-gate { 3515*7c478bd9Sstevel@tonic-gate regex_t reg; 3516*7c478bd9Sstevel@tonic-gate link_desc_t linkd = {NULL}; 3517*7c478bd9Sstevel@tonic-gate 3518*7c478bd9Sstevel@tonic-gate if (hdp == NULL || path == NULL || !link_flag(flags) || 3519*7c478bd9Sstevel@tonic-gate !HDL_RDWR(hdp) || devlink_callback == NULL) { 3520*7c478bd9Sstevel@tonic-gate errno = EINVAL; 3521*7c478bd9Sstevel@tonic-gate return (-1); 3522*7c478bd9Sstevel@tonic-gate } 3523*7c478bd9Sstevel@tonic-gate 3524*7c478bd9Sstevel@tonic-gate linkd.flags = flags; 3525*7c478bd9Sstevel@tonic-gate linkd.arg = arg; 3526*7c478bd9Sstevel@tonic-gate linkd.fcn = devlink_callback; 3527*7c478bd9Sstevel@tonic-gate 3528*7c478bd9Sstevel@tonic-gate if (re) { 3529*7c478bd9Sstevel@tonic-gate if (regcomp(®, re, REG_EXTENDED) != 0) 3530*7c478bd9Sstevel@tonic-gate return (-1); 3531*7c478bd9Sstevel@tonic-gate linkd.regp = ® 3532*7c478bd9Sstevel@tonic-gate } 3533*7c478bd9Sstevel@tonic-gate 3534*7c478bd9Sstevel@tonic-gate if (minor_colon(path) == NULL) { 3535*7c478bd9Sstevel@tonic-gate walk_cache_node(hdp, path, &linkd); 3536*7c478bd9Sstevel@tonic-gate } else { 3537*7c478bd9Sstevel@tonic-gate walk_cache_minor(hdp, path, &linkd); 3538*7c478bd9Sstevel@tonic-gate } 3539*7c478bd9Sstevel@tonic-gate 3540*7c478bd9Sstevel@tonic-gate if (re) 3541*7c478bd9Sstevel@tonic-gate regfree(®); 3542*7c478bd9Sstevel@tonic-gate 3543*7c478bd9Sstevel@tonic-gate return (0); 3544*7c478bd9Sstevel@tonic-gate } 3545*7c478bd9Sstevel@tonic-gate 3546*7c478bd9Sstevel@tonic-gate #define DEBUG_ENV_VAR "_DEVLINK_DEBUG" 3547*7c478bd9Sstevel@tonic-gate static int _devlink_debug = -1; 3548*7c478bd9Sstevel@tonic-gate 3549*7c478bd9Sstevel@tonic-gate /* 3550*7c478bd9Sstevel@tonic-gate * debug level is initialized to -1. 3551*7c478bd9Sstevel@tonic-gate * On first call into this routine, debug level is set. 3552*7c478bd9Sstevel@tonic-gate * If debug level is zero, debugging msgs are disabled. 3553*7c478bd9Sstevel@tonic-gate */ 3554*7c478bd9Sstevel@tonic-gate static void 3555*7c478bd9Sstevel@tonic-gate debug_print(debug_level_t msglevel, const char *fmt, va_list ap) 3556*7c478bd9Sstevel@tonic-gate { 3557*7c478bd9Sstevel@tonic-gate char *cp; 3558*7c478bd9Sstevel@tonic-gate int save; 3559*7c478bd9Sstevel@tonic-gate 3560*7c478bd9Sstevel@tonic-gate /* 3561*7c478bd9Sstevel@tonic-gate * We shouldn't be here if debug is disabled 3562*7c478bd9Sstevel@tonic-gate */ 3563*7c478bd9Sstevel@tonic-gate assert(_devlink_debug != 0); 3564*7c478bd9Sstevel@tonic-gate 3565*7c478bd9Sstevel@tonic-gate /* 3566*7c478bd9Sstevel@tonic-gate * Set debug level on first call into this routine 3567*7c478bd9Sstevel@tonic-gate */ 3568*7c478bd9Sstevel@tonic-gate if (_devlink_debug < 0) { 3569*7c478bd9Sstevel@tonic-gate if ((cp = getenv(DEBUG_ENV_VAR)) == NULL) { 3570*7c478bd9Sstevel@tonic-gate _devlink_debug = 0; 3571*7c478bd9Sstevel@tonic-gate return; 3572*7c478bd9Sstevel@tonic-gate } 3573*7c478bd9Sstevel@tonic-gate 3574*7c478bd9Sstevel@tonic-gate save = errno; 3575*7c478bd9Sstevel@tonic-gate errno = 0; 3576*7c478bd9Sstevel@tonic-gate _devlink_debug = strtol(cp, NULL, 10); 3577*7c478bd9Sstevel@tonic-gate if (errno != 0 || _devlink_debug < 0) { 3578*7c478bd9Sstevel@tonic-gate _devlink_debug = 0; 3579*7c478bd9Sstevel@tonic-gate errno = save; 3580*7c478bd9Sstevel@tonic-gate return; 3581*7c478bd9Sstevel@tonic-gate } 3582*7c478bd9Sstevel@tonic-gate errno = save; 3583*7c478bd9Sstevel@tonic-gate 3584*7c478bd9Sstevel@tonic-gate if (!_devlink_debug) 3585*7c478bd9Sstevel@tonic-gate return; 3586*7c478bd9Sstevel@tonic-gate } 3587*7c478bd9Sstevel@tonic-gate 3588*7c478bd9Sstevel@tonic-gate /* debug msgs are enabled */ 3589*7c478bd9Sstevel@tonic-gate assert(_devlink_debug > 0); 3590*7c478bd9Sstevel@tonic-gate 3591*7c478bd9Sstevel@tonic-gate if (_devlink_debug < msglevel) 3592*7c478bd9Sstevel@tonic-gate return; 3593*7c478bd9Sstevel@tonic-gate 3594*7c478bd9Sstevel@tonic-gate 3595*7c478bd9Sstevel@tonic-gate /* Print a distinctive label for error msgs */ 3596*7c478bd9Sstevel@tonic-gate if (msglevel == DBG_ERR) { 3597*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "[ERROR]: "); 3598*7c478bd9Sstevel@tonic-gate } 3599*7c478bd9Sstevel@tonic-gate 3600*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 3601*7c478bd9Sstevel@tonic-gate } 3602*7c478bd9Sstevel@tonic-gate 3603*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3604*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */ 3605*7c478bd9Sstevel@tonic-gate void 3606*7c478bd9Sstevel@tonic-gate dprintf(debug_level_t msglevel, const char *fmt, ...) 3607*7c478bd9Sstevel@tonic-gate { 3608*7c478bd9Sstevel@tonic-gate va_list ap; 3609*7c478bd9Sstevel@tonic-gate 3610*7c478bd9Sstevel@tonic-gate assert(msglevel > 0); 3611*7c478bd9Sstevel@tonic-gate 3612*7c478bd9Sstevel@tonic-gate if (!_devlink_debug) 3613*7c478bd9Sstevel@tonic-gate return; 3614*7c478bd9Sstevel@tonic-gate 3615*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 3616*7c478bd9Sstevel@tonic-gate debug_print(msglevel, fmt, ap); 3617*7c478bd9Sstevel@tonic-gate va_end(ap); 3618*7c478bd9Sstevel@tonic-gate } 3619