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 #include "libdevinfo.h" 27 #include <strings.h> 28 #include <sys/modctl.h> 29 30 /* 31 * 32 * This file contains interfaces to translate <driver><instance><minorname> 33 * information into /devices and /dev paths. It does this using interfaces to 34 * the kernel instance tree so that it can provide translations for devices 35 * which are no longer present. An example consumer of these interfaces is 36 * iostat(8) - which shows, in its first iteration, activity since reboot. 37 * With persistant kstats, a device which was busy a long time ago can still 38 * have a decaying presence in iostat output, and that output, when '-n' is 39 * used, should show the public name. 40 */ 41 42 typedef struct { 43 di_devlink_handle_t i_devlink_hdl; 44 } *idim_t; 45 46 di_dim_t 47 di_dim_init() 48 { 49 idim_t idim; 50 51 if ((idim = (idim_t)malloc(sizeof (*idim))) == NULL) 52 return (NULL); 53 idim->i_devlink_hdl = di_devlink_init(NULL, 0); 54 if (idim->i_devlink_hdl == NULL) { 55 free(idim); 56 return (NULL); 57 } 58 return ((di_dim_t)idim); 59 } 60 61 void 62 di_dim_fini(di_dim_t dim) 63 { 64 idim_t idim = (idim_t)dim; 65 66 if (idim->i_devlink_hdl) { 67 (void) di_devlink_fini(&idim->i_devlink_hdl); 68 } 69 free(idim); 70 } 71 72 /*ARGSUSED*/ 73 char * 74 di_dim_path_devices(di_dim_t dim, char *drv_name, int instance, 75 char *minor_name) 76 { 77 major_t major; 78 int len; 79 int mlen; 80 char *devices; 81 82 /* convert drv_name to major_t */ 83 if (modctl(MODGETMAJBIND, drv_name, strlen(drv_name) + 1, &major) < 0) 84 return (NULL); 85 86 /* find the length of the devices path given major,instance */ 87 if (modctl(MODGETDEVFSPATH_MI_LEN, major, instance, &len) != 0) 88 return (NULL); 89 90 /* 91 * MODGETDEVFSPATH_MI_LEN result includes '\0' termination, but we 92 * may need to add space for ":<minor_name>" 93 */ 94 if (minor_name) 95 mlen = len + 1 + strlen(minor_name); 96 else 97 mlen = len; 98 if ((devices = (char *)malloc(mlen)) == NULL) 99 return (NULL); 100 101 if (modctl(MODGETDEVFSPATH_MI, major, instance, len, devices) != 0) { 102 free(devices); 103 return (NULL); 104 } 105 106 if (minor_name) { 107 /* add ':<minot_name>' to the end of /devices path */ 108 (void) strcat(devices, ":"); 109 (void) strcat(devices, minor_name); 110 } 111 return (devices); 112 } 113 114 /* di_dim_path_dev di_devlink callback */ 115 static int 116 di_dim_path_dev_callback(di_devlink_t dl, void *arg) 117 { 118 char **devp = (char **)arg; 119 char *devpath = (char *)di_devlink_path(dl); 120 121 if (devpath) 122 *devp = strdup(devpath); 123 return (DI_WALK_TERMINATE); 124 } 125 126 char * 127 di_dim_path_dev(di_dim_t dim, char *drv_name, int instance, char *minor_name) 128 { 129 idim_t idim = (idim_t)dim; 130 char *devices; 131 char *dev = NULL; 132 133 /* we must have a minor_name to resolve to a public name */ 134 if (minor_name == NULL) 135 return (NULL); 136 137 /* convert <driver><instance><minor_name> to /devices path */ 138 devices = di_dim_path_devices(dim, drv_name, instance, minor_name); 139 if (devices == NULL) 140 return (NULL); 141 142 /* convert /devices path to /dev path */ 143 (void) di_devlink_walk(idim->i_devlink_hdl, NULL, 144 devices, DI_PRIMARY_LINK, (void *)&dev, di_dim_path_dev_callback); 145 free(devices); 146 return (dev); 147 } 148