xref: /illumos-gate/usr/src/cmd/devfsadm/devalloc.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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 2007 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 disk,
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 	int		hotpluggable = 0;
65 	char		*p = NULL;
66 	char		path[MAXPATHLEN + 4];
67 	char		rpath[MAXPATHLEN + 4];		/* for ",raw" */
68 
69 	dstsize = sizeof (path);
70 	if (strcmp(root_dir, "") != 0) {
71 		if (strlcat(path, root_dir, dstsize) >= dstsize)
72 			return (0);
73 		len = strlen(path);
74 	} else {
75 		len = 0;
76 	}
77 	(void) snprintf(path, dstsize - len, "%s", link);
78 	if ((p = realpath(path, rpath)) == NULL) {
79 		p = path;
80 	} else {
81 		if (strstr(link, "rdsk")) {
82 			p = rpath;
83 		} else {
84 			(void) snprintf(path, dstsize, "%s%s", rpath, ",raw");
85 			p = path;
86 		}
87 	}
88 	if ((fd = open(p, O_RDONLY | O_NONBLOCK)) < 0)
89 		return (0);
90 	(void) ioctl(fd, DKIOCREMOVABLE, &removable);
91 	(void) ioctl(fd, DKIOCHOTPLUGGABLE, &hotpluggable);
92 	(void) close(fd);
93 
94 	if (removable && hotpluggable)
95 		return (1);
96 
97 	return (0);
98 }
99 
100 /*
101  * _reset_devalloc
102  *	If device allocation is being turned on, creates device_allocate
103  *	device_maps if they do not exist.
104  *	Puts DEVICE_ALLOCATION=ON/OFF in device_allocate to indicate if
105  *	device allocation is on/off.
106  */
107 void
108 _reset_devalloc(int action)
109 {
110 	da_args	dargs;
111 
112 	if (action == DA_ON)
113 		(void) _make_db();
114 	else if ((action == DA_OFF) && (open(DEVALLOC, O_RDONLY) == -1))
115 		return;
116 
117 	if (action == DA_ON)
118 		dargs.optflag = DA_ON;
119 	else if (action == DA_OFF)
120 		dargs.optflag = DA_OFF | DA_ALLOC_ONLY;
121 
122 	dargs.rootdir = NULL;
123 	dargs.devnames = NULL;
124 	dargs.devinfo = NULL;
125 
126 	(void) da_update_device(&dargs);
127 }
128 
129 /*
130  * _make_db
131  *	execs /usr/sbin/mkdevalloc to create device_allocate and
132  *	device_maps.
133  */
134 static int
135 _make_db()
136 {
137 	int	status;
138 	pid_t	pid, wpid;
139 
140 	pid = vfork();
141 	switch (pid) {
142 	case -1:
143 		return (1);
144 	case 0:
145 		if (execl(MKDEVALLOC, MKDEVALLOC, DA_IS_LABELED, NULL) == -1)
146 			exit((errno == ENOENT) ? 0 : 1);
147 	default:
148 		for (;;) {
149 			wpid = waitpid(pid, &status, 0);
150 			if (wpid == (pid_t)-1) {
151 				if (errno == EINTR)
152 					continue;
153 				else
154 					return (1);
155 			} else {
156 				break;
157 			}
158 		}
159 		break;
160 	}
161 
162 	return ((WIFEXITED(status) == 0) ? 1 : WEXITSTATUS(status));
163 }
164 
165 
166 /*
167  * _update_devalloc_db
168  * 	Forms allocatable device entries to be written to device_allocate and
169  *	device_maps.
170  */
171 /* ARGSUSED */
172 void
173 _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname,
174     char *root_dir)
175 {
176 	int		i;
177 	deventry_t	*entry = NULL, *dentry = NULL;
178 
179 	if (action == DA_ADD) {
180 		for (i = 0; i < DA_COUNT; i++) {
181 			switch (i) {
182 			case 0:
183 				dentry = devlist->audio;
184 				break;
185 			case 1:
186 				dentry = devlist->cd;
187 				break;
188 			case 2:
189 				dentry = devlist->floppy;
190 				break;
191 			case 3:
192 				dentry = devlist->tape;
193 				break;
194 			case 4:
195 				dentry = devlist->rmdisk;
196 				break;
197 			default:
198 				return;
199 			}
200 			if (dentry)
201 				_update_dev(dentry, action, NULL);
202 		}
203 	} else if (action == DA_REMOVE) {
204 		if (devflag & DA_AUDIO)
205 			dentry = devlist->audio;
206 		else if (devflag & DA_CD)
207 			dentry = devlist->cd;
208 		else if (devflag & DA_FLOPPY)
209 			dentry = devlist->floppy;
210 		else if (devflag & DA_TAPE)
211 			dentry = devlist->tape;
212 		else if (devflag & DA_RMDISK)
213 			dentry = devlist->rmdisk;
214 		else
215 			return;
216 
217 		for (entry = dentry; entry != NULL; entry = entry->next) {
218 			if (strcmp(entry->devinfo.devname, devname) == 0)
219 				break;
220 		}
221 		_update_dev(entry, action, devname);
222 	}
223 }
224 
225 static void
226 _update_dev(deventry_t *dentry, int action, char *devname)
227 {
228 	da_args		dargs;
229 	deventry_t	newentry, *entry;
230 
231 	dargs.rootdir = NULL;
232 	dargs.devnames = NULL;
233 
234 	if (action == DA_ADD) {
235 		dargs.optflag = DA_ADD | DA_FORCE;
236 		for (entry = dentry; entry != NULL; entry = entry->next) {
237 			dargs.devinfo = &(entry->devinfo);
238 			(void) da_update_device(&dargs);
239 		}
240 	} else if (action == DA_REMOVE) {
241 		dargs.optflag = DA_REMOVE;
242 		if (dentry) {
243 			entry = dentry;
244 		} else {
245 			newentry.devinfo.devname = strdup(devname);
246 			newentry.devinfo.devtype =
247 			newentry.devinfo.devauths =
248 			newentry.devinfo.devexec =
249 			newentry.devinfo.devopts =
250 			newentry.devinfo.devlist = NULL;
251 			newentry.devinfo.instance = 0;
252 			newentry.next = NULL;
253 			entry = &newentry;
254 		}
255 		dargs.devinfo = &(entry->devinfo);
256 		(void) da_update_device(&dargs);
257 	}
258 }
259