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 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Device allocation related work. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <unistd.h> 39 #include <fcntl.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <sys/dkio.h> 43 #include <sys/wait.h> 44 #include <bsm/devalloc.h> 45 46 #define DEALLOCATE "/usr/sbin/deallocate" 47 #define MKDEVALLOC "/usr/sbin/mkdevalloc" 48 49 static void _update_dev(deventry_t *, int, char *); 50 static int _make_db(); 51 52 53 /* 54 * _da_check_for_usb 55 * returns 1 if device pointed by 'link' is a removable hotplugged 56 * else returns 0. 57 */ 58 int 59 _da_check_for_usb(char *link, char *root_dir) 60 { 61 int fd = -1; 62 int len, dstsize; 63 int removable = 0; 64 char *p = NULL; 65 char path[MAXPATHLEN]; 66 67 dstsize = sizeof (path); 68 if (strcmp(root_dir, "") != 0) { 69 if (strlcat(path, root_dir, dstsize) >= dstsize) 70 return (0); 71 len = strlen(path); 72 } else { 73 len = 0; 74 } 75 if (strstr(link, "rdsk")) { 76 (void) snprintf(path, dstsize - len, "%s", link); 77 } else if (strstr(link, "dsk")) { 78 p = rindex(link, '/'); 79 if (p == NULL) 80 return (0); 81 p++; 82 (void) snprintf(path, dstsize - len, "%s%s", "/dev/rdsk/", p); 83 } else { 84 return (0); 85 } 86 87 if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0) 88 return (0); 89 (void) ioctl(fd, DKIOCREMOVABLE, &removable); 90 (void) close(fd); 91 92 return (removable); 93 } 94 95 /* 96 * _reset_devalloc 97 * If device allocation is being turned on, creates device_allocate 98 * device_maps if they do not exist. 99 * Puts DEVICE_ALLOCATION=ON/OFF in device_allocate to indicate if 100 * device allocation is on/off. 101 */ 102 void 103 _reset_devalloc(int action) 104 { 105 da_args dargs; 106 107 if (action == DA_ON) 108 (void) _make_db(); 109 else if ((action == DA_OFF) && (open(DEVALLOC, O_RDONLY) == -1)) 110 return; 111 112 if (action == DA_ON) 113 dargs.optflag = DA_ON; 114 else if (action == DA_OFF) 115 dargs.optflag = DA_OFF | DA_ALLOC_ONLY; 116 117 dargs.rootdir = NULL; 118 dargs.devnames = NULL; 119 dargs.devinfo = NULL; 120 121 (void) da_update_device(&dargs); 122 } 123 124 /* 125 * _make_db 126 * execs /usr/sbin/mkdevalloc to create device_allocate and 127 * device_maps. 128 */ 129 static int 130 _make_db() 131 { 132 int status; 133 pid_t pid, wpid; 134 135 pid = vfork(); 136 switch (pid) { 137 case -1: 138 return (1); 139 case 0: 140 if (execl(MKDEVALLOC, MKDEVALLOC, DA_IS_LABELED, NULL) == -1) 141 exit((errno == ENOENT) ? 0 : 1); 142 default: 143 for (;;) { 144 wpid = waitpid(pid, &status, 0); 145 if (wpid == (pid_t)-1) { 146 if (errno == EINTR) 147 continue; 148 else 149 return (1); 150 } else { 151 break; 152 } 153 } 154 break; 155 } 156 157 return ((WIFEXITED(status) == 0) ? 1 : WEXITSTATUS(status)); 158 } 159 160 161 /* 162 * _update_devalloc_db 163 * Forms allocatable device entries to be written to device_allocate and 164 * device_maps. 165 */ 166 /* ARGSUSED */ 167 void 168 _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname, 169 char *root_dir) 170 { 171 int i; 172 deventry_t *entry = NULL, *dentry = NULL; 173 174 if (action == DA_ADD) { 175 for (i = 0; i < DA_COUNT; i++) { 176 switch (i) { 177 case 0: 178 dentry = devlist->audio; 179 break; 180 case 1: 181 dentry = devlist->cd; 182 break; 183 case 2: 184 dentry = devlist->floppy; 185 break; 186 case 3: 187 dentry = devlist->tape; 188 break; 189 case 4: 190 dentry = devlist->rmdisk; 191 break; 192 default: 193 return; 194 } 195 if (dentry) 196 _update_dev(dentry, action, NULL); 197 } 198 } else if (action == DA_REMOVE) { 199 if (devflag & DA_AUDIO) 200 dentry = devlist->audio; 201 else if (devflag & DA_CD) 202 dentry = devlist->cd; 203 else if (devflag & DA_FLOPPY) 204 dentry = devlist->floppy; 205 else if (devflag & DA_TAPE) 206 dentry = devlist->tape; 207 else if (devflag & DA_RMDISK) 208 dentry = devlist->rmdisk; 209 else 210 return; 211 212 for (entry = dentry; entry != NULL; entry = entry->next) { 213 if (strcmp(entry->devinfo.devname, devname) == 0) 214 break; 215 } 216 _update_dev(entry, action, devname); 217 } 218 } 219 220 static void 221 _update_dev(deventry_t *dentry, int action, char *devname) 222 { 223 da_args dargs; 224 deventry_t newentry, *entry; 225 226 dargs.rootdir = NULL; 227 dargs.devnames = NULL; 228 229 if (action == DA_ADD) { 230 dargs.optflag = DA_ADD | DA_FORCE; 231 for (entry = dentry; entry != NULL; entry = entry->next) { 232 dargs.devinfo = &(entry->devinfo); 233 (void) da_update_device(&dargs); 234 } 235 } else if (action == DA_REMOVE) { 236 dargs.optflag = DA_REMOVE; 237 if (dentry) { 238 entry = dentry; 239 } else { 240 newentry.devinfo.devname = strdup(devname); 241 newentry.devinfo.devtype = 242 newentry.devinfo.devauths = 243 newentry.devinfo.devexec = 244 newentry.devinfo.devopts = 245 newentry.devinfo.devlist = NULL; 246 newentry.devinfo.instance = 0; 247 newentry.next = NULL; 248 entry = &newentry; 249 } 250 dargs.devinfo = &(entry->devinfo); 251 (void) da_update_device(&dargs); 252 } 253 } 254