/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Device allocation related work. */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/dkio.h> #include <sys/wait.h> #include <bsm/devalloc.h> #define DEALLOCATE "/usr/sbin/deallocate" #define MKDEVALLOC "/usr/sbin/mkdevalloc" static void _update_dev(deventry_t *, int, char *); static int _make_db(); /* * _da_check_for_usb * returns 1 if device pointed by 'link' is a removable hotplugged * else returns 0. */ int _da_check_for_usb(char *link, char *root_dir) { int fd = -1; int len, dstsize; int removable = 0; char *p = NULL; char path[MAXPATHLEN]; dstsize = sizeof (path); if (strcmp(root_dir, "") != 0) { if (strlcat(path, root_dir, dstsize) >= dstsize) return (0); len = strlen(path); } else { len = 0; } if (strstr(link, "rdsk")) { (void) snprintf(path, dstsize - len, "%s", link); } else if (strstr(link, "dsk")) { p = rindex(link, '/'); if (p == NULL) return (0); p++; (void) snprintf(path, dstsize - len, "%s%s", "/dev/rdsk/", p); } else { return (0); } if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0) return (0); (void) ioctl(fd, DKIOCREMOVABLE, &removable); (void) close(fd); return (removable); } /* * _reset_devalloc * If device allocation is being turned on, creates device_allocate * device_maps if they do not exist. * Puts DEVICE_ALLOCATION=ON/OFF in device_allocate to indicate if * device allocation is on/off. */ void _reset_devalloc(int action) { da_args dargs; if (action == DA_ON) (void) _make_db(); else if ((action == DA_OFF) && (open(DEVALLOC, O_RDONLY) == -1)) return; if (action == DA_ON) dargs.optflag = DA_ON; else if (action == DA_OFF) dargs.optflag = DA_OFF | DA_ALLOC_ONLY; dargs.rootdir = NULL; dargs.devnames = NULL; dargs.devinfo = NULL; (void) da_update_device(&dargs); } /* * _make_db * execs /usr/sbin/mkdevalloc to create device_allocate and * device_maps. */ static int _make_db() { int status; pid_t pid, wpid; pid = vfork(); switch (pid) { case -1: return (1); case 0: if (execl(MKDEVALLOC, MKDEVALLOC, DA_IS_LABELED, NULL) == -1) exit((errno == ENOENT) ? 0 : 1); default: for (;;) { wpid = waitpid(pid, &status, 0); if (wpid == (pid_t)-1) { if (errno == EINTR) continue; else return (1); } else { break; } } break; } return ((WIFEXITED(status) == 0) ? 1 : WEXITSTATUS(status)); } /* * _update_devalloc_db * Forms allocatable device entries to be written to device_allocate and * device_maps. */ /* ARGSUSED */ void _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname, char *root_dir) { int i; deventry_t *entry = NULL, *dentry = NULL; if (action == DA_ADD) { for (i = 0; i < DA_COUNT; i++) { switch (i) { case 0: dentry = devlist->audio; break; case 1: dentry = devlist->cd; break; case 2: dentry = devlist->floppy; break; case 3: dentry = devlist->tape; break; case 4: dentry = devlist->rmdisk; break; default: return; } if (dentry) _update_dev(dentry, action, NULL); } } else if (action == DA_REMOVE) { if (devflag & DA_AUDIO) dentry = devlist->audio; else if (devflag & DA_CD) dentry = devlist->cd; else if (devflag & DA_FLOPPY) dentry = devlist->floppy; else if (devflag & DA_TAPE) dentry = devlist->tape; else if (devflag & DA_RMDISK) dentry = devlist->rmdisk; else return; for (entry = dentry; entry != NULL; entry = entry->next) { if (strcmp(entry->devinfo.devname, devname) == 0) break; } _update_dev(entry, action, devname); } } static void _update_dev(deventry_t *dentry, int action, char *devname) { da_args dargs; deventry_t newentry, *entry; dargs.rootdir = NULL; dargs.devnames = NULL; if (action == DA_ADD) { dargs.optflag = DA_ADD | DA_FORCE; for (entry = dentry; entry != NULL; entry = entry->next) { dargs.devinfo = &(entry->devinfo); (void) da_update_device(&dargs); } } else if (action == DA_REMOVE) { dargs.optflag = DA_REMOVE; if (dentry) { entry = dentry; } else { newentry.devinfo.devname = strdup(devname); newentry.devinfo.devtype = newentry.devinfo.devauths = newentry.devinfo.devexec = newentry.devinfo.devopts = newentry.devinfo.devlist = NULL; newentry.devinfo.instance = 0; newentry.next = NULL; entry = &newentry; } dargs.devinfo = &(entry->devinfo); (void) da_update_device(&dargs); } }