145916cd2Sjpk /* 245916cd2Sjpk * CDDL HEADER START 345916cd2Sjpk * 445916cd2Sjpk * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 745916cd2Sjpk * 845916cd2Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 945916cd2Sjpk * or http://www.opensolaris.org/os/licensing. 1045916cd2Sjpk * See the License for the specific language governing permissions 1145916cd2Sjpk * and limitations under the License. 1245916cd2Sjpk * 1345916cd2Sjpk * When distributing Covered Code, include this CDDL HEADER in each 1445916cd2Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1545916cd2Sjpk * If applicable, add the following below this CDDL HEADER, with the 1645916cd2Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 1745916cd2Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 1845916cd2Sjpk * 1945916cd2Sjpk * CDDL HEADER END 2045916cd2Sjpk */ 2145916cd2Sjpk 2245916cd2Sjpk /* 23*399f0677SJan Parcel * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 2445916cd2Sjpk */ 2545916cd2Sjpk 2645916cd2Sjpk #include <stdlib.h> 2745916cd2Sjpk #include <ctype.h> 2845916cd2Sjpk #include <unistd.h> 2945916cd2Sjpk #include <limits.h> 3045916cd2Sjpk #include <fcntl.h> 3145916cd2Sjpk #include <sys/types.h> 3245916cd2Sjpk #include <sys/stat.h> 3345916cd2Sjpk #include <utime.h> 3445916cd2Sjpk #include <synch.h> 3545916cd2Sjpk #include <strings.h> 3645916cd2Sjpk #include <string.h> 3745916cd2Sjpk #include <libintl.h> 3845916cd2Sjpk #include <errno.h> 3945916cd2Sjpk #include <auth_list.h> 407e3e5701SJan Parcel #include <syslog.h> 4145916cd2Sjpk #include <bsm/devices.h> 4245916cd2Sjpk #include <bsm/devalloc.h> 43*399f0677SJan Parcel #include <tsol/label.h> 4445916cd2Sjpk 4545916cd2Sjpk #define DA_DEFS "/etc/security/tsol/devalloc_defaults" 4645916cd2Sjpk 4745916cd2Sjpk extern int _readbufline(char *, int, char *, int, int *); 4845916cd2Sjpk extern char *strtok_r(char *, const char *, char **); 4945916cd2Sjpk extern char *_strtok_escape(char *, char *, char **); 5045916cd2Sjpk extern int getdaon(void); 5145916cd2Sjpk extern int da_matchname(devalloc_t *, char *); 5245916cd2Sjpk extern int da_match(devalloc_t *, da_args *); 5345916cd2Sjpk extern int dmap_matchname(devmap_t *, char *); 5445916cd2Sjpk extern int dm_match(devmap_t *, da_args *); 557e3e5701SJan Parcel extern int dmap_matchtype(devmap_t *dmap, char *type); 567e3e5701SJan Parcel extern int dmap_matchdev(devmap_t *dmap, char *dev); 577e3e5701SJan Parcel extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num); 587e3e5701SJan Parcel extern char *dmap_physname(devmap_t *dmap); 5945916cd2Sjpk 6045916cd2Sjpk /* 6145916cd2Sjpk * The following structure is for recording old entries to be retained. 6245916cd2Sjpk * We read the entries from the database into a linked list in memory, 6345916cd2Sjpk * then turn around and write them out again. 6445916cd2Sjpk */ 6545916cd2Sjpk typedef struct strentry { 6645916cd2Sjpk struct strentry *se_next; 6745916cd2Sjpk char se_str[4096 + 1]; 6845916cd2Sjpk } strentry_t; 6945916cd2Sjpk 7045916cd2Sjpk /* 7145916cd2Sjpk * da_check_longindevperm - 7245916cd2Sjpk * reads /etc/logindevperm and checks if specified device is in the file. 7345916cd2Sjpk * returns 1 if specified device found in /etc/logindevperm, else returns 0 7445916cd2Sjpk */ 7545916cd2Sjpk int 7645916cd2Sjpk da_check_logindevperm(char *devname) 7745916cd2Sjpk { 7845916cd2Sjpk int ret = 0; 7945916cd2Sjpk int fd = -1; 8045916cd2Sjpk int nlen, plen, slen, lineno, fsize; 8145916cd2Sjpk char line[MAX_CANON]; 8245916cd2Sjpk char *field_delims = " \t\n"; 8345916cd2Sjpk char *fbuf = NULL; 8445916cd2Sjpk char *ptr, *device; 8545916cd2Sjpk char *lasts = NULL; 8645916cd2Sjpk FILE *fp; 8745916cd2Sjpk struct stat f_stat; 8845916cd2Sjpk 8945916cd2Sjpk /* 9045916cd2Sjpk * check if /etc/logindevperm exists and get its size 9145916cd2Sjpk */ 9245916cd2Sjpk if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1) 9345916cd2Sjpk return (0); 9445916cd2Sjpk if (fstat(fd, &f_stat) != 0) { 9545916cd2Sjpk (void) close(fd); 9645916cd2Sjpk return (0); 9745916cd2Sjpk } 9845916cd2Sjpk fsize = f_stat.st_size; 9945916cd2Sjpk if ((fbuf = (char *)malloc(fsize)) == NULL) { 10045916cd2Sjpk (void) close(fd); 10145916cd2Sjpk return (0); 10245916cd2Sjpk } 103004388ebScasper if ((fp = fdopen(fd, "rF")) == NULL) { 10445916cd2Sjpk free(fbuf); 10545916cd2Sjpk (void) close(fd); 10645916cd2Sjpk return (0); 10745916cd2Sjpk } 10845916cd2Sjpk 10945916cd2Sjpk /* 11045916cd2Sjpk * read and parse /etc/logindevperm 11145916cd2Sjpk */ 11245916cd2Sjpk plen = nlen = lineno = 0; 11345916cd2Sjpk while (fgets(line, MAX_CANON, fp) != NULL) { 11445916cd2Sjpk lineno++; 11545916cd2Sjpk if ((ptr = strchr(line, '#')) != NULL) 11645916cd2Sjpk *ptr = '\0'; /* handle comments */ 11745916cd2Sjpk if (strtok_r(line, field_delims, &lasts) == NULL) 11845916cd2Sjpk continue; /* ignore blank lines */ 11945916cd2Sjpk if (strtok_r(NULL, field_delims, &lasts) == NULL) 12045916cd2Sjpk /* invalid entry */ 12145916cd2Sjpk continue; 12245916cd2Sjpk if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL) 12345916cd2Sjpk /* empty device list */ 12445916cd2Sjpk continue; 12545916cd2Sjpk nlen = strlen(ptr) + 1; /* +1 terminator */ 12645916cd2Sjpk nlen += (plen + 1); 12745916cd2Sjpk if (plen == 0) 12845916cd2Sjpk slen = snprintf(fbuf, nlen, "%s", ptr); 12945916cd2Sjpk else 13045916cd2Sjpk slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr); 13145916cd2Sjpk if (slen >= fsize) { 13245916cd2Sjpk fbuf[0] = '\0'; 13345916cd2Sjpk (void) fclose(fp); 13445916cd2Sjpk return (slen); 13545916cd2Sjpk } 13645916cd2Sjpk plen += slen; 13745916cd2Sjpk } 13845916cd2Sjpk (void) fclose(fp); 13945916cd2Sjpk 14045916cd2Sjpk /* 14145916cd2Sjpk * check if devname exists in /etc/logindevperm 14245916cd2Sjpk */ 14345916cd2Sjpk device = strtok_r(fbuf, ":", &lasts); 14445916cd2Sjpk while (device != NULL) { 14545916cd2Sjpk /* 14645916cd2Sjpk * device and devname may be one of these types - 14745916cd2Sjpk * /dev/xx 14845916cd2Sjpk * /dev/xx* 14945916cd2Sjpk * /dev/dir/xx 15045916cd2Sjpk * /dev/dir/xx* 15145916cd2Sjpk * /dev/dir/"*" 15245916cd2Sjpk */ 15345916cd2Sjpk if (strcmp(device, devname) == 0) { 15445916cd2Sjpk /* /dev/xx, /dev/dir/xx */ 15545916cd2Sjpk free(fbuf); 15645916cd2Sjpk return (1); 15745916cd2Sjpk } 15845916cd2Sjpk if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) { 15945916cd2Sjpk /* all wildcard types */ 16045916cd2Sjpk *ptr = '\0'; 16145916cd2Sjpk if (strncmp(device, devname, strlen(device)) == 0) { 16245916cd2Sjpk free(fbuf); 16345916cd2Sjpk return (1); 16445916cd2Sjpk } 16545916cd2Sjpk } 16645916cd2Sjpk device = strtok_r(NULL, ":", &lasts); 16745916cd2Sjpk } 16845916cd2Sjpk 16945916cd2Sjpk return (ret); 17045916cd2Sjpk } 17145916cd2Sjpk 17245916cd2Sjpk /* 17345916cd2Sjpk * _da_read_file - 17445916cd2Sjpk * establishes readers/writer lock on fname; reads in the file if its 17545916cd2Sjpk * contents changed since the last time we read it. 17645916cd2Sjpk * returns size of buffer read, or -1 on failure. 17745916cd2Sjpk */ 17845916cd2Sjpk int 17945916cd2Sjpk _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock, 18045916cd2Sjpk int flag) 18145916cd2Sjpk { 18245916cd2Sjpk int fd = -1; 18345916cd2Sjpk int fsize = 0; 18445916cd2Sjpk time_t newtime; 18545916cd2Sjpk struct stat f_stat; 18645916cd2Sjpk 18745916cd2Sjpk if (flag & DA_FORCE) 18845916cd2Sjpk *ftime = 0; 18945916cd2Sjpk 19045916cd2Sjpk /* check the size and the time stamp on the file */ 19145916cd2Sjpk if (rw_rdlock(flock) != 0) 19245916cd2Sjpk return (-1); 19345916cd2Sjpk if (stat(fname, &f_stat) != 0) { 19445916cd2Sjpk (void) rw_unlock(flock); 19545916cd2Sjpk return (-1); 19645916cd2Sjpk } 19745916cd2Sjpk fsize = f_stat.st_size; 19845916cd2Sjpk newtime = f_stat.st_mtime; 19945916cd2Sjpk (void) rw_unlock(flock); 20045916cd2Sjpk 20145916cd2Sjpk while (newtime > *ftime) { 20245916cd2Sjpk /* 20345916cd2Sjpk * file has been modified since we last read it; or this 20445916cd2Sjpk * is a forced read. 20545916cd2Sjpk * read file into the buffer with rw lock. 20645916cd2Sjpk */ 20745916cd2Sjpk if (rw_wrlock(flock) != 0) 20845916cd2Sjpk return (-1); 209004388ebScasper if ((fd = open(fname, O_RDONLY)) == -1) { 21045916cd2Sjpk (void) rw_unlock(flock); 21145916cd2Sjpk return (-1); 21245916cd2Sjpk } 21345916cd2Sjpk if (*fbuf != NULL) { 21445916cd2Sjpk free(*fbuf); 21545916cd2Sjpk *fbuf = NULL; 21645916cd2Sjpk } 21745916cd2Sjpk if ((*fbuf = malloc(fsize)) == NULL) { 21845916cd2Sjpk (void) rw_unlock(flock); 21945916cd2Sjpk (void) close(fd); 22045916cd2Sjpk return (-1); 22145916cd2Sjpk } 22245916cd2Sjpk if (read(fd, *fbuf, fsize) < fsize) { 22345916cd2Sjpk free(*fbuf); 22445916cd2Sjpk (void) rw_unlock(flock); 22545916cd2Sjpk (void) close(fd); 22645916cd2Sjpk return (-1); 22745916cd2Sjpk } 22845916cd2Sjpk (void) rw_unlock(flock); 22945916cd2Sjpk /* 23045916cd2Sjpk * verify that the file did not change just after we read it. 23145916cd2Sjpk */ 23245916cd2Sjpk if (rw_rdlock(flock) != 0) { 23345916cd2Sjpk free(*fbuf); 23445916cd2Sjpk (void) close(fd); 23545916cd2Sjpk return (-1); 23645916cd2Sjpk } 23745916cd2Sjpk if (stat(fname, &f_stat) != 0) { 23845916cd2Sjpk free(*fbuf); 23945916cd2Sjpk (void) rw_unlock(flock); 24045916cd2Sjpk (void) close(fd); 24145916cd2Sjpk return (-1); 24245916cd2Sjpk } 24345916cd2Sjpk fsize = f_stat.st_size; 24445916cd2Sjpk newtime = f_stat.st_mtime; 24545916cd2Sjpk (void) rw_unlock(flock); 24645916cd2Sjpk (void) close(fd); 24745916cd2Sjpk *ftime = newtime; 24845916cd2Sjpk } 24945916cd2Sjpk 25045916cd2Sjpk return (fsize); 25145916cd2Sjpk } 25245916cd2Sjpk 25345916cd2Sjpk /* 25445916cd2Sjpk * _update_zonename - 25545916cd2Sjpk * add/remove current zone's name to the given devalloc_t. 25645916cd2Sjpk */ 25745916cd2Sjpk void 25845916cd2Sjpk _update_zonename(da_args *dargs, devalloc_t *dap) 25945916cd2Sjpk { 26045916cd2Sjpk int i, j; 26145916cd2Sjpk int oldsize, newsize; 26245916cd2Sjpk int has_zonename = 0; 26345916cd2Sjpk char *zonename; 26445916cd2Sjpk kva_t *newkva, *oldkva; 26545916cd2Sjpk kv_t *newdata, *olddata; 26645916cd2Sjpk devinfo_t *devinfo; 26745916cd2Sjpk 26845916cd2Sjpk devinfo = dargs->devinfo; 26945916cd2Sjpk oldkva = dap->da_devopts; 27045916cd2Sjpk if (oldkva == NULL) { 27145916cd2Sjpk if (dargs->optflag & DA_REMOVE_ZONE) 27245916cd2Sjpk return; 27345916cd2Sjpk if (dargs->optflag & DA_ADD_ZONE) { 27445916cd2Sjpk newkva = _str2kva(devinfo->devopts, KV_ASSIGN, 27545916cd2Sjpk KV_TOKEN_DELIMIT); 27645916cd2Sjpk if (newkva != NULL) 27745916cd2Sjpk dap->da_devopts = newkva; 27845916cd2Sjpk return; 27945916cd2Sjpk } 28045916cd2Sjpk } 28145916cd2Sjpk newsize = oldsize = oldkva->length; 28245916cd2Sjpk if (kva_match(oldkva, DAOPT_ZONE)) 28345916cd2Sjpk has_zonename = 1; 28445916cd2Sjpk if (dargs->optflag & DA_ADD_ZONE) { 28545916cd2Sjpk if ((zonename = index(devinfo->devopts, '=')) == NULL) 28645916cd2Sjpk return; 28745916cd2Sjpk zonename++; 28845916cd2Sjpk if (has_zonename) { 28945916cd2Sjpk (void) _insert2kva(oldkva, DAOPT_ZONE, zonename); 29045916cd2Sjpk return; 29145916cd2Sjpk } 29245916cd2Sjpk newsize += 1; 29345916cd2Sjpk } else if (dargs->optflag & DA_REMOVE_ZONE) { 29445916cd2Sjpk if (has_zonename) { 29545916cd2Sjpk newsize -= 1; 29645916cd2Sjpk if (newsize == 0) { 29745916cd2Sjpk /* 29845916cd2Sjpk * If zone name was the only key/value pair, 29945916cd2Sjpk * put 'reserved' in the empty slot. 30045916cd2Sjpk */ 30145916cd2Sjpk _kva_free(oldkva); 30245916cd2Sjpk dap->da_devopts = NULL; 30345916cd2Sjpk return; 30445916cd2Sjpk } 30545916cd2Sjpk } else { 30645916cd2Sjpk return; 30745916cd2Sjpk } 30845916cd2Sjpk } 30945916cd2Sjpk newkva = _new_kva(newsize); 31045916cd2Sjpk newkva->length = 0; 31145916cd2Sjpk newdata = newkva->data; 31245916cd2Sjpk olddata = oldkva->data; 31345916cd2Sjpk for (i = 0, j = 0; i < oldsize; i++) { 31445916cd2Sjpk if ((dargs->optflag & DA_REMOVE_ZONE) && 31545916cd2Sjpk (strcmp(olddata[i].key, DAOPT_ZONE) == 0)) 31645916cd2Sjpk continue; 31745916cd2Sjpk newdata[j].key = strdup(olddata[i].key); 31845916cd2Sjpk newdata[j].value = strdup(olddata[i].value); 31945916cd2Sjpk newkva->length++; 32045916cd2Sjpk j++; 32145916cd2Sjpk } 32245916cd2Sjpk if (dargs->optflag & DA_ADD_ZONE) { 32345916cd2Sjpk newdata[j].key = strdup(DAOPT_ZONE); 32445916cd2Sjpk newdata[j].value = strdup(zonename); 32545916cd2Sjpk newkva->length++; 32645916cd2Sjpk } 32745916cd2Sjpk _kva_free(oldkva); 32845916cd2Sjpk dap->da_devopts = newkva; 32945916cd2Sjpk } 33045916cd2Sjpk 33145916cd2Sjpk /* 33245916cd2Sjpk * _dmap2str - 33345916cd2Sjpk * converts a device_map entry into a printable string 33445916cd2Sjpk * returns 0 on success, -1 on error. 33545916cd2Sjpk */ 33645916cd2Sjpk /*ARGSUSED*/ 33745916cd2Sjpk static int 3387e3e5701SJan Parcel _dmap2str(devmap_t *dmp, char *buf, int size, const char *sep) 33945916cd2Sjpk { 34045916cd2Sjpk int length; 34145916cd2Sjpk 34245916cd2Sjpk length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep); 34345916cd2Sjpk if (length >= size) 34445916cd2Sjpk return (-1); 34545916cd2Sjpk length += snprintf(buf + length, size - length, "%s%s", 34645916cd2Sjpk dmp->dmap_devtype, sep); 34745916cd2Sjpk if (length >= size) 34845916cd2Sjpk return (-1); 34945916cd2Sjpk length += snprintf(buf + length, size - length, "%s\n", 35045916cd2Sjpk dmp->dmap_devlist); 35145916cd2Sjpk if (length >= size) 35245916cd2Sjpk return (-1); 35345916cd2Sjpk return (0); 35445916cd2Sjpk } 35545916cd2Sjpk 35645916cd2Sjpk /* 35745916cd2Sjpk * _dmap2strentry - 35845916cd2Sjpk * calls dmap2str to break given devmap_t into printable entry. 35945916cd2Sjpk * returns pointer to decoded entry, NULL on error. 36045916cd2Sjpk */ 36145916cd2Sjpk static strentry_t * 3627e3e5701SJan Parcel _dmap2strentry(devmap_t *devmapp) 36345916cd2Sjpk { 36445916cd2Sjpk strentry_t *sep; 36545916cd2Sjpk 36645916cd2Sjpk if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 36745916cd2Sjpk return (NULL); 3687e3e5701SJan Parcel if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str), 36945916cd2Sjpk KV_TOKEN_DELIMIT"\\\n\t") != 0) { 37045916cd2Sjpk free(sep); 37145916cd2Sjpk return (NULL); 37245916cd2Sjpk } 37345916cd2Sjpk return (sep); 37445916cd2Sjpk } 37545916cd2Sjpk 37645916cd2Sjpk /* 37745916cd2Sjpk * fix_optstr - 37845916cd2Sjpk * removes trailing ':' from buf. 37945916cd2Sjpk */ 38045916cd2Sjpk void 38145916cd2Sjpk fix_optstr(char *buf) 38245916cd2Sjpk { 38345916cd2Sjpk char *p = NULL; 38445916cd2Sjpk 38545916cd2Sjpk if (p = rindex(buf, ':')) 38645916cd2Sjpk *p = ';'; 38745916cd2Sjpk } 38845916cd2Sjpk 38945916cd2Sjpk /* 39045916cd2Sjpk * _da2str - 39145916cd2Sjpk * converts a device_allocate entry into a printable string 39245916cd2Sjpk * returns 0 on success, -1 on error. 39345916cd2Sjpk */ 39445916cd2Sjpk static int 39545916cd2Sjpk _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep, 39645916cd2Sjpk const char *osep) 39745916cd2Sjpk { 39845916cd2Sjpk int length; 39945916cd2Sjpk int matching_entry = 0; 40045916cd2Sjpk char **dnames; 40145916cd2Sjpk 40245916cd2Sjpk if (dargs->optflag & DA_UPDATE && 40345916cd2Sjpk (dargs->optflag & DA_ADD_ZONE || 40445916cd2Sjpk dargs->optflag & DA_REMOVE_ZONE) && 40545916cd2Sjpk dargs->devnames) { 40645916cd2Sjpk for (dnames = dargs->devnames; *dnames != NULL; dnames++) { 40745916cd2Sjpk if (da_matchname(dap, *dnames)) { 40845916cd2Sjpk matching_entry = 1; 40945916cd2Sjpk break; 41045916cd2Sjpk } 41145916cd2Sjpk } 41245916cd2Sjpk } 41345916cd2Sjpk length = snprintf(buf, size, "%s%s", dap->da_devname, sep); 41445916cd2Sjpk if (length >= size) 41545916cd2Sjpk return (-1); 41645916cd2Sjpk length += snprintf(buf + length, size - length, "%s%s", 41745916cd2Sjpk dap->da_devtype, sep); 41845916cd2Sjpk if (length >= size) 41945916cd2Sjpk return (-1); 42045916cd2Sjpk if (matching_entry) 42145916cd2Sjpk _update_zonename(dargs, dap); 42245916cd2Sjpk if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) && 42345916cd2Sjpk (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) { 42445916cd2Sjpk length += snprintf(buf + length, size - length, "%s%s", 42545916cd2Sjpk DA_RESERVED, sep); 42645916cd2Sjpk } else { 42745916cd2Sjpk if (_kva2str(dap->da_devopts, buf + length, size - length, 42845916cd2Sjpk KV_ASSIGN, (char *)osep) != 0) 42945916cd2Sjpk return (-1); 43045916cd2Sjpk length = strlen(buf); 43145916cd2Sjpk } 43245916cd2Sjpk if (dap->da_devopts) 43345916cd2Sjpk fix_optstr(buf); 43445916cd2Sjpk if (length >= size) 43545916cd2Sjpk return (-1); 43645916cd2Sjpk length += snprintf(buf + length, size - length, "%s%s", 43745916cd2Sjpk DA_RESERVED, sep); 43845916cd2Sjpk if (length >= size) 43945916cd2Sjpk return (-1); 44045916cd2Sjpk length += snprintf(buf + length, size - length, "%s%s", 44145916cd2Sjpk dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep); 44245916cd2Sjpk if (length >= size) 44345916cd2Sjpk return (-1); 44445916cd2Sjpk length += snprintf(buf + length, size - length, "%s\n", 44545916cd2Sjpk dap->da_devexec ? dap->da_devexec : ""); 44645916cd2Sjpk if (length >= size) 44745916cd2Sjpk return (-1); 44845916cd2Sjpk 44945916cd2Sjpk return (0); 45045916cd2Sjpk } 45145916cd2Sjpk 45245916cd2Sjpk /* 45345916cd2Sjpk * _da2strentry - 45445916cd2Sjpk * calls da2str to break given devalloc_t into printable entry. 45545916cd2Sjpk * returns pointer to decoded entry, NULL on error. 45645916cd2Sjpk */ 45745916cd2Sjpk static strentry_t * 45845916cd2Sjpk _da2strentry(da_args *dargs, devalloc_t *dap) 45945916cd2Sjpk { 46045916cd2Sjpk strentry_t *sep; 46145916cd2Sjpk 46245916cd2Sjpk if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 46345916cd2Sjpk return (NULL); 46445916cd2Sjpk if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str), 46545916cd2Sjpk KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) { 46645916cd2Sjpk free(sep); 46745916cd2Sjpk return (NULL); 46845916cd2Sjpk } 46945916cd2Sjpk return (sep); 47045916cd2Sjpk } 47145916cd2Sjpk 47245916cd2Sjpk /* 47345916cd2Sjpk * _def2str 47445916cd2Sjpk * converts da_defs_t into a printable string. 47545916cd2Sjpk * returns 0 on success, -1 on error. 47645916cd2Sjpk */ 47745916cd2Sjpk static int 47845916cd2Sjpk _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep) 47945916cd2Sjpk { 48045916cd2Sjpk int length; 48145916cd2Sjpk 48245916cd2Sjpk length = snprintf(buf, size, "%s%s", da_defs->devtype, sep); 48345916cd2Sjpk if (length >= size) 48445916cd2Sjpk return (-1); 48545916cd2Sjpk if (da_defs->devopts) { 48645916cd2Sjpk if (_kva2str(da_defs->devopts, buf + length, size - length, 48745916cd2Sjpk KV_ASSIGN, KV_DELIMITER) != 0) 48845916cd2Sjpk return (-1); 48945916cd2Sjpk length = strlen(buf); 49045916cd2Sjpk } 49145916cd2Sjpk if (length >= size) 49245916cd2Sjpk return (-1); 49345916cd2Sjpk 49445916cd2Sjpk return (0); 49545916cd2Sjpk } 49645916cd2Sjpk 49745916cd2Sjpk /* 49845916cd2Sjpk * _def2strentry 49945916cd2Sjpk * calls _def2str to break given da_defs_t into printable entry. 50045916cd2Sjpk * returns pointer decoded entry, NULL on error. 50145916cd2Sjpk */ 50245916cd2Sjpk static strentry_t * 50345916cd2Sjpk _def2strentry(da_defs_t *da_defs) 50445916cd2Sjpk { 50545916cd2Sjpk strentry_t *sep; 50645916cd2Sjpk 50745916cd2Sjpk if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 50845916cd2Sjpk return (NULL); 50945916cd2Sjpk if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str), 51045916cd2Sjpk KV_TOKEN_DELIMIT) != 0) { 51145916cd2Sjpk free(sep); 51245916cd2Sjpk return (NULL); 51345916cd2Sjpk } 51445916cd2Sjpk 51545916cd2Sjpk return (sep); 51645916cd2Sjpk } 51745916cd2Sjpk 51845916cd2Sjpk /* 51945916cd2Sjpk * _build_defattrs 52045916cd2Sjpk * cycles through all defattr entries, stores them in memory. removes 52145916cd2Sjpk * entries with the given search_key (device type). 52245916cd2Sjpk * returns 0 if given entry not found, 1 if given entry removed, 2 on 52345916cd2Sjpk * error. 52445916cd2Sjpk */ 52545916cd2Sjpk static int 52645916cd2Sjpk _build_defattrs(da_args *dargs, strentry_t **head_defent) 52745916cd2Sjpk { 52845916cd2Sjpk int rc = 0; 52945916cd2Sjpk da_defs_t *da_defs; 53045916cd2Sjpk strentry_t *tail_str, *tmp_str; 53145916cd2Sjpk 53245916cd2Sjpk setdadefent(); 53345916cd2Sjpk while ((da_defs = getdadefent()) != NULL) { 53445916cd2Sjpk rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype)); 53545916cd2Sjpk if (rc && dargs->optflag & DA_ADD && 53645916cd2Sjpk !(dargs->optflag & DA_FORCE)) { 53745916cd2Sjpk /* 53845916cd2Sjpk * During DA_ADD, we keep an existing entry unless 53945916cd2Sjpk * we have DA_FORCE set to override that entry. 54045916cd2Sjpk */ 54145916cd2Sjpk dargs->optflag |= DA_NO_OVERRIDE; 54245916cd2Sjpk rc = 0; 54345916cd2Sjpk } 54445916cd2Sjpk if (rc == 0) { 54545916cd2Sjpk tmp_str = _def2strentry(da_defs); 54645916cd2Sjpk if (tmp_str == NULL) { 54745916cd2Sjpk freedadefent(da_defs); 54845916cd2Sjpk enddadefent(); 54945916cd2Sjpk return (2); 55045916cd2Sjpk } 55145916cd2Sjpk /* retaining defattr entry: tmp_str->se_str */ 55245916cd2Sjpk tmp_str->se_next = NULL; 55345916cd2Sjpk if (*head_defent == NULL) { 55445916cd2Sjpk *head_defent = tail_str = tmp_str; 55545916cd2Sjpk } else { 55645916cd2Sjpk tail_str->se_next = tmp_str; 55745916cd2Sjpk tail_str = tmp_str; 55845916cd2Sjpk } 55945916cd2Sjpk } 56045916cd2Sjpk freedadefent(da_defs); 56145916cd2Sjpk } 56245916cd2Sjpk enddadefent(); 56345916cd2Sjpk 56445916cd2Sjpk return (rc); 56545916cd2Sjpk } 56645916cd2Sjpk 56745916cd2Sjpk /* 568*399f0677SJan Parcel * We have to handle the "standard" types in devlist differently than 569*399f0677SJan Parcel * other devices, which are not covered by our auto-naming conventions. 570*399f0677SJan Parcel * 571*399f0677SJan Parcel * buf must be a buffer of size DA_MAX_NAME + 1 572*399f0677SJan Parcel */ 573*399f0677SJan Parcel int 574*399f0677SJan Parcel da_std_type(da_args *dargs, char *namebuf) 575*399f0677SJan Parcel { 576*399f0677SJan Parcel char *type = dargs->devinfo->devtype; 577*399f0677SJan Parcel int system_labeled; 578*399f0677SJan Parcel 579*399f0677SJan Parcel system_labeled = is_system_labeled(); 580*399f0677SJan Parcel 581*399f0677SJan Parcel /* check safely for sizes */ 582*399f0677SJan Parcel if (strcmp(DA_AUDIO_TYPE, type) == 0) { 583*399f0677SJan Parcel (void) strlcpy(namebuf, DA_AUDIO_NAME, DA_MAXNAME); 584*399f0677SJan Parcel return (1); 585*399f0677SJan Parcel } 586*399f0677SJan Parcel if (strcmp(DA_CD_TYPE, type) == 0) { 587*399f0677SJan Parcel if (system_labeled) 588*399f0677SJan Parcel (void) strlcpy(namebuf, DA_CD_NAME, DA_MAXNAME); 589*399f0677SJan Parcel else 590*399f0677SJan Parcel (void) strlcpy(namebuf, DA_CD_TYPE, DA_MAXNAME); 591*399f0677SJan Parcel return (1); 592*399f0677SJan Parcel } 593*399f0677SJan Parcel if (strcmp(DA_FLOPPY_TYPE, type) == 0) { 594*399f0677SJan Parcel if (system_labeled) 595*399f0677SJan Parcel (void) strlcpy(namebuf, DA_FLOPPY_NAME, DA_MAXNAME); 596*399f0677SJan Parcel else 597*399f0677SJan Parcel (void) strlcpy(namebuf, DA_FLOPPY_TYPE, DA_MAXNAME); 598*399f0677SJan Parcel return (1); 599*399f0677SJan Parcel } 600*399f0677SJan Parcel if (strcmp(DA_TAPE_TYPE, type) == 0) { 601*399f0677SJan Parcel if (system_labeled) 602*399f0677SJan Parcel (void) strlcpy(namebuf, DA_TAPE_NAME, DA_MAXNAME); 603*399f0677SJan Parcel else 604*399f0677SJan Parcel (void) strlcpy(namebuf, DA_TAPE_TYPE, DA_MAXNAME); 605*399f0677SJan Parcel return (1); 606*399f0677SJan Parcel } 607*399f0677SJan Parcel if (strcmp(DA_RMDISK_TYPE, type) == 0) { 608*399f0677SJan Parcel (void) strlcpy(namebuf, DA_RMDISK_NAME, DA_MAXNAME); 609*399f0677SJan Parcel return (1); 610*399f0677SJan Parcel } 611*399f0677SJan Parcel namebuf[0] = '\0'; 612*399f0677SJan Parcel return (0); 613*399f0677SJan Parcel } 614*399f0677SJan Parcel 615*399f0677SJan Parcel /* 616*399f0677SJan Parcel * allocatable: returns 617*399f0677SJan Parcel * -1 if no auths field, 618*399f0677SJan Parcel * 0 if not allocatable (marked '*') 619*399f0677SJan Parcel * 1 if not marked '*' 620*399f0677SJan Parcel */ 621*399f0677SJan Parcel static int 622*399f0677SJan Parcel allocatable(da_args *dargs) 623*399f0677SJan Parcel { 624*399f0677SJan Parcel 625*399f0677SJan Parcel if (!dargs->devinfo->devauths) 626*399f0677SJan Parcel return (-1); 627*399f0677SJan Parcel if (strcmp("*", dargs->devinfo->devauths) == 0) 628*399f0677SJan Parcel return (0); 629*399f0677SJan Parcel return (1); 630*399f0677SJan Parcel } 631*399f0677SJan Parcel 632*399f0677SJan Parcel /* 6337e3e5701SJan Parcel * _rebuild_lists - 6347e3e5701SJan Parcel * 6357e3e5701SJan Parcel * If dargs->optflag & DA_EVENT, does not assume the dargs list is 6367e3e5701SJan Parcel * complete or completely believable, since devfsadm caches 6377e3e5701SJan Parcel * ONLY what it has been exposed to via syseventd. 6387e3e5701SJan Parcel * 6397e3e5701SJan Parcel * Cycles through all the entries in the /etc files, stores them 640*399f0677SJan Parcel * in memory, takes note of device->dname numbers (e.g. rmdisk0, 6417e3e5701SJan Parcel * rmdisk12) 6427e3e5701SJan Parcel * 6437e3e5701SJan Parcel * Cycles through again, adds dargs entry 6447e3e5701SJan Parcel * with the name tname%d (lowest unused number for the device type) 6457e3e5701SJan Parcel * to the list of things for the caller to write out to a file, 6467e3e5701SJan Parcel * IFF it is a new entry. 6477e3e5701SJan Parcel * 648*399f0677SJan Parcel * It is an error for it to already be there, if it is allocatable. 6497e3e5701SJan Parcel * 6507e3e5701SJan Parcel * Add: 6517e3e5701SJan Parcel * Returns 0 if successful and 2 on error. 6527e3e5701SJan Parcel * Remove: 6537e3e5701SJan Parcel * Returns 0 if not found, 1 if found, 2 on error. 6547e3e5701SJan Parcel */ 6557e3e5701SJan Parcel static int 6567e3e5701SJan Parcel _rebuild_lists(da_args *dargs, strentry_t **head_devallocp, 6577e3e5701SJan Parcel strentry_t **head_devmapp) 6587e3e5701SJan Parcel { 6597e3e5701SJan Parcel int rc = 0; 6607e3e5701SJan Parcel devalloc_t *devallocp; 6617e3e5701SJan Parcel devmap_t *devmapp; 6627e3e5701SJan Parcel strentry_t *tail_str; 6637e3e5701SJan Parcel strentry_t *tmp_str; 6647e3e5701SJan Parcel uint64_t tmp_bitmap = 0; 665*399f0677SJan Parcel uint_t tmp = 0; 6667e3e5701SJan Parcel char *realname; 667*399f0677SJan Parcel int suffix; 6687e3e5701SJan Parcel int found = 0; 669*399f0677SJan Parcel int stdtype = 1; 670*399f0677SJan Parcel int is_allocatable = 1; 671*399f0677SJan Parcel char new_devname[DA_MAXNAME + 1]; 672*399f0677SJan Parcel char defname[DA_MAXNAME + 1]; /* default name for type */ 673*399f0677SJan Parcel char errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80]; 6747e3e5701SJan Parcel 6757e3e5701SJan Parcel if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY)) 6767e3e5701SJan Parcel return (2); 6777e3e5701SJan Parcel 6787e3e5701SJan Parcel if (dargs->optflag & DA_FORCE) 6797e3e5701SJan Parcel return (2); 6807e3e5701SJan Parcel 681*399f0677SJan Parcel if (dargs->optflag & DA_ADD) { 682*399f0677SJan Parcel stdtype = da_std_type(dargs, defname); 683*399f0677SJan Parcel is_allocatable = allocatable(dargs); 684*399f0677SJan Parcel } 685*399f0677SJan Parcel 6867e3e5701SJan Parcel /* read both files, maps first so we can compare actual devices */ 6877e3e5701SJan Parcel 6887e3e5701SJan Parcel /* build device_maps */ 6897e3e5701SJan Parcel setdmapent(); 6907e3e5701SJan Parcel while ((devmapp = getdmapent()) != NULL) { 691*399f0677SJan Parcel suffix = DA_MAX_DEVNO + 1; 6927e3e5701SJan Parcel if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype)) 6937e3e5701SJan Parcel == 1) { 6947e3e5701SJan Parcel if (dargs->optflag & DA_REMOVE) { 6957e3e5701SJan Parcel if ((devmapp->dmap_devarray == NULL) || 6967e3e5701SJan Parcel (devmapp->dmap_devarray[0] == NULL)) { 6977e3e5701SJan Parcel freedmapent(devmapp); 6987e3e5701SJan Parcel enddmapent(); 6997e3e5701SJan Parcel return (2); 7007e3e5701SJan Parcel } 7017e3e5701SJan Parcel realname = dmap_physname(devmapp); 7027e3e5701SJan Parcel if (realname == NULL) { 7037e3e5701SJan Parcel freedmapent(devmapp); 7047e3e5701SJan Parcel enddmapent(); 7057e3e5701SJan Parcel return (2); 7067e3e5701SJan Parcel } 7077e3e5701SJan Parcel if (strstr(realname, dargs->devinfo->devlist) 7087e3e5701SJan Parcel != NULL) { 709*399f0677SJan Parcel /* if need to free and safe to free */ 710*399f0677SJan Parcel if (dargs->devinfo->devname != NULL && 711*399f0677SJan Parcel (dargs->optflag & DA_EVENT) != 0) 7127e3e5701SJan Parcel free(dargs->devinfo->devname); 7137e3e5701SJan Parcel dargs->devinfo->devname = 7147e3e5701SJan Parcel strdup(devmapp->dmap_devname); 7157e3e5701SJan Parcel found = 1; 7167e3e5701SJan Parcel freedmapent(devmapp); 7177e3e5701SJan Parcel continue; /* don't retain */ 7187e3e5701SJan Parcel } 7197e3e5701SJan Parcel } else if (dargs->optflag & DA_ADD) { 7207e3e5701SJan Parcel /* 7217e3e5701SJan Parcel * Need to know which suffixes are in use 7227e3e5701SJan Parcel */ 7237e3e5701SJan Parcel rc = (dmap_exact_dev(devmapp, 7247e3e5701SJan Parcel dargs->devinfo->devlist, &suffix)); 7257e3e5701SJan Parcel 7267e3e5701SJan Parcel if (rc == 0) { 7277e3e5701SJan Parcel /* 7287e3e5701SJan Parcel * Same type, different device. Record 729*399f0677SJan Parcel * device suffix already in use, if 730*399f0677SJan Parcel * applicable. 7317e3e5701SJan Parcel */ 732*399f0677SJan Parcel if ((suffix < DA_MAX_DEVNO && 733*399f0677SJan Parcel suffix != -1) && stdtype) 734*399f0677SJan Parcel tmp_bitmap |= 735*399f0677SJan Parcel (uint64_t)(1LL << suffix); 736*399f0677SJan Parcel } else if ((rc == 1) && !is_allocatable) { 737*399f0677SJan Parcel rc = 0; 7387e3e5701SJan Parcel } else { 7397e3e5701SJan Parcel /* 740*399f0677SJan Parcel * Match allocatable on add is an error 7417e3e5701SJan Parcel * or mapping attempt returned error 7427e3e5701SJan Parcel */ 743*399f0677SJan Parcel (void) snprintf(errmsg, sizeof (errmsg), 744*399f0677SJan Parcel "Cannot add %s on node %s", 745*399f0677SJan Parcel dargs->devinfo->devtype, 746*399f0677SJan Parcel devmapp->dmap_devname); 747*399f0677SJan Parcel syslog(LOG_ERR, "%s", errmsg); 7487e3e5701SJan Parcel freedmapent(devmapp); 7497e3e5701SJan Parcel enddmapent(); 7507e3e5701SJan Parcel return (2); 7517e3e5701SJan Parcel } 7527e3e5701SJan Parcel } else 7537e3e5701SJan Parcel /* add other transaction types as needed */ 7547e3e5701SJan Parcel return (2); 755*399f0677SJan Parcel } else if ((dargs->optflag & DA_ADD) && 756*399f0677SJan Parcel (stdtype || is_allocatable) && 757*399f0677SJan Parcel dmap_exact_dev(devmapp, dargs->devinfo->devlist, 758*399f0677SJan Parcel &suffix)) { 759*399f0677SJan Parcel /* 760*399f0677SJan Parcel * no dups w/o DA_FORCE, even if type differs, 761*399f0677SJan Parcel * if there is a chance this operation is 762*399f0677SJan Parcel * machine-driven. The 5 "standard types" 763*399f0677SJan Parcel * can be machine-driven adds, and tend to 764*399f0677SJan Parcel * be allocatable. 765*399f0677SJan Parcel */ 766*399f0677SJan Parcel (void) snprintf(errmsg, sizeof (errmsg), 767*399f0677SJan Parcel "Cannot add %s on node %s type %s", 768*399f0677SJan Parcel dargs->devinfo->devtype, 769*399f0677SJan Parcel devmapp->dmap_devname, 770*399f0677SJan Parcel devmapp->dmap_devtype); 771*399f0677SJan Parcel syslog(LOG_ERR, "%s", errmsg); 772*399f0677SJan Parcel freedmapent(devmapp); 773*399f0677SJan Parcel enddmapent(); 774*399f0677SJan Parcel return (2); 775*399f0677SJan Parcel } 7767e3e5701SJan Parcel 7777e3e5701SJan Parcel tmp_str = _dmap2strentry(devmapp); 7787e3e5701SJan Parcel if (tmp_str == NULL) { 7797e3e5701SJan Parcel freedmapent(devmapp); 7807e3e5701SJan Parcel enddmapent(); 7817e3e5701SJan Parcel return (2); 7827e3e5701SJan Parcel } 7837e3e5701SJan Parcel /* retaining devmap entry: tmp_str->se_str */ 7847e3e5701SJan Parcel tmp_str->se_next = NULL; 7857e3e5701SJan Parcel if (*head_devmapp == NULL) { 7867e3e5701SJan Parcel *head_devmapp = tail_str = tmp_str; 7877e3e5701SJan Parcel } else { 7887e3e5701SJan Parcel tail_str->se_next = tmp_str; 7897e3e5701SJan Parcel tail_str = tmp_str; 7907e3e5701SJan Parcel } 7917e3e5701SJan Parcel freedmapent(devmapp); 7927e3e5701SJan Parcel } 7937e3e5701SJan Parcel enddmapent(); 7947e3e5701SJan Parcel 7957e3e5701SJan Parcel /* 7967e3e5701SJan Parcel * No need to rewrite the files if the item to be removed is not 7977e3e5701SJan Parcel * in the files -- wait for another call on another darg. 7987e3e5701SJan Parcel */ 7997e3e5701SJan Parcel if ((dargs->optflag & DA_REMOVE) && !found) 8007e3e5701SJan Parcel return (0); 8017e3e5701SJan Parcel 8027e3e5701SJan Parcel 8037e3e5701SJan Parcel if (dargs->optflag & DA_ADD) { 804*399f0677SJan Parcel int len; 8057e3e5701SJan Parcel /* 806*399f0677SJan Parcel * If we got here from an event, or from devfsadm, 807*399f0677SJan Parcel * we know the stored devname is a useless guess, 808*399f0677SJan Parcel * since the files had not been read when the name 809*399f0677SJan Parcel * was chosen, and we don't keep them anywhere else 810*399f0677SJan Parcel * that is sufficiently definitive. 8117e3e5701SJan Parcel */ 8127e3e5701SJan Parcel 8137e3e5701SJan Parcel for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++) 8147e3e5701SJan Parcel if (!(tmp_bitmap & (1LL << tmp))) 8157e3e5701SJan Parcel break; 8167e3e5701SJan Parcel /* Future: support more than 64 hotplug devices per type? */ 8177e3e5701SJan Parcel if (tmp > DA_MAX_DEVNO) 8187e3e5701SJan Parcel return (2); 8197e3e5701SJan Parcel 820*399f0677SJan Parcel /* 821*399f0677SJan Parcel * Let the caller choose the name unless BOTH the name and 822*399f0677SJan Parcel * device type one of: cdrom, floppy, audio, rmdisk, or tape. 823*399f0677SJan Parcel * (or sr, fd for unlabeled) 824*399f0677SJan Parcel */ 825*399f0677SJan Parcel len = strlen(defname); 826*399f0677SJan Parcel if (stdtype && 827*399f0677SJan Parcel (strncmp(dargs->devinfo->devname, defname, len) == 0)) { 8287e3e5701SJan Parcel (void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u", 829*399f0677SJan Parcel defname, tmp); 830*399f0677SJan Parcel /* if need to free and safe to free */ 831*399f0677SJan Parcel if (dargs->devinfo->devname != NULL && 832*399f0677SJan Parcel (dargs->optflag & DA_EVENT) != 0) 8337e3e5701SJan Parcel free(dargs->devinfo->devname); 8347e3e5701SJan Parcel dargs->devinfo->devname = strdup(new_devname); 8357e3e5701SJan Parcel } 836*399f0677SJan Parcel } 8377e3e5701SJan Parcel 8387e3e5701SJan Parcel /* 8397e3e5701SJan Parcel * Now adjust devalloc list to match devmaps 8407e3e5701SJan Parcel * Note we now have the correct devname for da_match to use. 8417e3e5701SJan Parcel */ 8427e3e5701SJan Parcel setdaent(); 8437e3e5701SJan Parcel while ((devallocp = getdaent()) != NULL) { 8447e3e5701SJan Parcel rc = da_match(devallocp, dargs); 8457e3e5701SJan Parcel if (rc == 1) { 8467e3e5701SJan Parcel if (dargs->optflag & DA_ADD) { 8477e3e5701SJan Parcel /* logging is on if DA_EVENT is set */ 8487e3e5701SJan Parcel if (dargs->optflag & DA_EVENT) { 8497e3e5701SJan Parcel (void) snprintf(errmsg, sizeof (errmsg), 8507e3e5701SJan Parcel "%s and %s out of sync," 8517e3e5701SJan Parcel "%s only in %s.", 8527e3e5701SJan Parcel DEVALLOC, DEVMAP, 8537e3e5701SJan Parcel devallocp->da_devname, DEVALLOC); 8547e3e5701SJan Parcel syslog(LOG_ERR, "%s", errmsg); 8557e3e5701SJan Parcel } 8567e3e5701SJan Parcel freedaent(devallocp); 8577e3e5701SJan Parcel enddaent(); 8587e3e5701SJan Parcel return (2); 8597e3e5701SJan Parcel } else if (dargs->optflag & DA_REMOVE) { 8607e3e5701SJan Parcel /* make list w/o this entry */ 8617e3e5701SJan Parcel freedaent(devallocp); 8627e3e5701SJan Parcel continue; 8637e3e5701SJan Parcel } 8647e3e5701SJan Parcel } 8657e3e5701SJan Parcel tmp_str = _da2strentry(dargs, devallocp); 8667e3e5701SJan Parcel if (tmp_str == NULL) { 8677e3e5701SJan Parcel freedaent(devallocp); 8687e3e5701SJan Parcel enddaent(); 8697e3e5701SJan Parcel return (2); 8707e3e5701SJan Parcel } 8717e3e5701SJan Parcel /* retaining devalloc entry: tmp_str->se_str */ 8727e3e5701SJan Parcel tmp_str->se_next = NULL; 8737e3e5701SJan Parcel if (*head_devallocp == NULL) { 8747e3e5701SJan Parcel *head_devallocp = tail_str = tmp_str; 8757e3e5701SJan Parcel } else { 8767e3e5701SJan Parcel tail_str->se_next = tmp_str; 8777e3e5701SJan Parcel tail_str = tmp_str; 8787e3e5701SJan Parcel } 8797e3e5701SJan Parcel freedaent(devallocp); 8807e3e5701SJan Parcel } 8817e3e5701SJan Parcel enddaent(); 8827e3e5701SJan Parcel 8837e3e5701SJan Parcel /* the caller needs to know if a remove needs to rewrite files */ 8847e3e5701SJan Parcel if (dargs->optflag & DA_REMOVE) 8857e3e5701SJan Parcel return (1); /* 0 and 2 cases returned earlier */ 8867e3e5701SJan Parcel 8877e3e5701SJan Parcel return (0); /* Successful DA_ADD */ 8887e3e5701SJan Parcel } 889*399f0677SJan Parcel 8907e3e5701SJan Parcel /* 89145916cd2Sjpk * _build_lists - 8927e3e5701SJan Parcel * Cycles through all the entries, stores them in memory. removes entries 89345916cd2Sjpk * with the given search_key (device name or type). 89445916cd2Sjpk * returns 0 if given entry not found, 1 if given entry removed, 2 on 89545916cd2Sjpk * error. 89645916cd2Sjpk */ 89745916cd2Sjpk static int 89845916cd2Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp, 89945916cd2Sjpk strentry_t **head_devmapp) 90045916cd2Sjpk { 90145916cd2Sjpk int rc = 0; 902*399f0677SJan Parcel int found = 0; 90345916cd2Sjpk devalloc_t *devallocp; 90445916cd2Sjpk devmap_t *devmapp; 90545916cd2Sjpk strentry_t *tail_str; 90645916cd2Sjpk strentry_t *tmp_str; 90745916cd2Sjpk 90845916cd2Sjpk if (dargs->optflag & DA_MAPS_ONLY) 90945916cd2Sjpk goto dmap_only; 91045916cd2Sjpk 91145916cd2Sjpk /* build device_allocate */ 91245916cd2Sjpk setdaent(); 91345916cd2Sjpk while ((devallocp = getdaent()) != NULL) { 91445916cd2Sjpk rc = da_match(devallocp, dargs); 915*399f0677SJan Parcel /* if in _build_lists and DA_ADD is set, so is DA_FORCE */ 91645916cd2Sjpk if (rc == 0) { 91745916cd2Sjpk tmp_str = _da2strentry(dargs, devallocp); 91845916cd2Sjpk if (tmp_str == NULL) { 91945916cd2Sjpk freedaent(devallocp); 92045916cd2Sjpk enddaent(); 92145916cd2Sjpk return (2); 92245916cd2Sjpk } 92345916cd2Sjpk /* retaining devalloc entry: tmp_str->se_str */ 92445916cd2Sjpk tmp_str->se_next = NULL; 92545916cd2Sjpk if (*head_devallocp == NULL) { 92645916cd2Sjpk *head_devallocp = tail_str = tmp_str; 92745916cd2Sjpk } else { 92845916cd2Sjpk tail_str->se_next = tmp_str; 92945916cd2Sjpk tail_str = tmp_str; 93045916cd2Sjpk } 931*399f0677SJan Parcel } else if (rc == 1) 932*399f0677SJan Parcel found = 1; 933*399f0677SJan Parcel 93445916cd2Sjpk freedaent(devallocp); 93545916cd2Sjpk } 93645916cd2Sjpk enddaent(); 93745916cd2Sjpk 93845916cd2Sjpk dmap_only: 93945916cd2Sjpk if (dargs->optflag & DA_ALLOC_ONLY) 94045916cd2Sjpk return (rc); 94145916cd2Sjpk 94245916cd2Sjpk /* build device_maps */ 94345916cd2Sjpk rc = 0; 94445916cd2Sjpk setdmapent(); 94545916cd2Sjpk while ((devmapp = getdmapent()) != NULL) { 94645916cd2Sjpk rc = dm_match(devmapp, dargs); 94745916cd2Sjpk if (rc == 0) { 9487e3e5701SJan Parcel tmp_str = _dmap2strentry(devmapp); 94945916cd2Sjpk if (tmp_str == NULL) { 95045916cd2Sjpk freedmapent(devmapp); 95145916cd2Sjpk enddmapent(); 95245916cd2Sjpk return (2); 95345916cd2Sjpk } 95445916cd2Sjpk /* retaining devmap entry: tmp_str->se_str */ 95545916cd2Sjpk tmp_str->se_next = NULL; 95645916cd2Sjpk if (*head_devmapp == NULL) { 95745916cd2Sjpk *head_devmapp = tail_str = tmp_str; 95845916cd2Sjpk } else { 95945916cd2Sjpk tail_str->se_next = tmp_str; 96045916cd2Sjpk tail_str = tmp_str; 96145916cd2Sjpk } 96245916cd2Sjpk } 96345916cd2Sjpk freedmapent(devmapp); 96445916cd2Sjpk } 96545916cd2Sjpk enddmapent(); 96645916cd2Sjpk 967*399f0677SJan Parcel /* later code cleanup may cause the use of "found" in other cases */ 968*399f0677SJan Parcel if (dargs->optflag & DA_REMOVE) 969*399f0677SJan Parcel return (found); 97045916cd2Sjpk return (rc); 97145916cd2Sjpk } 97245916cd2Sjpk 97345916cd2Sjpk /* 97445916cd2Sjpk * _write_defattrs 97545916cd2Sjpk * writes current entries to devalloc_defaults. 97645916cd2Sjpk */ 97745916cd2Sjpk static void 97845916cd2Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent) 97945916cd2Sjpk { 98045916cd2Sjpk strentry_t *tmp_str; 98145916cd2Sjpk 98245916cd2Sjpk for (tmp_str = head_defent; tmp_str != NULL; 98345916cd2Sjpk tmp_str = tmp_str->se_next) { 98445916cd2Sjpk (void) fputs(tmp_str->se_str, fp); 98545916cd2Sjpk (void) fputs("\n", fp); 98645916cd2Sjpk } 98745916cd2Sjpk 98845916cd2Sjpk } 98945916cd2Sjpk 99045916cd2Sjpk /* 99145916cd2Sjpk * _write_device_allocate - 99245916cd2Sjpk * writes current entries in the list to device_allocate. 9937e3e5701SJan Parcel * frees the strings 99445916cd2Sjpk */ 99545916cd2Sjpk static void 99645916cd2Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp) 99745916cd2Sjpk { 99845916cd2Sjpk int is_on = -1; 9997e3e5701SJan Parcel strentry_t *tmp_str, *old_str; 100045916cd2Sjpk struct stat dastat; 100145916cd2Sjpk 100245916cd2Sjpk (void) fseek(dafp, (off_t)0, SEEK_SET); 100345916cd2Sjpk 100445916cd2Sjpk /* 100545916cd2Sjpk * if the devalloc on/off string existed before, 100645916cd2Sjpk * put it back before anything else. 100745916cd2Sjpk * we need to check for the string only if the file 100845916cd2Sjpk * exists. 100945916cd2Sjpk */ 101045916cd2Sjpk if (stat(odevalloc, &dastat) == 0) { 101145916cd2Sjpk is_on = da_is_on(); 101245916cd2Sjpk if (is_on == 0) 101345916cd2Sjpk (void) fputs(DA_OFF_STR, dafp); 101445916cd2Sjpk else if (is_on == 1) 101545916cd2Sjpk (void) fputs(DA_ON_STR, dafp); 101645916cd2Sjpk } 101745916cd2Sjpk tmp_str = head_devallocp; 101845916cd2Sjpk while (tmp_str) { 101945916cd2Sjpk (void) fputs(tmp_str->se_str, dafp); 102045916cd2Sjpk (void) fputs("\n", dafp); 10217e3e5701SJan Parcel old_str = tmp_str; 102245916cd2Sjpk tmp_str = tmp_str->se_next; 10237e3e5701SJan Parcel free(old_str); 102445916cd2Sjpk } 102545916cd2Sjpk } 102645916cd2Sjpk 102745916cd2Sjpk /* 102845916cd2Sjpk * _write_device_maps - 102945916cd2Sjpk * writes current entries in the list to device_maps. 10307e3e5701SJan Parcel * and frees the strings 103145916cd2Sjpk */ 103245916cd2Sjpk static void 103345916cd2Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp) 103445916cd2Sjpk { 10357e3e5701SJan Parcel strentry_t *tmp_str, *old_str; 103645916cd2Sjpk 103745916cd2Sjpk (void) fseek(dmfp, (off_t)0, SEEK_SET); 103845916cd2Sjpk 103945916cd2Sjpk tmp_str = head_devmapp; 104045916cd2Sjpk while (tmp_str) { 104145916cd2Sjpk (void) fputs(tmp_str->se_str, dmfp); 104245916cd2Sjpk (void) fputs("\n", dmfp); 10437e3e5701SJan Parcel old_str = tmp_str; 104445916cd2Sjpk tmp_str = tmp_str->se_next; 10457e3e5701SJan Parcel free(old_str); 104645916cd2Sjpk } 104745916cd2Sjpk } 104845916cd2Sjpk 104945916cd2Sjpk /* 105045916cd2Sjpk * _write_new_defattrs 105145916cd2Sjpk * writes the new entry to devalloc_defaults. 105245916cd2Sjpk * returns 0 on success, -1 on error. 105345916cd2Sjpk */ 105445916cd2Sjpk static int 105545916cd2Sjpk _write_new_defattrs(FILE *fp, da_args *dargs) 105645916cd2Sjpk { 105745916cd2Sjpk int count; 105845916cd2Sjpk char *tok = NULL, *tokp = NULL; 105945916cd2Sjpk char *lasts; 106045916cd2Sjpk devinfo_t *devinfo = dargs->devinfo; 106145916cd2Sjpk 106245916cd2Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 106345916cd2Sjpk return (-1); 106445916cd2Sjpk if (!devinfo->devopts) 106545916cd2Sjpk return (0); 106645916cd2Sjpk (void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""), 106745916cd2Sjpk KV_TOKEN_DELIMIT); 10687e3e5701SJan Parcel if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) { 106945916cd2Sjpk (void) strcpy(tokp, devinfo->devopts); 107045916cd2Sjpk if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) { 107145916cd2Sjpk (void) fprintf(fp, "%s", tok); 107245916cd2Sjpk count = 1; 107345916cd2Sjpk } 107445916cd2Sjpk while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) { 107545916cd2Sjpk if (count) 107645916cd2Sjpk (void) fprintf(fp, "%s", KV_DELIMITER); 107745916cd2Sjpk (void) fprintf(fp, "%s", tok); 107845916cd2Sjpk count++; 107945916cd2Sjpk } 108045916cd2Sjpk } else { 108145916cd2Sjpk (void) fprintf(fp, "%s", devinfo->devopts); 108245916cd2Sjpk } 108345916cd2Sjpk 108445916cd2Sjpk return (0); 108545916cd2Sjpk } 108645916cd2Sjpk 108745916cd2Sjpk /* 108845916cd2Sjpk * _write_new_entry - 108945916cd2Sjpk * writes the new devalloc_t to device_allocate or the new devmap_t to 109045916cd2Sjpk * device_maps. 109145916cd2Sjpk * returns 0 on success, -1 on error. 109245916cd2Sjpk */ 109345916cd2Sjpk static int 109445916cd2Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag) 109545916cd2Sjpk { 109645916cd2Sjpk int count; 109745916cd2Sjpk char *tok = NULL, *tokp = NULL; 109845916cd2Sjpk char *lasts; 109945916cd2Sjpk devinfo_t *devinfo = dargs->devinfo; 110045916cd2Sjpk 110145916cd2Sjpk if (flag & DA_MAPS_ONLY) 110245916cd2Sjpk goto dmap_only; 110345916cd2Sjpk 110445916cd2Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 110545916cd2Sjpk return (-1); 110645916cd2Sjpk 110745916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", 110845916cd2Sjpk (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER); 110945916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", 111045916cd2Sjpk (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER); 111145916cd2Sjpk if (devinfo->devopts == NULL) { 111245916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, 111345916cd2Sjpk KV_DELIMITER); 111445916cd2Sjpk } else { 11157e3e5701SJan Parcel if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1)) 11167e3e5701SJan Parcel != NULL) { 111745916cd2Sjpk (void) strcpy(tokp, devinfo->devopts); 111845916cd2Sjpk if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) != 111945916cd2Sjpk NULL) { 112045916cd2Sjpk (void) fprintf(fp, "%s", tok); 112145916cd2Sjpk count = 1; 112245916cd2Sjpk } 112345916cd2Sjpk while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, 112445916cd2Sjpk &lasts)) != NULL) { 112545916cd2Sjpk if (count) 112645916cd2Sjpk (void) fprintf(fp, "%s", 112745916cd2Sjpk KV_TOKEN_DELIMIT "\\\n\t"); 112845916cd2Sjpk (void) fprintf(fp, "%s", tok); 112945916cd2Sjpk count++; 113045916cd2Sjpk } 113145916cd2Sjpk if (count) 113245916cd2Sjpk (void) fprintf(fp, "%s", 113345916cd2Sjpk KV_DELIMITER "\\\n\t"); 113445916cd2Sjpk } else { 113545916cd2Sjpk (void) fprintf(fp, "%s%s", devinfo->devopts, 113645916cd2Sjpk KV_DELIMITER "\\\n\t"); 113745916cd2Sjpk } 113845916cd2Sjpk } 113945916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER); 114045916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", 114145916cd2Sjpk (devinfo->devauths ? devinfo->devauths : DA_ANYUSER), 114245916cd2Sjpk KV_DELIMITER); 114345916cd2Sjpk (void) fprintf(fp, "%s\n", 114445916cd2Sjpk (devinfo->devexec ? devinfo->devexec : KV_DELIMITER)); 114545916cd2Sjpk 114645916cd2Sjpk dmap_only: 114745916cd2Sjpk if (flag & DA_ALLOC_ONLY) 114845916cd2Sjpk return (0); 114945916cd2Sjpk 115045916cd2Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 115145916cd2Sjpk return (-1); 115245916cd2Sjpk 115345916cd2Sjpk (void) fprintf(fp, "%s%s\\\n", 115445916cd2Sjpk (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT); 115545916cd2Sjpk (void) fprintf(fp, "\t%s%s\\\n", 115645916cd2Sjpk (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT); 115745916cd2Sjpk (void) fprintf(fp, "\t%s\n", 115845916cd2Sjpk (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT)); 115945916cd2Sjpk 116045916cd2Sjpk return (0); 116145916cd2Sjpk } 116245916cd2Sjpk 116345916cd2Sjpk /* 116445916cd2Sjpk * _da_lock_devdb - 116545916cd2Sjpk * locks the database files; lock can be either broken explicitly by 116645916cd2Sjpk * closing the fd of the lock file, or it expires automatically at process 116745916cd2Sjpk * termination. 116845916cd2Sjpk * returns fd of the lock file or -1 on error. 116945916cd2Sjpk */ 117045916cd2Sjpk int 117145916cd2Sjpk _da_lock_devdb(char *rootdir) 117245916cd2Sjpk { 117345916cd2Sjpk int lockfd = -1; 117410ddde3aSaj int ret; 117510ddde3aSaj int count = 0; 117610ddde3aSaj int retry = 10; 117710ddde3aSaj int retry_sleep; 117810ddde3aSaj uint_t seed; 117945916cd2Sjpk char *lockfile; 118045916cd2Sjpk char path[MAXPATHLEN]; 118145916cd2Sjpk int size = sizeof (path); 118245916cd2Sjpk 118345916cd2Sjpk if (rootdir == NULL) { 118445916cd2Sjpk lockfile = DA_DB_LOCK; 118545916cd2Sjpk } else { 118645916cd2Sjpk path[0] = '\0'; 118745916cd2Sjpk if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size) 118845916cd2Sjpk return (-1); 118945916cd2Sjpk lockfile = path; 119045916cd2Sjpk } 119145916cd2Sjpk 119245916cd2Sjpk if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) 119345916cd2Sjpk /* cannot open lock file */ 119445916cd2Sjpk return (-1); 119545916cd2Sjpk 119645916cd2Sjpk (void) fchown(lockfd, DA_UID, DA_GID); 119745916cd2Sjpk 119845916cd2Sjpk if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) { 119945916cd2Sjpk /* cannot position lock file */ 120045916cd2Sjpk (void) close(lockfd); 120145916cd2Sjpk return (-1); 120245916cd2Sjpk } 120310ddde3aSaj errno = 0; 120410ddde3aSaj while (retry > 0) { 120510ddde3aSaj count++; 120610ddde3aSaj seed = (uint_t)gethrtime(); 120710ddde3aSaj ret = lockf(lockfd, F_TLOCK, 0); 120810ddde3aSaj if (ret == 0) { 120910ddde3aSaj (void) utime(lockfile, NULL); 121010ddde3aSaj return (lockfd); 121110ddde3aSaj } 121210ddde3aSaj if ((errno != EACCES) && (errno != EAGAIN)) { 121345916cd2Sjpk /* cannot set lock */ 121445916cd2Sjpk (void) close(lockfd); 121545916cd2Sjpk return (-1); 121645916cd2Sjpk } 121710ddde3aSaj retry--; 121810ddde3aSaj retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count; 121910ddde3aSaj (void) sleep(retry_sleep); 122010ddde3aSaj errno = 0; 122110ddde3aSaj } 122245916cd2Sjpk 122310ddde3aSaj return (-1); 122445916cd2Sjpk } 122545916cd2Sjpk 122645916cd2Sjpk /* 122745916cd2Sjpk * da_open_devdb - 122845916cd2Sjpk * opens one or both database files - device_allocate, device_maps - in 122945916cd2Sjpk * the specified mode. 123045916cd2Sjpk * locks the database files; lock is either broken explicitly by the 123145916cd2Sjpk * caller by closing the lock file fd, or it expires automatically at 123245916cd2Sjpk * process termination. 123345916cd2Sjpk * writes the file pointer of opened file in the input args - dafp, dmfp. 123445916cd2Sjpk * returns fd of the lock file on success, -2 if database file does not 123545916cd2Sjpk * exist, -1 on other errors. 123645916cd2Sjpk */ 123745916cd2Sjpk int 123845916cd2Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag) 123945916cd2Sjpk { 124045916cd2Sjpk int oflag = 0; 124145916cd2Sjpk int fda = -1; 124245916cd2Sjpk int fdm = -1; 124345916cd2Sjpk int lockfd = -1; 124445916cd2Sjpk char *fname; 124545916cd2Sjpk char *fmode; 124645916cd2Sjpk char path[MAXPATHLEN]; 124745916cd2Sjpk FILE *devfile; 124845916cd2Sjpk 124945916cd2Sjpk if ((dafp == NULL) && (dmfp == NULL)) 125045916cd2Sjpk return (-1); 125145916cd2Sjpk 125245916cd2Sjpk if (flag & DA_RDWR) { 125345916cd2Sjpk oflag = DA_RDWR; 1254004388ebScasper fmode = "r+F"; 125545916cd2Sjpk } else if (flag & DA_RDONLY) { 125645916cd2Sjpk oflag = DA_RDONLY; 1257004388ebScasper fmode = "rF"; 125845916cd2Sjpk } 125945916cd2Sjpk 126045916cd2Sjpk if ((lockfd = _da_lock_devdb(rootdir)) == -1) 126145916cd2Sjpk return (-1); 126245916cd2Sjpk 126345916cd2Sjpk if ((dafp == NULL) || (flag & DA_MAPS_ONLY)) 126445916cd2Sjpk goto dmap_only; 126545916cd2Sjpk 126645916cd2Sjpk path[0] = '\0'; 126745916cd2Sjpk 126845916cd2Sjpk /* 126945916cd2Sjpk * open the device allocation file 127045916cd2Sjpk */ 127145916cd2Sjpk if (rootdir == NULL) { 127245916cd2Sjpk fname = DEVALLOC; 127345916cd2Sjpk } else { 127445916cd2Sjpk if (snprintf(path, sizeof (path), "%s%s", rootdir, 127545916cd2Sjpk DEVALLOC) >= sizeof (path)) { 127645916cd2Sjpk if (lockfd != -1) 127745916cd2Sjpk (void) close(lockfd); 127845916cd2Sjpk return (-1); 127945916cd2Sjpk } 128045916cd2Sjpk fname = path; 128145916cd2Sjpk } 128245916cd2Sjpk if ((fda = open(fname, oflag, DA_DBMODE)) == -1) { 128345916cd2Sjpk if (lockfd != -1) 128445916cd2Sjpk (void) close(lockfd); 128545916cd2Sjpk return ((errno == ENOENT) ? -2 : -1); 128645916cd2Sjpk } 128745916cd2Sjpk if ((devfile = fdopen(fda, fmode)) == NULL) { 128845916cd2Sjpk (void) close(fda); 128945916cd2Sjpk if (lockfd != -1) 129045916cd2Sjpk (void) close(lockfd); 129145916cd2Sjpk return (-1); 129245916cd2Sjpk } 129345916cd2Sjpk *dafp = devfile; 129445916cd2Sjpk (void) fchmod(fda, DA_DBMODE); 129545916cd2Sjpk 129645916cd2Sjpk if ((flag & DA_ALLOC_ONLY)) 129745916cd2Sjpk goto out; 129845916cd2Sjpk 129945916cd2Sjpk dmap_only: 130045916cd2Sjpk path[0] = '\0'; 130145916cd2Sjpk /* 130245916cd2Sjpk * open the device map file 130345916cd2Sjpk */ 130445916cd2Sjpk if (rootdir == NULL) { 130545916cd2Sjpk fname = DEVMAP; 130645916cd2Sjpk } else { 130745916cd2Sjpk if (snprintf(path, sizeof (path), "%s%s", rootdir, 130845916cd2Sjpk DEVMAP) >= sizeof (path)) { 130945916cd2Sjpk (void) close(fda); 131045916cd2Sjpk if (lockfd != -1) 131145916cd2Sjpk (void) close(lockfd); 131245916cd2Sjpk return (-1); 131345916cd2Sjpk } 131445916cd2Sjpk fname = path; 131545916cd2Sjpk } 131645916cd2Sjpk 131745916cd2Sjpk if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) { 131845916cd2Sjpk if (lockfd != -1) 131945916cd2Sjpk (void) close(lockfd); 132045916cd2Sjpk return ((errno == ENOENT) ? -2 : -1); 132145916cd2Sjpk } 132245916cd2Sjpk 132345916cd2Sjpk if ((devfile = fdopen(fdm, fmode)) == NULL) { 132445916cd2Sjpk (void) close(fdm); 132545916cd2Sjpk (void) close(fda); 132645916cd2Sjpk if (lockfd != -1) 132745916cd2Sjpk (void) close(lockfd); 132845916cd2Sjpk return (-1); 132945916cd2Sjpk } 133045916cd2Sjpk *dmfp = devfile; 133145916cd2Sjpk (void) fchmod(fdm, DA_DBMODE); 133245916cd2Sjpk 133345916cd2Sjpk out: 133445916cd2Sjpk return (lockfd); 133545916cd2Sjpk } 133645916cd2Sjpk 133745916cd2Sjpk /* 133845916cd2Sjpk * _record_on_off - 133945916cd2Sjpk * adds either DA_ON_STR or DA_OFF_STR to device_allocate 134045916cd2Sjpk * returns 0 on success, -1 on error. 134145916cd2Sjpk */ 134245916cd2Sjpk static int 134345916cd2Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp) 134445916cd2Sjpk { 134545916cd2Sjpk int dafd; 134645916cd2Sjpk int nsize; 134745916cd2Sjpk int nitems = 1; 134845916cd2Sjpk int actionlen; 134945916cd2Sjpk int str_found = 0; 135045916cd2Sjpk int len = 0, nlen = 0, plen = 0; 135145916cd2Sjpk char *ptr = NULL; 135245916cd2Sjpk char *actionstr; 135345916cd2Sjpk char *nbuf = NULL; 135445916cd2Sjpk char line[MAX_CANON]; 135545916cd2Sjpk struct stat dastat; 135645916cd2Sjpk 135745916cd2Sjpk if (dargs->optflag & DA_ON) 135845916cd2Sjpk actionstr = DA_ON_STR; 135945916cd2Sjpk else 136045916cd2Sjpk actionstr = DA_OFF_STR; 136145916cd2Sjpk actionlen = strlen(actionstr); 136245916cd2Sjpk dafd = fileno(dafp); 136345916cd2Sjpk if (fstat(dafd, &dastat) == -1) 136445916cd2Sjpk return (-1); 136545916cd2Sjpk 136645916cd2Sjpk /* check the old device_allocate for on/off string */ 136745916cd2Sjpk ptr = fgets(line, MAX_CANON, dafp); 136845916cd2Sjpk if (ptr != NULL) { 136945916cd2Sjpk if ((strcmp(line, DA_ON_STR) == 0) || 137045916cd2Sjpk (strcmp(line, DA_OFF_STR) == 0)) { 137145916cd2Sjpk str_found = 1; 137245916cd2Sjpk nsize = dastat.st_size; 137345916cd2Sjpk } 137445916cd2Sjpk } 137545916cd2Sjpk if (!ptr || !str_found) { 137645916cd2Sjpk /* 137745916cd2Sjpk * the file never had either the on or the off string; 137845916cd2Sjpk * make room for it. 137945916cd2Sjpk */ 138045916cd2Sjpk str_found = 0; 138145916cd2Sjpk nsize = dastat.st_size + actionlen + 1; 138245916cd2Sjpk } 13837e3e5701SJan Parcel if ((nbuf = (char *)malloc(nsize + 1)) == NULL) 138445916cd2Sjpk return (-1); 138545916cd2Sjpk nbuf[0] = '\0'; 138645916cd2Sjpk /* put the on/off string */ 138745916cd2Sjpk (void) strcpy(nbuf, actionstr); 138845916cd2Sjpk nlen = strlen(nbuf); 138945916cd2Sjpk plen = nlen; 139045916cd2Sjpk if (ptr && !str_found) { 139145916cd2Sjpk /* now put the first line that we read in fgets */ 139245916cd2Sjpk nlen = plen + strlen(line) + 1; 139345916cd2Sjpk len = snprintf(nbuf + plen, nlen - plen, "%s", line); 139445916cd2Sjpk if (len >= nsize) { 139545916cd2Sjpk free(nbuf); 139645916cd2Sjpk return (-1); 139745916cd2Sjpk } 139845916cd2Sjpk plen += len; 139945916cd2Sjpk } 140045916cd2Sjpk 140145916cd2Sjpk /* now get the rest of the old file */ 140245916cd2Sjpk while (fgets(line, MAX_CANON, dafp) != NULL) { 140345916cd2Sjpk nlen = plen + strlen(line) + 1; 140445916cd2Sjpk len = snprintf(nbuf + plen, nlen - plen, "%s", line); 140545916cd2Sjpk if (len >= nsize) { 140645916cd2Sjpk free(nbuf); 140745916cd2Sjpk return (-1); 140845916cd2Sjpk } 140945916cd2Sjpk plen += len; 141045916cd2Sjpk } 141145916cd2Sjpk len = strlen(nbuf) + 1; 141245916cd2Sjpk if (len < nsize) 141345916cd2Sjpk nbuf[len] = '\n'; 141445916cd2Sjpk 141545916cd2Sjpk /* write the on/off str + the old device_allocate to the temp file */ 141645916cd2Sjpk if (fwrite(nbuf, nsize, nitems, tafp) < nitems) { 141745916cd2Sjpk free(nbuf); 141845916cd2Sjpk return (-1); 141945916cd2Sjpk } 142045916cd2Sjpk 142145916cd2Sjpk free(nbuf); 142245916cd2Sjpk 142345916cd2Sjpk return (0); 142445916cd2Sjpk } 142545916cd2Sjpk 142645916cd2Sjpk /* 142745916cd2Sjpk * da_update_defattrs - 142845916cd2Sjpk * writes default attributes to devalloc_defaults 142945916cd2Sjpk * returns 0 on success, -1 on error. 143045916cd2Sjpk */ 143145916cd2Sjpk int 143245916cd2Sjpk da_update_defattrs(da_args *dargs) 143345916cd2Sjpk { 143445916cd2Sjpk int rc = 0, lockfd = 0, tmpfd = 0; 143545916cd2Sjpk char *defpath = DEFATTRS; 143645916cd2Sjpk char *tmpdefpath = TMPATTRS; 143745916cd2Sjpk FILE *tmpfp = NULL; 143845916cd2Sjpk struct stat dstat; 143945916cd2Sjpk strentry_t *head_defent = NULL; 144045916cd2Sjpk 144145916cd2Sjpk if (dargs == NULL) 144245916cd2Sjpk return (0); 144345916cd2Sjpk if ((lockfd = _da_lock_devdb(NULL)) == -1) 144445916cd2Sjpk return (-1); 144545916cd2Sjpk if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 144645916cd2Sjpk (void) close(lockfd); 144745916cd2Sjpk return (-1); 144845916cd2Sjpk } 144945916cd2Sjpk (void) fchown(tmpfd, DA_UID, DA_GID); 145045916cd2Sjpk if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) { 145145916cd2Sjpk (void) close(tmpfd); 145245916cd2Sjpk (void) unlink(tmpdefpath); 145345916cd2Sjpk (void) close(lockfd); 145445916cd2Sjpk return (-1); 145545916cd2Sjpk } 145645916cd2Sjpk /* 145745916cd2Sjpk * examine all entries, remove an old one if required, check 145845916cd2Sjpk * if a new one needs to be added. 145945916cd2Sjpk */ 146045916cd2Sjpk if (stat(defpath, &dstat) == 0) { 146145916cd2Sjpk if ((rc = _build_defattrs(dargs, &head_defent)) != 0) { 146245916cd2Sjpk if (rc == 1) { 146345916cd2Sjpk (void) close(tmpfd); 146445916cd2Sjpk (void) unlink(tmpdefpath); 146545916cd2Sjpk (void) close(lockfd); 146645916cd2Sjpk return (rc); 146745916cd2Sjpk } 146845916cd2Sjpk } 146945916cd2Sjpk } 147045916cd2Sjpk /* 147145916cd2Sjpk * write back any existing entries. 147245916cd2Sjpk */ 147345916cd2Sjpk _write_defattrs(tmpfp, head_defent); 147445916cd2Sjpk 147545916cd2Sjpk if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 147645916cd2Sjpk /* add new entries */ 147745916cd2Sjpk rc = _write_new_defattrs(tmpfp, dargs); 147845916cd2Sjpk (void) fclose(tmpfp); 147945916cd2Sjpk } else { 148045916cd2Sjpk (void) fclose(tmpfp); 148145916cd2Sjpk } 148245916cd2Sjpk if (rename(tmpdefpath, defpath) != 0) { 148345916cd2Sjpk rc = -1; 148445916cd2Sjpk (void) unlink(tmpdefpath); 148545916cd2Sjpk } 148645916cd2Sjpk (void) close(lockfd); 148745916cd2Sjpk 148845916cd2Sjpk return (rc); 148945916cd2Sjpk } 149045916cd2Sjpk 149145916cd2Sjpk /* 149245916cd2Sjpk * da_update_device - 14937e3e5701SJan Parcel * Writes existing entries and the SINGLE change requested by da_args, 14947e3e5701SJan Parcel * to device_allocate and device_maps. 14957e3e5701SJan Parcel * Returns 0 on success, -1 on error. 149645916cd2Sjpk */ 149745916cd2Sjpk int 149845916cd2Sjpk da_update_device(da_args *dargs) 149945916cd2Sjpk { 150045916cd2Sjpk int rc; 150145916cd2Sjpk int tafd = -1, tmfd = -1; 150245916cd2Sjpk int lockfd = -1; 150345916cd2Sjpk char *rootdir = NULL; 150410ddde3aSaj char *apathp = NULL, *mpathp = NULL; 150510ddde3aSaj char *dapathp = NULL, *dmpathp = NULL; 150610ddde3aSaj char apath[MAXPATHLEN], mpath[MAXPATHLEN]; 150710ddde3aSaj char dapath[MAXPATHLEN], dmpath[MAXPATHLEN]; 150845916cd2Sjpk FILE *tafp = NULL, *tmfp = NULL, *dafp = NULL; 150945916cd2Sjpk struct stat dastat; 151045916cd2Sjpk devinfo_t *devinfo; 151145916cd2Sjpk strentry_t *head_devmapp = NULL; 151245916cd2Sjpk strentry_t *head_devallocp = NULL; 151345916cd2Sjpk 151445916cd2Sjpk if (dargs == NULL) 151545916cd2Sjpk return (0); 151645916cd2Sjpk 151745916cd2Sjpk rootdir = dargs->rootdir; 151845916cd2Sjpk devinfo = dargs->devinfo; 151945916cd2Sjpk 152045916cd2Sjpk /* 152145916cd2Sjpk * adding/removing entries should be done in both 152245916cd2Sjpk * device_allocate and device_maps. updates can be 152345916cd2Sjpk * done in both or either of the files. 152445916cd2Sjpk */ 152545916cd2Sjpk if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) { 152645916cd2Sjpk if (dargs->optflag & DA_ALLOC_ONLY || 152745916cd2Sjpk dargs->optflag & DA_MAPS_ONLY) 152845916cd2Sjpk return (0); 152945916cd2Sjpk } 153045916cd2Sjpk 153145916cd2Sjpk /* 153245916cd2Sjpk * name, type and list are required fields for adding a new 153345916cd2Sjpk * device. 153445916cd2Sjpk */ 153545916cd2Sjpk if ((dargs->optflag & DA_ADD) && 153645916cd2Sjpk ((devinfo->devname == NULL) || 153745916cd2Sjpk (devinfo->devtype == NULL) || 153845916cd2Sjpk (devinfo->devlist == NULL))) { 153945916cd2Sjpk return (-1); 154045916cd2Sjpk } 154145916cd2Sjpk 154245916cd2Sjpk if (rootdir != NULL) { 154345916cd2Sjpk if (snprintf(apath, sizeof (apath), "%s%s", rootdir, 154445916cd2Sjpk TMPALLOC) >= sizeof (apath)) 154545916cd2Sjpk return (-1); 154645916cd2Sjpk apathp = apath; 154745916cd2Sjpk if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir, 154845916cd2Sjpk DEVALLOC) >= sizeof (dapath)) 154945916cd2Sjpk return (-1); 155045916cd2Sjpk dapathp = dapath; 155145916cd2Sjpk if (!(dargs->optflag & DA_ALLOC_ONLY)) { 155245916cd2Sjpk if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir, 155345916cd2Sjpk TMPMAP) >= sizeof (mpath)) 155445916cd2Sjpk return (-1); 155545916cd2Sjpk mpathp = mpath; 155645916cd2Sjpk if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir, 155745916cd2Sjpk DEVMAP) >= sizeof (dmpath)) 155845916cd2Sjpk return (-1); 155945916cd2Sjpk dmpathp = dmpath; 156045916cd2Sjpk } 156145916cd2Sjpk } else { 156245916cd2Sjpk apathp = TMPALLOC; 156345916cd2Sjpk dapathp = DEVALLOC; 156445916cd2Sjpk mpathp = TMPMAP; 156545916cd2Sjpk dmpathp = DEVMAP; 156645916cd2Sjpk } 156745916cd2Sjpk 156845916cd2Sjpk if (dargs->optflag & DA_MAPS_ONLY) 156945916cd2Sjpk goto dmap_only; 157045916cd2Sjpk 157145916cd2Sjpk /* 157245916cd2Sjpk * Check if we are here just to record on/off status of 157345916cd2Sjpk * device_allocation. 157445916cd2Sjpk */ 157545916cd2Sjpk if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) 157645916cd2Sjpk lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL, 157745916cd2Sjpk DA_RDONLY|DA_ALLOC_ONLY); 157845916cd2Sjpk else 157945916cd2Sjpk lockfd = _da_lock_devdb(rootdir); 158045916cd2Sjpk if (lockfd == -1) 158145916cd2Sjpk return (-1); 158245916cd2Sjpk 158345916cd2Sjpk if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 158445916cd2Sjpk (void) close(lockfd); 158545916cd2Sjpk (void) fclose(dafp); 158645916cd2Sjpk return (-1); 158745916cd2Sjpk } 158845916cd2Sjpk (void) fchown(tafd, DA_UID, DA_GID); 158945916cd2Sjpk if ((tafp = fdopen(tafd, "r+")) == NULL) { 159045916cd2Sjpk (void) close(tafd); 159145916cd2Sjpk (void) unlink(apathp); 159245916cd2Sjpk (void) fclose(dafp); 159345916cd2Sjpk (void) close(lockfd); 159445916cd2Sjpk return (-1); 159545916cd2Sjpk } 159645916cd2Sjpk 159745916cd2Sjpk /* 159845916cd2Sjpk * We don't need to parse the file if we are here just to record 159945916cd2Sjpk * on/off status of device_allocation. 160045916cd2Sjpk */ 160145916cd2Sjpk if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) { 160245916cd2Sjpk if (_record_on_off(dargs, tafp, dafp) == -1) { 160345916cd2Sjpk (void) close(tafd); 160445916cd2Sjpk (void) unlink(apathp); 160545916cd2Sjpk (void) fclose(dafp); 160645916cd2Sjpk (void) close(lockfd); 160745916cd2Sjpk return (-1); 160845916cd2Sjpk } 160945916cd2Sjpk (void) fclose(dafp); 161045916cd2Sjpk goto out; 161145916cd2Sjpk } 161245916cd2Sjpk 161345916cd2Sjpk /* 16147e3e5701SJan Parcel * If reacting to a hotplug, read the file entries, 16157e3e5701SJan Parcel * figure out what dname (tname + a new number) goes to the 16167e3e5701SJan Parcel * device being added/removed, and create a good head_devallocp and 16177e3e5701SJan Parcel * head_devmapp with everything good still in it (_rebuild_lists) 16187e3e5701SJan Parcel * 16197e3e5701SJan Parcel * Else examine all the entries, remove an old one if it is 16207e3e5701SJan Parcel * a duplicate with a device being added, returning the 16217e3e5701SJan Parcel * remaining list (_build_lists.) 16227e3e5701SJan Parcel * 16237e3e5701SJan Parcel * We need to do this only if the file exists already. 16247e3e5701SJan Parcel * 16257e3e5701SJan Parcel * Once we have built these lists, we need to free the strings 16267e3e5701SJan Parcel * in the head_* arrays before returning. 162745916cd2Sjpk */ 162845916cd2Sjpk if (stat(dapathp, &dastat) == 0) { 16297e3e5701SJan Parcel /* for device allocation, the /etc files are the "master" */ 16307e3e5701SJan Parcel if ((dargs->optflag & (DA_ADD| DA_EVENT)) && 16317e3e5701SJan Parcel (!(dargs->optflag & DA_FORCE))) 16327e3e5701SJan Parcel rc = _rebuild_lists(dargs, &head_devallocp, 16337e3e5701SJan Parcel &head_devmapp); 16347e3e5701SJan Parcel else 16357e3e5701SJan Parcel rc = _build_lists(dargs, &head_devallocp, 16367e3e5701SJan Parcel &head_devmapp); 16377e3e5701SJan Parcel 16387e3e5701SJan Parcel if (rc != 0 && rc != 1) { 163945916cd2Sjpk (void) close(tafd); 164045916cd2Sjpk (void) unlink(apathp); 164145916cd2Sjpk (void) close(lockfd); 16427e3e5701SJan Parcel return (-1); 164345916cd2Sjpk } 16447e3e5701SJan Parcel } else 16457e3e5701SJan Parcel rc = 0; 16467e3e5701SJan Parcel 16477e3e5701SJan Parcel if ((dargs->optflag & DA_REMOVE) && (rc == 0)) { 16487e3e5701SJan Parcel (void) close(tafd); 16497e3e5701SJan Parcel (void) unlink(apathp); 16507e3e5701SJan Parcel (void) close(lockfd); 16517e3e5701SJan Parcel return (0); 165245916cd2Sjpk } 16537e3e5701SJan Parcel /* 16547e3e5701SJan Parcel * TODO: clean up the workings of DA_UPDATE. 16557e3e5701SJan Parcel * Due to da_match looking at fields that are missing 16567e3e5701SJan Parcel * in dargs for DA_UPDATE, the da_match call returns no match, 16577e3e5701SJan Parcel * but due to the way _da2str combines the devalloc_t info with 16587e3e5701SJan Parcel * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work. 16597e3e5701SJan Parcel * 16607e3e5701SJan Parcel * This would not scale if any type of update was ever needed 16617e3e5701SJan Parcel * from the daemon. 16627e3e5701SJan Parcel */ 166345916cd2Sjpk 166445916cd2Sjpk /* 16657e3e5701SJan Parcel * Write out devallocp along with the devalloc on/off string. 166645916cd2Sjpk */ 166745916cd2Sjpk _write_device_allocate(dapathp, tafp, head_devallocp); 166845916cd2Sjpk 166945916cd2Sjpk if (dargs->optflag & DA_ALLOC_ONLY) 167045916cd2Sjpk goto out; 167145916cd2Sjpk 167245916cd2Sjpk dmap_only: 167345916cd2Sjpk if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 167445916cd2Sjpk (void) close(tafd); 167545916cd2Sjpk (void) unlink(apathp); 167645916cd2Sjpk (void) close(lockfd); 167745916cd2Sjpk return (-1); 167845916cd2Sjpk } 167945916cd2Sjpk (void) fchown(tmfd, DA_UID, DA_GID); 168045916cd2Sjpk if ((tmfp = fdopen(tmfd, "r+")) == NULL) { 168145916cd2Sjpk (void) close(tafd); 168245916cd2Sjpk (void) unlink(apathp); 168345916cd2Sjpk (void) close(tmfd); 168445916cd2Sjpk (void) unlink(mpathp); 168545916cd2Sjpk (void) close(lockfd); 168645916cd2Sjpk return (-1); 168745916cd2Sjpk } 168845916cd2Sjpk 16897e3e5701SJan Parcel /* 16907e3e5701SJan Parcel * Write back any non-removed pre-existing entries. 16917e3e5701SJan Parcel */ 169245916cd2Sjpk if (head_devmapp != NULL) 169345916cd2Sjpk _write_device_maps(tmfp, head_devmapp); 169445916cd2Sjpk 169545916cd2Sjpk out: 16967e3e5701SJan Parcel /* 16977e3e5701SJan Parcel * Add any new entries here. 16987e3e5701SJan Parcel */ 169945916cd2Sjpk if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 170045916cd2Sjpk /* add any new entries */ 170145916cd2Sjpk rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY); 170245916cd2Sjpk (void) fclose(tafp); 170345916cd2Sjpk 170445916cd2Sjpk if (rc == 0) 170545916cd2Sjpk rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY); 170645916cd2Sjpk (void) fclose(tmfp); 170745916cd2Sjpk } else { 170845916cd2Sjpk if (tafp) 170945916cd2Sjpk (void) fclose(tafp); 171045916cd2Sjpk if (tmfp) 171145916cd2Sjpk (void) fclose(tmfp); 171245916cd2Sjpk } 171345916cd2Sjpk 171445916cd2Sjpk rc = 0; 171545916cd2Sjpk if (!(dargs->optflag & DA_MAPS_ONLY)) { 171645916cd2Sjpk if (rename(apathp, dapathp) != 0) { 171745916cd2Sjpk rc = -1; 171845916cd2Sjpk (void) unlink(apathp); 171945916cd2Sjpk } 172045916cd2Sjpk } 172145916cd2Sjpk if (!(dargs->optflag & DA_ALLOC_ONLY)) { 172245916cd2Sjpk if (rename(mpathp, dmpathp) != 0) { 172345916cd2Sjpk rc = -1; 172445916cd2Sjpk (void) unlink(mpathp); 172545916cd2Sjpk } 172645916cd2Sjpk } 172745916cd2Sjpk 172845916cd2Sjpk (void) close(lockfd); 172945916cd2Sjpk 173045916cd2Sjpk return (rc); 173145916cd2Sjpk } 173245916cd2Sjpk 173345916cd2Sjpk /* 173445916cd2Sjpk * da_add_list - 173545916cd2Sjpk * adds new /dev link name to the linked list of devices. 173645916cd2Sjpk * returns 0 if link added successfully, -1 on error. 173745916cd2Sjpk */ 173845916cd2Sjpk int 173945916cd2Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) 174045916cd2Sjpk { 174145916cd2Sjpk int instance; 174245916cd2Sjpk int nlen, plen; 174345916cd2Sjpk int new_entry = 0; 174445916cd2Sjpk char *dtype, *dexec, *tname, *kval; 174545916cd2Sjpk char *minstr = NULL, *maxstr = NULL; 17467e3e5701SJan Parcel char dname[DA_MAXNAME + 1]; 174745916cd2Sjpk kva_t *kva; 174845916cd2Sjpk deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL; 174945916cd2Sjpk da_defs_t *da_defs; 175045916cd2Sjpk 175145916cd2Sjpk if (dlist == NULL || link == NULL) 175245916cd2Sjpk return (-1); 175345916cd2Sjpk 175445916cd2Sjpk dname[0] = '\0'; 175545916cd2Sjpk if (flag & DA_AUDIO) { 175645916cd2Sjpk dentry = dlist->audio; 175745916cd2Sjpk tname = DA_AUDIO_NAME; 175845916cd2Sjpk dtype = DA_AUDIO_TYPE; 175945916cd2Sjpk dexec = DA_DEFAULT_AUDIO_CLEAN; 176045916cd2Sjpk } else if (flag & DA_CD) { 176145916cd2Sjpk dentry = dlist->cd; 176245916cd2Sjpk tname = DA_CD_NAME; 176345916cd2Sjpk dtype = DA_CD_TYPE; 176445916cd2Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 176545916cd2Sjpk } else if (flag & DA_FLOPPY) { 176645916cd2Sjpk dentry = dlist->floppy; 176745916cd2Sjpk tname = DA_FLOPPY_NAME; 176845916cd2Sjpk dtype = DA_FLOPPY_TYPE; 176945916cd2Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 177045916cd2Sjpk } else if (flag & DA_TAPE) { 177145916cd2Sjpk dentry = dlist->tape; 177245916cd2Sjpk tname = DA_TAPE_NAME; 177345916cd2Sjpk dtype = DA_TAPE_TYPE; 177445916cd2Sjpk dexec = DA_DEFAULT_TAPE_CLEAN; 177545916cd2Sjpk } else if (flag & DA_RMDISK) { 177645916cd2Sjpk dentry = dlist->rmdisk; 177745916cd2Sjpk tname = DA_RMDISK_NAME; 177845916cd2Sjpk dtype = DA_RMDISK_TYPE; 177945916cd2Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 178045916cd2Sjpk } else { 178145916cd2Sjpk return (-1); 178245916cd2Sjpk } 178345916cd2Sjpk 178445916cd2Sjpk for (nentry = dentry; nentry != NULL; nentry = nentry->next) { 178545916cd2Sjpk pentry = nentry; 178645916cd2Sjpk (void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance); 178745916cd2Sjpk if (nentry->devinfo.instance == new_instance) 178845916cd2Sjpk /* 178945916cd2Sjpk * Add the new link name to the list of links 179045916cd2Sjpk * that the device 'dname' has. 179145916cd2Sjpk */ 179245916cd2Sjpk break; 179345916cd2Sjpk } 179445916cd2Sjpk 179545916cd2Sjpk if (nentry == NULL) { 179645916cd2Sjpk /* 179745916cd2Sjpk * Either this is the first entry ever, or no matching entry 179845916cd2Sjpk * was found. Create a new one and add to the list. 179945916cd2Sjpk */ 180045916cd2Sjpk if (dentry == NULL) /* first entry ever */ 180145916cd2Sjpk instance = 0; 180245916cd2Sjpk else /* no matching entry */ 180345916cd2Sjpk instance++; 180445916cd2Sjpk (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance); 180545916cd2Sjpk if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) == 180645916cd2Sjpk NULL) 180745916cd2Sjpk return (-1); 180845916cd2Sjpk if (pentry != NULL) 180945916cd2Sjpk pentry->next = nentry; 181045916cd2Sjpk new_entry = 1; 181145916cd2Sjpk nentry->devinfo.devname = strdup(dname); 181245916cd2Sjpk nentry->devinfo.devtype = dtype; 181345916cd2Sjpk nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH; 181445916cd2Sjpk nentry->devinfo.devexec = dexec; 181545916cd2Sjpk nentry->devinfo.instance = new_instance; 181645916cd2Sjpk /* 181745916cd2Sjpk * Look for default label range, authorizations and cleaning 181845916cd2Sjpk * program in devalloc_defaults. If label range is not 181945916cd2Sjpk * specified in devalloc_defaults, assume it to be admin_low 182045916cd2Sjpk * to admin_high. 182145916cd2Sjpk */ 182245916cd2Sjpk minstr = DA_DEFAULT_MIN; 182345916cd2Sjpk maxstr = DA_DEFAULT_MAX; 182445916cd2Sjpk setdadefent(); 182545916cd2Sjpk if (da_defs = getdadeftype(nentry->devinfo.devtype)) { 182645916cd2Sjpk kva = da_defs->devopts; 182745916cd2Sjpk if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL) 182845916cd2Sjpk minstr = strdup(kval); 182945916cd2Sjpk if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL) 183045916cd2Sjpk maxstr = strdup(kval); 183145916cd2Sjpk if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL) 183245916cd2Sjpk nentry->devinfo.devauths = strdup(kval); 183345916cd2Sjpk if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL) 183445916cd2Sjpk nentry->devinfo.devexec = strdup(kval); 183545916cd2Sjpk freedadefent(da_defs); 183645916cd2Sjpk } 183745916cd2Sjpk enddadefent(); 183845916cd2Sjpk kval = NULL; 183945916cd2Sjpk nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) + 184045916cd2Sjpk strlen(minstr) + strlen(KV_TOKEN_DELIMIT) + 184145916cd2Sjpk strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr) 184245916cd2Sjpk + 1; /* +1 for terminator */ 184345916cd2Sjpk if (kval = (char *)malloc(nlen)) 184445916cd2Sjpk (void) snprintf(kval, nlen, "%s%s%s%s%s%s%s", 184545916cd2Sjpk DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT, 184645916cd2Sjpk DAOPT_MAXLABEL, KV_ASSIGN, maxstr); 184745916cd2Sjpk nentry->devinfo.devopts = kval; 184845916cd2Sjpk 184945916cd2Sjpk nentry->devinfo.devlist = NULL; 185045916cd2Sjpk nentry->next = NULL; 185145916cd2Sjpk } 185245916cd2Sjpk 185345916cd2Sjpk nlen = strlen(link) + 1; /* +1 terminator */ 185445916cd2Sjpk if (nentry->devinfo.devlist) { 185545916cd2Sjpk plen = strlen(nentry->devinfo.devlist); 185645916cd2Sjpk nlen = nlen + plen + 1; /* +1 for blank to separate entries */ 185745916cd2Sjpk } else { 185845916cd2Sjpk plen = 0; 185945916cd2Sjpk } 186045916cd2Sjpk 186145916cd2Sjpk if ((nentry->devinfo.devlist = 186245916cd2Sjpk (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) { 186345916cd2Sjpk if (new_entry) { 186445916cd2Sjpk free(nentry->devinfo.devname); 186545916cd2Sjpk free(nentry); 186645916cd2Sjpk if (pentry != NULL) 186745916cd2Sjpk pentry->next = NULL; 186845916cd2Sjpk } 186945916cd2Sjpk return (-1); 187045916cd2Sjpk } 187145916cd2Sjpk 187245916cd2Sjpk if (plen == 0) 187345916cd2Sjpk (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link); 187445916cd2Sjpk else 187545916cd2Sjpk (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen, 187645916cd2Sjpk " %s", link); 187745916cd2Sjpk 187845916cd2Sjpk if (pentry == NULL) { 187945916cd2Sjpk /* 188045916cd2Sjpk * This is the first entry of this device type. 188145916cd2Sjpk */ 188245916cd2Sjpk if (flag & DA_AUDIO) 188345916cd2Sjpk dlist->audio = nentry; 188445916cd2Sjpk else if (flag & DA_CD) 188545916cd2Sjpk dlist->cd = nentry; 188645916cd2Sjpk else if (flag & DA_FLOPPY) 188745916cd2Sjpk dlist->floppy = nentry; 188845916cd2Sjpk else if (flag & DA_TAPE) 188945916cd2Sjpk dlist->tape = nentry; 189045916cd2Sjpk else if (flag & DA_RMDISK) 189145916cd2Sjpk dlist->rmdisk = nentry; 189245916cd2Sjpk } 189345916cd2Sjpk 189445916cd2Sjpk return (0); 189545916cd2Sjpk } 189645916cd2Sjpk 189745916cd2Sjpk /* 189845916cd2Sjpk * da_remove_list - 189945916cd2Sjpk * removes a /dev link name from the linked list of devices. 190045916cd2Sjpk * returns type of device if link for that device removed 190145916cd2Sjpk * successfully, else returns -1 on error. 190245916cd2Sjpk * if all links for a device are removed, stores that device 190345916cd2Sjpk * name in devname. 190445916cd2Sjpk */ 190545916cd2Sjpk int 190645916cd2Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size) 190745916cd2Sjpk { 190845916cd2Sjpk int flag; 190945916cd2Sjpk int remove_dev = 0; 191045916cd2Sjpk int nlen, plen, slen; 191145916cd2Sjpk char *lasts, *lname, *oldlist; 191245916cd2Sjpk struct stat rmstat; 191345916cd2Sjpk deventry_t *dentry, *current, *prev; 191445916cd2Sjpk 191545916cd2Sjpk if (type != NULL) 191645916cd2Sjpk flag = type; 191745916cd2Sjpk else if (link == NULL) 191845916cd2Sjpk return (-1); 191945916cd2Sjpk else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME)) 192045916cd2Sjpk flag = DA_AUDIO; 192145916cd2Sjpk else if (strstr(link, "dsk") || strstr(link, "rdsk") || 192245916cd2Sjpk strstr(link, "sr") || strstr(link, "rsr")) 192345916cd2Sjpk flag = DA_CD; 192445916cd2Sjpk else if (strstr(link, "fd") || strstr(link, "rfd") || 192545916cd2Sjpk strstr(link, "diskette") || strstr(link, "rdiskette")) 192645916cd2Sjpk flag = DA_FLOPPY; 192745916cd2Sjpk else if (strstr(link, DA_TAPE_NAME)) 192845916cd2Sjpk flag = DA_TAPE; 192945916cd2Sjpk else 193045916cd2Sjpk flag = DA_RMDISK; 193145916cd2Sjpk 193245916cd2Sjpk switch (type) { 193345916cd2Sjpk case DA_AUDIO: 193445916cd2Sjpk dentry = dlist->audio; 193545916cd2Sjpk break; 193645916cd2Sjpk case DA_CD: 193745916cd2Sjpk dentry = dlist->cd; 193845916cd2Sjpk break; 193945916cd2Sjpk case DA_FLOPPY: 194045916cd2Sjpk dentry = dlist->floppy; 194145916cd2Sjpk break; 194245916cd2Sjpk case DA_TAPE: 194345916cd2Sjpk dentry = dlist->tape; 194445916cd2Sjpk break; 194545916cd2Sjpk case DA_RMDISK: 194645916cd2Sjpk dentry = dlist->rmdisk; 194745916cd2Sjpk break; 194845916cd2Sjpk default: 194945916cd2Sjpk return (-1); 195045916cd2Sjpk } 195145916cd2Sjpk 195245916cd2Sjpk if ((type != NULL) && (link == NULL)) { 195345916cd2Sjpk for (current = dentry, prev = dentry; current != NULL; 195445916cd2Sjpk current = current->next) { 195545916cd2Sjpk oldlist = strdup(current->devinfo.devlist); 195645916cd2Sjpk for (lname = strtok_r(oldlist, " ", &lasts); 195745916cd2Sjpk lname != NULL; 195845916cd2Sjpk lname = strtok_r(NULL, " ", &lasts)) { 195945916cd2Sjpk if (stat(lname, &rmstat) != 0) { 196045916cd2Sjpk remove_dev = 1; 196145916cd2Sjpk goto remove_dev; 196245916cd2Sjpk } 196345916cd2Sjpk } 196445916cd2Sjpk prev = current; 196545916cd2Sjpk } 196645916cd2Sjpk return (-1); 196745916cd2Sjpk } 196845916cd2Sjpk 196945916cd2Sjpk for (current = dentry, prev = dentry; current != NULL; 197045916cd2Sjpk current = current->next) { 197145916cd2Sjpk plen = strlen(current->devinfo.devlist); 197245916cd2Sjpk nlen = strlen(link); 197345916cd2Sjpk if (plen == nlen) { 197445916cd2Sjpk if (strcmp(current->devinfo.devlist, link) == 0) { 197545916cd2Sjpk /* last name in the list */ 197645916cd2Sjpk remove_dev = 1; 197745916cd2Sjpk break; 197845916cd2Sjpk } 197945916cd2Sjpk } 198045916cd2Sjpk if (strstr(current->devinfo.devlist, link)) { 198145916cd2Sjpk nlen = plen - nlen + 1; 198245916cd2Sjpk oldlist = strdup(current->devinfo.devlist); 198345916cd2Sjpk if ((current->devinfo.devlist = 198445916cd2Sjpk (char *)realloc(current->devinfo.devlist, 198545916cd2Sjpk nlen)) == NULL) { 198645916cd2Sjpk free(oldlist); 198745916cd2Sjpk return (-1); 198845916cd2Sjpk } 198945916cd2Sjpk current->devinfo.devlist[0] = '\0'; 199045916cd2Sjpk nlen = plen = slen = 0; 199145916cd2Sjpk for (lname = strtok_r(oldlist, " ", &lasts); 199245916cd2Sjpk lname != NULL; 199345916cd2Sjpk lname = strtok_r(NULL, " ", &lasts)) { 199445916cd2Sjpk if (strcmp(lname, link) == 0) 199545916cd2Sjpk continue; 199645916cd2Sjpk nlen = strlen(lname) + plen + 1; 199745916cd2Sjpk if (plen == 0) { 199845916cd2Sjpk slen = 199945916cd2Sjpk snprintf(current->devinfo.devlist, 200045916cd2Sjpk nlen, "%s", lname); 200145916cd2Sjpk } else { 200245916cd2Sjpk slen = 200345916cd2Sjpk snprintf(current->devinfo.devlist + 200410ddde3aSaj plen, nlen - plen, " %s", lname); 200545916cd2Sjpk } 200645916cd2Sjpk plen = plen + slen + 1; 200745916cd2Sjpk } 200845916cd2Sjpk free(oldlist); 200945916cd2Sjpk break; 201045916cd2Sjpk } 201145916cd2Sjpk prev = current; 201245916cd2Sjpk } 201345916cd2Sjpk 201445916cd2Sjpk remove_dev: 201545916cd2Sjpk if (remove_dev == 1) { 201645916cd2Sjpk (void) strlcpy(devname, current->devinfo.devname, size); 201745916cd2Sjpk free(current->devinfo.devname); 201845916cd2Sjpk free(current->devinfo.devlist); 201945916cd2Sjpk current->devinfo.devname = current->devinfo.devlist = NULL; 202045916cd2Sjpk prev->next = current->next; 202145916cd2Sjpk free(current); 202245916cd2Sjpk current = NULL; 202345916cd2Sjpk } 202445916cd2Sjpk if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) { 202545916cd2Sjpk if (prev->next) { 202645916cd2Sjpk /* 202745916cd2Sjpk * what we removed above was the first entry 202845916cd2Sjpk * in the list. make the next entry to be the 202945916cd2Sjpk * first. 203045916cd2Sjpk */ 203145916cd2Sjpk current = prev->next; 203245916cd2Sjpk } else { 203345916cd2Sjpk /* 203445916cd2Sjpk * the matching entry was the only entry in the list 203545916cd2Sjpk * for this type. 203645916cd2Sjpk */ 203745916cd2Sjpk current = NULL; 203845916cd2Sjpk } 203945916cd2Sjpk if (flag & DA_AUDIO) 204045916cd2Sjpk dlist->audio = current; 204145916cd2Sjpk else if (flag & DA_CD) 204245916cd2Sjpk dlist->cd = current; 204345916cd2Sjpk else if (flag & DA_FLOPPY) 204445916cd2Sjpk dlist->floppy = current; 204545916cd2Sjpk else if (flag & DA_TAPE) 204645916cd2Sjpk dlist->tape = current; 204745916cd2Sjpk else if (flag & DA_RMDISK) 204845916cd2Sjpk dlist->rmdisk = current; 204945916cd2Sjpk } 205045916cd2Sjpk 205145916cd2Sjpk return (flag); 205245916cd2Sjpk } 205345916cd2Sjpk 205445916cd2Sjpk /* 20557e3e5701SJan Parcel * da_rm_list_entry - 20567e3e5701SJan Parcel * 20577e3e5701SJan Parcel * The adding of devnames to a devlist and the removal of a 20587e3e5701SJan Parcel * device are not symmetrical -- hot_cleanup gives a /devices 20597e3e5701SJan Parcel * name which is used to remove the dentry whose links all point to 20607e3e5701SJan Parcel * that /devices entry. 20617e3e5701SJan Parcel * 20627e3e5701SJan Parcel * The link argument is present if available to make debugging 20637e3e5701SJan Parcel * easier. 20647e3e5701SJan Parcel * 20657e3e5701SJan Parcel * da_rm_list_entry removes an entry from the linked list of devices. 20667e3e5701SJan Parcel * 20677e3e5701SJan Parcel * Returns 1 if the devname was removed successfully, 20687e3e5701SJan Parcel * 0 if not found, -1 for error. 20697e3e5701SJan Parcel */ 20707e3e5701SJan Parcel /*ARGSUSED*/ 20717e3e5701SJan Parcel int 20727e3e5701SJan Parcel da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname) 20737e3e5701SJan Parcel { 20747e3e5701SJan Parcel int retval = 0; 20757e3e5701SJan Parcel deventry_t **dentry, *current, *prev; 20767e3e5701SJan Parcel 20777e3e5701SJan Parcel switch (type) { 20787e3e5701SJan Parcel case DA_AUDIO: 20797e3e5701SJan Parcel dentry = &(dlist->audio); 20807e3e5701SJan Parcel break; 20817e3e5701SJan Parcel case DA_CD: 20827e3e5701SJan Parcel dentry = &(dlist->cd); 20837e3e5701SJan Parcel break; 20847e3e5701SJan Parcel case DA_FLOPPY: 20857e3e5701SJan Parcel dentry = &(dlist->floppy); 20867e3e5701SJan Parcel break; 20877e3e5701SJan Parcel case DA_TAPE: 20887e3e5701SJan Parcel dentry = &(dlist->tape); 20897e3e5701SJan Parcel break; 20907e3e5701SJan Parcel case DA_RMDISK: 20917e3e5701SJan Parcel dentry = &(dlist->rmdisk); 20927e3e5701SJan Parcel break; 20937e3e5701SJan Parcel default: 20947e3e5701SJan Parcel return (-1); 20957e3e5701SJan Parcel } 20967e3e5701SJan Parcel 20977e3e5701SJan Parcel /* Presumably in daemon mode, no need to remove entry, list is empty */ 20987e3e5701SJan Parcel if (*dentry == (deventry_t *)NULL) 20997e3e5701SJan Parcel return (0); 21007e3e5701SJan Parcel 21017e3e5701SJan Parcel prev = NULL; 21027e3e5701SJan Parcel for (current = *dentry; current != NULL; 21037e3e5701SJan Parcel prev = current, current = current->next) { 21047e3e5701SJan Parcel if (strcmp(devname, current->devinfo.devname)) 21057e3e5701SJan Parcel continue; 21067e3e5701SJan Parcel retval = 1; 21077e3e5701SJan Parcel break; 21087e3e5701SJan Parcel } 21097e3e5701SJan Parcel if (retval == 0) 21107e3e5701SJan Parcel return (0); 21117e3e5701SJan Parcel free(current->devinfo.devname); 21127e3e5701SJan Parcel if (current->devinfo.devlist != NULL) 21137e3e5701SJan Parcel free(current->devinfo.devlist); 21147e3e5701SJan Parcel if (current->devinfo.devopts != NULL) 21157e3e5701SJan Parcel free(current->devinfo.devopts); 21167e3e5701SJan Parcel 21177e3e5701SJan Parcel if (prev == NULL) 21187e3e5701SJan Parcel *dentry = current->next; 21197e3e5701SJan Parcel else 21207e3e5701SJan Parcel prev->next = current->next; 21217e3e5701SJan Parcel 21227e3e5701SJan Parcel free(current); 21237e3e5701SJan Parcel return (retval); 21247e3e5701SJan Parcel } 21257e3e5701SJan Parcel 21267e3e5701SJan Parcel /* 212745916cd2Sjpk * da_is_on - 212845916cd2Sjpk * checks if device allocation feature is turned on. 212945916cd2Sjpk * returns 1 if on, 0 if off, -1 if status string not 213045916cd2Sjpk * found in device_allocate. 213145916cd2Sjpk */ 213245916cd2Sjpk int 213345916cd2Sjpk da_is_on() 213445916cd2Sjpk { 213545916cd2Sjpk return (getdaon()); 213645916cd2Sjpk } 213745916cd2Sjpk 213845916cd2Sjpk /* 213945916cd2Sjpk * da_print_device - 214045916cd2Sjpk * debug routine to print device entries. 214145916cd2Sjpk */ 214245916cd2Sjpk void 214345916cd2Sjpk da_print_device(int flag, devlist_t *devlist) 214445916cd2Sjpk { 214545916cd2Sjpk deventry_t *entry, *dentry; 214645916cd2Sjpk devinfo_t *devinfo; 214745916cd2Sjpk 214845916cd2Sjpk if (flag & DA_AUDIO) 214945916cd2Sjpk dentry = devlist->audio; 215045916cd2Sjpk else if (flag & DA_CD) 215145916cd2Sjpk dentry = devlist->cd; 215245916cd2Sjpk else if (flag & DA_FLOPPY) 215345916cd2Sjpk dentry = devlist->floppy; 215445916cd2Sjpk else if (flag & DA_TAPE) 215545916cd2Sjpk dentry = devlist->tape; 215645916cd2Sjpk else if (flag & DA_RMDISK) 215745916cd2Sjpk dentry = devlist->rmdisk; 215845916cd2Sjpk else 215945916cd2Sjpk return; 216045916cd2Sjpk 216145916cd2Sjpk for (entry = dentry; entry != NULL; entry = entry->next) { 216245916cd2Sjpk devinfo = &(entry->devinfo); 216345916cd2Sjpk (void) fprintf(stdout, "name: %s\n", devinfo->devname); 216445916cd2Sjpk (void) fprintf(stdout, "type: %s\n", devinfo->devtype); 216545916cd2Sjpk (void) fprintf(stdout, "auth: %s\n", devinfo->devauths); 216645916cd2Sjpk (void) fprintf(stdout, "exec: %s\n", devinfo->devexec); 216745916cd2Sjpk (void) fprintf(stdout, "list: %s\n\n", devinfo->devlist); 216845916cd2Sjpk } 216945916cd2Sjpk } 2170