xref: /onnv-gate/usr/src/cmd/devfsadm/devalloc.c (revision 11529:0396f567d7e1)
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*11529SJan.Parcel@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
241676Sjpk  * Use is subject to license terms.
251676Sjpk  */
261676Sjpk 
271676Sjpk /*
281676Sjpk  * Device allocation related work.
291676Sjpk  */
301676Sjpk 
311676Sjpk #include <stdio.h>
321676Sjpk #include <stdlib.h>
331676Sjpk #include <errno.h>
341676Sjpk #include <string.h>
351676Sjpk #include <strings.h>
361676Sjpk #include <unistd.h>
371676Sjpk #include <fcntl.h>
381676Sjpk #include <sys/types.h>
391676Sjpk #include <sys/stat.h>
401676Sjpk #include <sys/dkio.h>
411676Sjpk #include <sys/wait.h>
421676Sjpk #include <bsm/devalloc.h>
431676Sjpk 
441676Sjpk #define	DEALLOCATE	 "/usr/sbin/deallocate"
451676Sjpk #define	MKDEVALLOC	"/usr/sbin/mkdevalloc"
461676Sjpk 
47*11529SJan.Parcel@Sun.COM static char *_update_dev(deventry_t *, int, const char *, char *, char *);
481676Sjpk static int _make_db();
49*11529SJan.Parcel@Sun.COM extern int event_driven;
501676Sjpk 
511676Sjpk 
521676Sjpk /*
531676Sjpk  * _da_check_for_usb
544400Saj  *	returns 1 if device pointed by 'link' is a removable hotplugged disk,
551676Sjpk  *	else returns 0.
561676Sjpk  */
571676Sjpk int
_da_check_for_usb(char * link,char * root_dir)581676Sjpk _da_check_for_usb(char *link, char *root_dir)
591676Sjpk {
601676Sjpk 	int		fd = -1;
611676Sjpk 	int		len, dstsize;
621676Sjpk 	int		removable = 0;
634400Saj 	int		hotpluggable = 0;
641676Sjpk 	char		*p = NULL;
654400Saj 	char		path[MAXPATHLEN + 4];
664400Saj 	char		rpath[MAXPATHLEN + 4];		/* for ",raw" */
671676Sjpk 
681676Sjpk 	dstsize = sizeof (path);
691676Sjpk 	if (strcmp(root_dir, "") != 0) {
701676Sjpk 		if (strlcat(path, root_dir, dstsize) >= dstsize)
711676Sjpk 			return (0);
721676Sjpk 		len = strlen(path);
731676Sjpk 	} else {
741676Sjpk 		len = 0;
751676Sjpk 	}
764400Saj 	(void) snprintf(path, dstsize - len, "%s", link);
774400Saj 	if ((p = realpath(path, rpath)) == NULL) {
784400Saj 		p = path;
791676Sjpk 	} else {
804400Saj 		if (strstr(link, "rdsk")) {
814400Saj 			p = rpath;
824400Saj 		} else {
834400Saj 			(void) snprintf(path, dstsize, "%s%s", rpath, ",raw");
844400Saj 			p = path;
854400Saj 		}
861676Sjpk 	}
874400Saj 	if ((fd = open(p, O_RDONLY | O_NONBLOCK)) < 0)
881676Sjpk 		return (0);
891676Sjpk 	(void) ioctl(fd, DKIOCREMOVABLE, &removable);
904400Saj 	(void) ioctl(fd, DKIOCHOTPLUGGABLE, &hotpluggable);
911676Sjpk 	(void) close(fd);
921676Sjpk 
934400Saj 	if (removable && hotpluggable)
944400Saj 		return (1);
954400Saj 
964400Saj 	return (0);
971676Sjpk }
981676Sjpk 
991676Sjpk /*
1001676Sjpk  * _reset_devalloc
1011676Sjpk  *	If device allocation is being turned on, creates device_allocate
1021676Sjpk  *	device_maps if they do not exist.
1031676Sjpk  *	Puts DEVICE_ALLOCATION=ON/OFF in device_allocate to indicate if
1041676Sjpk  *	device allocation is on/off.
1051676Sjpk  */
1061676Sjpk void
_reset_devalloc(int action)1071676Sjpk _reset_devalloc(int action)
1081676Sjpk {
1091676Sjpk 	da_args	dargs;
1101676Sjpk 
1111676Sjpk 	if (action == DA_ON)
1121676Sjpk 		(void) _make_db();
1131676Sjpk 	else if ((action == DA_OFF) && (open(DEVALLOC, O_RDONLY) == -1))
1141676Sjpk 		return;
1151676Sjpk 
1161676Sjpk 	if (action == DA_ON)
1171676Sjpk 		dargs.optflag = DA_ON;
1181676Sjpk 	else if (action == DA_OFF)
1191676Sjpk 		dargs.optflag = DA_OFF | DA_ALLOC_ONLY;
1201676Sjpk 
1211676Sjpk 	dargs.rootdir = NULL;
1221676Sjpk 	dargs.devnames = NULL;
1231676Sjpk 	dargs.devinfo = NULL;
1241676Sjpk 
1251676Sjpk 	(void) da_update_device(&dargs);
1261676Sjpk }
1271676Sjpk 
1281676Sjpk /*
1291676Sjpk  * _make_db
1301676Sjpk  *	execs /usr/sbin/mkdevalloc to create device_allocate and
1311676Sjpk  *	device_maps.
1321676Sjpk  */
1331676Sjpk static int
_make_db()1341676Sjpk _make_db()
1351676Sjpk {
1361676Sjpk 	int	status;
1371676Sjpk 	pid_t	pid, wpid;
1381676Sjpk 
1391676Sjpk 	pid = vfork();
1401676Sjpk 	switch (pid) {
1411676Sjpk 	case -1:
1421676Sjpk 		return (1);
1431676Sjpk 	case 0:
1441676Sjpk 		if (execl(MKDEVALLOC, MKDEVALLOC, DA_IS_LABELED, NULL) == -1)
1451676Sjpk 			exit((errno == ENOENT) ? 0 : 1);
1461676Sjpk 	default:
1471676Sjpk 		for (;;) {
1481676Sjpk 			wpid = waitpid(pid, &status, 0);
1491676Sjpk 			if (wpid == (pid_t)-1) {
1501676Sjpk 				if (errno == EINTR)
1511676Sjpk 					continue;
1521676Sjpk 				else
1531676Sjpk 					return (1);
1541676Sjpk 			} else {
1551676Sjpk 				break;
1561676Sjpk 			}
1571676Sjpk 		}
1581676Sjpk 		break;
1591676Sjpk 	}
1601676Sjpk 
1611676Sjpk 	return ((WIFEXITED(status) == 0) ? 1 : WEXITSTATUS(status));
1621676Sjpk }
1631676Sjpk 
1641676Sjpk 
1651676Sjpk /*
1661676Sjpk  * _update_devalloc_db
1671676Sjpk  * 	Forms allocatable device entries to be written to device_allocate and
1681676Sjpk  *	device_maps.
169*11529SJan.Parcel@Sun.COM  *
170*11529SJan.Parcel@Sun.COM  *      Or finds the correct entry to remove, and removes it.
171*11529SJan.Parcel@Sun.COM  *
172*11529SJan.Parcel@Sun.COM  *    Note: devname is a /devices link in the REMOVE case.
1731676Sjpk  */
1741676Sjpk /* ARGSUSED */
1751676Sjpk void
_update_devalloc_db(devlist_t * devlist,int devflag,int action,char * devname,char * root_dir)1761676Sjpk _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname,
1771676Sjpk     char *root_dir)
1781676Sjpk {
1791676Sjpk 	int		i;
1801676Sjpk 	deventry_t	*entry = NULL, *dentry = NULL;
181*11529SJan.Parcel@Sun.COM 	char 		*typestring;
182*11529SJan.Parcel@Sun.COM 	char 		*nickname;  /* typestring + instance */
1831676Sjpk 
1841676Sjpk 	if (action == DA_ADD) {
1851676Sjpk 		for (i = 0; i < DA_COUNT; i++) {
1861676Sjpk 			switch (i) {
1871676Sjpk 			case 0:
1881676Sjpk 				dentry = devlist->audio;
1891676Sjpk 				break;
1901676Sjpk 			case 1:
1911676Sjpk 				dentry = devlist->cd;
1921676Sjpk 				break;
1931676Sjpk 			case 2:
1941676Sjpk 				dentry = devlist->floppy;
1951676Sjpk 				break;
1961676Sjpk 			case 3:
1971676Sjpk 				dentry = devlist->tape;
1981676Sjpk 				break;
1991676Sjpk 			case 4:
2001676Sjpk 				dentry = devlist->rmdisk;
2011676Sjpk 				break;
2021676Sjpk 			default:
2031676Sjpk 				return;
2041676Sjpk 			}
2051676Sjpk 			if (dentry)
206*11529SJan.Parcel@Sun.COM 				(void) _update_dev(dentry, action, NULL, NULL,
207*11529SJan.Parcel@Sun.COM 				    NULL);
2081676Sjpk 		}
2091676Sjpk 	} else if (action == DA_REMOVE) {
210*11529SJan.Parcel@Sun.COM 		if (devflag & DA_AUDIO) {
2111676Sjpk 			dentry = devlist->audio;
212*11529SJan.Parcel@Sun.COM 			typestring = DA_AUDIO_TYPE;
213*11529SJan.Parcel@Sun.COM 		} else if (devflag & DA_CD) {
2141676Sjpk 			dentry = devlist->cd;
215*11529SJan.Parcel@Sun.COM 			typestring = DA_CD_TYPE;
216*11529SJan.Parcel@Sun.COM 		} else if (devflag & DA_FLOPPY) {
2171676Sjpk 			dentry = devlist->floppy;
218*11529SJan.Parcel@Sun.COM 			typestring = DA_FLOPPY_TYPE;
219*11529SJan.Parcel@Sun.COM 		} else if (devflag & DA_TAPE) {
2201676Sjpk 			dentry = devlist->tape;
221*11529SJan.Parcel@Sun.COM 			typestring = DA_TAPE_TYPE;
222*11529SJan.Parcel@Sun.COM 		} else if (devflag & DA_RMDISK) {
2231676Sjpk 			dentry = devlist->rmdisk;
224*11529SJan.Parcel@Sun.COM 			typestring = DA_RMDISK_TYPE;
225*11529SJan.Parcel@Sun.COM 		} else
2261676Sjpk 			return;
2271676Sjpk 
228*11529SJan.Parcel@Sun.COM 		if (event_driven) {
229*11529SJan.Parcel@Sun.COM 			nickname = _update_dev(NULL, action, typestring, NULL,
230*11529SJan.Parcel@Sun.COM 			    devname);
231*11529SJan.Parcel@Sun.COM 
232*11529SJan.Parcel@Sun.COM 			if (nickname != NULL) {
233*11529SJan.Parcel@Sun.COM 				(void) da_rm_list_entry(devlist, devname,
234*11529SJan.Parcel@Sun.COM 				    devflag, nickname);
235*11529SJan.Parcel@Sun.COM 				free(nickname);
236*11529SJan.Parcel@Sun.COM 			}
237*11529SJan.Parcel@Sun.COM 			return;
238*11529SJan.Parcel@Sun.COM 		}
239*11529SJan.Parcel@Sun.COM 		/*
240*11529SJan.Parcel@Sun.COM 		 * Not reached as of now, could be reached if devfsadm is
241*11529SJan.Parcel@Sun.COM 		 * enhanced to clean up devalloc database more thoroughly.
242*11529SJan.Parcel@Sun.COM 		 * Will not reliably match for event-driven removes
243*11529SJan.Parcel@Sun.COM 		 */
2441676Sjpk 		for (entry = dentry; entry != NULL; entry = entry->next) {
2451676Sjpk 			if (strcmp(entry->devinfo.devname, devname) == 0)
2461676Sjpk 				break;
2471676Sjpk 		}
248*11529SJan.Parcel@Sun.COM 		(void) _update_dev(entry, action, NULL, devname, NULL);
2491676Sjpk 	}
2501676Sjpk }
2511676Sjpk 
252*11529SJan.Parcel@Sun.COM /*
253*11529SJan.Parcel@Sun.COM  *	_update_dev: Update device_allocate and/or device_maps files
254*11529SJan.Parcel@Sun.COM  *
255*11529SJan.Parcel@Sun.COM  *      If adding a device:
256*11529SJan.Parcel@Sun.COM  *	    dentry:	A linked list of allocatable devices
257*11529SJan.Parcel@Sun.COM  *	    action:	DA_ADD or DA_REMOVE
258*11529SJan.Parcel@Sun.COM  *	    devtype:	type of device linked list to update on removal
259*11529SJan.Parcel@Sun.COM  *	    devname:	short name (i.e. rmdisk5, cdrom0)  of device if known
260*11529SJan.Parcel@Sun.COM  *	    rm_link:	name of real /device from hot_cleanup
261*11529SJan.Parcel@Sun.COM  *
262*11529SJan.Parcel@Sun.COM  *	If the action is ADD or if the action is triggered by an event
263*11529SJan.Parcel@Sun.COM  *      from syseventd,  read the files FIRST and treat their data as
264*11529SJan.Parcel@Sun.COM  *      more-accurate than the dentry list, adjusting dentry contents if needed.
265*11529SJan.Parcel@Sun.COM  *
266*11529SJan.Parcel@Sun.COM  *	For DA_ADD, try to add each device in the list to the files.
267*11529SJan.Parcel@Sun.COM  *
268*11529SJan.Parcel@Sun.COM  *      If the action is DA_REMOVE and not a hotplug remove, adjust the files
269*11529SJan.Parcel@Sun.COM  *	as indicated by the linked list.
270*11529SJan.Parcel@Sun.COM  *
271*11529SJan.Parcel@Sun.COM  *	RETURNS:
272*11529SJan.Parcel@Sun.COM  *          If we successfully remove a device from the files,  returns
273*11529SJan.Parcel@Sun.COM  *          a char * to strdup'd devname of the device removed.
274*11529SJan.Parcel@Sun.COM  *
275*11529SJan.Parcel@Sun.COM  *	    The caller is responsible for freeing the return value.
276*11529SJan.Parcel@Sun.COM  *
277*11529SJan.Parcel@Sun.COM  *	NULL for all other cases, both success and failure.
278*11529SJan.Parcel@Sun.COM  *
279*11529SJan.Parcel@Sun.COM  */
280*11529SJan.Parcel@Sun.COM static char *
_update_dev(deventry_t * dentry,int action,const char * devtype,char * devname,char * rm_link)281*11529SJan.Parcel@Sun.COM _update_dev(deventry_t *dentry, int action, const char *devtype, char *devname,
282*11529SJan.Parcel@Sun.COM     char *rm_link)
2831676Sjpk {
2841676Sjpk 	da_args		dargs;
2851676Sjpk 	deventry_t	newentry, *entry;
286*11529SJan.Parcel@Sun.COM 	int status;
2871676Sjpk 
2881676Sjpk 	dargs.rootdir = NULL;
2891676Sjpk 	dargs.devnames = NULL;
2901676Sjpk 
291*11529SJan.Parcel@Sun.COM 	if (event_driven)
292*11529SJan.Parcel@Sun.COM 		dargs.optflag = DA_EVENT;
293*11529SJan.Parcel@Sun.COM 	else
294*11529SJan.Parcel@Sun.COM 		dargs.optflag = 0;
295*11529SJan.Parcel@Sun.COM 
2961676Sjpk 	if (action == DA_ADD) {
297*11529SJan.Parcel@Sun.COM 		dargs.optflag |= DA_ADD;
298*11529SJan.Parcel@Sun.COM 		/*
299*11529SJan.Parcel@Sun.COM 		 * Add Events do not have enough information to overrride the
300*11529SJan.Parcel@Sun.COM 		 * existing file contents.
301*11529SJan.Parcel@Sun.COM 		 */
302*11529SJan.Parcel@Sun.COM 
3031676Sjpk 		for (entry = dentry; entry != NULL; entry = entry->next) {
3041676Sjpk 			dargs.devinfo = &(entry->devinfo);
3051676Sjpk 			(void) da_update_device(&dargs);
3061676Sjpk 		}
3071676Sjpk 	} else if (action == DA_REMOVE) {
308*11529SJan.Parcel@Sun.COM 		dargs.optflag |= DA_REMOVE;
3091676Sjpk 		if (dentry) {
3101676Sjpk 			entry = dentry;
311*11529SJan.Parcel@Sun.COM 		} else if (dargs.optflag & DA_EVENT) {
312*11529SJan.Parcel@Sun.COM 			if (devname == NULL)
313*11529SJan.Parcel@Sun.COM 				newentry.devinfo.devname = NULL;
314*11529SJan.Parcel@Sun.COM 			else
315*11529SJan.Parcel@Sun.COM 				newentry.devinfo.devname = strdup(devname);
316*11529SJan.Parcel@Sun.COM 			newentry.devinfo.devtype = (char *)devtype;
317*11529SJan.Parcel@Sun.COM 			newentry.devinfo.devauths =
318*11529SJan.Parcel@Sun.COM 			    newentry.devinfo.devopts =
319*11529SJan.Parcel@Sun.COM 			    newentry.devinfo.devexec = NULL;
320*11529SJan.Parcel@Sun.COM 			newentry.devinfo.devlist = strdup(rm_link);
321*11529SJan.Parcel@Sun.COM 			newentry.devinfo.instance = 0;
322*11529SJan.Parcel@Sun.COM 			newentry.next = NULL;
323*11529SJan.Parcel@Sun.COM 			entry = &newentry;
3241676Sjpk 		} else {
3251676Sjpk 			newentry.devinfo.devname = strdup(devname);
326*11529SJan.Parcel@Sun.COM 			newentry.devinfo.devtype = (char *)devtype;
3271676Sjpk 			newentry.devinfo.devauths =
328*11529SJan.Parcel@Sun.COM 			    newentry.devinfo.devexec =
329*11529SJan.Parcel@Sun.COM 			    newentry.devinfo.devopts =
330*11529SJan.Parcel@Sun.COM 			    newentry.devinfo.devlist = NULL;
3311676Sjpk 			newentry.devinfo.instance = 0;
3321676Sjpk 			newentry.next = NULL;
3331676Sjpk 			entry = &newentry;
3341676Sjpk 		}
3351676Sjpk 		dargs.devinfo = &(entry->devinfo);
336*11529SJan.Parcel@Sun.COM 		/*
337*11529SJan.Parcel@Sun.COM 		 * da_update_device will fill in entry devname if
338*11529SJan.Parcel@Sun.COM 		 * event_driven is true and device is in the file
339*11529SJan.Parcel@Sun.COM 		 */
340*11529SJan.Parcel@Sun.COM 		status = da_update_device(&dargs);
341*11529SJan.Parcel@Sun.COM 		if (event_driven)
342*11529SJan.Parcel@Sun.COM 			if (newentry.devinfo.devlist != NULL)
343*11529SJan.Parcel@Sun.COM 				free(newentry.devinfo.devlist);
344*11529SJan.Parcel@Sun.COM 		if (status == 0)
345*11529SJan.Parcel@Sun.COM 			return (dargs.devinfo->devname);
346*11529SJan.Parcel@Sun.COM 		else free(dargs.devinfo->devname);
3471676Sjpk 	}
348*11529SJan.Parcel@Sun.COM 	return (NULL);
3491676Sjpk }
350