1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include "libdevinfo.h" 29 #include <strings.h> 30 #include <sys/modctl.h> 31 32 /* 33 * 34 * This file contains interfaces to translate <driver><instance><minorname> 35 * information into /devices and /dev paths. It does this using interfaces to 36 * the kernel instance tree so that it can provide translations for devices 37 * which are no longer present. An example consumer of these interfaces is 38 * iostat(1M) - which shows, in its first iteration, activity since reboot. 39 * With persistant kstats, a device which was busy a long time ago can still 40 * have a decaying presence in iostat output, and that output, when '-n' is 41 * used, should show the public name. 42 */ 43 44 typedef struct { 45 di_devlink_handle_t i_devlink_hdl; 46 } *idim_t; 47 48 di_dim_t 49 di_dim_init() 50 { 51 idim_t idim; 52 53 if ((idim = (idim_t)malloc(sizeof (*idim))) == NULL) 54 return (NULL); 55 idim->i_devlink_hdl = di_devlink_init(NULL, 0); 56 if (idim->i_devlink_hdl == NULL) { 57 free(idim); 58 return (NULL); 59 } 60 return ((di_dim_t)idim); 61 } 62 63 void 64 di_dim_fini(di_dim_t dim) 65 { 66 idim_t idim = (idim_t)dim; 67 68 if (idim->i_devlink_hdl) { 69 (void) di_devlink_fini(&idim->i_devlink_hdl); 70 } 71 free(idim); 72 } 73 74 /*ARGSUSED*/ 75 char * 76 di_dim_path_devices(di_dim_t dim, char *drv_name, int instance, 77 char *minor_name) 78 { 79 major_t major; 80 int len; 81 int mlen; 82 char *devices; 83 84 /* convert drv_name to major_t */ 85 if (modctl(MODGETMAJBIND, drv_name, strlen(drv_name) + 1, &major) < 0) 86 return (NULL); 87 88 /* find the length of the devices path given major,instance */ 89 if (modctl(MODGETDEVFSPATH_MI_LEN, major, instance, &len) != 0) 90 return (NULL); 91 92 /* 93 * MODGETDEVFSPATH_MI_LEN result includes '\0' termination, but we 94 * may need to add space for ":<minor_name>" 95 */ 96 if (minor_name) 97 mlen = len + 1 + strlen(minor_name); 98 else 99 mlen = len; 100 if ((devices = (char *)malloc(mlen)) == NULL) 101 return (NULL); 102 103 if (modctl(MODGETDEVFSPATH_MI, major, instance, len, devices) != 0) { 104 free(devices); 105 return (NULL); 106 } 107 108 if (minor_name) { 109 /* add ':<minot_name>' to the end of /devices path */ 110 (void) strcat(devices, ":"); 111 (void) strcat(devices, minor_name); 112 } 113 return (devices); 114 } 115 116 /* di_dim_path_dev di_devlink callback */ 117 static int 118 di_dim_path_dev_callback(di_devlink_t dl, void *arg) 119 { 120 char **devp = (char **)arg; 121 char *devpath = (char *)di_devlink_path(dl); 122 123 if (devpath) 124 *devp = strdup(devpath); 125 return (DI_WALK_TERMINATE); 126 } 127 128 char * 129 di_dim_path_dev(di_dim_t dim, char *drv_name, int instance, char *minor_name) 130 { 131 idim_t idim = (idim_t)dim; 132 char *devices; 133 char *dev = NULL; 134 135 /* we must have a minor_name to resolve to a public name */ 136 if (minor_name == NULL) 137 return (NULL); 138 139 /* convert <driver><instance><minor_name> to /devices path */ 140 devices = di_dim_path_devices(dim, drv_name, instance, minor_name); 141 if (devices == NULL) 142 return (NULL); 143 144 /* convert /devices path to /dev path */ 145 (void) di_devlink_walk(idim->i_devlink_hdl, NULL, 146 devices, DI_PRIMARY_LINK, (void *)&dev, di_dim_path_dev_callback); 147 free(devices); 148 return (dev); 149 } 150