145916cd2Sjpk /* 245916cd2Sjpk * CDDL HEADER START 345916cd2Sjpk * 445916cd2Sjpk * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 745916cd2Sjpk * 845916cd2Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 945916cd2Sjpk * or http://www.opensolaris.org/os/licensing. 1045916cd2Sjpk * See the License for the specific language governing permissions 1145916cd2Sjpk * and limitations under the License. 1245916cd2Sjpk * 1345916cd2Sjpk * When distributing Covered Code, include this CDDL HEADER in each 1445916cd2Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1545916cd2Sjpk * If applicable, add the following below this CDDL HEADER, with the 1645916cd2Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 1745916cd2Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 1845916cd2Sjpk * 1945916cd2Sjpk * CDDL HEADER END 2045916cd2Sjpk */ 2145916cd2Sjpk 2245916cd2Sjpk /* 23*7e3e5701SJan Parcel * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2445916cd2Sjpk * Use is subject to license terms. 2545916cd2Sjpk */ 2645916cd2Sjpk 2745916cd2Sjpk /* 2845916cd2Sjpk * Device allocation related work. 2945916cd2Sjpk */ 3045916cd2Sjpk 3145916cd2Sjpk #include <stdio.h> 3245916cd2Sjpk #include <stdlib.h> 3345916cd2Sjpk #include <errno.h> 3445916cd2Sjpk #include <string.h> 3545916cd2Sjpk #include <strings.h> 3645916cd2Sjpk #include <unistd.h> 3745916cd2Sjpk #include <fcntl.h> 3845916cd2Sjpk #include <sys/types.h> 3945916cd2Sjpk #include <sys/stat.h> 4045916cd2Sjpk #include <sys/dkio.h> 4145916cd2Sjpk #include <sys/wait.h> 4245916cd2Sjpk #include <bsm/devalloc.h> 4345916cd2Sjpk 4445916cd2Sjpk #define DEALLOCATE "/usr/sbin/deallocate" 4545916cd2Sjpk #define MKDEVALLOC "/usr/sbin/mkdevalloc" 4645916cd2Sjpk 47*7e3e5701SJan Parcel static char *_update_dev(deventry_t *, int, const char *, char *, char *); 4845916cd2Sjpk static int _make_db(); 49*7e3e5701SJan Parcel extern int event_driven; 5045916cd2Sjpk 5145916cd2Sjpk 5245916cd2Sjpk /* 5345916cd2Sjpk * _da_check_for_usb 546e670f77Saj * returns 1 if device pointed by 'link' is a removable hotplugged disk, 5545916cd2Sjpk * else returns 0. 5645916cd2Sjpk */ 5745916cd2Sjpk int 5845916cd2Sjpk _da_check_for_usb(char *link, char *root_dir) 5945916cd2Sjpk { 6045916cd2Sjpk int fd = -1; 6145916cd2Sjpk int len, dstsize; 6245916cd2Sjpk int removable = 0; 636e670f77Saj int hotpluggable = 0; 6445916cd2Sjpk char *p = NULL; 656e670f77Saj char path[MAXPATHLEN + 4]; 666e670f77Saj char rpath[MAXPATHLEN + 4]; /* for ",raw" */ 6745916cd2Sjpk 6845916cd2Sjpk dstsize = sizeof (path); 6945916cd2Sjpk if (strcmp(root_dir, "") != 0) { 7045916cd2Sjpk if (strlcat(path, root_dir, dstsize) >= dstsize) 7145916cd2Sjpk return (0); 7245916cd2Sjpk len = strlen(path); 7345916cd2Sjpk } else { 7445916cd2Sjpk len = 0; 7545916cd2Sjpk } 7645916cd2Sjpk (void) snprintf(path, dstsize - len, "%s", link); 776e670f77Saj if ((p = realpath(path, rpath)) == NULL) { 786e670f77Saj p = path; 7945916cd2Sjpk } else { 806e670f77Saj if (strstr(link, "rdsk")) { 816e670f77Saj p = rpath; 826e670f77Saj } else { 836e670f77Saj (void) snprintf(path, dstsize, "%s%s", rpath, ",raw"); 846e670f77Saj p = path; 8545916cd2Sjpk } 866e670f77Saj } 876e670f77Saj if ((fd = open(p, O_RDONLY | O_NONBLOCK)) < 0) 8845916cd2Sjpk return (0); 8945916cd2Sjpk (void) ioctl(fd, DKIOCREMOVABLE, &removable); 906e670f77Saj (void) ioctl(fd, DKIOCHOTPLUGGABLE, &hotpluggable); 9145916cd2Sjpk (void) close(fd); 9245916cd2Sjpk 936e670f77Saj if (removable && hotpluggable) 946e670f77Saj return (1); 956e670f77Saj 966e670f77Saj return (0); 9745916cd2Sjpk } 9845916cd2Sjpk 9945916cd2Sjpk /* 10045916cd2Sjpk * _reset_devalloc 10145916cd2Sjpk * If device allocation is being turned on, creates device_allocate 10245916cd2Sjpk * device_maps if they do not exist. 10345916cd2Sjpk * Puts DEVICE_ALLOCATION=ON/OFF in device_allocate to indicate if 10445916cd2Sjpk * device allocation is on/off. 10545916cd2Sjpk */ 10645916cd2Sjpk void 10745916cd2Sjpk _reset_devalloc(int action) 10845916cd2Sjpk { 10945916cd2Sjpk da_args dargs; 11045916cd2Sjpk 11145916cd2Sjpk if (action == DA_ON) 11245916cd2Sjpk (void) _make_db(); 11345916cd2Sjpk else if ((action == DA_OFF) && (open(DEVALLOC, O_RDONLY) == -1)) 11445916cd2Sjpk return; 11545916cd2Sjpk 11645916cd2Sjpk if (action == DA_ON) 11745916cd2Sjpk dargs.optflag = DA_ON; 11845916cd2Sjpk else if (action == DA_OFF) 11945916cd2Sjpk dargs.optflag = DA_OFF | DA_ALLOC_ONLY; 12045916cd2Sjpk 12145916cd2Sjpk dargs.rootdir = NULL; 12245916cd2Sjpk dargs.devnames = NULL; 12345916cd2Sjpk dargs.devinfo = NULL; 12445916cd2Sjpk 12545916cd2Sjpk (void) da_update_device(&dargs); 12645916cd2Sjpk } 12745916cd2Sjpk 12845916cd2Sjpk /* 12945916cd2Sjpk * _make_db 13045916cd2Sjpk * execs /usr/sbin/mkdevalloc to create device_allocate and 13145916cd2Sjpk * device_maps. 13245916cd2Sjpk */ 13345916cd2Sjpk static int 13445916cd2Sjpk _make_db() 13545916cd2Sjpk { 13645916cd2Sjpk int status; 13745916cd2Sjpk pid_t pid, wpid; 13845916cd2Sjpk 13945916cd2Sjpk pid = vfork(); 14045916cd2Sjpk switch (pid) { 14145916cd2Sjpk case -1: 14245916cd2Sjpk return (1); 14345916cd2Sjpk case 0: 14445916cd2Sjpk if (execl(MKDEVALLOC, MKDEVALLOC, DA_IS_LABELED, NULL) == -1) 14545916cd2Sjpk exit((errno == ENOENT) ? 0 : 1); 14645916cd2Sjpk default: 14745916cd2Sjpk for (;;) { 14845916cd2Sjpk wpid = waitpid(pid, &status, 0); 14945916cd2Sjpk if (wpid == (pid_t)-1) { 15045916cd2Sjpk if (errno == EINTR) 15145916cd2Sjpk continue; 15245916cd2Sjpk else 15345916cd2Sjpk return (1); 15445916cd2Sjpk } else { 15545916cd2Sjpk break; 15645916cd2Sjpk } 15745916cd2Sjpk } 15845916cd2Sjpk break; 15945916cd2Sjpk } 16045916cd2Sjpk 16145916cd2Sjpk return ((WIFEXITED(status) == 0) ? 1 : WEXITSTATUS(status)); 16245916cd2Sjpk } 16345916cd2Sjpk 16445916cd2Sjpk 16545916cd2Sjpk /* 16645916cd2Sjpk * _update_devalloc_db 16745916cd2Sjpk * Forms allocatable device entries to be written to device_allocate and 16845916cd2Sjpk * device_maps. 169*7e3e5701SJan Parcel * 170*7e3e5701SJan Parcel * Or finds the correct entry to remove, and removes it. 171*7e3e5701SJan Parcel * 172*7e3e5701SJan Parcel * Note: devname is a /devices link in the REMOVE case. 17345916cd2Sjpk */ 17445916cd2Sjpk /* ARGSUSED */ 17545916cd2Sjpk void 17645916cd2Sjpk _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname, 17745916cd2Sjpk char *root_dir) 17845916cd2Sjpk { 17945916cd2Sjpk int i; 18045916cd2Sjpk deventry_t *entry = NULL, *dentry = NULL; 181*7e3e5701SJan Parcel char *typestring; 182*7e3e5701SJan Parcel char *nickname; /* typestring + instance */ 18345916cd2Sjpk 18445916cd2Sjpk if (action == DA_ADD) { 18545916cd2Sjpk for (i = 0; i < DA_COUNT; i++) { 18645916cd2Sjpk switch (i) { 18745916cd2Sjpk case 0: 18845916cd2Sjpk dentry = devlist->audio; 18945916cd2Sjpk break; 19045916cd2Sjpk case 1: 19145916cd2Sjpk dentry = devlist->cd; 19245916cd2Sjpk break; 19345916cd2Sjpk case 2: 19445916cd2Sjpk dentry = devlist->floppy; 19545916cd2Sjpk break; 19645916cd2Sjpk case 3: 19745916cd2Sjpk dentry = devlist->tape; 19845916cd2Sjpk break; 19945916cd2Sjpk case 4: 20045916cd2Sjpk dentry = devlist->rmdisk; 20145916cd2Sjpk break; 20245916cd2Sjpk default: 20345916cd2Sjpk return; 20445916cd2Sjpk } 20545916cd2Sjpk if (dentry) 206*7e3e5701SJan Parcel (void) _update_dev(dentry, action, NULL, NULL, 207*7e3e5701SJan Parcel NULL); 20845916cd2Sjpk } 20945916cd2Sjpk } else if (action == DA_REMOVE) { 210*7e3e5701SJan Parcel if (devflag & DA_AUDIO) { 21145916cd2Sjpk dentry = devlist->audio; 212*7e3e5701SJan Parcel typestring = DA_AUDIO_TYPE; 213*7e3e5701SJan Parcel } else if (devflag & DA_CD) { 21445916cd2Sjpk dentry = devlist->cd; 215*7e3e5701SJan Parcel typestring = DA_CD_TYPE; 216*7e3e5701SJan Parcel } else if (devflag & DA_FLOPPY) { 21745916cd2Sjpk dentry = devlist->floppy; 218*7e3e5701SJan Parcel typestring = DA_FLOPPY_TYPE; 219*7e3e5701SJan Parcel } else if (devflag & DA_TAPE) { 22045916cd2Sjpk dentry = devlist->tape; 221*7e3e5701SJan Parcel typestring = DA_TAPE_TYPE; 222*7e3e5701SJan Parcel } else if (devflag & DA_RMDISK) { 22345916cd2Sjpk dentry = devlist->rmdisk; 224*7e3e5701SJan Parcel typestring = DA_RMDISK_TYPE; 225*7e3e5701SJan Parcel } else 22645916cd2Sjpk return; 22745916cd2Sjpk 228*7e3e5701SJan Parcel if (event_driven) { 229*7e3e5701SJan Parcel nickname = _update_dev(NULL, action, typestring, NULL, 230*7e3e5701SJan Parcel devname); 231*7e3e5701SJan Parcel 232*7e3e5701SJan Parcel if (nickname != NULL) { 233*7e3e5701SJan Parcel (void) da_rm_list_entry(devlist, devname, 234*7e3e5701SJan Parcel devflag, nickname); 235*7e3e5701SJan Parcel free(nickname); 236*7e3e5701SJan Parcel } 237*7e3e5701SJan Parcel return; 238*7e3e5701SJan Parcel } 239*7e3e5701SJan Parcel /* 240*7e3e5701SJan Parcel * Not reached as of now, could be reached if devfsadm is 241*7e3e5701SJan Parcel * enhanced to clean up devalloc database more thoroughly. 242*7e3e5701SJan Parcel * Will not reliably match for event-driven removes 243*7e3e5701SJan Parcel */ 24445916cd2Sjpk for (entry = dentry; entry != NULL; entry = entry->next) { 24545916cd2Sjpk if (strcmp(entry->devinfo.devname, devname) == 0) 24645916cd2Sjpk break; 24745916cd2Sjpk } 248*7e3e5701SJan Parcel (void) _update_dev(entry, action, NULL, devname, NULL); 24945916cd2Sjpk } 25045916cd2Sjpk } 25145916cd2Sjpk 252*7e3e5701SJan Parcel /* 253*7e3e5701SJan Parcel * _update_dev: Update device_allocate and/or device_maps files 254*7e3e5701SJan Parcel * 255*7e3e5701SJan Parcel * If adding a device: 256*7e3e5701SJan Parcel * dentry: A linked list of allocatable devices 257*7e3e5701SJan Parcel * action: DA_ADD or DA_REMOVE 258*7e3e5701SJan Parcel * devtype: type of device linked list to update on removal 259*7e3e5701SJan Parcel * devname: short name (i.e. rmdisk5, cdrom0) of device if known 260*7e3e5701SJan Parcel * rm_link: name of real /device from hot_cleanup 261*7e3e5701SJan Parcel * 262*7e3e5701SJan Parcel * If the action is ADD or if the action is triggered by an event 263*7e3e5701SJan Parcel * from syseventd, read the files FIRST and treat their data as 264*7e3e5701SJan Parcel * more-accurate than the dentry list, adjusting dentry contents if needed. 265*7e3e5701SJan Parcel * 266*7e3e5701SJan Parcel * For DA_ADD, try to add each device in the list to the files. 267*7e3e5701SJan Parcel * 268*7e3e5701SJan Parcel * If the action is DA_REMOVE and not a hotplug remove, adjust the files 269*7e3e5701SJan Parcel * as indicated by the linked list. 270*7e3e5701SJan Parcel * 271*7e3e5701SJan Parcel * RETURNS: 272*7e3e5701SJan Parcel * If we successfully remove a device from the files, returns 273*7e3e5701SJan Parcel * a char * to strdup'd devname of the device removed. 274*7e3e5701SJan Parcel * 275*7e3e5701SJan Parcel * The caller is responsible for freeing the return value. 276*7e3e5701SJan Parcel * 277*7e3e5701SJan Parcel * NULL for all other cases, both success and failure. 278*7e3e5701SJan Parcel * 279*7e3e5701SJan Parcel */ 280*7e3e5701SJan Parcel static char * 281*7e3e5701SJan Parcel _update_dev(deventry_t *dentry, int action, const char *devtype, char *devname, 282*7e3e5701SJan Parcel char *rm_link) 28345916cd2Sjpk { 28445916cd2Sjpk da_args dargs; 28545916cd2Sjpk deventry_t newentry, *entry; 286*7e3e5701SJan Parcel int status; 28745916cd2Sjpk 28845916cd2Sjpk dargs.rootdir = NULL; 28945916cd2Sjpk dargs.devnames = NULL; 29045916cd2Sjpk 291*7e3e5701SJan Parcel if (event_driven) 292*7e3e5701SJan Parcel dargs.optflag = DA_EVENT; 293*7e3e5701SJan Parcel else 294*7e3e5701SJan Parcel dargs.optflag = 0; 295*7e3e5701SJan Parcel 29645916cd2Sjpk if (action == DA_ADD) { 297*7e3e5701SJan Parcel dargs.optflag |= DA_ADD; 298*7e3e5701SJan Parcel /* 299*7e3e5701SJan Parcel * Add Events do not have enough information to overrride the 300*7e3e5701SJan Parcel * existing file contents. 301*7e3e5701SJan Parcel */ 302*7e3e5701SJan Parcel 30345916cd2Sjpk for (entry = dentry; entry != NULL; entry = entry->next) { 30445916cd2Sjpk dargs.devinfo = &(entry->devinfo); 30545916cd2Sjpk (void) da_update_device(&dargs); 30645916cd2Sjpk } 30745916cd2Sjpk } else if (action == DA_REMOVE) { 308*7e3e5701SJan Parcel dargs.optflag |= DA_REMOVE; 30945916cd2Sjpk if (dentry) { 31045916cd2Sjpk entry = dentry; 311*7e3e5701SJan Parcel } else if (dargs.optflag & DA_EVENT) { 312*7e3e5701SJan Parcel if (devname == NULL) 313*7e3e5701SJan Parcel newentry.devinfo.devname = NULL; 314*7e3e5701SJan Parcel else 315*7e3e5701SJan Parcel newentry.devinfo.devname = strdup(devname); 316*7e3e5701SJan Parcel newentry.devinfo.devtype = (char *)devtype; 317*7e3e5701SJan Parcel newentry.devinfo.devauths = 318*7e3e5701SJan Parcel newentry.devinfo.devopts = 319*7e3e5701SJan Parcel newentry.devinfo.devexec = NULL; 320*7e3e5701SJan Parcel newentry.devinfo.devlist = strdup(rm_link); 321*7e3e5701SJan Parcel newentry.devinfo.instance = 0; 322*7e3e5701SJan Parcel newentry.next = NULL; 323*7e3e5701SJan Parcel entry = &newentry; 32445916cd2Sjpk } else { 32545916cd2Sjpk newentry.devinfo.devname = strdup(devname); 326*7e3e5701SJan Parcel newentry.devinfo.devtype = (char *)devtype; 32745916cd2Sjpk newentry.devinfo.devauths = 32845916cd2Sjpk newentry.devinfo.devexec = 32945916cd2Sjpk newentry.devinfo.devopts = 33045916cd2Sjpk newentry.devinfo.devlist = NULL; 33145916cd2Sjpk newentry.devinfo.instance = 0; 33245916cd2Sjpk newentry.next = NULL; 33345916cd2Sjpk entry = &newentry; 33445916cd2Sjpk } 33545916cd2Sjpk dargs.devinfo = &(entry->devinfo); 336*7e3e5701SJan Parcel /* 337*7e3e5701SJan Parcel * da_update_device will fill in entry devname if 338*7e3e5701SJan Parcel * event_driven is true and device is in the file 339*7e3e5701SJan Parcel */ 340*7e3e5701SJan Parcel status = da_update_device(&dargs); 341*7e3e5701SJan Parcel if (event_driven) 342*7e3e5701SJan Parcel if (newentry.devinfo.devlist != NULL) 343*7e3e5701SJan Parcel free(newentry.devinfo.devlist); 344*7e3e5701SJan Parcel if (status == 0) 345*7e3e5701SJan Parcel return (dargs.devinfo->devname); 346*7e3e5701SJan Parcel else free(dargs.devinfo->devname); 34745916cd2Sjpk } 348*7e3e5701SJan Parcel return (NULL); 34945916cd2Sjpk } 350