11676Sjpk /* 21676Sjpk * CDDL HEADER START 31676Sjpk * 41676Sjpk * The contents of this file are subject to the terms of the 51676Sjpk * Common Development and Distribution License (the "License"). 61676Sjpk * You may not use this file except in compliance with the License. 71676Sjpk * 81676Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91676Sjpk * or http://www.opensolaris.org/os/licensing. 101676Sjpk * See the License for the specific language governing permissions 111676Sjpk * and limitations under the License. 121676Sjpk * 131676Sjpk * When distributing Covered Code, include this CDDL HEADER in each 141676Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151676Sjpk * If applicable, add the following below this CDDL HEADER, with the 161676Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 171676Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 181676Sjpk * 191676Sjpk * CDDL HEADER END 201676Sjpk */ 211676Sjpk 221676Sjpk /* 23*12373SJan.Parcel@Sun.COM * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 241676Sjpk */ 251676Sjpk 261676Sjpk #include <stdlib.h> 271676Sjpk #include <ctype.h> 281676Sjpk #include <unistd.h> 291676Sjpk #include <limits.h> 301676Sjpk #include <fcntl.h> 311676Sjpk #include <sys/types.h> 321676Sjpk #include <sys/stat.h> 331676Sjpk #include <utime.h> 341676Sjpk #include <synch.h> 351676Sjpk #include <strings.h> 361676Sjpk #include <string.h> 371676Sjpk #include <libintl.h> 381676Sjpk #include <errno.h> 391676Sjpk #include <auth_list.h> 4011529SJan.Parcel@Sun.COM #include <syslog.h> 411676Sjpk #include <bsm/devices.h> 421676Sjpk #include <bsm/devalloc.h> 43*12373SJan.Parcel@Sun.COM #include <tsol/label.h> 441676Sjpk 451676Sjpk #define DA_DEFS "/etc/security/tsol/devalloc_defaults" 461676Sjpk 471676Sjpk extern int _readbufline(char *, int, char *, int, int *); 481676Sjpk extern char *strtok_r(char *, const char *, char **); 491676Sjpk extern char *_strtok_escape(char *, char *, char **); 501676Sjpk extern int getdaon(void); 511676Sjpk extern int da_matchname(devalloc_t *, char *); 521676Sjpk extern int da_match(devalloc_t *, da_args *); 531676Sjpk extern int dmap_matchname(devmap_t *, char *); 541676Sjpk extern int dm_match(devmap_t *, da_args *); 5511529SJan.Parcel@Sun.COM extern int dmap_matchtype(devmap_t *dmap, char *type); 5611529SJan.Parcel@Sun.COM extern int dmap_matchdev(devmap_t *dmap, char *dev); 5711529SJan.Parcel@Sun.COM extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num); 5811529SJan.Parcel@Sun.COM extern char *dmap_physname(devmap_t *dmap); 591676Sjpk 601676Sjpk /* 611676Sjpk * The following structure is for recording old entries to be retained. 621676Sjpk * We read the entries from the database into a linked list in memory, 631676Sjpk * then turn around and write them out again. 641676Sjpk */ 651676Sjpk typedef struct strentry { 661676Sjpk struct strentry *se_next; 671676Sjpk char se_str[4096 + 1]; 681676Sjpk } strentry_t; 691676Sjpk 701676Sjpk /* 711676Sjpk * da_check_longindevperm - 721676Sjpk * reads /etc/logindevperm and checks if specified device is in the file. 731676Sjpk * returns 1 if specified device found in /etc/logindevperm, else returns 0 741676Sjpk */ 751676Sjpk int 761676Sjpk da_check_logindevperm(char *devname) 771676Sjpk { 781676Sjpk int ret = 0; 791676Sjpk int fd = -1; 801676Sjpk int nlen, plen, slen, lineno, fsize; 811676Sjpk char line[MAX_CANON]; 821676Sjpk char *field_delims = " \t\n"; 831676Sjpk char *fbuf = NULL; 841676Sjpk char *ptr, *device; 851676Sjpk char *lasts = NULL; 861676Sjpk FILE *fp; 871676Sjpk struct stat f_stat; 881676Sjpk 891676Sjpk /* 901676Sjpk * check if /etc/logindevperm exists and get its size 911676Sjpk */ 921676Sjpk if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1) 931676Sjpk return (0); 941676Sjpk if (fstat(fd, &f_stat) != 0) { 951676Sjpk (void) close(fd); 961676Sjpk return (0); 971676Sjpk } 981676Sjpk fsize = f_stat.st_size; 991676Sjpk if ((fbuf = (char *)malloc(fsize)) == NULL) { 1001676Sjpk (void) close(fd); 1011676Sjpk return (0); 1021676Sjpk } 1031914Scasper if ((fp = fdopen(fd, "rF")) == NULL) { 1041676Sjpk free(fbuf); 1051676Sjpk (void) close(fd); 1061676Sjpk return (0); 1071676Sjpk } 1081676Sjpk 1091676Sjpk /* 1101676Sjpk * read and parse /etc/logindevperm 1111676Sjpk */ 1121676Sjpk plen = nlen = lineno = 0; 1131676Sjpk while (fgets(line, MAX_CANON, fp) != NULL) { 1141676Sjpk lineno++; 1151676Sjpk if ((ptr = strchr(line, '#')) != NULL) 1161676Sjpk *ptr = '\0'; /* handle comments */ 1171676Sjpk if (strtok_r(line, field_delims, &lasts) == NULL) 1181676Sjpk continue; /* ignore blank lines */ 1191676Sjpk if (strtok_r(NULL, field_delims, &lasts) == NULL) 1201676Sjpk /* invalid entry */ 1211676Sjpk continue; 1221676Sjpk if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL) 1231676Sjpk /* empty device list */ 1241676Sjpk continue; 1251676Sjpk nlen = strlen(ptr) + 1; /* +1 terminator */ 1261676Sjpk nlen += (plen + 1); 1271676Sjpk if (plen == 0) 1281676Sjpk slen = snprintf(fbuf, nlen, "%s", ptr); 1291676Sjpk else 1301676Sjpk slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr); 1311676Sjpk if (slen >= fsize) { 1321676Sjpk fbuf[0] = '\0'; 1331676Sjpk (void) fclose(fp); 1341676Sjpk return (slen); 1351676Sjpk } 1361676Sjpk plen += slen; 1371676Sjpk } 1381676Sjpk (void) fclose(fp); 1391676Sjpk 1401676Sjpk /* 1411676Sjpk * check if devname exists in /etc/logindevperm 1421676Sjpk */ 1431676Sjpk device = strtok_r(fbuf, ":", &lasts); 1441676Sjpk while (device != NULL) { 1451676Sjpk /* 1461676Sjpk * device and devname may be one of these types - 1471676Sjpk * /dev/xx 1481676Sjpk * /dev/xx* 1491676Sjpk * /dev/dir/xx 1501676Sjpk * /dev/dir/xx* 1511676Sjpk * /dev/dir/"*" 1521676Sjpk */ 1531676Sjpk if (strcmp(device, devname) == 0) { 1541676Sjpk /* /dev/xx, /dev/dir/xx */ 1551676Sjpk free(fbuf); 1561676Sjpk return (1); 1571676Sjpk } 1581676Sjpk if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) { 1591676Sjpk /* all wildcard types */ 1601676Sjpk *ptr = '\0'; 1611676Sjpk if (strncmp(device, devname, strlen(device)) == 0) { 1621676Sjpk free(fbuf); 1631676Sjpk return (1); 1641676Sjpk } 1651676Sjpk } 1661676Sjpk device = strtok_r(NULL, ":", &lasts); 1671676Sjpk } 1681676Sjpk 1691676Sjpk return (ret); 1701676Sjpk } 1711676Sjpk 1721676Sjpk /* 1731676Sjpk * _da_read_file - 1741676Sjpk * establishes readers/writer lock on fname; reads in the file if its 1751676Sjpk * contents changed since the last time we read it. 1761676Sjpk * returns size of buffer read, or -1 on failure. 1771676Sjpk */ 1781676Sjpk int 1791676Sjpk _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock, 1801676Sjpk int flag) 1811676Sjpk { 1821676Sjpk int fd = -1; 1831676Sjpk int fsize = 0; 1841676Sjpk time_t newtime; 1851676Sjpk struct stat f_stat; 1861676Sjpk 1871676Sjpk if (flag & DA_FORCE) 1881676Sjpk *ftime = 0; 1891676Sjpk 1901676Sjpk /* check the size and the time stamp on the file */ 1911676Sjpk if (rw_rdlock(flock) != 0) 1921676Sjpk return (-1); 1931676Sjpk if (stat(fname, &f_stat) != 0) { 1941676Sjpk (void) rw_unlock(flock); 1951676Sjpk return (-1); 1961676Sjpk } 1971676Sjpk fsize = f_stat.st_size; 1981676Sjpk newtime = f_stat.st_mtime; 1991676Sjpk (void) rw_unlock(flock); 2001676Sjpk 2011676Sjpk while (newtime > *ftime) { 2021676Sjpk /* 2031676Sjpk * file has been modified since we last read it; or this 2041676Sjpk * is a forced read. 2051676Sjpk * read file into the buffer with rw lock. 2061676Sjpk */ 2071676Sjpk if (rw_wrlock(flock) != 0) 2081676Sjpk return (-1); 2091914Scasper if ((fd = open(fname, O_RDONLY)) == -1) { 2101676Sjpk (void) rw_unlock(flock); 2111676Sjpk return (-1); 2121676Sjpk } 2131676Sjpk if (*fbuf != NULL) { 2141676Sjpk free(*fbuf); 2151676Sjpk *fbuf = NULL; 2161676Sjpk } 2171676Sjpk if ((*fbuf = malloc(fsize)) == NULL) { 2181676Sjpk (void) rw_unlock(flock); 2191676Sjpk (void) close(fd); 2201676Sjpk return (-1); 2211676Sjpk } 2221676Sjpk if (read(fd, *fbuf, fsize) < fsize) { 2231676Sjpk free(*fbuf); 2241676Sjpk (void) rw_unlock(flock); 2251676Sjpk (void) close(fd); 2261676Sjpk return (-1); 2271676Sjpk } 2281676Sjpk (void) rw_unlock(flock); 2291676Sjpk /* 2301676Sjpk * verify that the file did not change just after we read it. 2311676Sjpk */ 2321676Sjpk if (rw_rdlock(flock) != 0) { 2331676Sjpk free(*fbuf); 2341676Sjpk (void) close(fd); 2351676Sjpk return (-1); 2361676Sjpk } 2371676Sjpk if (stat(fname, &f_stat) != 0) { 2381676Sjpk free(*fbuf); 2391676Sjpk (void) rw_unlock(flock); 2401676Sjpk (void) close(fd); 2411676Sjpk return (-1); 2421676Sjpk } 2431676Sjpk fsize = f_stat.st_size; 2441676Sjpk newtime = f_stat.st_mtime; 2451676Sjpk (void) rw_unlock(flock); 2461676Sjpk (void) close(fd); 2471676Sjpk *ftime = newtime; 2481676Sjpk } 2491676Sjpk 2501676Sjpk return (fsize); 2511676Sjpk } 2521676Sjpk 2531676Sjpk /* 2541676Sjpk * _update_zonename - 2551676Sjpk * add/remove current zone's name to the given devalloc_t. 2561676Sjpk */ 2571676Sjpk void 2581676Sjpk _update_zonename(da_args *dargs, devalloc_t *dap) 2591676Sjpk { 2601676Sjpk int i, j; 2611676Sjpk int oldsize, newsize; 2621676Sjpk int has_zonename = 0; 2631676Sjpk char *zonename; 2641676Sjpk kva_t *newkva, *oldkva; 2651676Sjpk kv_t *newdata, *olddata; 2661676Sjpk devinfo_t *devinfo; 2671676Sjpk 2681676Sjpk devinfo = dargs->devinfo; 2691676Sjpk oldkva = dap->da_devopts; 2701676Sjpk if (oldkva == NULL) { 2711676Sjpk if (dargs->optflag & DA_REMOVE_ZONE) 2721676Sjpk return; 2731676Sjpk if (dargs->optflag & DA_ADD_ZONE) { 2741676Sjpk newkva = _str2kva(devinfo->devopts, KV_ASSIGN, 2751676Sjpk KV_TOKEN_DELIMIT); 2761676Sjpk if (newkva != NULL) 2771676Sjpk dap->da_devopts = newkva; 2781676Sjpk return; 2791676Sjpk } 2801676Sjpk } 2811676Sjpk newsize = oldsize = oldkva->length; 2821676Sjpk if (kva_match(oldkva, DAOPT_ZONE)) 2831676Sjpk has_zonename = 1; 2841676Sjpk if (dargs->optflag & DA_ADD_ZONE) { 2851676Sjpk if ((zonename = index(devinfo->devopts, '=')) == NULL) 2861676Sjpk return; 2871676Sjpk zonename++; 2881676Sjpk if (has_zonename) { 2891676Sjpk (void) _insert2kva(oldkva, DAOPT_ZONE, zonename); 2901676Sjpk return; 2911676Sjpk } 2921676Sjpk newsize += 1; 2931676Sjpk } else if (dargs->optflag & DA_REMOVE_ZONE) { 2941676Sjpk if (has_zonename) { 2951676Sjpk newsize -= 1; 2961676Sjpk if (newsize == 0) { 2971676Sjpk /* 2981676Sjpk * If zone name was the only key/value pair, 2991676Sjpk * put 'reserved' in the empty slot. 3001676Sjpk */ 3011676Sjpk _kva_free(oldkva); 3021676Sjpk dap->da_devopts = NULL; 3031676Sjpk return; 3041676Sjpk } 3051676Sjpk } else { 3061676Sjpk return; 3071676Sjpk } 3081676Sjpk } 3091676Sjpk newkva = _new_kva(newsize); 3101676Sjpk newkva->length = 0; 3111676Sjpk newdata = newkva->data; 3121676Sjpk olddata = oldkva->data; 3131676Sjpk for (i = 0, j = 0; i < oldsize; i++) { 3141676Sjpk if ((dargs->optflag & DA_REMOVE_ZONE) && 3151676Sjpk (strcmp(olddata[i].key, DAOPT_ZONE) == 0)) 3161676Sjpk continue; 3171676Sjpk newdata[j].key = strdup(olddata[i].key); 3181676Sjpk newdata[j].value = strdup(olddata[i].value); 3191676Sjpk newkva->length++; 3201676Sjpk j++; 3211676Sjpk } 3221676Sjpk if (dargs->optflag & DA_ADD_ZONE) { 3231676Sjpk newdata[j].key = strdup(DAOPT_ZONE); 3241676Sjpk newdata[j].value = strdup(zonename); 3251676Sjpk newkva->length++; 3261676Sjpk } 3271676Sjpk _kva_free(oldkva); 3281676Sjpk dap->da_devopts = newkva; 3291676Sjpk } 3301676Sjpk 3311676Sjpk /* 3321676Sjpk * _dmap2str - 3331676Sjpk * converts a device_map entry into a printable string 3341676Sjpk * returns 0 on success, -1 on error. 3351676Sjpk */ 3361676Sjpk /*ARGSUSED*/ 3371676Sjpk static int 33811529SJan.Parcel@Sun.COM _dmap2str(devmap_t *dmp, char *buf, int size, const char *sep) 3391676Sjpk { 3401676Sjpk int length; 3411676Sjpk 3421676Sjpk length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep); 3431676Sjpk if (length >= size) 3441676Sjpk return (-1); 3451676Sjpk length += snprintf(buf + length, size - length, "%s%s", 3461676Sjpk dmp->dmap_devtype, sep); 3471676Sjpk if (length >= size) 3481676Sjpk return (-1); 3491676Sjpk length += snprintf(buf + length, size - length, "%s\n", 3501676Sjpk dmp->dmap_devlist); 3511676Sjpk if (length >= size) 3521676Sjpk return (-1); 3531676Sjpk return (0); 3541676Sjpk } 3551676Sjpk 3561676Sjpk /* 3571676Sjpk * _dmap2strentry - 3581676Sjpk * calls dmap2str to break given devmap_t into printable entry. 3591676Sjpk * returns pointer to decoded entry, NULL on error. 3601676Sjpk */ 3611676Sjpk static strentry_t * 36211529SJan.Parcel@Sun.COM _dmap2strentry(devmap_t *devmapp) 3631676Sjpk { 3641676Sjpk strentry_t *sep; 3651676Sjpk 3661676Sjpk if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 3671676Sjpk return (NULL); 36811529SJan.Parcel@Sun.COM if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str), 3691676Sjpk KV_TOKEN_DELIMIT"\\\n\t") != 0) { 3701676Sjpk free(sep); 3711676Sjpk return (NULL); 3721676Sjpk } 3731676Sjpk return (sep); 3741676Sjpk } 3751676Sjpk 3761676Sjpk /* 3771676Sjpk * fix_optstr - 3781676Sjpk * removes trailing ':' from buf. 3791676Sjpk */ 3801676Sjpk void 3811676Sjpk fix_optstr(char *buf) 3821676Sjpk { 3831676Sjpk char *p = NULL; 3841676Sjpk 3851676Sjpk if (p = rindex(buf, ':')) 3861676Sjpk *p = ';'; 3871676Sjpk } 3881676Sjpk 3891676Sjpk /* 3901676Sjpk * _da2str - 3911676Sjpk * converts a device_allocate entry into a printable string 3921676Sjpk * returns 0 on success, -1 on error. 3931676Sjpk */ 3941676Sjpk static int 3951676Sjpk _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep, 3961676Sjpk const char *osep) 3971676Sjpk { 3981676Sjpk int length; 3991676Sjpk int matching_entry = 0; 4001676Sjpk char **dnames; 4011676Sjpk 4021676Sjpk if (dargs->optflag & DA_UPDATE && 4031676Sjpk (dargs->optflag & DA_ADD_ZONE || 4041676Sjpk dargs->optflag & DA_REMOVE_ZONE) && 4051676Sjpk dargs->devnames) { 4061676Sjpk for (dnames = dargs->devnames; *dnames != NULL; dnames++) { 4071676Sjpk if (da_matchname(dap, *dnames)) { 4081676Sjpk matching_entry = 1; 4091676Sjpk break; 4101676Sjpk } 4111676Sjpk } 4121676Sjpk } 4131676Sjpk length = snprintf(buf, size, "%s%s", dap->da_devname, sep); 4141676Sjpk if (length >= size) 4151676Sjpk return (-1); 4161676Sjpk length += snprintf(buf + length, size - length, "%s%s", 4171676Sjpk dap->da_devtype, sep); 4181676Sjpk if (length >= size) 4191676Sjpk return (-1); 4201676Sjpk if (matching_entry) 4211676Sjpk _update_zonename(dargs, dap); 4221676Sjpk if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) && 4231676Sjpk (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) { 4241676Sjpk length += snprintf(buf + length, size - length, "%s%s", 4251676Sjpk DA_RESERVED, sep); 4261676Sjpk } else { 4271676Sjpk if (_kva2str(dap->da_devopts, buf + length, size - length, 4281676Sjpk KV_ASSIGN, (char *)osep) != 0) 4291676Sjpk return (-1); 4301676Sjpk length = strlen(buf); 4311676Sjpk } 4321676Sjpk if (dap->da_devopts) 4331676Sjpk fix_optstr(buf); 4341676Sjpk if (length >= size) 4351676Sjpk return (-1); 4361676Sjpk length += snprintf(buf + length, size - length, "%s%s", 4371676Sjpk DA_RESERVED, sep); 4381676Sjpk if (length >= size) 4391676Sjpk return (-1); 4401676Sjpk length += snprintf(buf + length, size - length, "%s%s", 4411676Sjpk dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep); 4421676Sjpk if (length >= size) 4431676Sjpk return (-1); 4441676Sjpk length += snprintf(buf + length, size - length, "%s\n", 4451676Sjpk dap->da_devexec ? dap->da_devexec : ""); 4461676Sjpk if (length >= size) 4471676Sjpk return (-1); 4481676Sjpk 4491676Sjpk return (0); 4501676Sjpk } 4511676Sjpk 4521676Sjpk /* 4531676Sjpk * _da2strentry - 4541676Sjpk * calls da2str to break given devalloc_t into printable entry. 4551676Sjpk * returns pointer to decoded entry, NULL on error. 4561676Sjpk */ 4571676Sjpk static strentry_t * 4581676Sjpk _da2strentry(da_args *dargs, devalloc_t *dap) 4591676Sjpk { 4601676Sjpk strentry_t *sep; 4611676Sjpk 4621676Sjpk if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 4631676Sjpk return (NULL); 4641676Sjpk if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str), 4651676Sjpk KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) { 4661676Sjpk free(sep); 4671676Sjpk return (NULL); 4681676Sjpk } 4691676Sjpk return (sep); 4701676Sjpk } 4711676Sjpk 4721676Sjpk /* 4731676Sjpk * _def2str 4741676Sjpk * converts da_defs_t into a printable string. 4751676Sjpk * returns 0 on success, -1 on error. 4761676Sjpk */ 4771676Sjpk static int 4781676Sjpk _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep) 4791676Sjpk { 4801676Sjpk int length; 4811676Sjpk 4821676Sjpk length = snprintf(buf, size, "%s%s", da_defs->devtype, sep); 4831676Sjpk if (length >= size) 4841676Sjpk return (-1); 4851676Sjpk if (da_defs->devopts) { 4861676Sjpk if (_kva2str(da_defs->devopts, buf + length, size - length, 4871676Sjpk KV_ASSIGN, KV_DELIMITER) != 0) 4881676Sjpk return (-1); 4891676Sjpk length = strlen(buf); 4901676Sjpk } 4911676Sjpk if (length >= size) 4921676Sjpk return (-1); 4931676Sjpk 4941676Sjpk return (0); 4951676Sjpk } 4961676Sjpk 4971676Sjpk /* 4981676Sjpk * _def2strentry 4991676Sjpk * calls _def2str to break given da_defs_t into printable entry. 5001676Sjpk * returns pointer decoded entry, NULL on error. 5011676Sjpk */ 5021676Sjpk static strentry_t * 5031676Sjpk _def2strentry(da_defs_t *da_defs) 5041676Sjpk { 5051676Sjpk strentry_t *sep; 5061676Sjpk 5071676Sjpk if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) 5081676Sjpk return (NULL); 5091676Sjpk if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str), 5101676Sjpk KV_TOKEN_DELIMIT) != 0) { 5111676Sjpk free(sep); 5121676Sjpk return (NULL); 5131676Sjpk } 5141676Sjpk 5151676Sjpk return (sep); 5161676Sjpk } 5171676Sjpk 5181676Sjpk /* 5191676Sjpk * _build_defattrs 5201676Sjpk * cycles through all defattr entries, stores them in memory. removes 5211676Sjpk * entries with the given search_key (device type). 5221676Sjpk * returns 0 if given entry not found, 1 if given entry removed, 2 on 5231676Sjpk * error. 5241676Sjpk */ 5251676Sjpk static int 5261676Sjpk _build_defattrs(da_args *dargs, strentry_t **head_defent) 5271676Sjpk { 5281676Sjpk int rc = 0; 5291676Sjpk da_defs_t *da_defs; 5301676Sjpk strentry_t *tail_str, *tmp_str; 5311676Sjpk 5321676Sjpk setdadefent(); 5331676Sjpk while ((da_defs = getdadefent()) != NULL) { 5341676Sjpk rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype)); 5351676Sjpk if (rc && dargs->optflag & DA_ADD && 5361676Sjpk !(dargs->optflag & DA_FORCE)) { 5371676Sjpk /* 5381676Sjpk * During DA_ADD, we keep an existing entry unless 5391676Sjpk * we have DA_FORCE set to override that entry. 5401676Sjpk */ 5411676Sjpk dargs->optflag |= DA_NO_OVERRIDE; 5421676Sjpk rc = 0; 5431676Sjpk } 5441676Sjpk if (rc == 0) { 5451676Sjpk tmp_str = _def2strentry(da_defs); 5461676Sjpk if (tmp_str == NULL) { 5471676Sjpk freedadefent(da_defs); 5481676Sjpk enddadefent(); 5491676Sjpk return (2); 5501676Sjpk } 5511676Sjpk /* retaining defattr entry: tmp_str->se_str */ 5521676Sjpk tmp_str->se_next = NULL; 5531676Sjpk if (*head_defent == NULL) { 5541676Sjpk *head_defent = tail_str = tmp_str; 5551676Sjpk } else { 5561676Sjpk tail_str->se_next = tmp_str; 5571676Sjpk tail_str = tmp_str; 5581676Sjpk } 5591676Sjpk } 5601676Sjpk freedadefent(da_defs); 5611676Sjpk } 5621676Sjpk enddadefent(); 5631676Sjpk 5641676Sjpk return (rc); 5651676Sjpk } 5661676Sjpk 5671676Sjpk /* 568*12373SJan.Parcel@Sun.COM * We have to handle the "standard" types in devlist differently than 569*12373SJan.Parcel@Sun.COM * other devices, which are not covered by our auto-naming conventions. 570*12373SJan.Parcel@Sun.COM * 571*12373SJan.Parcel@Sun.COM * buf must be a buffer of size DA_MAX_NAME + 1 572*12373SJan.Parcel@Sun.COM */ 573*12373SJan.Parcel@Sun.COM int 574*12373SJan.Parcel@Sun.COM da_std_type(da_args *dargs, char *namebuf) 575*12373SJan.Parcel@Sun.COM { 576*12373SJan.Parcel@Sun.COM char *type = dargs->devinfo->devtype; 577*12373SJan.Parcel@Sun.COM int system_labeled; 578*12373SJan.Parcel@Sun.COM 579*12373SJan.Parcel@Sun.COM system_labeled = is_system_labeled(); 580*12373SJan.Parcel@Sun.COM 581*12373SJan.Parcel@Sun.COM /* check safely for sizes */ 582*12373SJan.Parcel@Sun.COM if (strcmp(DA_AUDIO_TYPE, type) == 0) { 583*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_AUDIO_NAME, DA_MAXNAME); 584*12373SJan.Parcel@Sun.COM return (1); 585*12373SJan.Parcel@Sun.COM } 586*12373SJan.Parcel@Sun.COM if (strcmp(DA_CD_TYPE, type) == 0) { 587*12373SJan.Parcel@Sun.COM if (system_labeled) 588*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_CD_NAME, DA_MAXNAME); 589*12373SJan.Parcel@Sun.COM else 590*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_CD_TYPE, DA_MAXNAME); 591*12373SJan.Parcel@Sun.COM return (1); 592*12373SJan.Parcel@Sun.COM } 593*12373SJan.Parcel@Sun.COM if (strcmp(DA_FLOPPY_TYPE, type) == 0) { 594*12373SJan.Parcel@Sun.COM if (system_labeled) 595*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_FLOPPY_NAME, DA_MAXNAME); 596*12373SJan.Parcel@Sun.COM else 597*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_FLOPPY_TYPE, DA_MAXNAME); 598*12373SJan.Parcel@Sun.COM return (1); 599*12373SJan.Parcel@Sun.COM } 600*12373SJan.Parcel@Sun.COM if (strcmp(DA_TAPE_TYPE, type) == 0) { 601*12373SJan.Parcel@Sun.COM if (system_labeled) 602*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_TAPE_NAME, DA_MAXNAME); 603*12373SJan.Parcel@Sun.COM else 604*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_TAPE_TYPE, DA_MAXNAME); 605*12373SJan.Parcel@Sun.COM return (1); 606*12373SJan.Parcel@Sun.COM } 607*12373SJan.Parcel@Sun.COM if (strcmp(DA_RMDISK_TYPE, type) == 0) { 608*12373SJan.Parcel@Sun.COM (void) strlcpy(namebuf, DA_RMDISK_NAME, DA_MAXNAME); 609*12373SJan.Parcel@Sun.COM return (1); 610*12373SJan.Parcel@Sun.COM } 611*12373SJan.Parcel@Sun.COM namebuf[0] = '\0'; 612*12373SJan.Parcel@Sun.COM return (0); 613*12373SJan.Parcel@Sun.COM } 614*12373SJan.Parcel@Sun.COM 615*12373SJan.Parcel@Sun.COM /* 616*12373SJan.Parcel@Sun.COM * allocatable: returns 617*12373SJan.Parcel@Sun.COM * -1 if no auths field, 618*12373SJan.Parcel@Sun.COM * 0 if not allocatable (marked '*') 619*12373SJan.Parcel@Sun.COM * 1 if not marked '*' 620*12373SJan.Parcel@Sun.COM */ 621*12373SJan.Parcel@Sun.COM static int 622*12373SJan.Parcel@Sun.COM allocatable(da_args *dargs) 623*12373SJan.Parcel@Sun.COM { 624*12373SJan.Parcel@Sun.COM 625*12373SJan.Parcel@Sun.COM if (!dargs->devinfo->devauths) 626*12373SJan.Parcel@Sun.COM return (-1); 627*12373SJan.Parcel@Sun.COM if (strcmp("*", dargs->devinfo->devauths) == 0) 628*12373SJan.Parcel@Sun.COM return (0); 629*12373SJan.Parcel@Sun.COM return (1); 630*12373SJan.Parcel@Sun.COM } 631*12373SJan.Parcel@Sun.COM 632*12373SJan.Parcel@Sun.COM /* 63311529SJan.Parcel@Sun.COM * _rebuild_lists - 63411529SJan.Parcel@Sun.COM * 635*12373SJan.Parcel@Sun.COM * If dargs->optflag & DA_EVENT, does not assume the dargs list is 636*12373SJan.Parcel@Sun.COM * complete or completely believable, since devfsadm caches 637*12373SJan.Parcel@Sun.COM * ONLY what it has been exposed to via syseventd. 63811529SJan.Parcel@Sun.COM * 63911529SJan.Parcel@Sun.COM * Cycles through all the entries in the /etc files, stores them 640*12373SJan.Parcel@Sun.COM * in memory, takes note of device->dname numbers (e.g. rmdisk0, 641*12373SJan.Parcel@Sun.COM * rmdisk12) 64211529SJan.Parcel@Sun.COM * 643*12373SJan.Parcel@Sun.COM * Cycles through again, adds dargs entry 64411529SJan.Parcel@Sun.COM * with the name tname%d (lowest unused number for the device type) 64511529SJan.Parcel@Sun.COM * to the list of things for the caller to write out to a file, 646*12373SJan.Parcel@Sun.COM * IFF it is a new entry. 64711529SJan.Parcel@Sun.COM * 648*12373SJan.Parcel@Sun.COM * It is an error for it to already be there, if it is allocatable. 64911529SJan.Parcel@Sun.COM * 65011529SJan.Parcel@Sun.COM * Add: 651*12373SJan.Parcel@Sun.COM * Returns 0 if successful and 2 on error. 652*12373SJan.Parcel@Sun.COM * Remove: 653*12373SJan.Parcel@Sun.COM * Returns 0 if not found, 1 if found, 2 on error. 65411529SJan.Parcel@Sun.COM */ 65511529SJan.Parcel@Sun.COM static int 65611529SJan.Parcel@Sun.COM _rebuild_lists(da_args *dargs, strentry_t **head_devallocp, 65711529SJan.Parcel@Sun.COM strentry_t **head_devmapp) 65811529SJan.Parcel@Sun.COM { 65911529SJan.Parcel@Sun.COM int rc = 0; 66011529SJan.Parcel@Sun.COM devalloc_t *devallocp; 66111529SJan.Parcel@Sun.COM devmap_t *devmapp; 66211529SJan.Parcel@Sun.COM strentry_t *tail_str; 66311529SJan.Parcel@Sun.COM strentry_t *tmp_str; 66411529SJan.Parcel@Sun.COM uint64_t tmp_bitmap = 0; 665*12373SJan.Parcel@Sun.COM uint_t tmp = 0; 666*12373SJan.Parcel@Sun.COM char *realname; 667*12373SJan.Parcel@Sun.COM int suffix; 668*12373SJan.Parcel@Sun.COM int found = 0; 669*12373SJan.Parcel@Sun.COM int stdtype = 1; 670*12373SJan.Parcel@Sun.COM int is_allocatable = 1; 67111529SJan.Parcel@Sun.COM char new_devname[DA_MAXNAME + 1]; 672*12373SJan.Parcel@Sun.COM char defname[DA_MAXNAME + 1]; /* default name for type */ 67311529SJan.Parcel@Sun.COM char errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80]; 67411529SJan.Parcel@Sun.COM 67511529SJan.Parcel@Sun.COM if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY)) 67611529SJan.Parcel@Sun.COM return (2); 67711529SJan.Parcel@Sun.COM 67811529SJan.Parcel@Sun.COM if (dargs->optflag & DA_FORCE) 67911529SJan.Parcel@Sun.COM return (2); 68011529SJan.Parcel@Sun.COM 681*12373SJan.Parcel@Sun.COM if (dargs->optflag & DA_ADD) { 682*12373SJan.Parcel@Sun.COM stdtype = da_std_type(dargs, defname); 683*12373SJan.Parcel@Sun.COM is_allocatable = allocatable(dargs); 684*12373SJan.Parcel@Sun.COM } 685*12373SJan.Parcel@Sun.COM 68611529SJan.Parcel@Sun.COM /* read both files, maps first so we can compare actual devices */ 68711529SJan.Parcel@Sun.COM 68811529SJan.Parcel@Sun.COM /* build device_maps */ 68911529SJan.Parcel@Sun.COM setdmapent(); 69011529SJan.Parcel@Sun.COM while ((devmapp = getdmapent()) != NULL) { 691*12373SJan.Parcel@Sun.COM suffix = DA_MAX_DEVNO + 1; 69211529SJan.Parcel@Sun.COM if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype)) 69311529SJan.Parcel@Sun.COM == 1) { 69411529SJan.Parcel@Sun.COM if (dargs->optflag & DA_REMOVE) { 69511529SJan.Parcel@Sun.COM if ((devmapp->dmap_devarray == NULL) || 69611529SJan.Parcel@Sun.COM (devmapp->dmap_devarray[0] == NULL)) { 69711529SJan.Parcel@Sun.COM freedmapent(devmapp); 69811529SJan.Parcel@Sun.COM enddmapent(); 69911529SJan.Parcel@Sun.COM return (2); 70011529SJan.Parcel@Sun.COM } 70111529SJan.Parcel@Sun.COM realname = dmap_physname(devmapp); 70211529SJan.Parcel@Sun.COM if (realname == NULL) { 70311529SJan.Parcel@Sun.COM freedmapent(devmapp); 70411529SJan.Parcel@Sun.COM enddmapent(); 70511529SJan.Parcel@Sun.COM return (2); 70611529SJan.Parcel@Sun.COM } 70711529SJan.Parcel@Sun.COM if (strstr(realname, dargs->devinfo->devlist) 70811529SJan.Parcel@Sun.COM != NULL) { 709*12373SJan.Parcel@Sun.COM /* if need to free and safe to free */ 710*12373SJan.Parcel@Sun.COM if (dargs->devinfo->devname != NULL && 711*12373SJan.Parcel@Sun.COM (dargs->optflag & DA_EVENT) != 0) 71211529SJan.Parcel@Sun.COM free(dargs->devinfo->devname); 71311529SJan.Parcel@Sun.COM dargs->devinfo->devname = 71411529SJan.Parcel@Sun.COM strdup(devmapp->dmap_devname); 71511529SJan.Parcel@Sun.COM found = 1; 71611529SJan.Parcel@Sun.COM freedmapent(devmapp); 71711529SJan.Parcel@Sun.COM continue; /* don't retain */ 71811529SJan.Parcel@Sun.COM } 71911529SJan.Parcel@Sun.COM } else if (dargs->optflag & DA_ADD) { 72011529SJan.Parcel@Sun.COM /* 72111529SJan.Parcel@Sun.COM * Need to know which suffixes are in use 72211529SJan.Parcel@Sun.COM */ 72311529SJan.Parcel@Sun.COM rc = (dmap_exact_dev(devmapp, 72411529SJan.Parcel@Sun.COM dargs->devinfo->devlist, &suffix)); 72511529SJan.Parcel@Sun.COM 72611529SJan.Parcel@Sun.COM if (rc == 0) { 72711529SJan.Parcel@Sun.COM /* 72811529SJan.Parcel@Sun.COM * Same type, different device. Record 729*12373SJan.Parcel@Sun.COM * device suffix already in use, if 730*12373SJan.Parcel@Sun.COM * applicable. 73111529SJan.Parcel@Sun.COM */ 732*12373SJan.Parcel@Sun.COM if ((suffix < DA_MAX_DEVNO && 733*12373SJan.Parcel@Sun.COM suffix != -1) && stdtype) 734*12373SJan.Parcel@Sun.COM tmp_bitmap |= 735*12373SJan.Parcel@Sun.COM (uint64_t)(1LL << suffix); 736*12373SJan.Parcel@Sun.COM } else if ((rc == 1) && !is_allocatable) { 737*12373SJan.Parcel@Sun.COM rc = 0; 73811529SJan.Parcel@Sun.COM } else { 73911529SJan.Parcel@Sun.COM /* 740*12373SJan.Parcel@Sun.COM * Match allocatable on add is an error 74111529SJan.Parcel@Sun.COM * or mapping attempt returned error 74211529SJan.Parcel@Sun.COM */ 743*12373SJan.Parcel@Sun.COM (void) snprintf(errmsg, sizeof (errmsg), 744*12373SJan.Parcel@Sun.COM "Cannot add %s on node %s", 745*12373SJan.Parcel@Sun.COM dargs->devinfo->devtype, 746*12373SJan.Parcel@Sun.COM devmapp->dmap_devname); 747*12373SJan.Parcel@Sun.COM syslog(LOG_ERR, "%s", errmsg); 74811529SJan.Parcel@Sun.COM freedmapent(devmapp); 74911529SJan.Parcel@Sun.COM enddmapent(); 75011529SJan.Parcel@Sun.COM return (2); 75111529SJan.Parcel@Sun.COM } 75211529SJan.Parcel@Sun.COM } else 75311529SJan.Parcel@Sun.COM /* add other transaction types as needed */ 75411529SJan.Parcel@Sun.COM return (2); 755*12373SJan.Parcel@Sun.COM } else if ((dargs->optflag & DA_ADD) && 756*12373SJan.Parcel@Sun.COM (stdtype || is_allocatable) && 757*12373SJan.Parcel@Sun.COM dmap_exact_dev(devmapp, dargs->devinfo->devlist, 758*12373SJan.Parcel@Sun.COM &suffix)) { 759*12373SJan.Parcel@Sun.COM /* 760*12373SJan.Parcel@Sun.COM * no dups w/o DA_FORCE, even if type differs, 761*12373SJan.Parcel@Sun.COM * if there is a chance this operation is 762*12373SJan.Parcel@Sun.COM * machine-driven. The 5 "standard types" 763*12373SJan.Parcel@Sun.COM * can be machine-driven adds, and tend to 764*12373SJan.Parcel@Sun.COM * be allocatable. 765*12373SJan.Parcel@Sun.COM */ 766*12373SJan.Parcel@Sun.COM (void) snprintf(errmsg, sizeof (errmsg), 767*12373SJan.Parcel@Sun.COM "Cannot add %s on node %s type %s", 768*12373SJan.Parcel@Sun.COM dargs->devinfo->devtype, 769*12373SJan.Parcel@Sun.COM devmapp->dmap_devname, 770*12373SJan.Parcel@Sun.COM devmapp->dmap_devtype); 771*12373SJan.Parcel@Sun.COM syslog(LOG_ERR, "%s", errmsg); 772*12373SJan.Parcel@Sun.COM freedmapent(devmapp); 773*12373SJan.Parcel@Sun.COM enddmapent(); 774*12373SJan.Parcel@Sun.COM return (2); 775*12373SJan.Parcel@Sun.COM } 77611529SJan.Parcel@Sun.COM 77711529SJan.Parcel@Sun.COM tmp_str = _dmap2strentry(devmapp); 77811529SJan.Parcel@Sun.COM if (tmp_str == NULL) { 77911529SJan.Parcel@Sun.COM freedmapent(devmapp); 78011529SJan.Parcel@Sun.COM enddmapent(); 78111529SJan.Parcel@Sun.COM return (2); 78211529SJan.Parcel@Sun.COM } 78311529SJan.Parcel@Sun.COM /* retaining devmap entry: tmp_str->se_str */ 78411529SJan.Parcel@Sun.COM tmp_str->se_next = NULL; 78511529SJan.Parcel@Sun.COM if (*head_devmapp == NULL) { 78611529SJan.Parcel@Sun.COM *head_devmapp = tail_str = tmp_str; 78711529SJan.Parcel@Sun.COM } else { 78811529SJan.Parcel@Sun.COM tail_str->se_next = tmp_str; 78911529SJan.Parcel@Sun.COM tail_str = tmp_str; 79011529SJan.Parcel@Sun.COM } 79111529SJan.Parcel@Sun.COM freedmapent(devmapp); 79211529SJan.Parcel@Sun.COM } 79311529SJan.Parcel@Sun.COM enddmapent(); 79411529SJan.Parcel@Sun.COM 79511529SJan.Parcel@Sun.COM /* 79611529SJan.Parcel@Sun.COM * No need to rewrite the files if the item to be removed is not 79711529SJan.Parcel@Sun.COM * in the files -- wait for another call on another darg. 79811529SJan.Parcel@Sun.COM */ 79911529SJan.Parcel@Sun.COM if ((dargs->optflag & DA_REMOVE) && !found) 80011529SJan.Parcel@Sun.COM return (0); 80111529SJan.Parcel@Sun.COM 80211529SJan.Parcel@Sun.COM 80311529SJan.Parcel@Sun.COM if (dargs->optflag & DA_ADD) { 804*12373SJan.Parcel@Sun.COM int len; 80511529SJan.Parcel@Sun.COM /* 806*12373SJan.Parcel@Sun.COM * If we got here from an event, or from devfsadm, 807*12373SJan.Parcel@Sun.COM * we know the stored devname is a useless guess, 808*12373SJan.Parcel@Sun.COM * since the files had not been read when the name 809*12373SJan.Parcel@Sun.COM * was chosen, and we don't keep them anywhere else 810*12373SJan.Parcel@Sun.COM * that is sufficiently definitive. 81111529SJan.Parcel@Sun.COM */ 81211529SJan.Parcel@Sun.COM 81311529SJan.Parcel@Sun.COM for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++) 81411529SJan.Parcel@Sun.COM if (!(tmp_bitmap & (1LL << tmp))) 81511529SJan.Parcel@Sun.COM break; 81611529SJan.Parcel@Sun.COM /* Future: support more than 64 hotplug devices per type? */ 81711529SJan.Parcel@Sun.COM if (tmp > DA_MAX_DEVNO) 81811529SJan.Parcel@Sun.COM return (2); 81911529SJan.Parcel@Sun.COM 820*12373SJan.Parcel@Sun.COM /* 821*12373SJan.Parcel@Sun.COM * Let the caller choose the name unless BOTH the name and 822*12373SJan.Parcel@Sun.COM * device type one of: cdrom, floppy, audio, rmdisk, or tape. 823*12373SJan.Parcel@Sun.COM * (or sr, fd for unlabeled) 824*12373SJan.Parcel@Sun.COM */ 825*12373SJan.Parcel@Sun.COM len = strlen(defname); 826*12373SJan.Parcel@Sun.COM if (stdtype && 827*12373SJan.Parcel@Sun.COM (strncmp(dargs->devinfo->devname, defname, len) == 0)) { 828*12373SJan.Parcel@Sun.COM (void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u", 829*12373SJan.Parcel@Sun.COM defname, tmp); 830*12373SJan.Parcel@Sun.COM /* if need to free and safe to free */ 831*12373SJan.Parcel@Sun.COM if (dargs->devinfo->devname != NULL && 832*12373SJan.Parcel@Sun.COM (dargs->optflag & DA_EVENT) != 0) 833*12373SJan.Parcel@Sun.COM free(dargs->devinfo->devname); 834*12373SJan.Parcel@Sun.COM dargs->devinfo->devname = strdup(new_devname); 835*12373SJan.Parcel@Sun.COM } 83611529SJan.Parcel@Sun.COM } 83711529SJan.Parcel@Sun.COM 83811529SJan.Parcel@Sun.COM /* 83911529SJan.Parcel@Sun.COM * Now adjust devalloc list to match devmaps 84011529SJan.Parcel@Sun.COM * Note we now have the correct devname for da_match to use. 84111529SJan.Parcel@Sun.COM */ 84211529SJan.Parcel@Sun.COM setdaent(); 84311529SJan.Parcel@Sun.COM while ((devallocp = getdaent()) != NULL) { 84411529SJan.Parcel@Sun.COM rc = da_match(devallocp, dargs); 84511529SJan.Parcel@Sun.COM if (rc == 1) { 84611529SJan.Parcel@Sun.COM if (dargs->optflag & DA_ADD) { 84711529SJan.Parcel@Sun.COM /* logging is on if DA_EVENT is set */ 84811529SJan.Parcel@Sun.COM if (dargs->optflag & DA_EVENT) { 84911529SJan.Parcel@Sun.COM (void) snprintf(errmsg, sizeof (errmsg), 85011529SJan.Parcel@Sun.COM "%s and %s out of sync," 85111529SJan.Parcel@Sun.COM "%s only in %s.", 85211529SJan.Parcel@Sun.COM DEVALLOC, DEVMAP, 85311529SJan.Parcel@Sun.COM devallocp->da_devname, DEVALLOC); 85411529SJan.Parcel@Sun.COM syslog(LOG_ERR, "%s", errmsg); 85511529SJan.Parcel@Sun.COM } 85611529SJan.Parcel@Sun.COM freedaent(devallocp); 85711529SJan.Parcel@Sun.COM enddaent(); 85811529SJan.Parcel@Sun.COM return (2); 85911529SJan.Parcel@Sun.COM } else if (dargs->optflag & DA_REMOVE) { 86011529SJan.Parcel@Sun.COM /* make list w/o this entry */ 86111529SJan.Parcel@Sun.COM freedaent(devallocp); 86211529SJan.Parcel@Sun.COM continue; 86311529SJan.Parcel@Sun.COM } 86411529SJan.Parcel@Sun.COM } 86511529SJan.Parcel@Sun.COM tmp_str = _da2strentry(dargs, devallocp); 86611529SJan.Parcel@Sun.COM if (tmp_str == NULL) { 86711529SJan.Parcel@Sun.COM freedaent(devallocp); 86811529SJan.Parcel@Sun.COM enddaent(); 86911529SJan.Parcel@Sun.COM return (2); 87011529SJan.Parcel@Sun.COM } 87111529SJan.Parcel@Sun.COM /* retaining devalloc entry: tmp_str->se_str */ 87211529SJan.Parcel@Sun.COM tmp_str->se_next = NULL; 87311529SJan.Parcel@Sun.COM if (*head_devallocp == NULL) { 87411529SJan.Parcel@Sun.COM *head_devallocp = tail_str = tmp_str; 87511529SJan.Parcel@Sun.COM } else { 87611529SJan.Parcel@Sun.COM tail_str->se_next = tmp_str; 87711529SJan.Parcel@Sun.COM tail_str = tmp_str; 87811529SJan.Parcel@Sun.COM } 87911529SJan.Parcel@Sun.COM freedaent(devallocp); 88011529SJan.Parcel@Sun.COM } 88111529SJan.Parcel@Sun.COM enddaent(); 88211529SJan.Parcel@Sun.COM 88311529SJan.Parcel@Sun.COM /* the caller needs to know if a remove needs to rewrite files */ 88411529SJan.Parcel@Sun.COM if (dargs->optflag & DA_REMOVE) 88511529SJan.Parcel@Sun.COM return (1); /* 0 and 2 cases returned earlier */ 88611529SJan.Parcel@Sun.COM 88711529SJan.Parcel@Sun.COM return (0); /* Successful DA_ADD */ 88811529SJan.Parcel@Sun.COM } 889*12373SJan.Parcel@Sun.COM 89011529SJan.Parcel@Sun.COM /* 8911676Sjpk * _build_lists - 89211529SJan.Parcel@Sun.COM * Cycles through all the entries, stores them in memory. removes entries 8931676Sjpk * with the given search_key (device name or type). 8941676Sjpk * returns 0 if given entry not found, 1 if given entry removed, 2 on 8951676Sjpk * error. 8961676Sjpk */ 8971676Sjpk static int 8981676Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp, 8991676Sjpk strentry_t **head_devmapp) 9001676Sjpk { 9011676Sjpk int rc = 0; 902*12373SJan.Parcel@Sun.COM int found = 0; 9031676Sjpk devalloc_t *devallocp; 9041676Sjpk devmap_t *devmapp; 9051676Sjpk strentry_t *tail_str; 9061676Sjpk strentry_t *tmp_str; 9071676Sjpk 9081676Sjpk if (dargs->optflag & DA_MAPS_ONLY) 9091676Sjpk goto dmap_only; 9101676Sjpk 9111676Sjpk /* build device_allocate */ 9121676Sjpk setdaent(); 9131676Sjpk while ((devallocp = getdaent()) != NULL) { 9141676Sjpk rc = da_match(devallocp, dargs); 915*12373SJan.Parcel@Sun.COM /* if in _build_lists and DA_ADD is set, so is DA_FORCE */ 9161676Sjpk if (rc == 0) { 9171676Sjpk tmp_str = _da2strentry(dargs, devallocp); 9181676Sjpk if (tmp_str == NULL) { 9191676Sjpk freedaent(devallocp); 9201676Sjpk enddaent(); 9211676Sjpk return (2); 9221676Sjpk } 9231676Sjpk /* retaining devalloc entry: tmp_str->se_str */ 9241676Sjpk tmp_str->se_next = NULL; 9251676Sjpk if (*head_devallocp == NULL) { 9261676Sjpk *head_devallocp = tail_str = tmp_str; 9271676Sjpk } else { 9281676Sjpk tail_str->se_next = tmp_str; 9291676Sjpk tail_str = tmp_str; 9301676Sjpk } 931*12373SJan.Parcel@Sun.COM } else if (rc == 1) 932*12373SJan.Parcel@Sun.COM found = 1; 933*12373SJan.Parcel@Sun.COM 9341676Sjpk freedaent(devallocp); 9351676Sjpk } 9361676Sjpk enddaent(); 9371676Sjpk 9381676Sjpk dmap_only: 9391676Sjpk if (dargs->optflag & DA_ALLOC_ONLY) 9401676Sjpk return (rc); 9411676Sjpk 9421676Sjpk /* build device_maps */ 9431676Sjpk rc = 0; 9441676Sjpk setdmapent(); 9451676Sjpk while ((devmapp = getdmapent()) != NULL) { 9461676Sjpk rc = dm_match(devmapp, dargs); 9471676Sjpk if (rc == 0) { 94811529SJan.Parcel@Sun.COM tmp_str = _dmap2strentry(devmapp); 9491676Sjpk if (tmp_str == NULL) { 9501676Sjpk freedmapent(devmapp); 9511676Sjpk enddmapent(); 9521676Sjpk return (2); 9531676Sjpk } 9541676Sjpk /* retaining devmap entry: tmp_str->se_str */ 9551676Sjpk tmp_str->se_next = NULL; 9561676Sjpk if (*head_devmapp == NULL) { 9571676Sjpk *head_devmapp = tail_str = tmp_str; 9581676Sjpk } else { 9591676Sjpk tail_str->se_next = tmp_str; 9601676Sjpk tail_str = tmp_str; 9611676Sjpk } 9621676Sjpk } 9631676Sjpk freedmapent(devmapp); 9641676Sjpk } 9651676Sjpk enddmapent(); 9661676Sjpk 967*12373SJan.Parcel@Sun.COM /* later code cleanup may cause the use of "found" in other cases */ 968*12373SJan.Parcel@Sun.COM if (dargs->optflag & DA_REMOVE) 969*12373SJan.Parcel@Sun.COM return (found); 9701676Sjpk return (rc); 9711676Sjpk } 9721676Sjpk 9731676Sjpk /* 9741676Sjpk * _write_defattrs 9751676Sjpk * writes current entries to devalloc_defaults. 9761676Sjpk */ 9771676Sjpk static void 9781676Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent) 9791676Sjpk { 9801676Sjpk strentry_t *tmp_str; 9811676Sjpk 9821676Sjpk for (tmp_str = head_defent; tmp_str != NULL; 9831676Sjpk tmp_str = tmp_str->se_next) { 9841676Sjpk (void) fputs(tmp_str->se_str, fp); 9851676Sjpk (void) fputs("\n", fp); 9861676Sjpk } 9871676Sjpk 9881676Sjpk } 9891676Sjpk 9901676Sjpk /* 9911676Sjpk * _write_device_allocate - 9921676Sjpk * writes current entries in the list to device_allocate. 99311529SJan.Parcel@Sun.COM * frees the strings 9941676Sjpk */ 9951676Sjpk static void 9961676Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp) 9971676Sjpk { 9981676Sjpk int is_on = -1; 99911529SJan.Parcel@Sun.COM strentry_t *tmp_str, *old_str; 10001676Sjpk struct stat dastat; 10011676Sjpk 10021676Sjpk (void) fseek(dafp, (off_t)0, SEEK_SET); 10031676Sjpk 10041676Sjpk /* 10051676Sjpk * if the devalloc on/off string existed before, 10061676Sjpk * put it back before anything else. 10071676Sjpk * we need to check for the string only if the file 10081676Sjpk * exists. 10091676Sjpk */ 10101676Sjpk if (stat(odevalloc, &dastat) == 0) { 10111676Sjpk is_on = da_is_on(); 10121676Sjpk if (is_on == 0) 10131676Sjpk (void) fputs(DA_OFF_STR, dafp); 10141676Sjpk else if (is_on == 1) 10151676Sjpk (void) fputs(DA_ON_STR, dafp); 10161676Sjpk } 10171676Sjpk tmp_str = head_devallocp; 10181676Sjpk while (tmp_str) { 10191676Sjpk (void) fputs(tmp_str->se_str, dafp); 10201676Sjpk (void) fputs("\n", dafp); 102111529SJan.Parcel@Sun.COM old_str = tmp_str; 10221676Sjpk tmp_str = tmp_str->se_next; 102311529SJan.Parcel@Sun.COM free(old_str); 10241676Sjpk } 10251676Sjpk } 10261676Sjpk 10271676Sjpk /* 10281676Sjpk * _write_device_maps - 10291676Sjpk * writes current entries in the list to device_maps. 103011529SJan.Parcel@Sun.COM * and frees the strings 10311676Sjpk */ 10321676Sjpk static void 10331676Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp) 10341676Sjpk { 103511529SJan.Parcel@Sun.COM strentry_t *tmp_str, *old_str; 10361676Sjpk 10371676Sjpk (void) fseek(dmfp, (off_t)0, SEEK_SET); 10381676Sjpk 10391676Sjpk tmp_str = head_devmapp; 10401676Sjpk while (tmp_str) { 10411676Sjpk (void) fputs(tmp_str->se_str, dmfp); 10421676Sjpk (void) fputs("\n", dmfp); 104311529SJan.Parcel@Sun.COM old_str = tmp_str; 10441676Sjpk tmp_str = tmp_str->se_next; 104511529SJan.Parcel@Sun.COM free(old_str); 10461676Sjpk } 10471676Sjpk } 10481676Sjpk 10491676Sjpk /* 10501676Sjpk * _write_new_defattrs 10511676Sjpk * writes the new entry to devalloc_defaults. 10521676Sjpk * returns 0 on success, -1 on error. 10531676Sjpk */ 10541676Sjpk static int 10551676Sjpk _write_new_defattrs(FILE *fp, da_args *dargs) 10561676Sjpk { 10571676Sjpk int count; 10581676Sjpk char *tok = NULL, *tokp = NULL; 10591676Sjpk char *lasts; 10601676Sjpk devinfo_t *devinfo = dargs->devinfo; 10611676Sjpk 10621676Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 10631676Sjpk return (-1); 10641676Sjpk if (!devinfo->devopts) 10651676Sjpk return (0); 10661676Sjpk (void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""), 10671676Sjpk KV_TOKEN_DELIMIT); 106811529SJan.Parcel@Sun.COM if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) { 10691676Sjpk (void) strcpy(tokp, devinfo->devopts); 10701676Sjpk if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) { 10711676Sjpk (void) fprintf(fp, "%s", tok); 10721676Sjpk count = 1; 10731676Sjpk } 10741676Sjpk while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) { 10751676Sjpk if (count) 10761676Sjpk (void) fprintf(fp, "%s", KV_DELIMITER); 10771676Sjpk (void) fprintf(fp, "%s", tok); 10781676Sjpk count++; 10791676Sjpk } 10801676Sjpk } else { 10811676Sjpk (void) fprintf(fp, "%s", devinfo->devopts); 10821676Sjpk } 10831676Sjpk 10841676Sjpk return (0); 10851676Sjpk } 10861676Sjpk 10871676Sjpk /* 10881676Sjpk * _write_new_entry - 10891676Sjpk * writes the new devalloc_t to device_allocate or the new devmap_t to 10901676Sjpk * device_maps. 10911676Sjpk * returns 0 on success, -1 on error. 10921676Sjpk */ 10931676Sjpk static int 10941676Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag) 10951676Sjpk { 10961676Sjpk int count; 10971676Sjpk char *tok = NULL, *tokp = NULL; 10981676Sjpk char *lasts; 10991676Sjpk devinfo_t *devinfo = dargs->devinfo; 11001676Sjpk 11011676Sjpk if (flag & DA_MAPS_ONLY) 11021676Sjpk goto dmap_only; 11031676Sjpk 11041676Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 11051676Sjpk return (-1); 11061676Sjpk 11071676Sjpk (void) fprintf(fp, "%s%s\\\n\t", 11081676Sjpk (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER); 11091676Sjpk (void) fprintf(fp, "%s%s\\\n\t", 11101676Sjpk (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER); 11111676Sjpk if (devinfo->devopts == NULL) { 11121676Sjpk (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, 11131676Sjpk KV_DELIMITER); 11141676Sjpk } else { 111511529SJan.Parcel@Sun.COM if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1)) 111611529SJan.Parcel@Sun.COM != NULL) { 11171676Sjpk (void) strcpy(tokp, devinfo->devopts); 11181676Sjpk if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) != 11191676Sjpk NULL) { 11201676Sjpk (void) fprintf(fp, "%s", tok); 11211676Sjpk count = 1; 11221676Sjpk } 11231676Sjpk while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, 11241676Sjpk &lasts)) != NULL) { 11251676Sjpk if (count) 11261676Sjpk (void) fprintf(fp, "%s", 11271676Sjpk KV_TOKEN_DELIMIT "\\\n\t"); 11281676Sjpk (void) fprintf(fp, "%s", tok); 11291676Sjpk count++; 11301676Sjpk } 11311676Sjpk if (count) 11321676Sjpk (void) fprintf(fp, "%s", 11331676Sjpk KV_DELIMITER "\\\n\t"); 11341676Sjpk } else { 11351676Sjpk (void) fprintf(fp, "%s%s", devinfo->devopts, 11361676Sjpk KV_DELIMITER "\\\n\t"); 11371676Sjpk } 11381676Sjpk } 11391676Sjpk (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER); 11401676Sjpk (void) fprintf(fp, "%s%s\\\n\t", 11411676Sjpk (devinfo->devauths ? devinfo->devauths : DA_ANYUSER), 11421676Sjpk KV_DELIMITER); 11431676Sjpk (void) fprintf(fp, "%s\n", 11441676Sjpk (devinfo->devexec ? devinfo->devexec : KV_DELIMITER)); 11451676Sjpk 11461676Sjpk dmap_only: 11471676Sjpk if (flag & DA_ALLOC_ONLY) 11481676Sjpk return (0); 11491676Sjpk 11501676Sjpk if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) 11511676Sjpk return (-1); 11521676Sjpk 11531676Sjpk (void) fprintf(fp, "%s%s\\\n", 11541676Sjpk (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT); 11551676Sjpk (void) fprintf(fp, "\t%s%s\\\n", 11561676Sjpk (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT); 11571676Sjpk (void) fprintf(fp, "\t%s\n", 11581676Sjpk (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT)); 11591676Sjpk 11601676Sjpk return (0); 11611676Sjpk } 11621676Sjpk 11631676Sjpk /* 11641676Sjpk * _da_lock_devdb - 11651676Sjpk * locks the database files; lock can be either broken explicitly by 11661676Sjpk * closing the fd of the lock file, or it expires automatically at process 11671676Sjpk * termination. 11681676Sjpk * returns fd of the lock file or -1 on error. 11691676Sjpk */ 11701676Sjpk int 11711676Sjpk _da_lock_devdb(char *rootdir) 11721676Sjpk { 11731676Sjpk int lockfd = -1; 11744514Saj int ret; 11754514Saj int count = 0; 11764514Saj int retry = 10; 11774514Saj int retry_sleep; 11784514Saj uint_t seed; 11791676Sjpk char *lockfile; 11801676Sjpk char path[MAXPATHLEN]; 11811676Sjpk int size = sizeof (path); 11821676Sjpk 11831676Sjpk if (rootdir == NULL) { 11841676Sjpk lockfile = DA_DB_LOCK; 11851676Sjpk } else { 11861676Sjpk path[0] = '\0'; 11871676Sjpk if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size) 11881676Sjpk return (-1); 11891676Sjpk lockfile = path; 11901676Sjpk } 11911676Sjpk 11921676Sjpk if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) 11931676Sjpk /* cannot open lock file */ 11941676Sjpk return (-1); 11951676Sjpk 11961676Sjpk (void) fchown(lockfd, DA_UID, DA_GID); 11971676Sjpk 11981676Sjpk if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) { 11991676Sjpk /* cannot position lock file */ 12001676Sjpk (void) close(lockfd); 12011676Sjpk return (-1); 12021676Sjpk } 12034514Saj errno = 0; 12044514Saj while (retry > 0) { 12054514Saj count++; 12064514Saj seed = (uint_t)gethrtime(); 12074514Saj ret = lockf(lockfd, F_TLOCK, 0); 12084514Saj if (ret == 0) { 12094514Saj (void) utime(lockfile, NULL); 12104514Saj return (lockfd); 12114514Saj } 12124514Saj if ((errno != EACCES) && (errno != EAGAIN)) { 12134514Saj /* cannot set lock */ 12144514Saj (void) close(lockfd); 12154514Saj return (-1); 12164514Saj } 12174514Saj retry--; 12184514Saj retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count; 12194514Saj (void) sleep(retry_sleep); 12204514Saj errno = 0; 12211676Sjpk } 12221676Sjpk 12234514Saj return (-1); 12241676Sjpk } 12251676Sjpk 12261676Sjpk /* 12271676Sjpk * da_open_devdb - 12281676Sjpk * opens one or both database files - device_allocate, device_maps - in 12291676Sjpk * the specified mode. 12301676Sjpk * locks the database files; lock is either broken explicitly by the 12311676Sjpk * caller by closing the lock file fd, or it expires automatically at 12321676Sjpk * process termination. 12331676Sjpk * writes the file pointer of opened file in the input args - dafp, dmfp. 12341676Sjpk * returns fd of the lock file on success, -2 if database file does not 12351676Sjpk * exist, -1 on other errors. 12361676Sjpk */ 12371676Sjpk int 12381676Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag) 12391676Sjpk { 12401676Sjpk int oflag = 0; 12411676Sjpk int fda = -1; 12421676Sjpk int fdm = -1; 12431676Sjpk int lockfd = -1; 12441676Sjpk char *fname; 12451676Sjpk char *fmode; 12461676Sjpk char path[MAXPATHLEN]; 12471676Sjpk FILE *devfile; 12481676Sjpk 12491676Sjpk if ((dafp == NULL) && (dmfp == NULL)) 12501676Sjpk return (-1); 12511676Sjpk 12521676Sjpk if (flag & DA_RDWR) { 12531676Sjpk oflag = DA_RDWR; 12541914Scasper fmode = "r+F"; 12551676Sjpk } else if (flag & DA_RDONLY) { 12561676Sjpk oflag = DA_RDONLY; 12571914Scasper fmode = "rF"; 12581676Sjpk } 12591676Sjpk 12601676Sjpk if ((lockfd = _da_lock_devdb(rootdir)) == -1) 12611676Sjpk return (-1); 12621676Sjpk 12631676Sjpk if ((dafp == NULL) || (flag & DA_MAPS_ONLY)) 12641676Sjpk goto dmap_only; 12651676Sjpk 12661676Sjpk path[0] = '\0'; 12671676Sjpk 12681676Sjpk /* 12691676Sjpk * open the device allocation file 12701676Sjpk */ 12711676Sjpk if (rootdir == NULL) { 12721676Sjpk fname = DEVALLOC; 12731676Sjpk } else { 12741676Sjpk if (snprintf(path, sizeof (path), "%s%s", rootdir, 12751676Sjpk DEVALLOC) >= sizeof (path)) { 12761676Sjpk if (lockfd != -1) 12771676Sjpk (void) close(lockfd); 12781676Sjpk return (-1); 12791676Sjpk } 12801676Sjpk fname = path; 12811676Sjpk } 12821676Sjpk if ((fda = open(fname, oflag, DA_DBMODE)) == -1) { 12831676Sjpk if (lockfd != -1) 12841676Sjpk (void) close(lockfd); 12851676Sjpk return ((errno == ENOENT) ? -2 : -1); 12861676Sjpk } 12871676Sjpk if ((devfile = fdopen(fda, fmode)) == NULL) { 12881676Sjpk (void) close(fda); 12891676Sjpk if (lockfd != -1) 12901676Sjpk (void) close(lockfd); 12911676Sjpk return (-1); 12921676Sjpk } 12931676Sjpk *dafp = devfile; 12941676Sjpk (void) fchmod(fda, DA_DBMODE); 12951676Sjpk 12961676Sjpk if ((flag & DA_ALLOC_ONLY)) 12971676Sjpk goto out; 12981676Sjpk 12991676Sjpk dmap_only: 13001676Sjpk path[0] = '\0'; 13011676Sjpk /* 13021676Sjpk * open the device map file 13031676Sjpk */ 13041676Sjpk if (rootdir == NULL) { 13051676Sjpk fname = DEVMAP; 13061676Sjpk } else { 13071676Sjpk if (snprintf(path, sizeof (path), "%s%s", rootdir, 13081676Sjpk DEVMAP) >= sizeof (path)) { 13091676Sjpk (void) close(fda); 13101676Sjpk if (lockfd != -1) 13111676Sjpk (void) close(lockfd); 13121676Sjpk return (-1); 13131676Sjpk } 13141676Sjpk fname = path; 13151676Sjpk } 13161676Sjpk 13171676Sjpk if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) { 13181676Sjpk if (lockfd != -1) 13191676Sjpk (void) close(lockfd); 13201676Sjpk return ((errno == ENOENT) ? -2 : -1); 13211676Sjpk } 13221676Sjpk 13231676Sjpk if ((devfile = fdopen(fdm, fmode)) == NULL) { 13241676Sjpk (void) close(fdm); 13251676Sjpk (void) close(fda); 13261676Sjpk if (lockfd != -1) 13271676Sjpk (void) close(lockfd); 13281676Sjpk return (-1); 13291676Sjpk } 13301676Sjpk *dmfp = devfile; 13311676Sjpk (void) fchmod(fdm, DA_DBMODE); 13321676Sjpk 13331676Sjpk out: 13341676Sjpk return (lockfd); 13351676Sjpk } 13361676Sjpk 13371676Sjpk /* 13381676Sjpk * _record_on_off - 13391676Sjpk * adds either DA_ON_STR or DA_OFF_STR to device_allocate 13401676Sjpk * returns 0 on success, -1 on error. 13411676Sjpk */ 13421676Sjpk static int 13431676Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp) 13441676Sjpk { 13451676Sjpk int dafd; 13461676Sjpk int nsize; 13471676Sjpk int nitems = 1; 13481676Sjpk int actionlen; 13491676Sjpk int str_found = 0; 13501676Sjpk int len = 0, nlen = 0, plen = 0; 13511676Sjpk char *ptr = NULL; 13521676Sjpk char *actionstr; 13531676Sjpk char *nbuf = NULL; 13541676Sjpk char line[MAX_CANON]; 13551676Sjpk struct stat dastat; 13561676Sjpk 13571676Sjpk if (dargs->optflag & DA_ON) 13581676Sjpk actionstr = DA_ON_STR; 13591676Sjpk else 13601676Sjpk actionstr = DA_OFF_STR; 13611676Sjpk actionlen = strlen(actionstr); 13621676Sjpk dafd = fileno(dafp); 13631676Sjpk if (fstat(dafd, &dastat) == -1) 13641676Sjpk return (-1); 13651676Sjpk 13661676Sjpk /* check the old device_allocate for on/off string */ 13671676Sjpk ptr = fgets(line, MAX_CANON, dafp); 13681676Sjpk if (ptr != NULL) { 13691676Sjpk if ((strcmp(line, DA_ON_STR) == 0) || 13701676Sjpk (strcmp(line, DA_OFF_STR) == 0)) { 13711676Sjpk str_found = 1; 13721676Sjpk nsize = dastat.st_size; 13731676Sjpk } 13741676Sjpk } 13751676Sjpk if (!ptr || !str_found) { 13761676Sjpk /* 13771676Sjpk * the file never had either the on or the off string; 13781676Sjpk * make room for it. 13791676Sjpk */ 13801676Sjpk str_found = 0; 13811676Sjpk nsize = dastat.st_size + actionlen + 1; 13821676Sjpk } 138311529SJan.Parcel@Sun.COM if ((nbuf = (char *)malloc(nsize + 1)) == NULL) 13841676Sjpk return (-1); 13851676Sjpk nbuf[0] = '\0'; 13861676Sjpk /* put the on/off string */ 13871676Sjpk (void) strcpy(nbuf, actionstr); 13881676Sjpk nlen = strlen(nbuf); 13891676Sjpk plen = nlen; 13901676Sjpk if (ptr && !str_found) { 13911676Sjpk /* now put the first line that we read in fgets */ 13921676Sjpk nlen = plen + strlen(line) + 1; 13931676Sjpk len = snprintf(nbuf + plen, nlen - plen, "%s", line); 13941676Sjpk if (len >= nsize) { 13951676Sjpk free(nbuf); 13961676Sjpk return (-1); 13971676Sjpk } 13981676Sjpk plen += len; 13991676Sjpk } 14001676Sjpk 14011676Sjpk /* now get the rest of the old file */ 14021676Sjpk while (fgets(line, MAX_CANON, dafp) != NULL) { 14031676Sjpk nlen = plen + strlen(line) + 1; 14041676Sjpk len = snprintf(nbuf + plen, nlen - plen, "%s", line); 14051676Sjpk if (len >= nsize) { 14061676Sjpk free(nbuf); 14071676Sjpk return (-1); 14081676Sjpk } 14091676Sjpk plen += len; 14101676Sjpk } 14111676Sjpk len = strlen(nbuf) + 1; 14121676Sjpk if (len < nsize) 14131676Sjpk nbuf[len] = '\n'; 14141676Sjpk 14151676Sjpk /* write the on/off str + the old device_allocate to the temp file */ 14161676Sjpk if (fwrite(nbuf, nsize, nitems, tafp) < nitems) { 14171676Sjpk free(nbuf); 14181676Sjpk return (-1); 14191676Sjpk } 14201676Sjpk 14211676Sjpk free(nbuf); 14221676Sjpk 14231676Sjpk return (0); 14241676Sjpk } 14251676Sjpk 14261676Sjpk /* 14271676Sjpk * da_update_defattrs - 14281676Sjpk * writes default attributes to devalloc_defaults 14291676Sjpk * returns 0 on success, -1 on error. 14301676Sjpk */ 14311676Sjpk int 14321676Sjpk da_update_defattrs(da_args *dargs) 14331676Sjpk { 14341676Sjpk int rc = 0, lockfd = 0, tmpfd = 0; 14351676Sjpk char *defpath = DEFATTRS; 14361676Sjpk char *tmpdefpath = TMPATTRS; 14371676Sjpk FILE *tmpfp = NULL; 14381676Sjpk struct stat dstat; 14391676Sjpk strentry_t *head_defent = NULL; 14401676Sjpk 14411676Sjpk if (dargs == NULL) 14421676Sjpk return (0); 14431676Sjpk if ((lockfd = _da_lock_devdb(NULL)) == -1) 14441676Sjpk return (-1); 14451676Sjpk if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 14461676Sjpk (void) close(lockfd); 14471676Sjpk return (-1); 14481676Sjpk } 14491676Sjpk (void) fchown(tmpfd, DA_UID, DA_GID); 14501676Sjpk if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) { 14511676Sjpk (void) close(tmpfd); 14521676Sjpk (void) unlink(tmpdefpath); 14531676Sjpk (void) close(lockfd); 14541676Sjpk return (-1); 14551676Sjpk } 14561676Sjpk /* 14571676Sjpk * examine all entries, remove an old one if required, check 14581676Sjpk * if a new one needs to be added. 14591676Sjpk */ 14601676Sjpk if (stat(defpath, &dstat) == 0) { 14611676Sjpk if ((rc = _build_defattrs(dargs, &head_defent)) != 0) { 14621676Sjpk if (rc == 1) { 14631676Sjpk (void) close(tmpfd); 14641676Sjpk (void) unlink(tmpdefpath); 14651676Sjpk (void) close(lockfd); 14661676Sjpk return (rc); 14671676Sjpk } 14681676Sjpk } 14691676Sjpk } 14701676Sjpk /* 14711676Sjpk * write back any existing entries. 14721676Sjpk */ 14731676Sjpk _write_defattrs(tmpfp, head_defent); 14741676Sjpk 14751676Sjpk if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 14761676Sjpk /* add new entries */ 14771676Sjpk rc = _write_new_defattrs(tmpfp, dargs); 14781676Sjpk (void) fclose(tmpfp); 14791676Sjpk } else { 14801676Sjpk (void) fclose(tmpfp); 14811676Sjpk } 14821676Sjpk if (rename(tmpdefpath, defpath) != 0) { 14831676Sjpk rc = -1; 14841676Sjpk (void) unlink(tmpdefpath); 14851676Sjpk } 14861676Sjpk (void) close(lockfd); 14871676Sjpk 14881676Sjpk return (rc); 14891676Sjpk } 14901676Sjpk 14911676Sjpk /* 14921676Sjpk * da_update_device - 149311529SJan.Parcel@Sun.COM * Writes existing entries and the SINGLE change requested by da_args, 1494*12373SJan.Parcel@Sun.COM * to device_allocate and device_maps. 1495*12373SJan.Parcel@Sun.COM * Returns 0 on success, -1 on error. 14961676Sjpk */ 14971676Sjpk int 14981676Sjpk da_update_device(da_args *dargs) 14991676Sjpk { 15001676Sjpk int rc; 15011676Sjpk int tafd = -1, tmfd = -1; 15021676Sjpk int lockfd = -1; 15031676Sjpk char *rootdir = NULL; 15044514Saj char *apathp = NULL, *mpathp = NULL; 15054514Saj char *dapathp = NULL, *dmpathp = NULL; 15064514Saj char apath[MAXPATHLEN], mpath[MAXPATHLEN]; 15074514Saj char dapath[MAXPATHLEN], dmpath[MAXPATHLEN]; 15081676Sjpk FILE *tafp = NULL, *tmfp = NULL, *dafp = NULL; 15091676Sjpk struct stat dastat; 15101676Sjpk devinfo_t *devinfo; 15111676Sjpk strentry_t *head_devmapp = NULL; 15121676Sjpk strentry_t *head_devallocp = NULL; 15131676Sjpk 15141676Sjpk if (dargs == NULL) 15151676Sjpk return (0); 15161676Sjpk 15171676Sjpk rootdir = dargs->rootdir; 15181676Sjpk devinfo = dargs->devinfo; 15191676Sjpk 15201676Sjpk /* 15211676Sjpk * adding/removing entries should be done in both 15221676Sjpk * device_allocate and device_maps. updates can be 15231676Sjpk * done in both or either of the files. 15241676Sjpk */ 15251676Sjpk if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) { 15261676Sjpk if (dargs->optflag & DA_ALLOC_ONLY || 15271676Sjpk dargs->optflag & DA_MAPS_ONLY) 15281676Sjpk return (0); 15291676Sjpk } 15301676Sjpk 15311676Sjpk /* 15321676Sjpk * name, type and list are required fields for adding a new 15331676Sjpk * device. 15341676Sjpk */ 15351676Sjpk if ((dargs->optflag & DA_ADD) && 15361676Sjpk ((devinfo->devname == NULL) || 15371676Sjpk (devinfo->devtype == NULL) || 15381676Sjpk (devinfo->devlist == NULL))) { 15391676Sjpk return (-1); 15401676Sjpk } 15411676Sjpk 15421676Sjpk if (rootdir != NULL) { 15431676Sjpk if (snprintf(apath, sizeof (apath), "%s%s", rootdir, 15441676Sjpk TMPALLOC) >= sizeof (apath)) 15451676Sjpk return (-1); 15461676Sjpk apathp = apath; 15471676Sjpk if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir, 15481676Sjpk DEVALLOC) >= sizeof (dapath)) 15491676Sjpk return (-1); 15501676Sjpk dapathp = dapath; 15511676Sjpk if (!(dargs->optflag & DA_ALLOC_ONLY)) { 15521676Sjpk if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir, 15531676Sjpk TMPMAP) >= sizeof (mpath)) 15541676Sjpk return (-1); 15551676Sjpk mpathp = mpath; 15561676Sjpk if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir, 15571676Sjpk DEVMAP) >= sizeof (dmpath)) 15581676Sjpk return (-1); 15591676Sjpk dmpathp = dmpath; 15601676Sjpk } 15611676Sjpk } else { 15621676Sjpk apathp = TMPALLOC; 15631676Sjpk dapathp = DEVALLOC; 15641676Sjpk mpathp = TMPMAP; 15651676Sjpk dmpathp = DEVMAP; 15661676Sjpk } 15671676Sjpk 15681676Sjpk if (dargs->optflag & DA_MAPS_ONLY) 15691676Sjpk goto dmap_only; 15701676Sjpk 15711676Sjpk /* 15721676Sjpk * Check if we are here just to record on/off status of 15731676Sjpk * device_allocation. 15741676Sjpk */ 15751676Sjpk if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) 15761676Sjpk lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL, 15771676Sjpk DA_RDONLY|DA_ALLOC_ONLY); 15781676Sjpk else 15791676Sjpk lockfd = _da_lock_devdb(rootdir); 15801676Sjpk if (lockfd == -1) 15811676Sjpk return (-1); 15821676Sjpk 15831676Sjpk if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 15841676Sjpk (void) close(lockfd); 15851676Sjpk (void) fclose(dafp); 15861676Sjpk return (-1); 15871676Sjpk } 15881676Sjpk (void) fchown(tafd, DA_UID, DA_GID); 15891676Sjpk if ((tafp = fdopen(tafd, "r+")) == NULL) { 15901676Sjpk (void) close(tafd); 15911676Sjpk (void) unlink(apathp); 15921676Sjpk (void) fclose(dafp); 15931676Sjpk (void) close(lockfd); 15941676Sjpk return (-1); 15951676Sjpk } 15961676Sjpk 15971676Sjpk /* 15981676Sjpk * We don't need to parse the file if we are here just to record 15991676Sjpk * on/off status of device_allocation. 16001676Sjpk */ 16011676Sjpk if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) { 16021676Sjpk if (_record_on_off(dargs, tafp, dafp) == -1) { 16031676Sjpk (void) close(tafd); 16041676Sjpk (void) unlink(apathp); 16051676Sjpk (void) fclose(dafp); 16061676Sjpk (void) close(lockfd); 16071676Sjpk return (-1); 16081676Sjpk } 16091676Sjpk (void) fclose(dafp); 16101676Sjpk goto out; 16111676Sjpk } 16121676Sjpk 16131676Sjpk /* 161411529SJan.Parcel@Sun.COM * If reacting to a hotplug, read the file entries, 161511529SJan.Parcel@Sun.COM * figure out what dname (tname + a new number) goes to the 161611529SJan.Parcel@Sun.COM * device being added/removed, and create a good head_devallocp and 161711529SJan.Parcel@Sun.COM * head_devmapp with everything good still in it (_rebuild_lists) 161811529SJan.Parcel@Sun.COM * 161911529SJan.Parcel@Sun.COM * Else examine all the entries, remove an old one if it is 162011529SJan.Parcel@Sun.COM * a duplicate with a device being added, returning the 162111529SJan.Parcel@Sun.COM * remaining list (_build_lists.) 162211529SJan.Parcel@Sun.COM * 162311529SJan.Parcel@Sun.COM * We need to do this only if the file exists already. 162411529SJan.Parcel@Sun.COM * 162511529SJan.Parcel@Sun.COM * Once we have built these lists, we need to free the strings 162611529SJan.Parcel@Sun.COM * in the head_* arrays before returning. 16271676Sjpk */ 16281676Sjpk if (stat(dapathp, &dastat) == 0) { 162911529SJan.Parcel@Sun.COM /* for device allocation, the /etc files are the "master" */ 163011529SJan.Parcel@Sun.COM if ((dargs->optflag & (DA_ADD| DA_EVENT)) && 163111529SJan.Parcel@Sun.COM (!(dargs->optflag & DA_FORCE))) 163211529SJan.Parcel@Sun.COM rc = _rebuild_lists(dargs, &head_devallocp, 163311529SJan.Parcel@Sun.COM &head_devmapp); 163411529SJan.Parcel@Sun.COM else 163511529SJan.Parcel@Sun.COM rc = _build_lists(dargs, &head_devallocp, 163611529SJan.Parcel@Sun.COM &head_devmapp); 163711529SJan.Parcel@Sun.COM 163811529SJan.Parcel@Sun.COM if (rc != 0 && rc != 1) { 163911529SJan.Parcel@Sun.COM (void) close(tafd); 164011529SJan.Parcel@Sun.COM (void) unlink(apathp); 164111529SJan.Parcel@Sun.COM (void) close(lockfd); 164211529SJan.Parcel@Sun.COM return (-1); 16431676Sjpk } 164411529SJan.Parcel@Sun.COM } else 164511529SJan.Parcel@Sun.COM rc = 0; 164611529SJan.Parcel@Sun.COM 164711529SJan.Parcel@Sun.COM if ((dargs->optflag & DA_REMOVE) && (rc == 0)) { 164811529SJan.Parcel@Sun.COM (void) close(tafd); 164911529SJan.Parcel@Sun.COM (void) unlink(apathp); 165011529SJan.Parcel@Sun.COM (void) close(lockfd); 165111529SJan.Parcel@Sun.COM return (0); 16521676Sjpk } 165311529SJan.Parcel@Sun.COM /* 165411529SJan.Parcel@Sun.COM * TODO: clean up the workings of DA_UPDATE. 165511529SJan.Parcel@Sun.COM * Due to da_match looking at fields that are missing 165611529SJan.Parcel@Sun.COM * in dargs for DA_UPDATE, the da_match call returns no match, 165711529SJan.Parcel@Sun.COM * but due to the way _da2str combines the devalloc_t info with 165811529SJan.Parcel@Sun.COM * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work. 165911529SJan.Parcel@Sun.COM * 166011529SJan.Parcel@Sun.COM * This would not scale if any type of update was ever needed 166111529SJan.Parcel@Sun.COM * from the daemon. 166211529SJan.Parcel@Sun.COM */ 16631676Sjpk 16641676Sjpk /* 166511529SJan.Parcel@Sun.COM * Write out devallocp along with the devalloc on/off string. 16661676Sjpk */ 16671676Sjpk _write_device_allocate(dapathp, tafp, head_devallocp); 16681676Sjpk 16691676Sjpk if (dargs->optflag & DA_ALLOC_ONLY) 16701676Sjpk goto out; 16711676Sjpk 16721676Sjpk dmap_only: 16731676Sjpk if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { 16741676Sjpk (void) close(tafd); 16751676Sjpk (void) unlink(apathp); 16761676Sjpk (void) close(lockfd); 16771676Sjpk return (-1); 16781676Sjpk } 16791676Sjpk (void) fchown(tmfd, DA_UID, DA_GID); 16801676Sjpk if ((tmfp = fdopen(tmfd, "r+")) == NULL) { 16811676Sjpk (void) close(tafd); 16821676Sjpk (void) unlink(apathp); 16831676Sjpk (void) close(tmfd); 16841676Sjpk (void) unlink(mpathp); 16851676Sjpk (void) close(lockfd); 16861676Sjpk return (-1); 16871676Sjpk } 16881676Sjpk 168911529SJan.Parcel@Sun.COM /* 169011529SJan.Parcel@Sun.COM * Write back any non-removed pre-existing entries. 169111529SJan.Parcel@Sun.COM */ 16921676Sjpk if (head_devmapp != NULL) 16931676Sjpk _write_device_maps(tmfp, head_devmapp); 16941676Sjpk 16951676Sjpk out: 169611529SJan.Parcel@Sun.COM /* 169711529SJan.Parcel@Sun.COM * Add any new entries here. 169811529SJan.Parcel@Sun.COM */ 16991676Sjpk if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { 17001676Sjpk /* add any new entries */ 17011676Sjpk rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY); 17021676Sjpk (void) fclose(tafp); 17031676Sjpk 17041676Sjpk if (rc == 0) 17051676Sjpk rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY); 17061676Sjpk (void) fclose(tmfp); 17071676Sjpk } else { 17081676Sjpk if (tafp) 17091676Sjpk (void) fclose(tafp); 17101676Sjpk if (tmfp) 17111676Sjpk (void) fclose(tmfp); 17121676Sjpk } 17131676Sjpk 17141676Sjpk rc = 0; 17151676Sjpk if (!(dargs->optflag & DA_MAPS_ONLY)) { 17161676Sjpk if (rename(apathp, dapathp) != 0) { 17171676Sjpk rc = -1; 17181676Sjpk (void) unlink(apathp); 17191676Sjpk } 17201676Sjpk } 17211676Sjpk if (!(dargs->optflag & DA_ALLOC_ONLY)) { 17221676Sjpk if (rename(mpathp, dmpathp) != 0) { 17231676Sjpk rc = -1; 17241676Sjpk (void) unlink(mpathp); 17251676Sjpk } 17261676Sjpk } 17271676Sjpk 17281676Sjpk (void) close(lockfd); 17291676Sjpk 17301676Sjpk return (rc); 17311676Sjpk } 17321676Sjpk 17331676Sjpk /* 17341676Sjpk * da_add_list - 17351676Sjpk * adds new /dev link name to the linked list of devices. 17361676Sjpk * returns 0 if link added successfully, -1 on error. 17371676Sjpk */ 17381676Sjpk int 17391676Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) 17401676Sjpk { 17411676Sjpk int instance; 17421676Sjpk int nlen, plen; 17431676Sjpk int new_entry = 0; 17441676Sjpk char *dtype, *dexec, *tname, *kval; 17451676Sjpk char *minstr = NULL, *maxstr = NULL; 174611529SJan.Parcel@Sun.COM char dname[DA_MAXNAME + 1]; 17471676Sjpk kva_t *kva; 17481676Sjpk deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL; 17491676Sjpk da_defs_t *da_defs; 17501676Sjpk 17511676Sjpk if (dlist == NULL || link == NULL) 17521676Sjpk return (-1); 17531676Sjpk 17541676Sjpk dname[0] = '\0'; 17551676Sjpk if (flag & DA_AUDIO) { 17561676Sjpk dentry = dlist->audio; 17571676Sjpk tname = DA_AUDIO_NAME; 17581676Sjpk dtype = DA_AUDIO_TYPE; 17591676Sjpk dexec = DA_DEFAULT_AUDIO_CLEAN; 17601676Sjpk } else if (flag & DA_CD) { 17611676Sjpk dentry = dlist->cd; 17621676Sjpk tname = DA_CD_NAME; 17631676Sjpk dtype = DA_CD_TYPE; 17641676Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 17651676Sjpk } else if (flag & DA_FLOPPY) { 17661676Sjpk dentry = dlist->floppy; 17671676Sjpk tname = DA_FLOPPY_NAME; 17681676Sjpk dtype = DA_FLOPPY_TYPE; 17691676Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 17701676Sjpk } else if (flag & DA_TAPE) { 17711676Sjpk dentry = dlist->tape; 17721676Sjpk tname = DA_TAPE_NAME; 17731676Sjpk dtype = DA_TAPE_TYPE; 17741676Sjpk dexec = DA_DEFAULT_TAPE_CLEAN; 17751676Sjpk } else if (flag & DA_RMDISK) { 17761676Sjpk dentry = dlist->rmdisk; 17771676Sjpk tname = DA_RMDISK_NAME; 17781676Sjpk dtype = DA_RMDISK_TYPE; 17791676Sjpk dexec = DA_DEFAULT_DISK_CLEAN; 17801676Sjpk } else { 17811676Sjpk return (-1); 17821676Sjpk } 17831676Sjpk 17841676Sjpk for (nentry = dentry; nentry != NULL; nentry = nentry->next) { 17851676Sjpk pentry = nentry; 17861676Sjpk (void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance); 17871676Sjpk if (nentry->devinfo.instance == new_instance) 17881676Sjpk /* 17891676Sjpk * Add the new link name to the list of links 17901676Sjpk * that the device 'dname' has. 17911676Sjpk */ 17921676Sjpk break; 17931676Sjpk } 17941676Sjpk 17951676Sjpk if (nentry == NULL) { 17961676Sjpk /* 17971676Sjpk * Either this is the first entry ever, or no matching entry 17981676Sjpk * was found. Create a new one and add to the list. 17991676Sjpk */ 18001676Sjpk if (dentry == NULL) /* first entry ever */ 18011676Sjpk instance = 0; 18021676Sjpk else /* no matching entry */ 18031676Sjpk instance++; 18041676Sjpk (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance); 18051676Sjpk if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) == 18061676Sjpk NULL) 18071676Sjpk return (-1); 18081676Sjpk if (pentry != NULL) 18091676Sjpk pentry->next = nentry; 18101676Sjpk new_entry = 1; 18111676Sjpk nentry->devinfo.devname = strdup(dname); 18121676Sjpk nentry->devinfo.devtype = dtype; 18131676Sjpk nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH; 18141676Sjpk nentry->devinfo.devexec = dexec; 18151676Sjpk nentry->devinfo.instance = new_instance; 18161676Sjpk /* 18171676Sjpk * Look for default label range, authorizations and cleaning 18181676Sjpk * program in devalloc_defaults. If label range is not 18191676Sjpk * specified in devalloc_defaults, assume it to be admin_low 18201676Sjpk * to admin_high. 18211676Sjpk */ 18221676Sjpk minstr = DA_DEFAULT_MIN; 18231676Sjpk maxstr = DA_DEFAULT_MAX; 18241676Sjpk setdadefent(); 18251676Sjpk if (da_defs = getdadeftype(nentry->devinfo.devtype)) { 18261676Sjpk kva = da_defs->devopts; 18271676Sjpk if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL) 18281676Sjpk minstr = strdup(kval); 18291676Sjpk if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL) 18301676Sjpk maxstr = strdup(kval); 18311676Sjpk if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL) 18321676Sjpk nentry->devinfo.devauths = strdup(kval); 18331676Sjpk if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL) 18341676Sjpk nentry->devinfo.devexec = strdup(kval); 18351676Sjpk freedadefent(da_defs); 18361676Sjpk } 18371676Sjpk enddadefent(); 18381676Sjpk kval = NULL; 18391676Sjpk nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) + 18401676Sjpk strlen(minstr) + strlen(KV_TOKEN_DELIMIT) + 18411676Sjpk strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr) 18421676Sjpk + 1; /* +1 for terminator */ 18431676Sjpk if (kval = (char *)malloc(nlen)) 18441676Sjpk (void) snprintf(kval, nlen, "%s%s%s%s%s%s%s", 18451676Sjpk DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT, 18461676Sjpk DAOPT_MAXLABEL, KV_ASSIGN, maxstr); 18471676Sjpk nentry->devinfo.devopts = kval; 18481676Sjpk 18491676Sjpk nentry->devinfo.devlist = NULL; 18501676Sjpk nentry->next = NULL; 18511676Sjpk } 18521676Sjpk 18531676Sjpk nlen = strlen(link) + 1; /* +1 terminator */ 18541676Sjpk if (nentry->devinfo.devlist) { 18551676Sjpk plen = strlen(nentry->devinfo.devlist); 18561676Sjpk nlen = nlen + plen + 1; /* +1 for blank to separate entries */ 18571676Sjpk } else { 18581676Sjpk plen = 0; 18591676Sjpk } 18601676Sjpk 18611676Sjpk if ((nentry->devinfo.devlist = 18621676Sjpk (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) { 18631676Sjpk if (new_entry) { 18641676Sjpk free(nentry->devinfo.devname); 18651676Sjpk free(nentry); 18661676Sjpk if (pentry != NULL) 18671676Sjpk pentry->next = NULL; 18681676Sjpk } 18691676Sjpk return (-1); 18701676Sjpk } 18711676Sjpk 18721676Sjpk if (plen == 0) 18731676Sjpk (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link); 18741676Sjpk else 18751676Sjpk (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen, 18761676Sjpk " %s", link); 18771676Sjpk 18781676Sjpk if (pentry == NULL) { 18791676Sjpk /* 18801676Sjpk * This is the first entry of this device type. 18811676Sjpk */ 18821676Sjpk if (flag & DA_AUDIO) 18831676Sjpk dlist->audio = nentry; 18841676Sjpk else if (flag & DA_CD) 18851676Sjpk dlist->cd = nentry; 18861676Sjpk else if (flag & DA_FLOPPY) 18871676Sjpk dlist->floppy = nentry; 18881676Sjpk else if (flag & DA_TAPE) 18891676Sjpk dlist->tape = nentry; 18901676Sjpk else if (flag & DA_RMDISK) 18911676Sjpk dlist->rmdisk = nentry; 18921676Sjpk } 18931676Sjpk 18941676Sjpk return (0); 18951676Sjpk } 18961676Sjpk 18971676Sjpk /* 18981676Sjpk * da_remove_list - 18991676Sjpk * removes a /dev link name from the linked list of devices. 19001676Sjpk * returns type of device if link for that device removed 19011676Sjpk * successfully, else returns -1 on error. 19021676Sjpk * if all links for a device are removed, stores that device 19031676Sjpk * name in devname. 19041676Sjpk */ 19051676Sjpk int 19061676Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size) 19071676Sjpk { 19081676Sjpk int flag; 19091676Sjpk int remove_dev = 0; 19101676Sjpk int nlen, plen, slen; 19111676Sjpk char *lasts, *lname, *oldlist; 19121676Sjpk struct stat rmstat; 19131676Sjpk deventry_t *dentry, *current, *prev; 19141676Sjpk 19151676Sjpk if (type != NULL) 19161676Sjpk flag = type; 19171676Sjpk else if (link == NULL) 19181676Sjpk return (-1); 19191676Sjpk else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME)) 19201676Sjpk flag = DA_AUDIO; 19211676Sjpk else if (strstr(link, "dsk") || strstr(link, "rdsk") || 19221676Sjpk strstr(link, "sr") || strstr(link, "rsr")) 19231676Sjpk flag = DA_CD; 19241676Sjpk else if (strstr(link, "fd") || strstr(link, "rfd") || 19251676Sjpk strstr(link, "diskette") || strstr(link, "rdiskette")) 19261676Sjpk flag = DA_FLOPPY; 19271676Sjpk else if (strstr(link, DA_TAPE_NAME)) 19281676Sjpk flag = DA_TAPE; 19291676Sjpk else 19301676Sjpk flag = DA_RMDISK; 19311676Sjpk 19321676Sjpk switch (type) { 19331676Sjpk case DA_AUDIO: 19341676Sjpk dentry = dlist->audio; 19351676Sjpk break; 19361676Sjpk case DA_CD: 19371676Sjpk dentry = dlist->cd; 19381676Sjpk break; 19391676Sjpk case DA_FLOPPY: 19401676Sjpk dentry = dlist->floppy; 19411676Sjpk break; 19421676Sjpk case DA_TAPE: 19431676Sjpk dentry = dlist->tape; 19441676Sjpk break; 19451676Sjpk case DA_RMDISK: 19461676Sjpk dentry = dlist->rmdisk; 19471676Sjpk break; 19481676Sjpk default: 19491676Sjpk return (-1); 19501676Sjpk } 19511676Sjpk 19521676Sjpk if ((type != NULL) && (link == NULL)) { 19531676Sjpk for (current = dentry, prev = dentry; current != NULL; 19541676Sjpk current = current->next) { 19551676Sjpk oldlist = strdup(current->devinfo.devlist); 19561676Sjpk for (lname = strtok_r(oldlist, " ", &lasts); 19571676Sjpk lname != NULL; 19581676Sjpk lname = strtok_r(NULL, " ", &lasts)) { 19591676Sjpk if (stat(lname, &rmstat) != 0) { 19601676Sjpk remove_dev = 1; 19611676Sjpk goto remove_dev; 19621676Sjpk } 19631676Sjpk } 19641676Sjpk prev = current; 19651676Sjpk } 19661676Sjpk return (-1); 19671676Sjpk } 19681676Sjpk 19691676Sjpk for (current = dentry, prev = dentry; current != NULL; 19701676Sjpk current = current->next) { 19711676Sjpk plen = strlen(current->devinfo.devlist); 19721676Sjpk nlen = strlen(link); 19731676Sjpk if (plen == nlen) { 19741676Sjpk if (strcmp(current->devinfo.devlist, link) == 0) { 19751676Sjpk /* last name in the list */ 19761676Sjpk remove_dev = 1; 19771676Sjpk break; 19781676Sjpk } 19791676Sjpk } 19801676Sjpk if (strstr(current->devinfo.devlist, link)) { 19811676Sjpk nlen = plen - nlen + 1; 19821676Sjpk oldlist = strdup(current->devinfo.devlist); 19831676Sjpk if ((current->devinfo.devlist = 19841676Sjpk (char *)realloc(current->devinfo.devlist, 19851676Sjpk nlen)) == NULL) { 19861676Sjpk free(oldlist); 19871676Sjpk return (-1); 19881676Sjpk } 19891676Sjpk current->devinfo.devlist[0] = '\0'; 19901676Sjpk nlen = plen = slen = 0; 19911676Sjpk for (lname = strtok_r(oldlist, " ", &lasts); 19921676Sjpk lname != NULL; 19931676Sjpk lname = strtok_r(NULL, " ", &lasts)) { 19941676Sjpk if (strcmp(lname, link) == 0) 19951676Sjpk continue; 19961676Sjpk nlen = strlen(lname) + plen + 1; 19971676Sjpk if (plen == 0) { 19981676Sjpk slen = 19991676Sjpk snprintf(current->devinfo.devlist, 20004514Saj nlen, "%s", lname); 20011676Sjpk } else { 20021676Sjpk slen = 20031676Sjpk snprintf(current->devinfo.devlist + 20044514Saj plen, nlen - plen, " %s", lname); 20051676Sjpk } 20061676Sjpk plen = plen + slen + 1; 20071676Sjpk } 20081676Sjpk free(oldlist); 20091676Sjpk break; 20101676Sjpk } 20111676Sjpk prev = current; 20121676Sjpk } 20131676Sjpk 20141676Sjpk remove_dev: 20151676Sjpk if (remove_dev == 1) { 20161676Sjpk (void) strlcpy(devname, current->devinfo.devname, size); 20171676Sjpk free(current->devinfo.devname); 20181676Sjpk free(current->devinfo.devlist); 20191676Sjpk current->devinfo.devname = current->devinfo.devlist = NULL; 20201676Sjpk prev->next = current->next; 20211676Sjpk free(current); 20221676Sjpk current = NULL; 20231676Sjpk } 20241676Sjpk if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) { 20251676Sjpk if (prev->next) { 20261676Sjpk /* 20271676Sjpk * what we removed above was the first entry 20281676Sjpk * in the list. make the next entry to be the 20291676Sjpk * first. 20301676Sjpk */ 20311676Sjpk current = prev->next; 20321676Sjpk } else { 20331676Sjpk /* 20341676Sjpk * the matching entry was the only entry in the list 20351676Sjpk * for this type. 20361676Sjpk */ 20371676Sjpk current = NULL; 20381676Sjpk } 20391676Sjpk if (flag & DA_AUDIO) 20401676Sjpk dlist->audio = current; 20411676Sjpk else if (flag & DA_CD) 20421676Sjpk dlist->cd = current; 20431676Sjpk else if (flag & DA_FLOPPY) 20441676Sjpk dlist->floppy = current; 20451676Sjpk else if (flag & DA_TAPE) 20461676Sjpk dlist->tape = current; 20471676Sjpk else if (flag & DA_RMDISK) 20481676Sjpk dlist->rmdisk = current; 20491676Sjpk } 20501676Sjpk 20511676Sjpk return (flag); 20521676Sjpk } 20531676Sjpk 20541676Sjpk /* 205511529SJan.Parcel@Sun.COM * da_rm_list_entry - 205611529SJan.Parcel@Sun.COM * 205711529SJan.Parcel@Sun.COM * The adding of devnames to a devlist and the removal of a 205811529SJan.Parcel@Sun.COM * device are not symmetrical -- hot_cleanup gives a /devices 205911529SJan.Parcel@Sun.COM * name which is used to remove the dentry whose links all point to 206011529SJan.Parcel@Sun.COM * that /devices entry. 206111529SJan.Parcel@Sun.COM * 206211529SJan.Parcel@Sun.COM * The link argument is present if available to make debugging 206311529SJan.Parcel@Sun.COM * easier. 206411529SJan.Parcel@Sun.COM * 206511529SJan.Parcel@Sun.COM * da_rm_list_entry removes an entry from the linked list of devices. 206611529SJan.Parcel@Sun.COM * 206711529SJan.Parcel@Sun.COM * Returns 1 if the devname was removed successfully, 206811529SJan.Parcel@Sun.COM * 0 if not found, -1 for error. 206911529SJan.Parcel@Sun.COM */ 207011529SJan.Parcel@Sun.COM /*ARGSUSED*/ 207111529SJan.Parcel@Sun.COM int 207211529SJan.Parcel@Sun.COM da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname) 207311529SJan.Parcel@Sun.COM { 207411529SJan.Parcel@Sun.COM int retval = 0; 207511529SJan.Parcel@Sun.COM deventry_t **dentry, *current, *prev; 207611529SJan.Parcel@Sun.COM 207711529SJan.Parcel@Sun.COM switch (type) { 207811529SJan.Parcel@Sun.COM case DA_AUDIO: 207911529SJan.Parcel@Sun.COM dentry = &(dlist->audio); 208011529SJan.Parcel@Sun.COM break; 208111529SJan.Parcel@Sun.COM case DA_CD: 208211529SJan.Parcel@Sun.COM dentry = &(dlist->cd); 208311529SJan.Parcel@Sun.COM break; 208411529SJan.Parcel@Sun.COM case DA_FLOPPY: 208511529SJan.Parcel@Sun.COM dentry = &(dlist->floppy); 208611529SJan.Parcel@Sun.COM break; 208711529SJan.Parcel@Sun.COM case DA_TAPE: 208811529SJan.Parcel@Sun.COM dentry = &(dlist->tape); 208911529SJan.Parcel@Sun.COM break; 209011529SJan.Parcel@Sun.COM case DA_RMDISK: 209111529SJan.Parcel@Sun.COM dentry = &(dlist->rmdisk); 209211529SJan.Parcel@Sun.COM break; 209311529SJan.Parcel@Sun.COM default: 209411529SJan.Parcel@Sun.COM return (-1); 209511529SJan.Parcel@Sun.COM } 209611529SJan.Parcel@Sun.COM 209711529SJan.Parcel@Sun.COM /* Presumably in daemon mode, no need to remove entry, list is empty */ 209811529SJan.Parcel@Sun.COM if (*dentry == (deventry_t *)NULL) 209911529SJan.Parcel@Sun.COM return (0); 210011529SJan.Parcel@Sun.COM 210111529SJan.Parcel@Sun.COM prev = NULL; 210211529SJan.Parcel@Sun.COM for (current = *dentry; current != NULL; 210311529SJan.Parcel@Sun.COM prev = current, current = current->next) { 210411529SJan.Parcel@Sun.COM if (strcmp(devname, current->devinfo.devname)) 210511529SJan.Parcel@Sun.COM continue; 210611529SJan.Parcel@Sun.COM retval = 1; 210711529SJan.Parcel@Sun.COM break; 210811529SJan.Parcel@Sun.COM } 210911529SJan.Parcel@Sun.COM if (retval == 0) 211011529SJan.Parcel@Sun.COM return (0); 211111529SJan.Parcel@Sun.COM free(current->devinfo.devname); 211211529SJan.Parcel@Sun.COM if (current->devinfo.devlist != NULL) 211311529SJan.Parcel@Sun.COM free(current->devinfo.devlist); 211411529SJan.Parcel@Sun.COM if (current->devinfo.devopts != NULL) 211511529SJan.Parcel@Sun.COM free(current->devinfo.devopts); 211611529SJan.Parcel@Sun.COM 211711529SJan.Parcel@Sun.COM if (prev == NULL) 211811529SJan.Parcel@Sun.COM *dentry = current->next; 211911529SJan.Parcel@Sun.COM else 212011529SJan.Parcel@Sun.COM prev->next = current->next; 212111529SJan.Parcel@Sun.COM 212211529SJan.Parcel@Sun.COM free(current); 212311529SJan.Parcel@Sun.COM return (retval); 212411529SJan.Parcel@Sun.COM } 212511529SJan.Parcel@Sun.COM 212611529SJan.Parcel@Sun.COM /* 21271676Sjpk * da_is_on - 21281676Sjpk * checks if device allocation feature is turned on. 21291676Sjpk * returns 1 if on, 0 if off, -1 if status string not 21301676Sjpk * found in device_allocate. 21311676Sjpk */ 21321676Sjpk int 21331676Sjpk da_is_on() 21341676Sjpk { 21351676Sjpk return (getdaon()); 21361676Sjpk } 21371676Sjpk 21381676Sjpk /* 21391676Sjpk * da_print_device - 21401676Sjpk * debug routine to print device entries. 21411676Sjpk */ 21421676Sjpk void 21431676Sjpk da_print_device(int flag, devlist_t *devlist) 21441676Sjpk { 21451676Sjpk deventry_t *entry, *dentry; 21461676Sjpk devinfo_t *devinfo; 21471676Sjpk 21481676Sjpk if (flag & DA_AUDIO) 21491676Sjpk dentry = devlist->audio; 21501676Sjpk else if (flag & DA_CD) 21511676Sjpk dentry = devlist->cd; 21521676Sjpk else if (flag & DA_FLOPPY) 21531676Sjpk dentry = devlist->floppy; 21541676Sjpk else if (flag & DA_TAPE) 21551676Sjpk dentry = devlist->tape; 21561676Sjpk else if (flag & DA_RMDISK) 21571676Sjpk dentry = devlist->rmdisk; 21581676Sjpk else 21591676Sjpk return; 21601676Sjpk 21611676Sjpk for (entry = dentry; entry != NULL; entry = entry->next) { 21621676Sjpk devinfo = &(entry->devinfo); 21631676Sjpk (void) fprintf(stdout, "name: %s\n", devinfo->devname); 21641676Sjpk (void) fprintf(stdout, "type: %s\n", devinfo->devtype); 21651676Sjpk (void) fprintf(stdout, "auth: %s\n", devinfo->devauths); 21661676Sjpk (void) fprintf(stdout, "exec: %s\n", devinfo->devexec); 21671676Sjpk (void) fprintf(stdout, "list: %s\n\n", devinfo->devlist); 21681676Sjpk } 21691676Sjpk } 2170