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*7e3e5701SJan Parcel * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2445916cd2Sjpk * Use is subject to license terms. 2545916cd2Sjpk */ 2645916cd2Sjpk 2745916cd2Sjpk #include <stdlib.h> 2845916cd2Sjpk #include <ctype.h> 2945916cd2Sjpk #include <unistd.h> 3045916cd2Sjpk #include <limits.h> 3145916cd2Sjpk #include <fcntl.h> 3245916cd2Sjpk #include <sys/types.h> 3345916cd2Sjpk #include <sys/stat.h> 3445916cd2Sjpk #include <utime.h> 3545916cd2Sjpk #include <synch.h> 3645916cd2Sjpk #include <strings.h> 3745916cd2Sjpk #include <string.h> 3845916cd2Sjpk #include <libintl.h> 3945916cd2Sjpk #include <errno.h> 4045916cd2Sjpk #include <auth_list.h> 41*7e3e5701SJan Parcel #include <syslog.h> 4245916cd2Sjpk #include <bsm/devices.h> 4345916cd2Sjpk #include <bsm/devalloc.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 *); 55*7e3e5701SJan Parcel extern int dmap_matchtype(devmap_t *dmap, char *type); 56*7e3e5701SJan Parcel extern int dmap_matchdev(devmap_t *dmap, char *dev); 57*7e3e5701SJan Parcel extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num); 58*7e3e5701SJan 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 338*7e3e5701SJan 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 * 362*7e3e5701SJan Parcel _dmap2strentry(devmap_t *devmapp) 36345916cd2Sjpk { 36445916cd2Sjpk strentry_t *sep; 36545916cd2Sjpk 36645916cd2Sjpk if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 36745916cd2Sjpk return (NULL); 368*7e3e5701SJan 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*7e3e5701SJan Parcel * _rebuild_lists - 569*7e3e5701SJan Parcel * 570*7e3e5701SJan Parcel * If dargs->optflag & DA_EVENT, does not assume the dargs list is 571*7e3e5701SJan Parcel * complete or completely believable, since devfsadm caches 572*7e3e5701SJan Parcel * ONLY what it has been exposed to via syseventd. 573*7e3e5701SJan Parcel * 574*7e3e5701SJan Parcel * Cycles through all the entries in the /etc files, stores them 575*7e3e5701SJan Parcel * in memory, takes note of device->dname numbers (i.e. rmdisk0, 576*7e3e5701SJan Parcel * rmdisk12) 577*7e3e5701SJan Parcel * 578*7e3e5701SJan Parcel * Cycles through again, adds dargs entry 579*7e3e5701SJan Parcel * with the name tname%d (lowest unused number for the device type) 580*7e3e5701SJan Parcel * to the list of things for the caller to write out to a file, 581*7e3e5701SJan Parcel * IFF it is a new entry. 582*7e3e5701SJan Parcel * 583*7e3e5701SJan Parcel * It is an error for it to already be there. 584*7e3e5701SJan Parcel * 585*7e3e5701SJan Parcel * Add: 586*7e3e5701SJan Parcel * Returns 0 if successful and 2 on error. 587*7e3e5701SJan Parcel * Remove: 588*7e3e5701SJan Parcel * Returns 0 if not found, 1 if found, 2 on error. 589*7e3e5701SJan Parcel */ 590*7e3e5701SJan Parcel static int 591*7e3e5701SJan Parcel _rebuild_lists(da_args *dargs, strentry_t **head_devallocp, 592*7e3e5701SJan Parcel strentry_t **head_devmapp) 593*7e3e5701SJan Parcel { 594*7e3e5701SJan Parcel int rc = 0; 595*7e3e5701SJan Parcel devalloc_t *devallocp; 596*7e3e5701SJan Parcel devmap_t *devmapp; 597*7e3e5701SJan Parcel strentry_t *tail_str; 598*7e3e5701SJan Parcel strentry_t *tmp_str; 599*7e3e5701SJan Parcel uint64_t tmp_bitmap = 0; 600*7e3e5701SJan Parcel int tmp = 0; 601*7e3e5701SJan Parcel char new_devname[DA_MAXNAME + 1]; 602*7e3e5701SJan Parcel char errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80]; 603*7e3e5701SJan Parcel char *realname; 604*7e3e5701SJan Parcel int suffix = DA_MAX_DEVNO + 1; 605*7e3e5701SJan Parcel int found = 0; 606*7e3e5701SJan Parcel 607*7e3e5701SJan Parcel if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY)) 608*7e3e5701SJan Parcel return (2); 609*7e3e5701SJan Parcel 610*7e3e5701SJan Parcel if (dargs->optflag & DA_FORCE) 611*7e3e5701SJan Parcel return (2); 612*7e3e5701SJan Parcel 613*7e3e5701SJan Parcel /* read both files, maps first so we can compare actual devices */ 614*7e3e5701SJan Parcel 615*7e3e5701SJan Parcel /* build device_maps */ 616*7e3e5701SJan Parcel setdmapent(); 617*7e3e5701SJan Parcel while ((devmapp = getdmapent()) != NULL) { 618*7e3e5701SJan Parcel if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype)) 619*7e3e5701SJan Parcel == 1) { 620*7e3e5701SJan Parcel if (dargs->optflag & DA_REMOVE) { 621*7e3e5701SJan Parcel if ((devmapp->dmap_devarray == NULL) || 622*7e3e5701SJan Parcel (devmapp->dmap_devarray[0] == NULL)) { 623*7e3e5701SJan Parcel freedmapent(devmapp); 624*7e3e5701SJan Parcel enddmapent(); 625*7e3e5701SJan Parcel return (2); 626*7e3e5701SJan Parcel } 627*7e3e5701SJan Parcel realname = dmap_physname(devmapp); 628*7e3e5701SJan Parcel if (realname == NULL) { 629*7e3e5701SJan Parcel freedmapent(devmapp); 630*7e3e5701SJan Parcel enddmapent(); 631*7e3e5701SJan Parcel return (2); 632*7e3e5701SJan Parcel } 633*7e3e5701SJan Parcel if (strstr(realname, dargs->devinfo->devlist) 634*7e3e5701SJan Parcel != NULL) { 635*7e3e5701SJan Parcel if (dargs->devinfo->devname != NULL) 636*7e3e5701SJan Parcel free(dargs->devinfo->devname); 637*7e3e5701SJan Parcel dargs->devinfo->devname = 638*7e3e5701SJan Parcel strdup(devmapp->dmap_devname); 639*7e3e5701SJan Parcel found = 1; 640*7e3e5701SJan Parcel freedmapent(devmapp); 641*7e3e5701SJan Parcel continue; /* don't retain */ 642*7e3e5701SJan Parcel } 643*7e3e5701SJan Parcel } else if (dargs->optflag & DA_ADD) { 644*7e3e5701SJan Parcel /* 645*7e3e5701SJan Parcel * Need to know which suffixes are in use 646*7e3e5701SJan Parcel */ 647*7e3e5701SJan Parcel rc = (dmap_exact_dev(devmapp, 648*7e3e5701SJan Parcel dargs->devinfo->devlist, &suffix)); 649*7e3e5701SJan Parcel 650*7e3e5701SJan Parcel if (rc == 0) { 651*7e3e5701SJan Parcel /* 652*7e3e5701SJan Parcel * Same type, different device. Record 653*7e3e5701SJan Parcel * device suffix already in use. 654*7e3e5701SJan Parcel */ 655*7e3e5701SJan Parcel if (suffix > DA_MAX_DEVNO) { 656*7e3e5701SJan Parcel freedmapent(devmapp); 657*7e3e5701SJan Parcel enddmapent(); 658*7e3e5701SJan Parcel return (2); 659*7e3e5701SJan Parcel } 660*7e3e5701SJan Parcel tmp_bitmap |= (uint64_t)(1LL << suffix); 661*7e3e5701SJan Parcel } else { 662*7e3e5701SJan Parcel /* 663*7e3e5701SJan Parcel * Match on add is an error 664*7e3e5701SJan Parcel * or mapping attempt returned error 665*7e3e5701SJan Parcel */ 666*7e3e5701SJan Parcel freedmapent(devmapp); 667*7e3e5701SJan Parcel enddmapent(); 668*7e3e5701SJan Parcel return (2); 669*7e3e5701SJan Parcel } 670*7e3e5701SJan Parcel } else 671*7e3e5701SJan Parcel /* add other transaction types as needed */ 672*7e3e5701SJan Parcel return (2); 673*7e3e5701SJan Parcel 674*7e3e5701SJan Parcel } /* if same type */ 675*7e3e5701SJan Parcel 676*7e3e5701SJan Parcel tmp_str = _dmap2strentry(devmapp); 677*7e3e5701SJan Parcel if (tmp_str == NULL) { 678*7e3e5701SJan Parcel freedmapent(devmapp); 679*7e3e5701SJan Parcel enddmapent(); 680*7e3e5701SJan Parcel return (2); 681*7e3e5701SJan Parcel } 682*7e3e5701SJan Parcel /* retaining devmap entry: tmp_str->se_str */ 683*7e3e5701SJan Parcel tmp_str->se_next = NULL; 684*7e3e5701SJan Parcel if (*head_devmapp == NULL) { 685*7e3e5701SJan Parcel *head_devmapp = tail_str = tmp_str; 686*7e3e5701SJan Parcel } else { 687*7e3e5701SJan Parcel tail_str->se_next = tmp_str; 688*7e3e5701SJan Parcel tail_str = tmp_str; 689*7e3e5701SJan Parcel } 690*7e3e5701SJan Parcel freedmapent(devmapp); 691*7e3e5701SJan Parcel } 692*7e3e5701SJan Parcel enddmapent(); 693*7e3e5701SJan Parcel 694*7e3e5701SJan Parcel /* 695*7e3e5701SJan Parcel * No need to rewrite the files if the item to be removed is not 696*7e3e5701SJan Parcel * in the files -- wait for another call on another darg. 697*7e3e5701SJan Parcel */ 698*7e3e5701SJan Parcel if ((dargs->optflag & DA_REMOVE) && !found) 699*7e3e5701SJan Parcel return (0); 700*7e3e5701SJan Parcel 701*7e3e5701SJan Parcel 702*7e3e5701SJan Parcel if (dargs->optflag & DA_ADD) { 703*7e3e5701SJan Parcel /* 704*7e3e5701SJan Parcel * Since we got here from an event, we know the stored 705*7e3e5701SJan Parcel * devname is a useless guess, since the files had not 706*7e3e5701SJan Parcel * been read when the name was chosen, and we don't keep 707*7e3e5701SJan Parcel * them anywhere else that is sufficiently definitive. 708*7e3e5701SJan Parcel */ 709*7e3e5701SJan Parcel 710*7e3e5701SJan Parcel for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++) 711*7e3e5701SJan Parcel if (!(tmp_bitmap & (1LL << tmp))) 712*7e3e5701SJan Parcel break; 713*7e3e5701SJan Parcel /* Future: support more than 64 hotplug devices per type? */ 714*7e3e5701SJan Parcel if (tmp > DA_MAX_DEVNO) 715*7e3e5701SJan Parcel return (2); 716*7e3e5701SJan Parcel 717*7e3e5701SJan Parcel (void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u", 718*7e3e5701SJan Parcel dargs->devinfo->devtype, tmp); 719*7e3e5701SJan Parcel if (dargs->devinfo->devname != NULL) 720*7e3e5701SJan Parcel free(dargs->devinfo->devname); 721*7e3e5701SJan Parcel dargs->devinfo->devname = strdup(new_devname); 722*7e3e5701SJan Parcel } 723*7e3e5701SJan Parcel 724*7e3e5701SJan Parcel /* 725*7e3e5701SJan Parcel * Now adjust devalloc list to match devmaps 726*7e3e5701SJan Parcel * Note we now have the correct devname for da_match to use. 727*7e3e5701SJan Parcel */ 728*7e3e5701SJan Parcel setdaent(); 729*7e3e5701SJan Parcel while ((devallocp = getdaent()) != NULL) { 730*7e3e5701SJan Parcel rc = da_match(devallocp, dargs); 731*7e3e5701SJan Parcel if (rc == 1) { 732*7e3e5701SJan Parcel if (dargs->optflag & DA_ADD) { 733*7e3e5701SJan Parcel /* logging is on if DA_EVENT is set */ 734*7e3e5701SJan Parcel if (dargs->optflag & DA_EVENT) { 735*7e3e5701SJan Parcel (void) snprintf(errmsg, sizeof (errmsg), 736*7e3e5701SJan Parcel "%s and %s out of sync," 737*7e3e5701SJan Parcel "%s only in %s.", 738*7e3e5701SJan Parcel DEVALLOC, DEVMAP, 739*7e3e5701SJan Parcel devallocp->da_devname, DEVALLOC); 740*7e3e5701SJan Parcel syslog(LOG_ERR, "%s", errmsg); 741*7e3e5701SJan Parcel } 742*7e3e5701SJan Parcel freedaent(devallocp); 743*7e3e5701SJan Parcel enddaent(); 744*7e3e5701SJan Parcel return (2); 745*7e3e5701SJan Parcel } else if (dargs->optflag & DA_REMOVE) { 746*7e3e5701SJan Parcel /* make list w/o this entry */ 747*7e3e5701SJan Parcel freedaent(devallocp); 748*7e3e5701SJan Parcel continue; 749*7e3e5701SJan Parcel } 750*7e3e5701SJan Parcel } 751*7e3e5701SJan Parcel tmp_str = _da2strentry(dargs, devallocp); 752*7e3e5701SJan Parcel if (tmp_str == NULL) { 753*7e3e5701SJan Parcel freedaent(devallocp); 754*7e3e5701SJan Parcel enddaent(); 755*7e3e5701SJan Parcel return (2); 756*7e3e5701SJan Parcel } 757*7e3e5701SJan Parcel /* retaining devalloc entry: tmp_str->se_str */ 758*7e3e5701SJan Parcel tmp_str->se_next = NULL; 759*7e3e5701SJan Parcel if (*head_devallocp == NULL) { 760*7e3e5701SJan Parcel *head_devallocp = tail_str = tmp_str; 761*7e3e5701SJan Parcel } else { 762*7e3e5701SJan Parcel tail_str->se_next = tmp_str; 763*7e3e5701SJan Parcel tail_str = tmp_str; 764*7e3e5701SJan Parcel } 765*7e3e5701SJan Parcel freedaent(devallocp); 766*7e3e5701SJan Parcel } 767*7e3e5701SJan Parcel enddaent(); 768*7e3e5701SJan Parcel 769*7e3e5701SJan Parcel /* the caller needs to know if a remove needs to rewrite files */ 770*7e3e5701SJan Parcel if (dargs->optflag & DA_REMOVE) 771*7e3e5701SJan Parcel return (1); /* 0 and 2 cases returned earlier */ 772*7e3e5701SJan Parcel 773*7e3e5701SJan Parcel return (0); /* Successful DA_ADD */ 774*7e3e5701SJan Parcel } 775*7e3e5701SJan Parcel /* 77645916cd2Sjpk * _build_lists - 777*7e3e5701SJan Parcel * Cycles through all the entries, stores them in memory. removes entries 77845916cd2Sjpk * with the given search_key (device name or type). 77945916cd2Sjpk * returns 0 if given entry not found, 1 if given entry removed, 2 on 78045916cd2Sjpk * error. 78145916cd2Sjpk */ 78245916cd2Sjpk static int 78345916cd2Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp, 78445916cd2Sjpk strentry_t **head_devmapp) 78545916cd2Sjpk { 78645916cd2Sjpk int rc = 0; 78745916cd2Sjpk devalloc_t *devallocp; 78845916cd2Sjpk devmap_t *devmapp; 78945916cd2Sjpk strentry_t *tail_str; 79045916cd2Sjpk strentry_t *tmp_str; 79145916cd2Sjpk 79245916cd2Sjpk if (dargs->optflag & DA_MAPS_ONLY) 79345916cd2Sjpk goto dmap_only; 79445916cd2Sjpk 79545916cd2Sjpk /* build device_allocate */ 79645916cd2Sjpk setdaent(); 79745916cd2Sjpk while ((devallocp = getdaent()) != NULL) { 79845916cd2Sjpk rc = da_match(devallocp, dargs); 79945916cd2Sjpk if (rc && dargs->optflag & DA_ADD && 80045916cd2Sjpk !(dargs->optflag & DA_FORCE)) { 80145916cd2Sjpk /* 80245916cd2Sjpk * During DA_ADD, we keep an existing entry unless 80345916cd2Sjpk * we have DA_FORCE set to override that entry. 80445916cd2Sjpk */ 80545916cd2Sjpk dargs->optflag |= DA_NO_OVERRIDE; 80645916cd2Sjpk rc = 0; 80745916cd2Sjpk } 80845916cd2Sjpk if (rc == 0) { 80945916cd2Sjpk tmp_str = _da2strentry(dargs, devallocp); 81045916cd2Sjpk if (tmp_str == NULL) { 81145916cd2Sjpk freedaent(devallocp); 81245916cd2Sjpk enddaent(); 81345916cd2Sjpk return (2); 81445916cd2Sjpk } 81545916cd2Sjpk /* retaining devalloc entry: tmp_str->se_str */ 81645916cd2Sjpk tmp_str->se_next = NULL; 81745916cd2Sjpk if (*head_devallocp == NULL) { 81845916cd2Sjpk *head_devallocp = tail_str = tmp_str; 81945916cd2Sjpk } else { 82045916cd2Sjpk tail_str->se_next = tmp_str; 82145916cd2Sjpk tail_str = tmp_str; 82245916cd2Sjpk } 82345916cd2Sjpk } 82445916cd2Sjpk freedaent(devallocp); 82545916cd2Sjpk } 82645916cd2Sjpk enddaent(); 82745916cd2Sjpk 82845916cd2Sjpk dmap_only: 82945916cd2Sjpk if (dargs->optflag & DA_ALLOC_ONLY) 83045916cd2Sjpk return (rc); 83145916cd2Sjpk 83245916cd2Sjpk /* build device_maps */ 83345916cd2Sjpk rc = 0; 83445916cd2Sjpk setdmapent(); 83545916cd2Sjpk while ((devmapp = getdmapent()) != NULL) { 83645916cd2Sjpk rc = dm_match(devmapp, dargs); 83745916cd2Sjpk if (rc && dargs->optflag & DA_ADD && 83845916cd2Sjpk !(dargs->optflag & DA_FORCE)) { 83945916cd2Sjpk /* 84045916cd2Sjpk * During DA_ADD, we keep an existing entry unless 84145916cd2Sjpk * we have DA_FORCE set to override that entry. 84245916cd2Sjpk */ 84345916cd2Sjpk dargs->optflag |= DA_NO_OVERRIDE; 84445916cd2Sjpk rc = 0; 84545916cd2Sjpk } 84645916cd2Sjpk if (rc == 0) { 847*7e3e5701SJan Parcel tmp_str = _dmap2strentry(devmapp); 84845916cd2Sjpk if (tmp_str == NULL) { 84945916cd2Sjpk freedmapent(devmapp); 85045916cd2Sjpk enddmapent(); 85145916cd2Sjpk return (2); 85245916cd2Sjpk } 85345916cd2Sjpk /* retaining devmap entry: tmp_str->se_str */ 85445916cd2Sjpk tmp_str->se_next = NULL; 85545916cd2Sjpk if (*head_devmapp == NULL) { 85645916cd2Sjpk *head_devmapp = tail_str = tmp_str; 85745916cd2Sjpk } else { 85845916cd2Sjpk tail_str->se_next = tmp_str; 85945916cd2Sjpk tail_str = tmp_str; 86045916cd2Sjpk } 86145916cd2Sjpk } 86245916cd2Sjpk freedmapent(devmapp); 86345916cd2Sjpk } 86445916cd2Sjpk enddmapent(); 86545916cd2Sjpk 86645916cd2Sjpk return (rc); 86745916cd2Sjpk } 86845916cd2Sjpk 86945916cd2Sjpk /* 87045916cd2Sjpk * _write_defattrs 87145916cd2Sjpk * writes current entries to devalloc_defaults. 87245916cd2Sjpk */ 87345916cd2Sjpk static void 87445916cd2Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent) 87545916cd2Sjpk { 87645916cd2Sjpk strentry_t *tmp_str; 87745916cd2Sjpk 87845916cd2Sjpk for (tmp_str = head_defent; tmp_str != NULL; 87945916cd2Sjpk tmp_str = tmp_str->se_next) { 88045916cd2Sjpk (void) fputs(tmp_str->se_str, fp); 88145916cd2Sjpk (void) fputs("\n", fp); 88245916cd2Sjpk } 88345916cd2Sjpk 88445916cd2Sjpk } 88545916cd2Sjpk 88645916cd2Sjpk /* 88745916cd2Sjpk * _write_device_allocate - 88845916cd2Sjpk * writes current entries in the list to device_allocate. 889*7e3e5701SJan Parcel * frees the strings 89045916cd2Sjpk */ 89145916cd2Sjpk static void 89245916cd2Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp) 89345916cd2Sjpk { 89445916cd2Sjpk int is_on = -1; 895*7e3e5701SJan Parcel strentry_t *tmp_str, *old_str; 89645916cd2Sjpk struct stat dastat; 89745916cd2Sjpk 89845916cd2Sjpk (void) fseek(dafp, (off_t)0, SEEK_SET); 89945916cd2Sjpk 90045916cd2Sjpk /* 90145916cd2Sjpk * if the devalloc on/off string existed before, 90245916cd2Sjpk * put it back before anything else. 90345916cd2Sjpk * we need to check for the string only if the file 90445916cd2Sjpk * exists. 90545916cd2Sjpk */ 90645916cd2Sjpk if (stat(odevalloc, &dastat) == 0) { 90745916cd2Sjpk is_on = da_is_on(); 90845916cd2Sjpk if (is_on == 0) 90945916cd2Sjpk (void) fputs(DA_OFF_STR, dafp); 91045916cd2Sjpk else if (is_on == 1) 91145916cd2Sjpk (void) fputs(DA_ON_STR, dafp); 91245916cd2Sjpk } 91345916cd2Sjpk tmp_str = head_devallocp; 91445916cd2Sjpk while (tmp_str) { 91545916cd2Sjpk (void) fputs(tmp_str->se_str, dafp); 91645916cd2Sjpk (void) fputs("\n", dafp); 917*7e3e5701SJan Parcel old_str = tmp_str; 91845916cd2Sjpk tmp_str = tmp_str->se_next; 919*7e3e5701SJan Parcel free(old_str); 92045916cd2Sjpk } 92145916cd2Sjpk } 92245916cd2Sjpk 92345916cd2Sjpk /* 92445916cd2Sjpk * _write_device_maps - 92545916cd2Sjpk * writes current entries in the list to device_maps. 926*7e3e5701SJan Parcel * and frees the strings 92745916cd2Sjpk */ 92845916cd2Sjpk static void 92945916cd2Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp) 93045916cd2Sjpk { 931*7e3e5701SJan Parcel strentry_t *tmp_str, *old_str; 93245916cd2Sjpk 93345916cd2Sjpk (void) fseek(dmfp, (off_t)0, SEEK_SET); 93445916cd2Sjpk 93545916cd2Sjpk tmp_str = head_devmapp; 93645916cd2Sjpk while (tmp_str) { 93745916cd2Sjpk (void) fputs(tmp_str->se_str, dmfp); 93845916cd2Sjpk (void) fputs("\n", dmfp); 939*7e3e5701SJan Parcel old_str = tmp_str; 94045916cd2Sjpk tmp_str = tmp_str->se_next; 941*7e3e5701SJan Parcel free(old_str); 94245916cd2Sjpk } 94345916cd2Sjpk } 94445916cd2Sjpk 94545916cd2Sjpk /* 94645916cd2Sjpk * _write_new_defattrs 94745916cd2Sjpk * writes the new entry to devalloc_defaults. 94845916cd2Sjpk * returns 0 on success, -1 on error. 94945916cd2Sjpk */ 95045916cd2Sjpk static int 95145916cd2Sjpk _write_new_defattrs(FILE *fp, da_args *dargs) 95245916cd2Sjpk { 95345916cd2Sjpk int count; 95445916cd2Sjpk char *tok = NULL, *tokp = NULL; 95545916cd2Sjpk char *lasts; 95645916cd2Sjpk devinfo_t *devinfo = dargs->devinfo; 95745916cd2Sjpk 95845916cd2Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 95945916cd2Sjpk return (-1); 96045916cd2Sjpk if (!devinfo->devopts) 96145916cd2Sjpk return (0); 96245916cd2Sjpk (void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""), 96345916cd2Sjpk KV_TOKEN_DELIMIT); 964*7e3e5701SJan Parcel if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) { 96545916cd2Sjpk (void) strcpy(tokp, devinfo->devopts); 96645916cd2Sjpk if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) { 96745916cd2Sjpk (void) fprintf(fp, "%s", tok); 96845916cd2Sjpk count = 1; 96945916cd2Sjpk } 97045916cd2Sjpk while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) { 97145916cd2Sjpk if (count) 97245916cd2Sjpk (void) fprintf(fp, "%s", KV_DELIMITER); 97345916cd2Sjpk (void) fprintf(fp, "%s", tok); 97445916cd2Sjpk count++; 97545916cd2Sjpk } 97645916cd2Sjpk } else { 97745916cd2Sjpk (void) fprintf(fp, "%s", devinfo->devopts); 97845916cd2Sjpk } 97945916cd2Sjpk 98045916cd2Sjpk return (0); 98145916cd2Sjpk } 98245916cd2Sjpk 98345916cd2Sjpk /* 98445916cd2Sjpk * _write_new_entry - 98545916cd2Sjpk * writes the new devalloc_t to device_allocate or the new devmap_t to 98645916cd2Sjpk * device_maps. 98745916cd2Sjpk * returns 0 on success, -1 on error. 98845916cd2Sjpk */ 98945916cd2Sjpk static int 99045916cd2Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag) 99145916cd2Sjpk { 99245916cd2Sjpk int count; 99345916cd2Sjpk char *tok = NULL, *tokp = NULL; 99445916cd2Sjpk char *lasts; 99545916cd2Sjpk devinfo_t *devinfo = dargs->devinfo; 99645916cd2Sjpk 99745916cd2Sjpk if (flag & DA_MAPS_ONLY) 99845916cd2Sjpk goto dmap_only; 99945916cd2Sjpk 100045916cd2Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 100145916cd2Sjpk return (-1); 100245916cd2Sjpk 100345916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", 100445916cd2Sjpk (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER); 100545916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", 100645916cd2Sjpk (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER); 100745916cd2Sjpk if (devinfo->devopts == NULL) { 100845916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, 100945916cd2Sjpk KV_DELIMITER); 101045916cd2Sjpk } else { 1011*7e3e5701SJan Parcel if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1)) 1012*7e3e5701SJan Parcel != NULL) { 101345916cd2Sjpk (void) strcpy(tokp, devinfo->devopts); 101445916cd2Sjpk if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) != 101545916cd2Sjpk NULL) { 101645916cd2Sjpk (void) fprintf(fp, "%s", tok); 101745916cd2Sjpk count = 1; 101845916cd2Sjpk } 101945916cd2Sjpk while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, 102045916cd2Sjpk &lasts)) != NULL) { 102145916cd2Sjpk if (count) 102245916cd2Sjpk (void) fprintf(fp, "%s", 102345916cd2Sjpk KV_TOKEN_DELIMIT "\\\n\t"); 102445916cd2Sjpk (void) fprintf(fp, "%s", tok); 102545916cd2Sjpk count++; 102645916cd2Sjpk } 102745916cd2Sjpk if (count) 102845916cd2Sjpk (void) fprintf(fp, "%s", 102945916cd2Sjpk KV_DELIMITER "\\\n\t"); 103045916cd2Sjpk } else { 103145916cd2Sjpk (void) fprintf(fp, "%s%s", devinfo->devopts, 103245916cd2Sjpk KV_DELIMITER "\\\n\t"); 103345916cd2Sjpk } 103445916cd2Sjpk } 103545916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER); 103645916cd2Sjpk (void) fprintf(fp, "%s%s\\\n\t", 103745916cd2Sjpk (devinfo->devauths ? devinfo->devauths : DA_ANYUSER), 103845916cd2Sjpk KV_DELIMITER); 103945916cd2Sjpk (void) fprintf(fp, "%s\n", 104045916cd2Sjpk (devinfo->devexec ? devinfo->devexec : KV_DELIMITER)); 104145916cd2Sjpk 104245916cd2Sjpk dmap_only: 104345916cd2Sjpk if (flag & DA_ALLOC_ONLY) 104445916cd2Sjpk return (0); 104545916cd2Sjpk 104645916cd2Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 104745916cd2Sjpk return (-1); 104845916cd2Sjpk 104945916cd2Sjpk (void) fprintf(fp, "%s%s\\\n", 105045916cd2Sjpk (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT); 105145916cd2Sjpk (void) fprintf(fp, "\t%s%s\\\n", 105245916cd2Sjpk (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT); 105345916cd2Sjpk (void) fprintf(fp, "\t%s\n", 105445916cd2Sjpk (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT)); 105545916cd2Sjpk 105645916cd2Sjpk return (0); 105745916cd2Sjpk } 105845916cd2Sjpk 105945916cd2Sjpk /* 106045916cd2Sjpk * _da_lock_devdb - 106145916cd2Sjpk * locks the database files; lock can be either broken explicitly by 106245916cd2Sjpk * closing the fd of the lock file, or it expires automatically at process 106345916cd2Sjpk * termination. 106445916cd2Sjpk * returns fd of the lock file or -1 on error. 106545916cd2Sjpk */ 106645916cd2Sjpk int 106745916cd2Sjpk _da_lock_devdb(char *rootdir) 106845916cd2Sjpk { 106945916cd2Sjpk int lockfd = -1; 107010ddde3aSaj int ret; 107110ddde3aSaj int count = 0; 107210ddde3aSaj int retry = 10; 107310ddde3aSaj int retry_sleep; 107410ddde3aSaj uint_t seed; 107545916cd2Sjpk char *lockfile; 107645916cd2Sjpk char path[MAXPATHLEN]; 107745916cd2Sjpk int size = sizeof (path); 107845916cd2Sjpk 107945916cd2Sjpk if (rootdir == NULL) { 108045916cd2Sjpk lockfile = DA_DB_LOCK; 108145916cd2Sjpk } else { 108245916cd2Sjpk path[0] = '\0'; 108345916cd2Sjpk if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size) 108445916cd2Sjpk return (-1); 108545916cd2Sjpk lockfile = path; 108645916cd2Sjpk } 108745916cd2Sjpk 108845916cd2Sjpk if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) 108945916cd2Sjpk /* cannot open lock file */ 109045916cd2Sjpk return (-1); 109145916cd2Sjpk 109245916cd2Sjpk (void) fchown(lockfd, DA_UID, DA_GID); 109345916cd2Sjpk 109445916cd2Sjpk if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) { 109545916cd2Sjpk /* cannot position lock file */ 109645916cd2Sjpk (void) close(lockfd); 109745916cd2Sjpk return (-1); 109845916cd2Sjpk } 109910ddde3aSaj errno = 0; 110010ddde3aSaj while (retry > 0) { 110110ddde3aSaj count++; 110210ddde3aSaj seed = (uint_t)gethrtime(); 110310ddde3aSaj ret = lockf(lockfd, F_TLOCK, 0); 110410ddde3aSaj if (ret == 0) { 110510ddde3aSaj (void) utime(lockfile, NULL); 110610ddde3aSaj return (lockfd); 110710ddde3aSaj } 110810ddde3aSaj if ((errno != EACCES) && (errno != EAGAIN)) { 110945916cd2Sjpk /* cannot set lock */ 111045916cd2Sjpk (void) close(lockfd); 111145916cd2Sjpk return (-1); 111245916cd2Sjpk } 111310ddde3aSaj retry--; 111410ddde3aSaj retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count; 111510ddde3aSaj (void) sleep(retry_sleep); 111610ddde3aSaj errno = 0; 111710ddde3aSaj } 111845916cd2Sjpk 111910ddde3aSaj return (-1); 112045916cd2Sjpk } 112145916cd2Sjpk 112245916cd2Sjpk /* 112345916cd2Sjpk * da_open_devdb - 112445916cd2Sjpk * opens one or both database files - device_allocate, device_maps - in 112545916cd2Sjpk * the specified mode. 112645916cd2Sjpk * locks the database files; lock is either broken explicitly by the 112745916cd2Sjpk * caller by closing the lock file fd, or it expires automatically at 112845916cd2Sjpk * process termination. 112945916cd2Sjpk * writes the file pointer of opened file in the input args - dafp, dmfp. 113045916cd2Sjpk * returns fd of the lock file on success, -2 if database file does not 113145916cd2Sjpk * exist, -1 on other errors. 113245916cd2Sjpk */ 113345916cd2Sjpk int 113445916cd2Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag) 113545916cd2Sjpk { 113645916cd2Sjpk int oflag = 0; 113745916cd2Sjpk int fda = -1; 113845916cd2Sjpk int fdm = -1; 113945916cd2Sjpk int lockfd = -1; 114045916cd2Sjpk char *fname; 114145916cd2Sjpk char *fmode; 114245916cd2Sjpk char path[MAXPATHLEN]; 114345916cd2Sjpk FILE *devfile; 114445916cd2Sjpk 114545916cd2Sjpk if ((dafp == NULL) && (dmfp == NULL)) 114645916cd2Sjpk return (-1); 114745916cd2Sjpk 114845916cd2Sjpk if (flag & DA_RDWR) { 114945916cd2Sjpk oflag = DA_RDWR; 1150004388ebScasper fmode = "r+F"; 115145916cd2Sjpk } else if (flag & DA_RDONLY) { 115245916cd2Sjpk oflag = DA_RDONLY; 1153004388ebScasper fmode = "rF"; 115445916cd2Sjpk } 115545916cd2Sjpk 115645916cd2Sjpk if ((lockfd = _da_lock_devdb(rootdir)) == -1) 115745916cd2Sjpk return (-1); 115845916cd2Sjpk 115945916cd2Sjpk if ((dafp == NULL) || (flag & DA_MAPS_ONLY)) 116045916cd2Sjpk goto dmap_only; 116145916cd2Sjpk 116245916cd2Sjpk path[0] = '\0'; 116345916cd2Sjpk 116445916cd2Sjpk /* 116545916cd2Sjpk * open the device allocation file 116645916cd2Sjpk */ 116745916cd2Sjpk if (rootdir == NULL) { 116845916cd2Sjpk fname = DEVALLOC; 116945916cd2Sjpk } else { 117045916cd2Sjpk if (snprintf(path, sizeof (path), "%s%s", rootdir, 117145916cd2Sjpk DEVALLOC) >= sizeof (path)) { 117245916cd2Sjpk if (lockfd != -1) 117345916cd2Sjpk (void) close(lockfd); 117445916cd2Sjpk return (-1); 117545916cd2Sjpk } 117645916cd2Sjpk fname = path; 117745916cd2Sjpk } 117845916cd2Sjpk if ((fda = open(fname, oflag, DA_DBMODE)) == -1) { 117945916cd2Sjpk if (lockfd != -1) 118045916cd2Sjpk (void) close(lockfd); 118145916cd2Sjpk return ((errno == ENOENT) ? -2 : -1); 118245916cd2Sjpk } 118345916cd2Sjpk if ((devfile = fdopen(fda, fmode)) == NULL) { 118445916cd2Sjpk (void) close(fda); 118545916cd2Sjpk if (lockfd != -1) 118645916cd2Sjpk (void) close(lockfd); 118745916cd2Sjpk return (-1); 118845916cd2Sjpk } 118945916cd2Sjpk *dafp = devfile; 119045916cd2Sjpk (void) fchmod(fda, DA_DBMODE); 119145916cd2Sjpk 119245916cd2Sjpk if ((flag & DA_ALLOC_ONLY)) 119345916cd2Sjpk goto out; 119445916cd2Sjpk 119545916cd2Sjpk dmap_only: 119645916cd2Sjpk path[0] = '\0'; 119745916cd2Sjpk /* 119845916cd2Sjpk * open the device map file 119945916cd2Sjpk */ 120045916cd2Sjpk if (rootdir == NULL) { 120145916cd2Sjpk fname = DEVMAP; 120245916cd2Sjpk } else { 120345916cd2Sjpk if (snprintf(path, sizeof (path), "%s%s", rootdir, 120445916cd2Sjpk DEVMAP) >= sizeof (path)) { 120545916cd2Sjpk (void) close(fda); 120645916cd2Sjpk if (lockfd != -1) 120745916cd2Sjpk (void) close(lockfd); 120845916cd2Sjpk return (-1); 120945916cd2Sjpk } 121045916cd2Sjpk fname = path; 121145916cd2Sjpk } 121245916cd2Sjpk 121345916cd2Sjpk if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) { 121445916cd2Sjpk if (lockfd != -1) 121545916cd2Sjpk (void) close(lockfd); 121645916cd2Sjpk return ((errno == ENOENT) ? -2 : -1); 121745916cd2Sjpk } 121845916cd2Sjpk 121945916cd2Sjpk if ((devfile = fdopen(fdm, fmode)) == NULL) { 122045916cd2Sjpk (void) close(fdm); 122145916cd2Sjpk (void) close(fda); 122245916cd2Sjpk if (lockfd != -1) 122345916cd2Sjpk (void) close(lockfd); 122445916cd2Sjpk return (-1); 122545916cd2Sjpk } 122645916cd2Sjpk *dmfp = devfile; 122745916cd2Sjpk (void) fchmod(fdm, DA_DBMODE); 122845916cd2Sjpk 122945916cd2Sjpk out: 123045916cd2Sjpk return (lockfd); 123145916cd2Sjpk } 123245916cd2Sjpk 123345916cd2Sjpk /* 123445916cd2Sjpk * _record_on_off - 123545916cd2Sjpk * adds either DA_ON_STR or DA_OFF_STR to device_allocate 123645916cd2Sjpk * returns 0 on success, -1 on error. 123745916cd2Sjpk */ 123845916cd2Sjpk static int 123945916cd2Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp) 124045916cd2Sjpk { 124145916cd2Sjpk int dafd; 124245916cd2Sjpk int nsize; 124345916cd2Sjpk int nitems = 1; 124445916cd2Sjpk int actionlen; 124545916cd2Sjpk int str_found = 0; 124645916cd2Sjpk int len = 0, nlen = 0, plen = 0; 124745916cd2Sjpk char *ptr = NULL; 124845916cd2Sjpk char *actionstr; 124945916cd2Sjpk char *nbuf = NULL; 125045916cd2Sjpk char line[MAX_CANON]; 125145916cd2Sjpk struct stat dastat; 125245916cd2Sjpk 125345916cd2Sjpk if (dargs->optflag & DA_ON) 125445916cd2Sjpk actionstr = DA_ON_STR; 125545916cd2Sjpk else 125645916cd2Sjpk actionstr = DA_OFF_STR; 125745916cd2Sjpk actionlen = strlen(actionstr); 125845916cd2Sjpk dafd = fileno(dafp); 125945916cd2Sjpk if (fstat(dafd, &dastat) == -1) 126045916cd2Sjpk return (-1); 126145916cd2Sjpk 126245916cd2Sjpk /* check the old device_allocate for on/off string */ 126345916cd2Sjpk ptr = fgets(line, MAX_CANON, dafp); 126445916cd2Sjpk if (ptr != NULL) { 126545916cd2Sjpk if ((strcmp(line, DA_ON_STR) == 0) || 126645916cd2Sjpk (strcmp(line, DA_OFF_STR) == 0)) { 126745916cd2Sjpk str_found = 1; 126845916cd2Sjpk nsize = dastat.st_size; 126945916cd2Sjpk } 127045916cd2Sjpk } 127145916cd2Sjpk if (!ptr || !str_found) { 127245916cd2Sjpk /* 127345916cd2Sjpk * the file never had either the on or the off string; 127445916cd2Sjpk * make room for it. 127545916cd2Sjpk */ 127645916cd2Sjpk str_found = 0; 127745916cd2Sjpk nsize = dastat.st_size + actionlen + 1; 127845916cd2Sjpk } 1279*7e3e5701SJan Parcel if ((nbuf = (char *)malloc(nsize + 1)) == NULL) 128045916cd2Sjpk return (-1); 128145916cd2Sjpk nbuf[0] = '\0'; 128245916cd2Sjpk /* put the on/off string */ 128345916cd2Sjpk (void) strcpy(nbuf, actionstr); 128445916cd2Sjpk nlen = strlen(nbuf); 128545916cd2Sjpk plen = nlen; 128645916cd2Sjpk if (ptr && !str_found) { 128745916cd2Sjpk /* now put the first line that we read in fgets */ 128845916cd2Sjpk nlen = plen + strlen(line) + 1; 128945916cd2Sjpk len = snprintf(nbuf + plen, nlen - plen, "%s", line); 129045916cd2Sjpk if (len >= nsize) { 129145916cd2Sjpk free(nbuf); 129245916cd2Sjpk return (-1); 129345916cd2Sjpk } 129445916cd2Sjpk plen += len; 129545916cd2Sjpk } 129645916cd2Sjpk 129745916cd2Sjpk /* now get the rest of the old file */ 129845916cd2Sjpk while (fgets(line, MAX_CANON, dafp) != NULL) { 129945916cd2Sjpk nlen = plen + strlen(line) + 1; 130045916cd2Sjpk len = snprintf(nbuf + plen, nlen - plen, "%s", line); 130145916cd2Sjpk if (len >= nsize) { 130245916cd2Sjpk free(nbuf); 130345916cd2Sjpk return (-1); 130445916cd2Sjpk } 130545916cd2Sjpk plen += len; 130645916cd2Sjpk } 130745916cd2Sjpk len = strlen(nbuf) + 1; 130845916cd2Sjpk if (len < nsize) 130945916cd2Sjpk nbuf[len] = '\n'; 131045916cd2Sjpk 131145916cd2Sjpk /* write the on/off str + the old device_allocate to the temp file */ 131245916cd2Sjpk if (fwrite(nbuf, nsize, nitems, tafp) < nitems) { 131345916cd2Sjpk free(nbuf); 131445916cd2Sjpk return (-1); 131545916cd2Sjpk } 131645916cd2Sjpk 131745916cd2Sjpk free(nbuf); 131845916cd2Sjpk 131945916cd2Sjpk return (0); 132045916cd2Sjpk } 132145916cd2Sjpk 132245916cd2Sjpk /* 132345916cd2Sjpk * da_update_defattrs - 132445916cd2Sjpk * writes default attributes to devalloc_defaults 132545916cd2Sjpk * returns 0 on success, -1 on error. 132645916cd2Sjpk */ 132745916cd2Sjpk int 132845916cd2Sjpk da_update_defattrs(da_args *dargs) 132945916cd2Sjpk { 133045916cd2Sjpk int rc = 0, lockfd = 0, tmpfd = 0; 133145916cd2Sjpk char *defpath = DEFATTRS; 133245916cd2Sjpk char *tmpdefpath = TMPATTRS; 133345916cd2Sjpk FILE *tmpfp = NULL; 133445916cd2Sjpk struct stat dstat; 133545916cd2Sjpk strentry_t *head_defent = NULL; 133645916cd2Sjpk 133745916cd2Sjpk if (dargs == NULL) 133845916cd2Sjpk return (0); 133945916cd2Sjpk if ((lockfd = _da_lock_devdb(NULL)) == -1) 134045916cd2Sjpk return (-1); 134145916cd2Sjpk if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 134245916cd2Sjpk (void) close(lockfd); 134345916cd2Sjpk return (-1); 134445916cd2Sjpk } 134545916cd2Sjpk (void) fchown(tmpfd, DA_UID, DA_GID); 134645916cd2Sjpk if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) { 134745916cd2Sjpk (void) close(tmpfd); 134845916cd2Sjpk (void) unlink(tmpdefpath); 134945916cd2Sjpk (void) close(lockfd); 135045916cd2Sjpk return (-1); 135145916cd2Sjpk } 135245916cd2Sjpk /* 135345916cd2Sjpk * examine all entries, remove an old one if required, check 135445916cd2Sjpk * if a new one needs to be added. 135545916cd2Sjpk */ 135645916cd2Sjpk if (stat(defpath, &dstat) == 0) { 135745916cd2Sjpk if ((rc = _build_defattrs(dargs, &head_defent)) != 0) { 135845916cd2Sjpk if (rc == 1) { 135945916cd2Sjpk (void) close(tmpfd); 136045916cd2Sjpk (void) unlink(tmpdefpath); 136145916cd2Sjpk (void) close(lockfd); 136245916cd2Sjpk return (rc); 136345916cd2Sjpk } 136445916cd2Sjpk } 136545916cd2Sjpk } 136645916cd2Sjpk /* 136745916cd2Sjpk * write back any existing entries. 136845916cd2Sjpk */ 136945916cd2Sjpk _write_defattrs(tmpfp, head_defent); 137045916cd2Sjpk 137145916cd2Sjpk if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 137245916cd2Sjpk /* add new entries */ 137345916cd2Sjpk rc = _write_new_defattrs(tmpfp, dargs); 137445916cd2Sjpk (void) fclose(tmpfp); 137545916cd2Sjpk } else { 137645916cd2Sjpk (void) fclose(tmpfp); 137745916cd2Sjpk } 137845916cd2Sjpk if (rename(tmpdefpath, defpath) != 0) { 137945916cd2Sjpk rc = -1; 138045916cd2Sjpk (void) unlink(tmpdefpath); 138145916cd2Sjpk } 138245916cd2Sjpk (void) close(lockfd); 138345916cd2Sjpk 138445916cd2Sjpk return (rc); 138545916cd2Sjpk } 138645916cd2Sjpk 138745916cd2Sjpk /* 138845916cd2Sjpk * da_update_device - 1389*7e3e5701SJan Parcel * Writes existing entries and the SINGLE change requested by da_args, 1390*7e3e5701SJan Parcel * to device_allocate and device_maps. 1391*7e3e5701SJan Parcel * Returns 0 on success, -1 on error. 139245916cd2Sjpk */ 139345916cd2Sjpk int 139445916cd2Sjpk da_update_device(da_args *dargs) 139545916cd2Sjpk { 139645916cd2Sjpk int rc; 139745916cd2Sjpk int tafd = -1, tmfd = -1; 139845916cd2Sjpk int lockfd = -1; 139945916cd2Sjpk char *rootdir = NULL; 140010ddde3aSaj char *apathp = NULL, *mpathp = NULL; 140110ddde3aSaj char *dapathp = NULL, *dmpathp = NULL; 140210ddde3aSaj char apath[MAXPATHLEN], mpath[MAXPATHLEN]; 140310ddde3aSaj char dapath[MAXPATHLEN], dmpath[MAXPATHLEN]; 140445916cd2Sjpk FILE *tafp = NULL, *tmfp = NULL, *dafp = NULL; 140545916cd2Sjpk struct stat dastat; 140645916cd2Sjpk devinfo_t *devinfo; 140745916cd2Sjpk strentry_t *head_devmapp = NULL; 140845916cd2Sjpk strentry_t *head_devallocp = NULL; 140945916cd2Sjpk 141045916cd2Sjpk if (dargs == NULL) 141145916cd2Sjpk return (0); 141245916cd2Sjpk 141345916cd2Sjpk rootdir = dargs->rootdir; 141445916cd2Sjpk devinfo = dargs->devinfo; 141545916cd2Sjpk 141645916cd2Sjpk /* 141745916cd2Sjpk * adding/removing entries should be done in both 141845916cd2Sjpk * device_allocate and device_maps. updates can be 141945916cd2Sjpk * done in both or either of the files. 142045916cd2Sjpk */ 142145916cd2Sjpk if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) { 142245916cd2Sjpk if (dargs->optflag & DA_ALLOC_ONLY || 142345916cd2Sjpk dargs->optflag & DA_MAPS_ONLY) 142445916cd2Sjpk return (0); 142545916cd2Sjpk } 142645916cd2Sjpk 142745916cd2Sjpk /* 142845916cd2Sjpk * name, type and list are required fields for adding a new 142945916cd2Sjpk * device. 143045916cd2Sjpk */ 143145916cd2Sjpk if ((dargs->optflag & DA_ADD) && 143245916cd2Sjpk ((devinfo->devname == NULL) || 143345916cd2Sjpk (devinfo->devtype == NULL) || 143445916cd2Sjpk (devinfo->devlist == NULL))) { 143545916cd2Sjpk return (-1); 143645916cd2Sjpk } 143745916cd2Sjpk 143845916cd2Sjpk if (rootdir != NULL) { 143945916cd2Sjpk if (snprintf(apath, sizeof (apath), "%s%s", rootdir, 144045916cd2Sjpk TMPALLOC) >= sizeof (apath)) 144145916cd2Sjpk return (-1); 144245916cd2Sjpk apathp = apath; 144345916cd2Sjpk if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir, 144445916cd2Sjpk DEVALLOC) >= sizeof (dapath)) 144545916cd2Sjpk return (-1); 144645916cd2Sjpk dapathp = dapath; 144745916cd2Sjpk if (!(dargs->optflag & DA_ALLOC_ONLY)) { 144845916cd2Sjpk if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir, 144945916cd2Sjpk TMPMAP) >= sizeof (mpath)) 145045916cd2Sjpk return (-1); 145145916cd2Sjpk mpathp = mpath; 145245916cd2Sjpk if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir, 145345916cd2Sjpk DEVMAP) >= sizeof (dmpath)) 145445916cd2Sjpk return (-1); 145545916cd2Sjpk dmpathp = dmpath; 145645916cd2Sjpk } 145745916cd2Sjpk } else { 145845916cd2Sjpk apathp = TMPALLOC; 145945916cd2Sjpk dapathp = DEVALLOC; 146045916cd2Sjpk mpathp = TMPMAP; 146145916cd2Sjpk dmpathp = DEVMAP; 146245916cd2Sjpk } 146345916cd2Sjpk 146445916cd2Sjpk if (dargs->optflag & DA_MAPS_ONLY) 146545916cd2Sjpk goto dmap_only; 146645916cd2Sjpk 146745916cd2Sjpk /* 146845916cd2Sjpk * Check if we are here just to record on/off status of 146945916cd2Sjpk * device_allocation. 147045916cd2Sjpk */ 147145916cd2Sjpk if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) 147245916cd2Sjpk lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL, 147345916cd2Sjpk DA_RDONLY|DA_ALLOC_ONLY); 147445916cd2Sjpk else 147545916cd2Sjpk lockfd = _da_lock_devdb(rootdir); 147645916cd2Sjpk if (lockfd == -1) 147745916cd2Sjpk return (-1); 147845916cd2Sjpk 147945916cd2Sjpk if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 148045916cd2Sjpk (void) close(lockfd); 148145916cd2Sjpk (void) fclose(dafp); 148245916cd2Sjpk return (-1); 148345916cd2Sjpk } 148445916cd2Sjpk (void) fchown(tafd, DA_UID, DA_GID); 148545916cd2Sjpk if ((tafp = fdopen(tafd, "r+")) == NULL) { 148645916cd2Sjpk (void) close(tafd); 148745916cd2Sjpk (void) unlink(apathp); 148845916cd2Sjpk (void) fclose(dafp); 148945916cd2Sjpk (void) close(lockfd); 149045916cd2Sjpk return (-1); 149145916cd2Sjpk } 149245916cd2Sjpk 149345916cd2Sjpk /* 149445916cd2Sjpk * We don't need to parse the file if we are here just to record 149545916cd2Sjpk * on/off status of device_allocation. 149645916cd2Sjpk */ 149745916cd2Sjpk if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) { 149845916cd2Sjpk if (_record_on_off(dargs, tafp, dafp) == -1) { 149945916cd2Sjpk (void) close(tafd); 150045916cd2Sjpk (void) unlink(apathp); 150145916cd2Sjpk (void) fclose(dafp); 150245916cd2Sjpk (void) close(lockfd); 150345916cd2Sjpk return (-1); 150445916cd2Sjpk } 150545916cd2Sjpk (void) fclose(dafp); 150645916cd2Sjpk goto out; 150745916cd2Sjpk } 150845916cd2Sjpk 150945916cd2Sjpk /* 1510*7e3e5701SJan Parcel * If reacting to a hotplug, read the file entries, 1511*7e3e5701SJan Parcel * figure out what dname (tname + a new number) goes to the 1512*7e3e5701SJan Parcel * device being added/removed, and create a good head_devallocp and 1513*7e3e5701SJan Parcel * head_devmapp with everything good still in it (_rebuild_lists) 1514*7e3e5701SJan Parcel * 1515*7e3e5701SJan Parcel * Else examine all the entries, remove an old one if it is 1516*7e3e5701SJan Parcel * a duplicate with a device being added, returning the 1517*7e3e5701SJan Parcel * remaining list (_build_lists.) 1518*7e3e5701SJan Parcel * 1519*7e3e5701SJan Parcel * We need to do this only if the file exists already. 1520*7e3e5701SJan Parcel * 1521*7e3e5701SJan Parcel * Once we have built these lists, we need to free the strings 1522*7e3e5701SJan Parcel * in the head_* arrays before returning. 152345916cd2Sjpk */ 152445916cd2Sjpk if (stat(dapathp, &dastat) == 0) { 1525*7e3e5701SJan Parcel /* for device allocation, the /etc files are the "master" */ 1526*7e3e5701SJan Parcel if ((dargs->optflag & (DA_ADD| DA_EVENT)) && 1527*7e3e5701SJan Parcel (!(dargs->optflag & DA_FORCE))) 1528*7e3e5701SJan Parcel rc = _rebuild_lists(dargs, &head_devallocp, 1529*7e3e5701SJan Parcel &head_devmapp); 1530*7e3e5701SJan Parcel else 1531*7e3e5701SJan Parcel rc = _build_lists(dargs, &head_devallocp, 1532*7e3e5701SJan Parcel &head_devmapp); 1533*7e3e5701SJan Parcel 1534*7e3e5701SJan Parcel if (rc != 0 && rc != 1) { 153545916cd2Sjpk (void) close(tafd); 153645916cd2Sjpk (void) unlink(apathp); 153745916cd2Sjpk (void) close(lockfd); 1538*7e3e5701SJan Parcel return (-1); 153945916cd2Sjpk } 1540*7e3e5701SJan Parcel } else 1541*7e3e5701SJan Parcel rc = 0; 1542*7e3e5701SJan Parcel 1543*7e3e5701SJan Parcel if ((dargs->optflag & DA_REMOVE) && (rc == 0)) { 1544*7e3e5701SJan Parcel (void) close(tafd); 1545*7e3e5701SJan Parcel (void) unlink(apathp); 1546*7e3e5701SJan Parcel (void) close(lockfd); 1547*7e3e5701SJan Parcel return (0); 154845916cd2Sjpk } 1549*7e3e5701SJan Parcel /* 1550*7e3e5701SJan Parcel * TODO: clean up the workings of DA_UPDATE. 1551*7e3e5701SJan Parcel * Due to da_match looking at fields that are missing 1552*7e3e5701SJan Parcel * in dargs for DA_UPDATE, the da_match call returns no match, 1553*7e3e5701SJan Parcel * but due to the way _da2str combines the devalloc_t info with 1554*7e3e5701SJan Parcel * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work. 1555*7e3e5701SJan Parcel * 1556*7e3e5701SJan Parcel * This would not scale if any type of update was ever needed 1557*7e3e5701SJan Parcel * from the daemon. 1558*7e3e5701SJan Parcel */ 155945916cd2Sjpk 156045916cd2Sjpk /* 1561*7e3e5701SJan Parcel * Write out devallocp along with the devalloc on/off string. 156245916cd2Sjpk */ 156345916cd2Sjpk _write_device_allocate(dapathp, tafp, head_devallocp); 156445916cd2Sjpk 156545916cd2Sjpk if (dargs->optflag & DA_ALLOC_ONLY) 156645916cd2Sjpk goto out; 156745916cd2Sjpk 156845916cd2Sjpk dmap_only: 156945916cd2Sjpk if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 157045916cd2Sjpk (void) close(tafd); 157145916cd2Sjpk (void) unlink(apathp); 157245916cd2Sjpk (void) close(lockfd); 157345916cd2Sjpk return (-1); 157445916cd2Sjpk } 157545916cd2Sjpk (void) fchown(tmfd, DA_UID, DA_GID); 157645916cd2Sjpk if ((tmfp = fdopen(tmfd, "r+")) == NULL) { 157745916cd2Sjpk (void) close(tafd); 157845916cd2Sjpk (void) unlink(apathp); 157945916cd2Sjpk (void) close(tmfd); 158045916cd2Sjpk (void) unlink(mpathp); 158145916cd2Sjpk (void) close(lockfd); 158245916cd2Sjpk return (-1); 158345916cd2Sjpk } 158445916cd2Sjpk 1585*7e3e5701SJan Parcel /* 1586*7e3e5701SJan Parcel * Write back any non-removed pre-existing entries. 1587*7e3e5701SJan Parcel */ 158845916cd2Sjpk if (head_devmapp != NULL) 158945916cd2Sjpk _write_device_maps(tmfp, head_devmapp); 159045916cd2Sjpk 159145916cd2Sjpk out: 1592*7e3e5701SJan Parcel /* 1593*7e3e5701SJan Parcel * Add any new entries here. 1594*7e3e5701SJan Parcel */ 159545916cd2Sjpk if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 159645916cd2Sjpk /* add any new entries */ 159745916cd2Sjpk rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY); 159845916cd2Sjpk (void) fclose(tafp); 159945916cd2Sjpk 160045916cd2Sjpk if (rc == 0) 160145916cd2Sjpk rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY); 160245916cd2Sjpk (void) fclose(tmfp); 160345916cd2Sjpk } else { 160445916cd2Sjpk if (tafp) 160545916cd2Sjpk (void) fclose(tafp); 160645916cd2Sjpk if (tmfp) 160745916cd2Sjpk (void) fclose(tmfp); 160845916cd2Sjpk } 160945916cd2Sjpk 161045916cd2Sjpk rc = 0; 161145916cd2Sjpk if (!(dargs->optflag & DA_MAPS_ONLY)) { 161245916cd2Sjpk if (rename(apathp, dapathp) != 0) { 161345916cd2Sjpk rc = -1; 161445916cd2Sjpk (void) unlink(apathp); 161545916cd2Sjpk } 161645916cd2Sjpk } 161745916cd2Sjpk if (!(dargs->optflag & DA_ALLOC_ONLY)) { 161845916cd2Sjpk if (rename(mpathp, dmpathp) != 0) { 161945916cd2Sjpk rc = -1; 162045916cd2Sjpk (void) unlink(mpathp); 162145916cd2Sjpk } 162245916cd2Sjpk } 162345916cd2Sjpk 162445916cd2Sjpk (void) close(lockfd); 162545916cd2Sjpk 162645916cd2Sjpk return (rc); 162745916cd2Sjpk } 162845916cd2Sjpk 162945916cd2Sjpk /* 163045916cd2Sjpk * da_add_list - 163145916cd2Sjpk * adds new /dev link name to the linked list of devices. 163245916cd2Sjpk * returns 0 if link added successfully, -1 on error. 163345916cd2Sjpk */ 163445916cd2Sjpk int 163545916cd2Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) 163645916cd2Sjpk { 163745916cd2Sjpk int instance; 163845916cd2Sjpk int nlen, plen; 163945916cd2Sjpk int new_entry = 0; 164045916cd2Sjpk char *dtype, *dexec, *tname, *kval; 164145916cd2Sjpk char *minstr = NULL, *maxstr = NULL; 1642*7e3e5701SJan Parcel char dname[DA_MAXNAME + 1]; 164345916cd2Sjpk kva_t *kva; 164445916cd2Sjpk deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL; 164545916cd2Sjpk da_defs_t *da_defs; 164645916cd2Sjpk 164745916cd2Sjpk if (dlist == NULL || link == NULL) 164845916cd2Sjpk return (-1); 164945916cd2Sjpk 165045916cd2Sjpk dname[0] = '\0'; 165145916cd2Sjpk if (flag & DA_AUDIO) { 165245916cd2Sjpk dentry = dlist->audio; 165345916cd2Sjpk tname = DA_AUDIO_NAME; 165445916cd2Sjpk dtype = DA_AUDIO_TYPE; 165545916cd2Sjpk dexec = DA_DEFAULT_AUDIO_CLEAN; 165645916cd2Sjpk } else if (flag & DA_CD) { 165745916cd2Sjpk dentry = dlist->cd; 165845916cd2Sjpk tname = DA_CD_NAME; 165945916cd2Sjpk dtype = DA_CD_TYPE; 166045916cd2Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 166145916cd2Sjpk } else if (flag & DA_FLOPPY) { 166245916cd2Sjpk dentry = dlist->floppy; 166345916cd2Sjpk tname = DA_FLOPPY_NAME; 166445916cd2Sjpk dtype = DA_FLOPPY_TYPE; 166545916cd2Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 166645916cd2Sjpk } else if (flag & DA_TAPE) { 166745916cd2Sjpk dentry = dlist->tape; 166845916cd2Sjpk tname = DA_TAPE_NAME; 166945916cd2Sjpk dtype = DA_TAPE_TYPE; 167045916cd2Sjpk dexec = DA_DEFAULT_TAPE_CLEAN; 167145916cd2Sjpk } else if (flag & DA_RMDISK) { 167245916cd2Sjpk dentry = dlist->rmdisk; 167345916cd2Sjpk tname = DA_RMDISK_NAME; 167445916cd2Sjpk dtype = DA_RMDISK_TYPE; 167545916cd2Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 167645916cd2Sjpk } else { 167745916cd2Sjpk return (-1); 167845916cd2Sjpk } 167945916cd2Sjpk 168045916cd2Sjpk for (nentry = dentry; nentry != NULL; nentry = nentry->next) { 168145916cd2Sjpk pentry = nentry; 168245916cd2Sjpk (void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance); 168345916cd2Sjpk if (nentry->devinfo.instance == new_instance) 168445916cd2Sjpk /* 168545916cd2Sjpk * Add the new link name to the list of links 168645916cd2Sjpk * that the device 'dname' has. 168745916cd2Sjpk */ 168845916cd2Sjpk break; 168945916cd2Sjpk } 169045916cd2Sjpk 169145916cd2Sjpk if (nentry == NULL) { 169245916cd2Sjpk /* 169345916cd2Sjpk * Either this is the first entry ever, or no matching entry 169445916cd2Sjpk * was found. Create a new one and add to the list. 169545916cd2Sjpk */ 169645916cd2Sjpk if (dentry == NULL) /* first entry ever */ 169745916cd2Sjpk instance = 0; 169845916cd2Sjpk else /* no matching entry */ 169945916cd2Sjpk instance++; 170045916cd2Sjpk (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance); 170145916cd2Sjpk if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) == 170245916cd2Sjpk NULL) 170345916cd2Sjpk return (-1); 170445916cd2Sjpk if (pentry != NULL) 170545916cd2Sjpk pentry->next = nentry; 170645916cd2Sjpk new_entry = 1; 170745916cd2Sjpk nentry->devinfo.devname = strdup(dname); 170845916cd2Sjpk nentry->devinfo.devtype = dtype; 170945916cd2Sjpk nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH; 171045916cd2Sjpk nentry->devinfo.devexec = dexec; 171145916cd2Sjpk nentry->devinfo.instance = new_instance; 171245916cd2Sjpk /* 171345916cd2Sjpk * Look for default label range, authorizations and cleaning 171445916cd2Sjpk * program in devalloc_defaults. If label range is not 171545916cd2Sjpk * specified in devalloc_defaults, assume it to be admin_low 171645916cd2Sjpk * to admin_high. 171745916cd2Sjpk */ 171845916cd2Sjpk minstr = DA_DEFAULT_MIN; 171945916cd2Sjpk maxstr = DA_DEFAULT_MAX; 172045916cd2Sjpk setdadefent(); 172145916cd2Sjpk if (da_defs = getdadeftype(nentry->devinfo.devtype)) { 172245916cd2Sjpk kva = da_defs->devopts; 172345916cd2Sjpk if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL) 172445916cd2Sjpk minstr = strdup(kval); 172545916cd2Sjpk if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL) 172645916cd2Sjpk maxstr = strdup(kval); 172745916cd2Sjpk if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL) 172845916cd2Sjpk nentry->devinfo.devauths = strdup(kval); 172945916cd2Sjpk if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL) 173045916cd2Sjpk nentry->devinfo.devexec = strdup(kval); 173145916cd2Sjpk freedadefent(da_defs); 173245916cd2Sjpk } 173345916cd2Sjpk enddadefent(); 173445916cd2Sjpk kval = NULL; 173545916cd2Sjpk nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) + 173645916cd2Sjpk strlen(minstr) + strlen(KV_TOKEN_DELIMIT) + 173745916cd2Sjpk strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr) 173845916cd2Sjpk + 1; /* +1 for terminator */ 173945916cd2Sjpk if (kval = (char *)malloc(nlen)) 174045916cd2Sjpk (void) snprintf(kval, nlen, "%s%s%s%s%s%s%s", 174145916cd2Sjpk DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT, 174245916cd2Sjpk DAOPT_MAXLABEL, KV_ASSIGN, maxstr); 174345916cd2Sjpk nentry->devinfo.devopts = kval; 174445916cd2Sjpk 174545916cd2Sjpk nentry->devinfo.devlist = NULL; 174645916cd2Sjpk nentry->next = NULL; 174745916cd2Sjpk } 174845916cd2Sjpk 174945916cd2Sjpk nlen = strlen(link) + 1; /* +1 terminator */ 175045916cd2Sjpk if (nentry->devinfo.devlist) { 175145916cd2Sjpk plen = strlen(nentry->devinfo.devlist); 175245916cd2Sjpk nlen = nlen + plen + 1; /* +1 for blank to separate entries */ 175345916cd2Sjpk } else { 175445916cd2Sjpk plen = 0; 175545916cd2Sjpk } 175645916cd2Sjpk 175745916cd2Sjpk if ((nentry->devinfo.devlist = 175845916cd2Sjpk (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) { 175945916cd2Sjpk if (new_entry) { 176045916cd2Sjpk free(nentry->devinfo.devname); 176145916cd2Sjpk free(nentry); 176245916cd2Sjpk if (pentry != NULL) 176345916cd2Sjpk pentry->next = NULL; 176445916cd2Sjpk } 176545916cd2Sjpk return (-1); 176645916cd2Sjpk } 176745916cd2Sjpk 176845916cd2Sjpk if (plen == 0) 176945916cd2Sjpk (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link); 177045916cd2Sjpk else 177145916cd2Sjpk (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen, 177245916cd2Sjpk " %s", link); 177345916cd2Sjpk 177445916cd2Sjpk if (pentry == NULL) { 177545916cd2Sjpk /* 177645916cd2Sjpk * This is the first entry of this device type. 177745916cd2Sjpk */ 177845916cd2Sjpk if (flag & DA_AUDIO) 177945916cd2Sjpk dlist->audio = nentry; 178045916cd2Sjpk else if (flag & DA_CD) 178145916cd2Sjpk dlist->cd = nentry; 178245916cd2Sjpk else if (flag & DA_FLOPPY) 178345916cd2Sjpk dlist->floppy = nentry; 178445916cd2Sjpk else if (flag & DA_TAPE) 178545916cd2Sjpk dlist->tape = nentry; 178645916cd2Sjpk else if (flag & DA_RMDISK) 178745916cd2Sjpk dlist->rmdisk = nentry; 178845916cd2Sjpk } 178945916cd2Sjpk 179045916cd2Sjpk return (0); 179145916cd2Sjpk } 179245916cd2Sjpk 179345916cd2Sjpk /* 179445916cd2Sjpk * da_remove_list - 179545916cd2Sjpk * removes a /dev link name from the linked list of devices. 179645916cd2Sjpk * returns type of device if link for that device removed 179745916cd2Sjpk * successfully, else returns -1 on error. 179845916cd2Sjpk * if all links for a device are removed, stores that device 179945916cd2Sjpk * name in devname. 180045916cd2Sjpk */ 180145916cd2Sjpk int 180245916cd2Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size) 180345916cd2Sjpk { 180445916cd2Sjpk int flag; 180545916cd2Sjpk int remove_dev = 0; 180645916cd2Sjpk int nlen, plen, slen; 180745916cd2Sjpk char *lasts, *lname, *oldlist; 180845916cd2Sjpk struct stat rmstat; 180945916cd2Sjpk deventry_t *dentry, *current, *prev; 181045916cd2Sjpk 181145916cd2Sjpk if (type != NULL) 181245916cd2Sjpk flag = type; 181345916cd2Sjpk else if (link == NULL) 181445916cd2Sjpk return (-1); 181545916cd2Sjpk else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME)) 181645916cd2Sjpk flag = DA_AUDIO; 181745916cd2Sjpk else if (strstr(link, "dsk") || strstr(link, "rdsk") || 181845916cd2Sjpk strstr(link, "sr") || strstr(link, "rsr")) 181945916cd2Sjpk flag = DA_CD; 182045916cd2Sjpk else if (strstr(link, "fd") || strstr(link, "rfd") || 182145916cd2Sjpk strstr(link, "diskette") || strstr(link, "rdiskette")) 182245916cd2Sjpk flag = DA_FLOPPY; 182345916cd2Sjpk else if (strstr(link, DA_TAPE_NAME)) 182445916cd2Sjpk flag = DA_TAPE; 182545916cd2Sjpk else 182645916cd2Sjpk flag = DA_RMDISK; 182745916cd2Sjpk 182845916cd2Sjpk switch (type) { 182945916cd2Sjpk case DA_AUDIO: 183045916cd2Sjpk dentry = dlist->audio; 183145916cd2Sjpk break; 183245916cd2Sjpk case DA_CD: 183345916cd2Sjpk dentry = dlist->cd; 183445916cd2Sjpk break; 183545916cd2Sjpk case DA_FLOPPY: 183645916cd2Sjpk dentry = dlist->floppy; 183745916cd2Sjpk break; 183845916cd2Sjpk case DA_TAPE: 183945916cd2Sjpk dentry = dlist->tape; 184045916cd2Sjpk break; 184145916cd2Sjpk case DA_RMDISK: 184245916cd2Sjpk dentry = dlist->rmdisk; 184345916cd2Sjpk break; 184445916cd2Sjpk default: 184545916cd2Sjpk return (-1); 184645916cd2Sjpk } 184745916cd2Sjpk 184845916cd2Sjpk if ((type != NULL) && (link == NULL)) { 184945916cd2Sjpk for (current = dentry, prev = dentry; current != NULL; 185045916cd2Sjpk current = current->next) { 185145916cd2Sjpk oldlist = strdup(current->devinfo.devlist); 185245916cd2Sjpk for (lname = strtok_r(oldlist, " ", &lasts); 185345916cd2Sjpk lname != NULL; 185445916cd2Sjpk lname = strtok_r(NULL, " ", &lasts)) { 185545916cd2Sjpk if (stat(lname, &rmstat) != 0) { 185645916cd2Sjpk remove_dev = 1; 185745916cd2Sjpk goto remove_dev; 185845916cd2Sjpk } 185945916cd2Sjpk } 186045916cd2Sjpk prev = current; 186145916cd2Sjpk } 186245916cd2Sjpk return (-1); 186345916cd2Sjpk } 186445916cd2Sjpk 186545916cd2Sjpk for (current = dentry, prev = dentry; current != NULL; 186645916cd2Sjpk current = current->next) { 186745916cd2Sjpk plen = strlen(current->devinfo.devlist); 186845916cd2Sjpk nlen = strlen(link); 186945916cd2Sjpk if (plen == nlen) { 187045916cd2Sjpk if (strcmp(current->devinfo.devlist, link) == 0) { 187145916cd2Sjpk /* last name in the list */ 187245916cd2Sjpk remove_dev = 1; 187345916cd2Sjpk break; 187445916cd2Sjpk } 187545916cd2Sjpk } 187645916cd2Sjpk if (strstr(current->devinfo.devlist, link)) { 187745916cd2Sjpk nlen = plen - nlen + 1; 187845916cd2Sjpk oldlist = strdup(current->devinfo.devlist); 187945916cd2Sjpk if ((current->devinfo.devlist = 188045916cd2Sjpk (char *)realloc(current->devinfo.devlist, 188145916cd2Sjpk nlen)) == NULL) { 188245916cd2Sjpk free(oldlist); 188345916cd2Sjpk return (-1); 188445916cd2Sjpk } 188545916cd2Sjpk current->devinfo.devlist[0] = '\0'; 188645916cd2Sjpk nlen = plen = slen = 0; 188745916cd2Sjpk for (lname = strtok_r(oldlist, " ", &lasts); 188845916cd2Sjpk lname != NULL; 188945916cd2Sjpk lname = strtok_r(NULL, " ", &lasts)) { 189045916cd2Sjpk if (strcmp(lname, link) == 0) 189145916cd2Sjpk continue; 189245916cd2Sjpk nlen = strlen(lname) + plen + 1; 189345916cd2Sjpk if (plen == 0) { 189445916cd2Sjpk slen = 189545916cd2Sjpk snprintf(current->devinfo.devlist, 189645916cd2Sjpk nlen, "%s", lname); 189745916cd2Sjpk } else { 189845916cd2Sjpk slen = 189945916cd2Sjpk snprintf(current->devinfo.devlist + 190010ddde3aSaj plen, nlen - plen, " %s", lname); 190145916cd2Sjpk } 190245916cd2Sjpk plen = plen + slen + 1; 190345916cd2Sjpk } 190445916cd2Sjpk free(oldlist); 190545916cd2Sjpk break; 190645916cd2Sjpk } 190745916cd2Sjpk prev = current; 190845916cd2Sjpk } 190945916cd2Sjpk 191045916cd2Sjpk remove_dev: 191145916cd2Sjpk if (remove_dev == 1) { 191245916cd2Sjpk (void) strlcpy(devname, current->devinfo.devname, size); 191345916cd2Sjpk free(current->devinfo.devname); 191445916cd2Sjpk free(current->devinfo.devlist); 191545916cd2Sjpk current->devinfo.devname = current->devinfo.devlist = NULL; 191645916cd2Sjpk prev->next = current->next; 191745916cd2Sjpk free(current); 191845916cd2Sjpk current = NULL; 191945916cd2Sjpk } 192045916cd2Sjpk if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) { 192145916cd2Sjpk if (prev->next) { 192245916cd2Sjpk /* 192345916cd2Sjpk * what we removed above was the first entry 192445916cd2Sjpk * in the list. make the next entry to be the 192545916cd2Sjpk * first. 192645916cd2Sjpk */ 192745916cd2Sjpk current = prev->next; 192845916cd2Sjpk } else { 192945916cd2Sjpk /* 193045916cd2Sjpk * the matching entry was the only entry in the list 193145916cd2Sjpk * for this type. 193245916cd2Sjpk */ 193345916cd2Sjpk current = NULL; 193445916cd2Sjpk } 193545916cd2Sjpk if (flag & DA_AUDIO) 193645916cd2Sjpk dlist->audio = current; 193745916cd2Sjpk else if (flag & DA_CD) 193845916cd2Sjpk dlist->cd = current; 193945916cd2Sjpk else if (flag & DA_FLOPPY) 194045916cd2Sjpk dlist->floppy = current; 194145916cd2Sjpk else if (flag & DA_TAPE) 194245916cd2Sjpk dlist->tape = current; 194345916cd2Sjpk else if (flag & DA_RMDISK) 194445916cd2Sjpk dlist->rmdisk = current; 194545916cd2Sjpk } 194645916cd2Sjpk 194745916cd2Sjpk return (flag); 194845916cd2Sjpk } 194945916cd2Sjpk 195045916cd2Sjpk /* 1951*7e3e5701SJan Parcel * da_rm_list_entry - 1952*7e3e5701SJan Parcel * 1953*7e3e5701SJan Parcel * The adding of devnames to a devlist and the removal of a 1954*7e3e5701SJan Parcel * device are not symmetrical -- hot_cleanup gives a /devices 1955*7e3e5701SJan Parcel * name which is used to remove the dentry whose links all point to 1956*7e3e5701SJan Parcel * that /devices entry. 1957*7e3e5701SJan Parcel * 1958*7e3e5701SJan Parcel * The link argument is present if available to make debugging 1959*7e3e5701SJan Parcel * easier. 1960*7e3e5701SJan Parcel * 1961*7e3e5701SJan Parcel * da_rm_list_entry removes an entry from the linked list of devices. 1962*7e3e5701SJan Parcel * 1963*7e3e5701SJan Parcel * Returns 1 if the devname was removed successfully, 1964*7e3e5701SJan Parcel * 0 if not found, -1 for error. 1965*7e3e5701SJan Parcel */ 1966*7e3e5701SJan Parcel /*ARGSUSED*/ 1967*7e3e5701SJan Parcel int 1968*7e3e5701SJan Parcel da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname) 1969*7e3e5701SJan Parcel { 1970*7e3e5701SJan Parcel int retval = 0; 1971*7e3e5701SJan Parcel deventry_t **dentry, *current, *prev; 1972*7e3e5701SJan Parcel 1973*7e3e5701SJan Parcel switch (type) { 1974*7e3e5701SJan Parcel case DA_AUDIO: 1975*7e3e5701SJan Parcel dentry = &(dlist->audio); 1976*7e3e5701SJan Parcel break; 1977*7e3e5701SJan Parcel case DA_CD: 1978*7e3e5701SJan Parcel dentry = &(dlist->cd); 1979*7e3e5701SJan Parcel break; 1980*7e3e5701SJan Parcel case DA_FLOPPY: 1981*7e3e5701SJan Parcel dentry = &(dlist->floppy); 1982*7e3e5701SJan Parcel break; 1983*7e3e5701SJan Parcel case DA_TAPE: 1984*7e3e5701SJan Parcel dentry = &(dlist->tape); 1985*7e3e5701SJan Parcel break; 1986*7e3e5701SJan Parcel case DA_RMDISK: 1987*7e3e5701SJan Parcel dentry = &(dlist->rmdisk); 1988*7e3e5701SJan Parcel break; 1989*7e3e5701SJan Parcel default: 1990*7e3e5701SJan Parcel return (-1); 1991*7e3e5701SJan Parcel } 1992*7e3e5701SJan Parcel 1993*7e3e5701SJan Parcel /* Presumably in daemon mode, no need to remove entry, list is empty */ 1994*7e3e5701SJan Parcel if (*dentry == (deventry_t *)NULL) 1995*7e3e5701SJan Parcel return (0); 1996*7e3e5701SJan Parcel 1997*7e3e5701SJan Parcel prev = NULL; 1998*7e3e5701SJan Parcel for (current = *dentry; current != NULL; 1999*7e3e5701SJan Parcel prev = current, current = current->next) { 2000*7e3e5701SJan Parcel if (strcmp(devname, current->devinfo.devname)) 2001*7e3e5701SJan Parcel continue; 2002*7e3e5701SJan Parcel retval = 1; 2003*7e3e5701SJan Parcel break; 2004*7e3e5701SJan Parcel } 2005*7e3e5701SJan Parcel if (retval == 0) 2006*7e3e5701SJan Parcel return (0); 2007*7e3e5701SJan Parcel free(current->devinfo.devname); 2008*7e3e5701SJan Parcel if (current->devinfo.devlist != NULL) 2009*7e3e5701SJan Parcel free(current->devinfo.devlist); 2010*7e3e5701SJan Parcel if (current->devinfo.devopts != NULL) 2011*7e3e5701SJan Parcel free(current->devinfo.devopts); 2012*7e3e5701SJan Parcel 2013*7e3e5701SJan Parcel if (prev == NULL) 2014*7e3e5701SJan Parcel *dentry = current->next; 2015*7e3e5701SJan Parcel else 2016*7e3e5701SJan Parcel prev->next = current->next; 2017*7e3e5701SJan Parcel 2018*7e3e5701SJan Parcel free(current); 2019*7e3e5701SJan Parcel return (retval); 2020*7e3e5701SJan Parcel } 2021*7e3e5701SJan Parcel 2022*7e3e5701SJan Parcel /* 202345916cd2Sjpk * da_is_on - 202445916cd2Sjpk * checks if device allocation feature is turned on. 202545916cd2Sjpk * returns 1 if on, 0 if off, -1 if status string not 202645916cd2Sjpk * found in device_allocate. 202745916cd2Sjpk */ 202845916cd2Sjpk int 202945916cd2Sjpk da_is_on() 203045916cd2Sjpk { 203145916cd2Sjpk return (getdaon()); 203245916cd2Sjpk } 203345916cd2Sjpk 203445916cd2Sjpk /* 203545916cd2Sjpk * da_print_device - 203645916cd2Sjpk * debug routine to print device entries. 203745916cd2Sjpk */ 203845916cd2Sjpk void 203945916cd2Sjpk da_print_device(int flag, devlist_t *devlist) 204045916cd2Sjpk { 204145916cd2Sjpk deventry_t *entry, *dentry; 204245916cd2Sjpk devinfo_t *devinfo; 204345916cd2Sjpk 204445916cd2Sjpk if (flag & DA_AUDIO) 204545916cd2Sjpk dentry = devlist->audio; 204645916cd2Sjpk else if (flag & DA_CD) 204745916cd2Sjpk dentry = devlist->cd; 204845916cd2Sjpk else if (flag & DA_FLOPPY) 204945916cd2Sjpk dentry = devlist->floppy; 205045916cd2Sjpk else if (flag & DA_TAPE) 205145916cd2Sjpk dentry = devlist->tape; 205245916cd2Sjpk else if (flag & DA_RMDISK) 205345916cd2Sjpk dentry = devlist->rmdisk; 205445916cd2Sjpk else 205545916cd2Sjpk return; 205645916cd2Sjpk 205745916cd2Sjpk for (entry = dentry; entry != NULL; entry = entry->next) { 205845916cd2Sjpk devinfo = &(entry->devinfo); 205945916cd2Sjpk (void) fprintf(stdout, "name: %s\n", devinfo->devname); 206045916cd2Sjpk (void) fprintf(stdout, "type: %s\n", devinfo->devtype); 206145916cd2Sjpk (void) fprintf(stdout, "auth: %s\n", devinfo->devauths); 206245916cd2Sjpk (void) fprintf(stdout, "exec: %s\n", devinfo->devexec); 206345916cd2Sjpk (void) fprintf(stdout, "list: %s\n\n", devinfo->devlist); 206445916cd2Sjpk } 206545916cd2Sjpk } 2066