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