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
da_check_logindevperm(char * devname)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
_da_read_file(char * fname,char ** fbuf,time_t * ftime,rwlock_t * flock,int flag)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
_update_zonename(da_args * dargs,devalloc_t * dap)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
_dmap2str(devmap_t * dmp,char * buf,int size,const char * sep)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 *
_dmap2strentry(devmap_t * devmapp)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
fix_optstr(char * buf)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
_da2str(da_args * dargs,devalloc_t * dap,char * buf,int size,const char * sep,const char * osep)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 *
_da2strentry(da_args * dargs,devalloc_t * dap)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
_def2str(da_defs_t * da_defs,char * buf,int size,const char * sep)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 *
_def2strentry(da_defs_t * da_defs)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
_build_defattrs(da_args * dargs,strentry_t ** head_defent)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
da_std_type(da_args * dargs,char * namebuf)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
allocatable(da_args * dargs)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
_rebuild_lists(da_args * dargs,strentry_t ** head_devallocp,strentry_t ** head_devmapp)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
_build_lists(da_args * dargs,strentry_t ** head_devallocp,strentry_t ** head_devmapp)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
_write_defattrs(FILE * fp,strentry_t * head_defent)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
_write_device_allocate(char * odevalloc,FILE * dafp,strentry_t * head_devallocp)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
_write_device_maps(FILE * dmfp,strentry_t * head_devmapp)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
_write_new_defattrs(FILE * fp,da_args * dargs)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
_write_new_entry(FILE * fp,da_args * dargs,int flag)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
_da_lock_devdb(char * rootdir)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
da_open_devdb(char * rootdir,FILE ** dafp,FILE ** dmfp,int flag)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
_record_on_off(da_args * dargs,FILE * tafp,FILE * dafp)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
da_update_defattrs(da_args * dargs)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
da_update_device(da_args * dargs)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
da_add_list(devlist_t * dlist,char * link,int new_instance,int flag)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
da_remove_list(devlist_t * dlist,char * link,int type,char * devname,int size)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
da_rm_list_entry(devlist_t * dlist,char * link,int type,char * devname)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
da_is_on()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
da_print_device(int flag,devlist_t * devlist)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