diff options
author | Jan Parcel <Jan.Parcel@Sun.COM> | 2010-01-17 09:36:52 -0800 |
---|---|---|
committer | Jan Parcel <Jan.Parcel@Sun.COM> | 2010-01-17 09:36:52 -0800 |
commit | 7e3e5701c73b753fb9dd17a0cbe0568b4cdda39e (patch) | |
tree | ce7ea5da313d5bf779be070d1d789eb175f7abce /usr/src | |
parent | 9820c71034357bd7840b87218016a93aea266a6f (diff) | |
download | illumos-joyent-7e3e5701c73b753fb9dd17a0cbe0568b4cdda39e.tar.gz |
6868082 TX: devfsadm must rely on device_maps file with multiple hot-pluggable usb devices
6855420 TX: USB built-in floppy drive should automatically populate the Device Manager
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/allocate/mkdevalloc.c | 13 | ||||
-rw-r--r-- | usr/src/cmd/devfsadm/devalloc.c | 133 | ||||
-rw-r--r-- | usr/src/cmd/devfsadm/devfsadm.c | 31 | ||||
-rw-r--r-- | usr/src/lib/Makefile | 2 | ||||
-rw-r--r-- | usr/src/lib/libbsm/Makefile.com | 6 | ||||
-rw-r--r-- | usr/src/lib/libbsm/common/devalloc.c | 391 | ||||
-rw-r--r-- | usr/src/lib/libbsm/common/devalloc.h | 9 | ||||
-rw-r--r-- | usr/src/lib/libbsm/common/getdment.c | 75 | ||||
-rw-r--r-- | usr/src/lib/libbsm/common/mapfile-vers | 3 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/device_info.h | 8 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo_devperm.c | 10 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/mapfile-vers | 3 |
12 files changed, 594 insertions, 90 deletions
diff --git a/usr/src/cmd/allocate/mkdevalloc.c b/usr/src/cmd/allocate/mkdevalloc.c index 750b1eeb9a..508f5961c4 100644 --- a/usr/src/cmd/allocate/mkdevalloc.c +++ b/usr/src/cmd/allocate/mkdevalloc.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * scan /dev directory for mountable objects and construct device_allocate * file for allocate.... @@ -94,7 +92,7 @@ struct tape { #define DFLT_NTAPE 10 /* size of initial array */ #define SIZE_OF_RST 3 /* |rmt| */ #define SIZE_OF_NRST 4 /* |nrmt| */ -#define SIZE_OF_TMP 4 /* |/tmp| */ +#define SIZE_OF_TMP 4 /* |/tmp| */ #define SIZE_OF_RMT 8 /* |/dev/rmt| */ #define TAPE_CLEAN SECLIB"/st_clean" @@ -909,7 +907,7 @@ docd() continue; /* get device # (disk #) */ - if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) <= 0) + if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) != 2) continue; /* see if this is one of the cd special devices */ @@ -1117,7 +1115,7 @@ dormdisk(int cd_count) continue; /* get device # (disk #) */ - if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) <= 0) + if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) != 2) continue; /* see if we've already examined this device */ @@ -1165,6 +1163,9 @@ dormdisk(int cd_count) /* will exit(1) if insufficient memory */ nrmdisk = expandmem(i, (void **)&rmdisk, sizeof (struct rmdisk)); + /* When we expand rmdisk, need to expand rmdisk_r */ + (void) expandmem(i, (void **)&rmdisk_r, + sizeof (struct rmdisk)); } nm = (char *)malloc(SIZE_OF_DSK + 1 + strlen(dep->d_name) + 1); if (nm == NULL) diff --git a/usr/src/cmd/devfsadm/devalloc.c b/usr/src/cmd/devfsadm/devalloc.c index 1f0f6a8e77..11147269cb 100644 --- a/usr/src/cmd/devfsadm/devalloc.c +++ b/usr/src/cmd/devfsadm/devalloc.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Device allocation related work. */ @@ -46,8 +44,9 @@ #define DEALLOCATE "/usr/sbin/deallocate" #define MKDEVALLOC "/usr/sbin/mkdevalloc" -static void _update_dev(deventry_t *, int, char *); +static char *_update_dev(deventry_t *, int, const char *, char *, char *); static int _make_db(); +extern int event_driven; /* @@ -167,6 +166,10 @@ _make_db() * _update_devalloc_db * Forms allocatable device entries to be written to device_allocate and * device_maps. + * + * Or finds the correct entry to remove, and removes it. + * + * Note: devname is a /devices link in the REMOVE case. */ /* ARGSUSED */ void @@ -175,6 +178,8 @@ _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname, { int i; deventry_t *entry = NULL, *dentry = NULL; + char *typestring; + char *nickname; /* typestring + instance */ if (action == DA_ADD) { for (i = 0; i < DA_COUNT; i++) { @@ -198,61 +203,147 @@ _update_devalloc_db(devlist_t *devlist, int devflag, int action, char *devname, return; } if (dentry) - _update_dev(dentry, action, NULL); + (void) _update_dev(dentry, action, NULL, NULL, + NULL); } } else if (action == DA_REMOVE) { - if (devflag & DA_AUDIO) + if (devflag & DA_AUDIO) { dentry = devlist->audio; - else if (devflag & DA_CD) + typestring = DA_AUDIO_TYPE; + } else if (devflag & DA_CD) { dentry = devlist->cd; - else if (devflag & DA_FLOPPY) + typestring = DA_CD_TYPE; + } else if (devflag & DA_FLOPPY) { dentry = devlist->floppy; - else if (devflag & DA_TAPE) + typestring = DA_FLOPPY_TYPE; + } else if (devflag & DA_TAPE) { dentry = devlist->tape; - else if (devflag & DA_RMDISK) + typestring = DA_TAPE_TYPE; + } else if (devflag & DA_RMDISK) { dentry = devlist->rmdisk; - else + typestring = DA_RMDISK_TYPE; + } else return; + if (event_driven) { + nickname = _update_dev(NULL, action, typestring, NULL, + devname); + + if (nickname != NULL) { + (void) da_rm_list_entry(devlist, devname, + devflag, nickname); + free(nickname); + } + return; + } + /* + * Not reached as of now, could be reached if devfsadm is + * enhanced to clean up devalloc database more thoroughly. + * Will not reliably match for event-driven removes + */ for (entry = dentry; entry != NULL; entry = entry->next) { if (strcmp(entry->devinfo.devname, devname) == 0) break; } - _update_dev(entry, action, devname); + (void) _update_dev(entry, action, NULL, devname, NULL); } } -static void -_update_dev(deventry_t *dentry, int action, char *devname) +/* + * _update_dev: Update device_allocate and/or device_maps files + * + * If adding a device: + * dentry: A linked list of allocatable devices + * action: DA_ADD or DA_REMOVE + * devtype: type of device linked list to update on removal + * devname: short name (i.e. rmdisk5, cdrom0) of device if known + * rm_link: name of real /device from hot_cleanup + * + * If the action is ADD or if the action is triggered by an event + * from syseventd, read the files FIRST and treat their data as + * more-accurate than the dentry list, adjusting dentry contents if needed. + * + * For DA_ADD, try to add each device in the list to the files. + * + * If the action is DA_REMOVE and not a hotplug remove, adjust the files + * as indicated by the linked list. + * + * RETURNS: + * If we successfully remove a device from the files, returns + * a char * to strdup'd devname of the device removed. + * + * The caller is responsible for freeing the return value. + * + * NULL for all other cases, both success and failure. + * + */ +static char * +_update_dev(deventry_t *dentry, int action, const char *devtype, char *devname, + char *rm_link) { da_args dargs; deventry_t newentry, *entry; + int status; dargs.rootdir = NULL; dargs.devnames = NULL; + if (event_driven) + dargs.optflag = DA_EVENT; + else + dargs.optflag = 0; + if (action == DA_ADD) { - dargs.optflag = DA_ADD | DA_FORCE; + dargs.optflag |= DA_ADD; + /* + * Add Events do not have enough information to overrride the + * existing file contents. + */ + 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; + dargs.optflag |= DA_REMOVE; if (dentry) { entry = dentry; + } else if (dargs.optflag & DA_EVENT) { + if (devname == NULL) + newentry.devinfo.devname = NULL; + else + newentry.devinfo.devname = strdup(devname); + newentry.devinfo.devtype = (char *)devtype; + newentry.devinfo.devauths = + newentry.devinfo.devopts = + newentry.devinfo.devexec = NULL; + newentry.devinfo.devlist = strdup(rm_link); + newentry.devinfo.instance = 0; + newentry.next = NULL; + entry = &newentry; } else { newentry.devinfo.devname = strdup(devname); - newentry.devinfo.devtype = + newentry.devinfo.devtype = (char *)devtype; newentry.devinfo.devauths = - newentry.devinfo.devexec = - newentry.devinfo.devopts = - newentry.devinfo.devlist = NULL; + 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); + /* + * da_update_device will fill in entry devname if + * event_driven is true and device is in the file + */ + status = da_update_device(&dargs); + if (event_driven) + if (newentry.devinfo.devlist != NULL) + free(newentry.devinfo.devlist); + if (status == 0) + return (dargs.devinfo->devname); + else free(dargs.devinfo->devname); } + return (NULL); } diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c index 11e25b3071..523924b3c4 100644 --- a/usr/src/cmd/devfsadm/devfsadm.c +++ b/usr/src/cmd/devfsadm/devfsadm.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -96,6 +96,9 @@ static int update_all_drivers = FALSE; /* set if invoked via /usr/lib/devfsadm/devfsadmd */ static int daemon_mode = FALSE; +/* set if event_handler triggered */ +int event_driven = FALSE; + /* output directed to syslog during daemon mode if set */ static int logflag = FALSE; @@ -1645,6 +1648,12 @@ event_handler(sysevent_t *ev) int instance; int branch_event = 0; + /* + * If this is event-driven, then we cannot trust the static devlist + * to be correct. + */ + + event_driven = TRUE; subclass = sysevent_get_subclass_name(ev); vprint(EVENT_MID, "event_handler: %s id:0X%llx\n", subclass, sysevent_get_seq(ev)); @@ -4307,22 +4316,22 @@ hot_cleanup(char *node_path, char *minor_name, char *ev_subclass, /* update device allocation database */ if (system_labeled) { - int ret = 0; int devtype = 0; - char devname[MAXNAMELEN]; - devname[0] = '\0'; - if (strstr(node_path, DA_SOUND_NAME)) + if (strstr(path, DA_SOUND_NAME)) devtype = DA_AUDIO; - else if (strstr(node_path, "disk")) + else if (strstr(path, "storage")) + devtype = DA_RMDISK; + else if (strstr(path, "disk")) + devtype = DA_RMDISK; + else if (strstr(path, "floppy")) + /* TODO: detect usb cds and floppies at insert time */ devtype = DA_RMDISK; else goto out; - ret = da_remove_list(&devlist, NULL, devtype, devname, - sizeof (devname)); - if (ret != -1) - (void) _update_devalloc_db(&devlist, devtype, DA_REMOVE, - devname, root_dir); + + (void) _update_devalloc_db(&devlist, devtype, DA_REMOVE, + node_path, root_dir); } out: diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 033931fb88..a4e59dbd14 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -568,7 +568,7 @@ $(CLOSED_BUILD)libc: $(CLOSED)/lib/libc_i18n libast: libsocket libadutils: libldap5 libresolv libsocket libnsl nsswitch: libadutils libidmap -libbsm: libtsol +libbsm: libtsol libdevinfo libcmd: libsum libast libsocket libnsl libcmdutils: libavl libcontract: libnvpair diff --git a/usr/src/lib/libbsm/Makefile.com b/usr/src/lib/libbsm/Makefile.com index 367586ba90..2858c32102 100644 --- a/usr/src/lib/libbsm/Makefile.com +++ b/usr/src/lib/libbsm/Makefile.com @@ -19,11 +19,9 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# LIBRARY = libbsm.a VERS = .1 @@ -88,7 +86,7 @@ ROOTLINT= $(LINTSRC:%=$(ROOTLINTDIR)/%) CLEANFILES += $(LINTOUT) $(LINTLIB) CFLAGS += $(CCVERBOSE) -LDLIBS += -lsocket -lnsl -lmd -lc -lsecdb -ltsol -linetutil +LDLIBS += -lsocket -lnsl -lmd -lc -ldevinfo -lsecdb -ltsol -linetutil COMDIR= ../common diff --git a/usr/src/lib/libbsm/common/devalloc.c b/usr/src/lib/libbsm/common/devalloc.c index e39b57fa23..cdeaf322f3 100644 --- a/usr/src/lib/libbsm/common/devalloc.c +++ b/usr/src/lib/libbsm/common/devalloc.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdlib.h> #include <ctype.h> #include <unistd.h> @@ -40,6 +38,7 @@ #include <libintl.h> #include <errno.h> #include <auth_list.h> +#include <syslog.h> #include <bsm/devices.h> #include <bsm/devalloc.h> @@ -53,6 +52,10 @@ extern int da_matchname(devalloc_t *, char *); extern int da_match(devalloc_t *, da_args *); extern int dmap_matchname(devmap_t *, char *); extern int dm_match(devmap_t *, da_args *); +extern int dmap_matchtype(devmap_t *dmap, char *type); +extern int dmap_matchdev(devmap_t *dmap, char *dev); +extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num); +extern char *dmap_physname(devmap_t *dmap); /* * The following structure is for recording old entries to be retained. @@ -332,7 +335,7 @@ _update_zonename(da_args *dargs, devalloc_t *dap) */ /*ARGSUSED*/ static int -_dmap2str(da_args *dargs, devmap_t *dmp, char *buf, int size, const char *sep) +_dmap2str(devmap_t *dmp, char *buf, int size, const char *sep) { int length; @@ -356,13 +359,13 @@ _dmap2str(da_args *dargs, devmap_t *dmp, char *buf, int size, const char *sep) * returns pointer to decoded entry, NULL on error. */ static strentry_t * -_dmap2strentry(da_args *dargs, devmap_t *devmapp) +_dmap2strentry(devmap_t *devmapp) { strentry_t *sep; if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) return (NULL); - if (_dmap2str(dargs, devmapp, sep->se_str, sizeof (sep->se_str), + if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str), KV_TOKEN_DELIMIT"\\\n\t") != 0) { free(sep); return (NULL); @@ -562,8 +565,216 @@ _build_defattrs(da_args *dargs, strentry_t **head_defent) } /* + * _rebuild_lists - + * + * If dargs->optflag & DA_EVENT, does not assume the dargs list is + * complete or completely believable, since devfsadm caches + * ONLY what it has been exposed to via syseventd. + * + * Cycles through all the entries in the /etc files, stores them + * in memory, takes note of device->dname numbers (i.e. rmdisk0, + * rmdisk12) + * + * Cycles through again, adds dargs entry + * with the name tname%d (lowest unused number for the device type) + * to the list of things for the caller to write out to a file, + * IFF it is a new entry. + * + * It is an error for it to already be there. + * + * Add: + * Returns 0 if successful and 2 on error. + * Remove: + * Returns 0 if not found, 1 if found, 2 on error. + */ +static int +_rebuild_lists(da_args *dargs, strentry_t **head_devallocp, + strentry_t **head_devmapp) +{ + int rc = 0; + devalloc_t *devallocp; + devmap_t *devmapp; + strentry_t *tail_str; + strentry_t *tmp_str; + uint64_t tmp_bitmap = 0; + int tmp = 0; + char new_devname[DA_MAXNAME + 1]; + char errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80]; + char *realname; + int suffix = DA_MAX_DEVNO + 1; + int found = 0; + + if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY)) + return (2); + + if (dargs->optflag & DA_FORCE) + return (2); + + /* read both files, maps first so we can compare actual devices */ + + /* build device_maps */ + setdmapent(); + while ((devmapp = getdmapent()) != NULL) { + if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype)) + == 1) { + if (dargs->optflag & DA_REMOVE) { + if ((devmapp->dmap_devarray == NULL) || + (devmapp->dmap_devarray[0] == NULL)) { + freedmapent(devmapp); + enddmapent(); + return (2); + } + realname = dmap_physname(devmapp); + if (realname == NULL) { + freedmapent(devmapp); + enddmapent(); + return (2); + } + if (strstr(realname, dargs->devinfo->devlist) + != NULL) { + if (dargs->devinfo->devname != NULL) + free(dargs->devinfo->devname); + dargs->devinfo->devname = + strdup(devmapp->dmap_devname); + found = 1; + freedmapent(devmapp); + continue; /* don't retain */ + } + } else if (dargs->optflag & DA_ADD) { + /* + * Need to know which suffixes are in use + */ + rc = (dmap_exact_dev(devmapp, + dargs->devinfo->devlist, &suffix)); + + if (rc == 0) { + /* + * Same type, different device. Record + * device suffix already in use. + */ + if (suffix > DA_MAX_DEVNO) { + freedmapent(devmapp); + enddmapent(); + return (2); + } + tmp_bitmap |= (uint64_t)(1LL << suffix); + } else { + /* + * Match on add is an error + * or mapping attempt returned error + */ + freedmapent(devmapp); + enddmapent(); + return (2); + } + } else + /* add other transaction types as needed */ + return (2); + + } /* if same type */ + + tmp_str = _dmap2strentry(devmapp); + if (tmp_str == NULL) { + freedmapent(devmapp); + enddmapent(); + return (2); + } + /* retaining devmap entry: tmp_str->se_str */ + tmp_str->se_next = NULL; + if (*head_devmapp == NULL) { + *head_devmapp = tail_str = tmp_str; + } else { + tail_str->se_next = tmp_str; + tail_str = tmp_str; + } + freedmapent(devmapp); + } + enddmapent(); + + /* + * No need to rewrite the files if the item to be removed is not + * in the files -- wait for another call on another darg. + */ + if ((dargs->optflag & DA_REMOVE) && !found) + return (0); + + + if (dargs->optflag & DA_ADD) { + /* + * Since we got here from an event, we know the stored + * devname is a useless guess, since the files had not + * been read when the name was chosen, and we don't keep + * them anywhere else that is sufficiently definitive. + */ + + for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++) + if (!(tmp_bitmap & (1LL << tmp))) + break; + /* Future: support more than 64 hotplug devices per type? */ + if (tmp > DA_MAX_DEVNO) + return (2); + + (void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u", + dargs->devinfo->devtype, tmp); + if (dargs->devinfo->devname != NULL) + free(dargs->devinfo->devname); + dargs->devinfo->devname = strdup(new_devname); + } + + /* + * Now adjust devalloc list to match devmaps + * Note we now have the correct devname for da_match to use. + */ + setdaent(); + while ((devallocp = getdaent()) != NULL) { + rc = da_match(devallocp, dargs); + if (rc == 1) { + if (dargs->optflag & DA_ADD) { + /* logging is on if DA_EVENT is set */ + if (dargs->optflag & DA_EVENT) { + (void) snprintf(errmsg, sizeof (errmsg), + "%s and %s out of sync," + "%s only in %s.", + DEVALLOC, DEVMAP, + devallocp->da_devname, DEVALLOC); + syslog(LOG_ERR, "%s", errmsg); + } + freedaent(devallocp); + enddaent(); + return (2); + } else if (dargs->optflag & DA_REMOVE) { + /* make list w/o this entry */ + freedaent(devallocp); + continue; + } + } + tmp_str = _da2strentry(dargs, devallocp); + if (tmp_str == NULL) { + freedaent(devallocp); + enddaent(); + return (2); + } + /* retaining devalloc entry: tmp_str->se_str */ + tmp_str->se_next = NULL; + if (*head_devallocp == NULL) { + *head_devallocp = tail_str = tmp_str; + } else { + tail_str->se_next = tmp_str; + tail_str = tmp_str; + } + freedaent(devallocp); + } + enddaent(); + + /* the caller needs to know if a remove needs to rewrite files */ + if (dargs->optflag & DA_REMOVE) + return (1); /* 0 and 2 cases returned earlier */ + + return (0); /* Successful DA_ADD */ +} +/* * _build_lists - - * cycles through all the entries, stores them in memory. removes entries + * Cycles through all the entries, stores them in memory. removes entries * with the given search_key (device name or type). * returns 0 if given entry not found, 1 if given entry removed, 2 on * error. @@ -633,7 +844,7 @@ dmap_only: rc = 0; } if (rc == 0) { - tmp_str = _dmap2strentry(dargs, devmapp); + tmp_str = _dmap2strentry(devmapp); if (tmp_str == NULL) { freedmapent(devmapp); enddmapent(); @@ -675,12 +886,13 @@ _write_defattrs(FILE *fp, strentry_t *head_defent) /* * _write_device_allocate - * writes current entries in the list to device_allocate. + * frees the strings */ static void _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp) { int is_on = -1; - strentry_t *tmp_str; + strentry_t *tmp_str, *old_str; struct stat dastat; (void) fseek(dafp, (off_t)0, SEEK_SET); @@ -702,18 +914,21 @@ _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp) while (tmp_str) { (void) fputs(tmp_str->se_str, dafp); (void) fputs("\n", dafp); + old_str = tmp_str; tmp_str = tmp_str->se_next; + free(old_str); } } /* * _write_device_maps - * writes current entries in the list to device_maps. + * and frees the strings */ static void _write_device_maps(FILE *dmfp, strentry_t *head_devmapp) { - strentry_t *tmp_str; + strentry_t *tmp_str, *old_str; (void) fseek(dmfp, (off_t)0, SEEK_SET); @@ -721,7 +936,9 @@ _write_device_maps(FILE *dmfp, strentry_t *head_devmapp) while (tmp_str) { (void) fputs(tmp_str->se_str, dmfp); (void) fputs("\n", dmfp); + old_str = tmp_str; tmp_str = tmp_str->se_next; + free(old_str); } } @@ -744,7 +961,7 @@ _write_new_defattrs(FILE *fp, da_args *dargs) return (0); (void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT); - if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) { + if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) { (void) strcpy(tokp, devinfo->devopts); if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) { (void) fprintf(fp, "%s", tok); @@ -791,7 +1008,8 @@ _write_new_entry(FILE *fp, da_args *dargs, int flag) (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER); } else { - if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) { + if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1)) + != NULL) { (void) strcpy(tokp, devinfo->devopts); if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) != NULL) { @@ -1058,7 +1276,7 @@ _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp) str_found = 0; nsize = dastat.st_size + actionlen + 1; } - if ((nbuf = (char *)malloc(nsize)) == NULL) + if ((nbuf = (char *)malloc(nsize + 1)) == NULL) return (-1); nbuf[0] = '\0'; /* put the on/off string */ @@ -1168,8 +1386,9 @@ da_update_defattrs(da_args *dargs) /* * da_update_device - - * writes devices entries to device_allocate and device_maps. - * returns 0 on success, -1 on error. + * Writes existing entries and the SINGLE change requested by da_args, + * to device_allocate and device_maps. + * Returns 0 on success, -1 on error. */ int da_update_device(da_args *dargs) @@ -1288,25 +1507,58 @@ da_update_device(da_args *dargs) } /* - * examine all the entries, remove an old one if forced to, - * and check that they are suitable for updating. - * we need to do this only if the file exists already. + * If reacting to a hotplug, read the file entries, + * figure out what dname (tname + a new number) goes to the + * device being added/removed, and create a good head_devallocp and + * head_devmapp with everything good still in it (_rebuild_lists) + * + * Else examine all the entries, remove an old one if it is + * a duplicate with a device being added, returning the + * remaining list (_build_lists.) + * + * We need to do this only if the file exists already. + * + * Once we have built these lists, we need to free the strings + * in the head_* arrays before returning. */ if (stat(dapathp, &dastat) == 0) { - if ((rc = _build_lists(dargs, &head_devallocp, - &head_devmapp)) != 0) { - if (rc != 1) { - (void) close(tafd); - (void) unlink(apathp); - (void) close(lockfd); - return (rc); - } + /* for device allocation, the /etc files are the "master" */ + if ((dargs->optflag & (DA_ADD| DA_EVENT)) && + (!(dargs->optflag & DA_FORCE))) + rc = _rebuild_lists(dargs, &head_devallocp, + &head_devmapp); + else + rc = _build_lists(dargs, &head_devallocp, + &head_devmapp); + + if (rc != 0 && rc != 1) { + (void) close(tafd); + (void) unlink(apathp); + (void) close(lockfd); + return (-1); } + } else + rc = 0; + + if ((dargs->optflag & DA_REMOVE) && (rc == 0)) { + (void) close(tafd); + (void) unlink(apathp); + (void) close(lockfd); + return (0); } + /* + * TODO: clean up the workings of DA_UPDATE. + * Due to da_match looking at fields that are missing + * in dargs for DA_UPDATE, the da_match call returns no match, + * but due to the way _da2str combines the devalloc_t info with + * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work. + * + * This would not scale if any type of update was ever needed + * from the daemon. + */ /* - * write back any existing devalloc entries, along with - * the devalloc on/off string. + * Write out devallocp along with the devalloc on/off string. */ _write_device_allocate(dapathp, tafp, head_devallocp); @@ -1330,11 +1582,16 @@ dmap_only: return (-1); } - /* write back any existing devmap entries */ + /* + * Write back any non-removed pre-existing entries. + */ if (head_devmapp != NULL) _write_device_maps(tmfp, head_devmapp); out: + /* + * Add any new entries here. + */ if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { /* add any new entries */ rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY); @@ -1382,7 +1639,7 @@ da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) int new_entry = 0; char *dtype, *dexec, *tname, *kval; char *minstr = NULL, *maxstr = NULL; - char dname[DA_MAXNAME]; + char dname[DA_MAXNAME + 1]; kva_t *kva; deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL; da_defs_t *da_defs; @@ -1500,9 +1757,7 @@ da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) if ((nentry->devinfo.devlist = (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) { if (new_entry) { - nentry->devinfo.devname = NULL; free(nentry->devinfo.devname); - nentry = NULL; free(nentry); if (pentry != NULL) pentry->next = NULL; @@ -1693,6 +1948,78 @@ remove_dev: } /* + * da_rm_list_entry - + * + * The adding of devnames to a devlist and the removal of a + * device are not symmetrical -- hot_cleanup gives a /devices + * name which is used to remove the dentry whose links all point to + * that /devices entry. + * + * The link argument is present if available to make debugging + * easier. + * + * da_rm_list_entry removes an entry from the linked list of devices. + * + * Returns 1 if the devname was removed successfully, + * 0 if not found, -1 for error. + */ +/*ARGSUSED*/ +int +da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname) +{ + int retval = 0; + deventry_t **dentry, *current, *prev; + + switch (type) { + case DA_AUDIO: + dentry = &(dlist->audio); + break; + case DA_CD: + dentry = &(dlist->cd); + break; + case DA_FLOPPY: + dentry = &(dlist->floppy); + break; + case DA_TAPE: + dentry = &(dlist->tape); + break; + case DA_RMDISK: + dentry = &(dlist->rmdisk); + break; + default: + return (-1); + } + + /* Presumably in daemon mode, no need to remove entry, list is empty */ + if (*dentry == (deventry_t *)NULL) + return (0); + + prev = NULL; + for (current = *dentry; current != NULL; + prev = current, current = current->next) { + if (strcmp(devname, current->devinfo.devname)) + continue; + retval = 1; + break; + } + if (retval == 0) + return (0); + free(current->devinfo.devname); + if (current->devinfo.devlist != NULL) + free(current->devinfo.devlist); + if (current->devinfo.devopts != NULL) + free(current->devinfo.devopts); + + if (prev == NULL) + *dentry = current->next; + else + prev->next = current->next; + + free(current); + return (retval); +} + +/* * da_is_on - * checks if device allocation feature is turned on. * returns 1 if on, 0 if off, -1 if status string not diff --git a/usr/src/lib/libbsm/common/devalloc.h b/usr/src/lib/libbsm/common/devalloc.h index 6755f94001..303be1aa45 100644 --- a/usr/src/lib/libbsm/common/devalloc.h +++ b/usr/src/lib/libbsm/common/devalloc.h @@ -20,15 +20,13 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DEVALLOC_H #define _DEVALLOC_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -45,7 +43,7 @@ extern "C" { #define DA_UID (uid_t)0 /* root */ #define DA_GID (gid_t)3 /* sys */ #define ALLOC_MODE 0600 -#define DEALLOC_MODE 0000 +#define DEALLOC_MODE 0000 #define LOGINDEVPERM "/etc/logindevperm" #define DA_DB_LOCK "/etc/security/.da_db_lock" @@ -73,6 +71,7 @@ extern "C" { #define DA_AUTHLEN MAX_CANON /* approx. sum of strlen of all */ /* device auths in auth_list.h */ #define DA_MAXNAME 80 +#define DA_MAX_DEVNO ((8 * sizeof (uint64_t)) - 1) #define DA_BUFSIZE 4096 #define DA_RDWR O_RDWR|O_CREAT|O_NONBLOCK @@ -95,6 +94,7 @@ extern "C" { #define DA_OFF 0x00000800 #define DA_NO_OVERRIDE 0x00001000 #define DA_DEFATTRS 0x00002000 +#define DA_EVENT 0x00004000 #define DA_AUDIO 0x00001000 #define DA_CD 0x00002000 @@ -171,6 +171,7 @@ int da_update_device(da_args *); int da_update_defattrs(da_args *); int da_add_list(devlist_t *, char *, int, int); int da_remove_list(devlist_t *, char *, int, char *, int); +int da_rm_list_entry(devlist_t *, char *, int, char *); void da_print_device(int, devlist_t *); diff --git a/usr/src/lib/libbsm/common/getdment.c b/usr/src/lib/libbsm/common/getdment.c index 0bf82e86e3..33256cbf39 100644 --- a/usr/src/lib/libbsm/common/getdment.c +++ b/usr/src/lib/libbsm/common/getdment.c @@ -19,14 +19,16 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <string.h> +#include <strings.h> #include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <device_info.h> #include <bsm/devices.h> #include <bsm/devalloc.h> @@ -281,6 +283,31 @@ getdmaptype(char *type) } /* + * dmap_match_one_dev - + * Checks if the specified devmap_t contains strings + * for the same logical link as the device specified. + * This guarantees that the beginnings of a devlist build + * match a more-complete devlist for the same device. + * + * Returns 1 for a match, else returns 0. + */ +static int +dmap_match_one_dev(devmap_t *dmap, char *dev) +{ + char **dva; + char *dv; + + if (dmap->dmap_devarray == NULL) + return (0); + + for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva++) { + if (strstr(dev, dv) != NULL) + return (1); + } + return (0); +} + +/* * dmap_matchdev - * checks if the specified devmap_t is for the device specified. * returns 1 if it is, else returns 0. @@ -302,6 +329,25 @@ dmap_matchdev(devmap_t *dmap, char *dev) } /* + * Requires a match of the /dev/?dsk links, not just the logical devname + * Returns 1 for match found, 0 for match not found, 2 for invalid arguments. + */ +int +dmap_exact_dev(devmap_t *dmap, char *dev, int *num) +{ + char *dv; + + if ((dev == NULL) || (dmap->dmap_devname == NULL)) + return (2); + dv = dmap->dmap_devname; + dv += strcspn(dmap->dmap_devname, "0123456789"); + if (sscanf(dv, "%d", num) != 1) + return (2); + /* during some add processes, dev can be shorter than dmap */ + return (dmap_match_one_dev(dmap, dev)); +} + +/* * dmap_matchtype - * checks if the specified devmap_t is for the device specified. * returns 1 if it is, else returns 0. @@ -330,6 +376,29 @@ dmap_matchname(devmap_t *dmap, char *name) } /* + * dmap_physname: path to /devices device + * Returns: + * strdup'd (i.e. malloc'd) real device file if successful + * NULL on error + */ +char * +dmap_physname(devmap_t *dmap) +{ + char *oldlink; + char stage_link[PATH_MAX + 1]; + + if ((dmap == NULL) || (dmap->dmap_devarray == NULL) || + (dmap->dmap_devarray[0] == NULL)) + return (NULL); + + (void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link)); + + if (devfs_resolve_link(stage_link, &oldlink) == 0) + return (oldlink); + return (NULL); +} + +/* * dm_match - * calls dmap_matchname or dmap_matchtype as appropriate. */ diff --git a/usr/src/lib/libbsm/common/mapfile-vers b/usr/src/lib/libbsm/common/mapfile-vers index 7007eff427..41922451a7 100644 --- a/usr/src/lib/libbsm/common/mapfile-vers +++ b/usr/src/lib/libbsm/common/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -297,6 +297,7 @@ SUNWprivate_1.1 { da_open_devdb; da_print_device; da_remove_list; + da_rm_list_entry; da_update_defattrs; da_update_device; _endac; diff --git a/usr/src/lib/libdevinfo/device_info.h b/usr/src/lib/libdevinfo/device_info.h index 32e65ac8d8..62087d1ba3 100644 --- a/usr/src/lib/libdevinfo/device_info.h +++ b/usr/src/lib/libdevinfo/device_info.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -129,6 +129,12 @@ extern int devfs_get_all_prom_names(const char *, uint_t, extern void devfs_free_all_prom_names(struct devfs_prom_path *); /* + * Interpret a /dev link to its /devices path (does not require path to + * still exist, as long as the links exist) + */ +extern int devfs_resolve_link(char *, char **); + +/* * map a device name from install OS environment to target OS environment or * vice-versa. */ diff --git a/usr/src/lib/libdevinfo/devinfo_devperm.c b/usr/src/lib/libdevinfo/devinfo_devperm.c index e2716af8d3..d802783def 100644 --- a/usr/src/lib/libdevinfo/devinfo_devperm.c +++ b/usr/src/lib/libdevinfo/devinfo_devperm.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -269,8 +269,8 @@ logindevperm(const char *ttyn, uid_t uid, gid_t gid, void (*errmsg)(char *)) * devpath: Absolute path to /dev link * devfs_path: Returns malloced string: /devices path w/out "/devices" */ -static int -resolve_link(char *devpath, char **devfs_path) +int +devfs_resolve_link(char *devpath, char **devfs_path) { char contents[PATH_MAX + 1]; char stage_link[PATH_MAX + 1]; @@ -313,7 +313,7 @@ resolve_link(char *devpath, char **devfs_path) (void) strcat(stage_link, contents); } - return (resolve_link(stage_link, devfs_path)); + return (devfs_resolve_link(stage_link, devfs_path)); } if (devfs_path) { @@ -339,7 +339,7 @@ check_driver_match(char *path, char *line) char saveline[MAX_LINELEN]; char *p; - if (resolve_link(path, &devfs_path) == 0) { + if (devfs_resolve_link(path, &devfs_path) == 0) { char *p; char pwd_buf[PATH_MAX]; di_node_t node; diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers index bf0c6caf21..bfad2642f2 100644 --- a/usr/src/lib/libdevinfo/mapfile-vers +++ b/usr/src/lib/libdevinfo/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -152,6 +152,7 @@ SUNW_1.1 { SUNWprivate_1.1 { global: devfs_add_minor_perm; + devfs_resolve_link; devfs_bootdev_free_list; devfs_bootdev_get_list; devfs_bootdev_modifiable; |