11676Sjpk /*
21676Sjpk  * CDDL HEADER START
31676Sjpk  *
41676Sjpk  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
71676Sjpk  *
81676Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91676Sjpk  * or http://www.opensolaris.org/os/licensing.
101676Sjpk  * See the License for the specific language governing permissions
111676Sjpk  * and limitations under the License.
121676Sjpk  *
131676Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
141676Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151676Sjpk  * If applicable, add the following below this CDDL HEADER, with the
161676Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
171676Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
181676Sjpk  *
191676Sjpk  * CDDL HEADER END
201676Sjpk  */
211676Sjpk 
221676Sjpk /*
23*4400Saj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241676Sjpk  * Use is subject to license terms.
251676Sjpk  */
261676Sjpk 
271676Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
281676Sjpk 
291676Sjpk /*
301676Sjpk  * Device allocation related work.
311676Sjpk  */
321676Sjpk 
331676Sjpk #include <stdio.h>
341676Sjpk #include <stdlib.h>
351676Sjpk #include <errno.h>
361676Sjpk #include <string.h>
371676Sjpk #include <strings.h>
381676Sjpk #include <unistd.h>
391676Sjpk #include <fcntl.h>
401676Sjpk #include <sys/types.h>
411676Sjpk #include <sys/stat.h>
421676Sjpk #include <sys/dkio.h>
431676Sjpk #include <sys/wait.h>
441676Sjpk #include <bsm/devalloc.h>
451676Sjpk 
461676Sjpk #define	DEALLOCATE	 "/usr/sbin/deallocate"
471676Sjpk #define	MKDEVALLOC	"/usr/sbin/mkdevalloc"
481676Sjpk 
491676Sjpk static void _update_dev(deventry_t *, int, char *);
501676Sjpk static int _make_db();
511676Sjpk 
521676Sjpk 
531676Sjpk /*
541676Sjpk  * _da_check_for_usb
55*4400Saj  *	returns 1 if device pointed by 'link' is a removable hotplugged disk,
561676Sjpk  *	else returns 0.
571676Sjpk  */
581676Sjpk int
591676Sjpk _da_check_for_usb(char *link, char *root_dir)
601676Sjpk {
611676Sjpk 	int		fd = -1;
621676Sjpk 	int		len, dstsize;
631676Sjpk 	int		removable = 0;
64*4400Saj 	int		hotpluggable = 0;
651676Sjpk 	char		*p = NULL;
66*4400Saj 	char		path[MAXPATHLEN + 4];
67*4400Saj 	char		rpath[MAXPATHLEN + 4];		/* for ",raw" */
681676Sjpk 
691676Sjpk 	dstsize = sizeof (path);
701676Sjpk 	if (strcmp(root_dir, "") != 0) {
711676Sjpk 		if (strlcat(path, root_dir, dstsize) >= dstsize)
721676Sjpk 			return (0);
731676Sjpk 		len = strlen(path);
741676Sjpk 	} else {
751676Sjpk 		len = 0;
761676Sjpk 	}
77*4400Saj 	(void) snprintf(path, dstsize - len, "%s", link);
78*4400Saj 	if ((p = realpath(path, rpath)) == NULL) {
79*4400Saj 		p = path;
801676Sjpk 	} else {
81*4400Saj 		if (strstr(link, "rdsk")) {
82*4400Saj 			p = rpath;
83*4400Saj 		} else {
84*4400Saj 			(void) snprintf(path, dstsize, "%s%s", rpath, ",raw");
85*4400Saj 			p = path;
86*4400Saj 		}
871676Sjpk 	}
88*4400Saj 	if ((fd = open(p, O_RDONLY | O_NONBLOCK)) < 0)
891676Sjpk 		return (0);
901676Sjpk 	(void) ioctl(fd, DKIOCREMOVABLE, &removable);
91*4400Saj 	(void) ioctl(fd, DKIOCHOTPLUGGABLE, &hotpluggable);
921676Sjpk 	(void) close(fd);
931676Sjpk 
94*4400Saj 	if (removable && hotpluggable)
95*4400Saj 		return (1);
96*4400Saj 
97*4400Saj 	return (0);
981676Sjpk }
991676Sjpk 
1001676Sjpk /*
1011676Sjpk  * _reset_devalloc
1021676Sjpk  *	If device allocation is being turned on, creates device_allocate
1031676Sjpk  *	device_maps if they do not exist.
1041676Sjpk  *	Puts DEVICE_ALLOCATION=ON/OFF in device_allocate to indicate if
1051676Sjpk  *	device allocation is on/off.
1061676Sjpk  */
1071676Sjpk void
1081676Sjpk _reset_devalloc(int action)
1091676Sjpk {
1101676Sjpk 	da_args	dargs;
1111676Sjpk 
1121676Sjpk 	if (action == DA_ON)
1131676Sjpk 		(void) _make_db();
1141676Sjpk 	else if ((action == DA_OFF) && (open(DEVALLOC, O_RDONLY) == -1))
1151676Sjpk 		return;
1161676Sjpk 
1171676Sjpk 	if (action == DA_ON)
1181676Sjpk 		dargs.optflag = DA_ON;
1191676Sjpk 	else if (action == DA_OFF)
1201676Sjpk 		dargs.optflag = DA_OFF | DA_ALLOC_ONLY;
1211676Sjpk 
1221676Sjpk 	dargs.rootdir = NULL;
1231676Sjpk 	dargs.devnames = NULL;
1241676Sjpk 	dargs.devinfo = NULL;
1251676Sjpk 
1261676Sjpk 	(void) da_update_device(&dargs);
1271676Sjpk }
1281676Sjpk 
1291676Sjpk /*
1301676Sjpk  * _make_db
1311676Sjpk  *	execs /usr/sbin/mkdevalloc to create device_allocate and
1321676Sjpk  *	device_maps.
1331676Sjpk  */
1341676Sjpk static int
1351676Sjpk _make_db()
1361676Sjpk {
1371676Sjpk 	int	status;
1381676Sjpk 	pid_t	pid, wpid;
1391676Sjpk 
1401676Sjpk 	pid = vfork();
1411676Sjpk 	switch (pid) {
1421676Sjpk 	case -1:
1431676Sjpk 		return (1);
1441676Sjpk 	case 0:
1451676Sjpk 		if (execl(MKDEVALLOC, MKDEVALLOC, DA_IS_LABELED, NULL) == -1)
1461676Sjpk 			exit((errno == ENOENT) ? 0 : 1);
1471676Sjpk 	default:
1481676Sjpk 		for (;;) {
1491676Sjpk 			wpid = waitpid(pid, &status, 0);
1501676Sjpk 			if (wpid == (pid_t)-1) {
1511676Sjpk 				if (errno == EINTR)
1521676Sjpk 					continue;
1531676Sjpk 				else
1541676Sjpk 					return (1);
1551676Sjpk 			} else {
1561676Sjpk 				break;
1571676Sjpk 			}
1581676Sjpk 		}
1591676Sjpk 		break;
1601676Sjpk 	}
1611676Sjpk 
1621676Sjpk 	return ((WIFEXITED(status) == 0) ? 1 : WEXITSTATUS(status));
1631676Sjpk }
1641676Sjpk 
1651676Sjpk 
1661676Sjpk /*
1671676Sjpk  * _update_devalloc_db
1681676Sjpk  * 	Forms allocatable device entries to be written to device_allocate and
1691676Sjpk  *	device_maps.
1701676Sjpk  */
1711676Sjpk /* ARGSUSED */
1721676Sjpk void
1731676Sjpk _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname,
1741676Sjpk     char *root_dir)
1751676Sjpk {
1761676Sjpk 	int		i;
1771676Sjpk 	deventry_t	*entry = NULL, *dentry = NULL;
1781676Sjpk 
1791676Sjpk 	if (action == DA_ADD) {
1801676Sjpk 		for (i = 0; i < DA_COUNT; i++) {
1811676Sjpk 			switch (i) {
1821676Sjpk 			case 0:
1831676Sjpk 				dentry = devlist->audio;
1841676Sjpk 				break;
1851676Sjpk 			case 1:
1861676Sjpk 				dentry = devlist->cd;
1871676Sjpk 				break;
1881676Sjpk 			case 2:
1891676Sjpk 				dentry = devlist->floppy;
1901676Sjpk 				break;
1911676Sjpk 			case 3:
1921676Sjpk 				dentry = devlist->tape;
1931676Sjpk 				break;
1941676Sjpk 			case 4:
1951676Sjpk 				dentry = devlist->rmdisk;
1961676Sjpk 				break;
1971676Sjpk 			default:
1981676Sjpk 				return;
1991676Sjpk 			}
2001676Sjpk 			if (dentry)
2011676Sjpk 				_update_dev(dentry, action, NULL);
2021676Sjpk 		}
2031676Sjpk 	} else if (action == DA_REMOVE) {
2041676Sjpk 		if (devflag & DA_AUDIO)
2051676Sjpk 			dentry = devlist->audio;
2061676Sjpk 		else if (devflag & DA_CD)
2071676Sjpk 			dentry = devlist->cd;
2081676Sjpk 		else if (devflag & DA_FLOPPY)
2091676Sjpk 			dentry = devlist->floppy;
2101676Sjpk 		else if (devflag & DA_TAPE)
2111676Sjpk 			dentry = devlist->tape;
2121676Sjpk 		else if (devflag & DA_RMDISK)
2131676Sjpk 			dentry = devlist->rmdisk;
2141676Sjpk 		else
2151676Sjpk 			return;
2161676Sjpk 
2171676Sjpk 		for (entry = dentry; entry != NULL; entry = entry->next) {
2181676Sjpk 			if (strcmp(entry->devinfo.devname, devname) == 0)
2191676Sjpk 				break;
2201676Sjpk 		}
2211676Sjpk 		_update_dev(entry, action, devname);
2221676Sjpk 	}
2231676Sjpk }
2241676Sjpk 
2251676Sjpk static void
2261676Sjpk _update_dev(deventry_t *dentry, int action, char *devname)
2271676Sjpk {
2281676Sjpk 	da_args		dargs;
2291676Sjpk 	deventry_t	newentry, *entry;
2301676Sjpk 
2311676Sjpk 	dargs.rootdir = NULL;
2321676Sjpk 	dargs.devnames = NULL;
2331676Sjpk 
2341676Sjpk 	if (action == DA_ADD) {
2351676Sjpk 		dargs.optflag = DA_ADD | DA_FORCE;
2361676Sjpk 		for (entry = dentry; entry != NULL; entry = entry->next) {
2371676Sjpk 			dargs.devinfo = &(entry->devinfo);
2381676Sjpk 			(void) da_update_device(&dargs);
2391676Sjpk 		}
2401676Sjpk 	} else if (action == DA_REMOVE) {
2411676Sjpk 		dargs.optflag = DA_REMOVE;
2421676Sjpk 		if (dentry) {
2431676Sjpk 			entry = dentry;
2441676Sjpk 		} else {
2451676Sjpk 			newentry.devinfo.devname = strdup(devname);
2461676Sjpk 			newentry.devinfo.devtype =
2471676Sjpk 			newentry.devinfo.devauths =
2481676Sjpk 			newentry.devinfo.devexec =
2491676Sjpk 			newentry.devinfo.devopts =
2501676Sjpk 			newentry.devinfo.devlist = NULL;
2511676Sjpk 			newentry.devinfo.instance = 0;
2521676Sjpk 			newentry.next = NULL;
2531676Sjpk 			entry = &newentry;
2541676Sjpk 		}
2551676Sjpk 		dargs.devinfo = &(entry->devinfo);
2561676Sjpk 		(void) da_update_device(&dargs);
2571676Sjpk 	}
2581676Sjpk }
259