diff options
author | jpk <none@none> | 2006-03-24 12:29:20 -0800 |
---|---|---|
committer | jpk <none@none> | 2006-03-24 12:29:20 -0800 |
commit | 45916cd2fec6e79bca5dee0421bd39e3c2910d1e (patch) | |
tree | 6b3ea6982435d47edc8972c72c62f9d111e8bb10 /usr/src/lib/libbsm/common/devalloc.c | |
parent | 2c9565cfcd87a2045c2e4b76f31ac4e978903589 (diff) | |
download | illumos-gate-45916cd2fec6e79bca5dee0421bd39e3c2910d1e.tar.gz |
PSARC/2002/762 Layered Trusted Solaris
PSARC/2005/060 TSNET: Trusted Networking with Security Labels
PSARC/2005/259 Layered Trusted Solaris Label Interfaces
PSARC/2005/573 Solaris Trusted Extensions for Printing
PSARC/2005/691 Trusted Extensions for Device Allocation
PSARC/2005/723 Solaris Trusted Extensions Filesystem Labeling
PSARC/2006/009 Labeled Auditing
PSARC/2006/155 Trusted Extensions RBAC Changes
PSARC/2006/191 is_system_labeled
6293271 Zone processes should use zone_kcred instead of kcred
6394554 integrate Solaris Trusted Extensions
--HG--
rename : usr/src/cmd/dminfo/Makefile => deleted_files/usr/src/cmd/dminfo/Makefile
rename : usr/src/cmd/dminfo/dminfo.c => usr/src/cmd/allocate/dminfo.c
Diffstat (limited to 'usr/src/lib/libbsm/common/devalloc.c')
-rw-r--r-- | usr/src/lib/libbsm/common/devalloc.c | 1723 |
1 files changed, 1723 insertions, 0 deletions
diff --git a/usr/src/lib/libbsm/common/devalloc.c b/usr/src/lib/libbsm/common/devalloc.c new file mode 100644 index 0000000000..4541191349 --- /dev/null +++ b/usr/src/lib/libbsm/common/devalloc.c @@ -0,0 +1,1723 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <limits.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <utime.h> +#include <synch.h> +#include <strings.h> +#include <string.h> +#include <libintl.h> +#include <errno.h> +#include <auth_list.h> +#include <bsm/devices.h> +#include <bsm/devalloc.h> + +#define DA_DEFS "/etc/security/tsol/devalloc_defaults" + +extern int _readbufline(char *, int, char *, int, int *); +extern char *strtok_r(char *, const char *, char **); +extern char *_strtok_escape(char *, char *, char **); +extern int getdaon(void); +extern int da_matchname(devalloc_t *, char *); +extern int da_match(devalloc_t *, da_args *); +extern int dmap_matchname(devmap_t *, char *); +extern int dm_match(devmap_t *, da_args *); + +/* + * The following structure is for recording old entries to be retained. + * We read the entries from the database into a linked list in memory, + * then turn around and write them out again. + */ +typedef struct strentry { + struct strentry *se_next; + char se_str[4096 + 1]; +} strentry_t; + +/* + * da_check_longindevperm - + * reads /etc/logindevperm and checks if specified device is in the file. + * returns 1 if specified device found in /etc/logindevperm, else returns 0 + */ +int +da_check_logindevperm(char *devname) +{ + int ret = 0; + int fd = -1; + int nlen, plen, slen, lineno, fsize; + char line[MAX_CANON]; + char *field_delims = " \t\n"; + char *fbuf = NULL; + char *ptr, *device; + char *lasts = NULL; + FILE *fp; + struct stat f_stat; + + /* + * check if /etc/logindevperm exists and get its size + */ + if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1) + return (0); + if (fstat(fd, &f_stat) != 0) { + (void) close(fd); + return (0); + } + fsize = f_stat.st_size; + if ((fbuf = (char *)malloc(fsize)) == NULL) { + (void) close(fd); + return (0); + } + if ((fp = fdopen(fd, "r")) == NULL) { + free(fbuf); + (void) close(fd); + return (0); + } + + /* + * read and parse /etc/logindevperm + */ + plen = nlen = lineno = 0; + while (fgets(line, MAX_CANON, fp) != NULL) { + lineno++; + if ((ptr = strchr(line, '#')) != NULL) + *ptr = '\0'; /* handle comments */ + if (strtok_r(line, field_delims, &lasts) == NULL) + continue; /* ignore blank lines */ + if (strtok_r(NULL, field_delims, &lasts) == NULL) + /* invalid entry */ + continue; + if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL) + /* empty device list */ + continue; + nlen = strlen(ptr) + 1; /* +1 terminator */ + nlen += (plen + 1); + if (plen == 0) + slen = snprintf(fbuf, nlen, "%s", ptr); + else + slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr); + if (slen >= fsize) { + fbuf[0] = '\0'; + (void) fclose(fp); + return (slen); + } + plen += slen; + } + (void) fclose(fp); + + /* + * check if devname exists in /etc/logindevperm + */ + device = strtok_r(fbuf, ":", &lasts); + while (device != NULL) { + /* + * device and devname may be one of these types - + * /dev/xx + * /dev/xx* + * /dev/dir/xx + * /dev/dir/xx* + * /dev/dir/"*" + */ + if (strcmp(device, devname) == 0) { + /* /dev/xx, /dev/dir/xx */ + free(fbuf); + return (1); + } + if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) { + /* all wildcard types */ + *ptr = '\0'; + if (strncmp(device, devname, strlen(device)) == 0) { + free(fbuf); + return (1); + } + } + device = strtok_r(NULL, ":", &lasts); + } + + return (ret); +} + +/* + * _da_read_file - + * establishes readers/writer lock on fname; reads in the file if its + * contents changed since the last time we read it. + * returns size of buffer read, or -1 on failure. + */ +int +_da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock, + int flag) +{ + int fd = -1; + int fsize = 0; + time_t newtime; + FILE *fp = NULL; + struct stat f_stat; + + if (flag & DA_FORCE) + *ftime = 0; + + /* check the size and the time stamp on the file */ + if (rw_rdlock(flock) != 0) + return (-1); + if (stat(fname, &f_stat) != 0) { + (void) rw_unlock(flock); + return (-1); + } + fsize = f_stat.st_size; + newtime = f_stat.st_mtime; + (void) rw_unlock(flock); + + while (newtime > *ftime) { + /* + * file has been modified since we last read it; or this + * is a forced read. + * read file into the buffer with rw lock. + */ + if (rw_wrlock(flock) != 0) + return (-1); + if ((fp = fopen(fname, "r")) == NULL) { + (void) rw_unlock(flock); + return (-1); + } + fd = fileno(fp); + if (*fbuf != NULL) { + free(*fbuf); + *fbuf = NULL; + } + if ((*fbuf = malloc(fsize)) == NULL) { + (void) rw_unlock(flock); + (void) close(fd); + return (-1); + } + if (read(fd, *fbuf, fsize) < fsize) { + free(*fbuf); + (void) rw_unlock(flock); + (void) close(fd); + return (-1); + } + (void) rw_unlock(flock); + /* + * verify that the file did not change just after we read it. + */ + if (rw_rdlock(flock) != 0) { + free(*fbuf); + (void) close(fd); + return (-1); + } + if (stat(fname, &f_stat) != 0) { + free(*fbuf); + (void) rw_unlock(flock); + (void) close(fd); + return (-1); + } + fsize = f_stat.st_size; + newtime = f_stat.st_mtime; + (void) rw_unlock(flock); + (void) close(fd); + *ftime = newtime; + } + + return (fsize); +} + +/* + * _update_zonename - + * add/remove current zone's name to the given devalloc_t. + */ +void +_update_zonename(da_args *dargs, devalloc_t *dap) +{ + int i, j; + int oldsize, newsize; + int has_zonename = 0; + char *zonename; + kva_t *newkva, *oldkva; + kv_t *newdata, *olddata; + devinfo_t *devinfo; + + devinfo = dargs->devinfo; + oldkva = dap->da_devopts; + if (oldkva == NULL) { + if (dargs->optflag & DA_REMOVE_ZONE) + return; + if (dargs->optflag & DA_ADD_ZONE) { + newkva = _str2kva(devinfo->devopts, KV_ASSIGN, + KV_TOKEN_DELIMIT); + if (newkva != NULL) + dap->da_devopts = newkva; + return; + } + } + newsize = oldsize = oldkva->length; + if (kva_match(oldkva, DAOPT_ZONE)) + has_zonename = 1; + if (dargs->optflag & DA_ADD_ZONE) { + if ((zonename = index(devinfo->devopts, '=')) == NULL) + return; + zonename++; + if (has_zonename) { + (void) _insert2kva(oldkva, DAOPT_ZONE, zonename); + return; + } + newsize += 1; + } else if (dargs->optflag & DA_REMOVE_ZONE) { + if (has_zonename) { + newsize -= 1; + if (newsize == 0) { + /* + * If zone name was the only key/value pair, + * put 'reserved' in the empty slot. + */ + _kva_free(oldkva); + dap->da_devopts = NULL; + return; + } + } else { + return; + } + } + newkva = _new_kva(newsize); + newkva->length = 0; + newdata = newkva->data; + olddata = oldkva->data; + for (i = 0, j = 0; i < oldsize; i++) { + if ((dargs->optflag & DA_REMOVE_ZONE) && + (strcmp(olddata[i].key, DAOPT_ZONE) == 0)) + continue; + newdata[j].key = strdup(olddata[i].key); + newdata[j].value = strdup(olddata[i].value); + newkva->length++; + j++; + } + if (dargs->optflag & DA_ADD_ZONE) { + newdata[j].key = strdup(DAOPT_ZONE); + newdata[j].value = strdup(zonename); + newkva->length++; + } + _kva_free(oldkva); + dap->da_devopts = newkva; +} + +/* + * _dmap2str - + * converts a device_map entry into a printable string + * returns 0 on success, -1 on error. + */ +/*ARGSUSED*/ +static int +_dmap2str(da_args *dargs, devmap_t *dmp, char *buf, int size, const char *sep) +{ + int length; + + length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep); + if (length >= size) + return (-1); + length += snprintf(buf + length, size - length, "%s%s", + dmp->dmap_devtype, sep); + if (length >= size) + return (-1); + length += snprintf(buf + length, size - length, "%s\n", + dmp->dmap_devlist); + if (length >= size) + return (-1); + return (0); +} + +/* + * _dmap2strentry - + * calls dmap2str to break given devmap_t into printable entry. + * returns pointer to decoded entry, NULL on error. + */ +static strentry_t * +_dmap2strentry(da_args *dargs, devmap_t *devmapp) +{ + strentry_t *sep; + + if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) + return (NULL); + if (_dmap2str(dargs, devmapp, sep->se_str, sizeof (sep->se_str), + KV_TOKEN_DELIMIT"\\\n\t") != 0) { + free(sep); + return (NULL); + } + return (sep); +} + +/* + * fix_optstr - + * removes trailing ':' from buf. + */ +void +fix_optstr(char *buf) +{ + char *p = NULL; + + if (p = rindex(buf, ':')) + *p = ';'; +} + +/* + * _da2str - + * converts a device_allocate entry into a printable string + * returns 0 on success, -1 on error. + */ +static int +_da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep, + const char *osep) +{ + int length; + int matching_entry = 0; + char **dnames; + + if (dargs->optflag & DA_UPDATE && + (dargs->optflag & DA_ADD_ZONE || + dargs->optflag & DA_REMOVE_ZONE) && + dargs->devnames) { + for (dnames = dargs->devnames; *dnames != NULL; dnames++) { + if (da_matchname(dap, *dnames)) { + matching_entry = 1; + break; + } + } + } + length = snprintf(buf, size, "%s%s", dap->da_devname, sep); + if (length >= size) + return (-1); + length += snprintf(buf + length, size - length, "%s%s", + dap->da_devtype, sep); + if (length >= size) + return (-1); + if (matching_entry) + _update_zonename(dargs, dap); + if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) && + (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) { + length += snprintf(buf + length, size - length, "%s%s", + DA_RESERVED, sep); + } else { + if (_kva2str(dap->da_devopts, buf + length, size - length, + KV_ASSIGN, (char *)osep) != 0) + return (-1); + length = strlen(buf); + } + if (dap->da_devopts) + fix_optstr(buf); + if (length >= size) + return (-1); + length += snprintf(buf + length, size - length, "%s%s", + DA_RESERVED, sep); + if (length >= size) + return (-1); + length += snprintf(buf + length, size - length, "%s%s", + dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep); + if (length >= size) + return (-1); + length += snprintf(buf + length, size - length, "%s\n", + dap->da_devexec ? dap->da_devexec : ""); + if (length >= size) + return (-1); + + return (0); +} + +/* + * _da2strentry - + * calls da2str to break given devalloc_t into printable entry. + * returns pointer to decoded entry, NULL on error. + */ +static strentry_t * +_da2strentry(da_args *dargs, devalloc_t *dap) +{ + strentry_t *sep; + + if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) + return (NULL); + if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str), + KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) { + free(sep); + return (NULL); + } + return (sep); +} + +/* + * _def2str + * converts da_defs_t into a printable string. + * returns 0 on success, -1 on error. + */ +static int +_def2str(da_defs_t *da_defs, char *buf, int size, const char *sep) +{ + int length; + + length = snprintf(buf, size, "%s%s", da_defs->devtype, sep); + if (length >= size) + return (-1); + if (da_defs->devopts) { + if (_kva2str(da_defs->devopts, buf + length, size - length, + KV_ASSIGN, KV_DELIMITER) != 0) + return (-1); + length = strlen(buf); + } + if (length >= size) + return (-1); + + return (0); +} + +/* + * _def2strentry + * calls _def2str to break given da_defs_t into printable entry. + * returns pointer decoded entry, NULL on error. + */ +static strentry_t * +_def2strentry(da_defs_t *da_defs) +{ + strentry_t *sep; + + if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL) + return (NULL); + if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str), + KV_TOKEN_DELIMIT) != 0) { + free(sep); + return (NULL); + } + + return (sep); +} + +/* + * _build_defattrs + * cycles through all defattr entries, stores them in memory. removes + * entries with the given search_key (device type). + * returns 0 if given entry not found, 1 if given entry removed, 2 on + * error. + */ +static int +_build_defattrs(da_args *dargs, strentry_t **head_defent) +{ + int rc = 0; + da_defs_t *da_defs; + strentry_t *tail_str, *tmp_str; + + setdadefent(); + while ((da_defs = getdadefent()) != NULL) { + rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype)); + if (rc && dargs->optflag & DA_ADD && + !(dargs->optflag & DA_FORCE)) { + /* + * During DA_ADD, we keep an existing entry unless + * we have DA_FORCE set to override that entry. + */ + dargs->optflag |= DA_NO_OVERRIDE; + rc = 0; + } + if (rc == 0) { + tmp_str = _def2strentry(da_defs); + if (tmp_str == NULL) { + freedadefent(da_defs); + enddadefent(); + return (2); + } + /* retaining defattr entry: tmp_str->se_str */ + tmp_str->se_next = NULL; + if (*head_defent == NULL) { + *head_defent = tail_str = tmp_str; + } else { + tail_str->se_next = tmp_str; + tail_str = tmp_str; + } + } + freedadefent(da_defs); + } + enddadefent(); + + return (rc); +} + +/* + * _build_lists - + * cycles through all the entries, stores them in memory. removes entries + * with the given search_key (device name or type). + * returns 0 if given entry not found, 1 if given entry removed, 2 on + * error. + */ +static int +_build_lists(da_args *dargs, strentry_t **head_devallocp, + strentry_t **head_devmapp) +{ + int rc = 0; + devalloc_t *devallocp; + devmap_t *devmapp; + strentry_t *tail_str; + strentry_t *tmp_str; + + if (dargs->optflag & DA_MAPS_ONLY) + goto dmap_only; + + /* build device_allocate */ + setdaent(); + while ((devallocp = getdaent()) != NULL) { + rc = da_match(devallocp, dargs); + if (rc && dargs->optflag & DA_ADD && + !(dargs->optflag & DA_FORCE)) { + /* + * During DA_ADD, we keep an existing entry unless + * we have DA_FORCE set to override that entry. + */ + dargs->optflag |= DA_NO_OVERRIDE; + rc = 0; + } + if (rc == 0) { + tmp_str = _da2strentry(dargs, devallocp); + if (tmp_str == NULL) { + freedaent(devallocp); + enddaent(); + return (2); + } + /* retaining devalloc entry: tmp_str->se_str */ + tmp_str->se_next = NULL; + if (*head_devallocp == NULL) { + *head_devallocp = tail_str = tmp_str; + } else { + tail_str->se_next = tmp_str; + tail_str = tmp_str; + } + } + freedaent(devallocp); + } + enddaent(); + +dmap_only: + if (dargs->optflag & DA_ALLOC_ONLY) + return (rc); + + /* build device_maps */ + rc = 0; + setdmapent(); + while ((devmapp = getdmapent()) != NULL) { + rc = dm_match(devmapp, dargs); + if (rc && dargs->optflag & DA_ADD && + !(dargs->optflag & DA_FORCE)) { + /* + * During DA_ADD, we keep an existing entry unless + * we have DA_FORCE set to override that entry. + */ + dargs->optflag |= DA_NO_OVERRIDE; + rc = 0; + } + if (rc == 0) { + tmp_str = _dmap2strentry(dargs, devmapp); + if (tmp_str == NULL) { + freedmapent(devmapp); + enddmapent(); + return (2); + } + /* retaining devmap entry: tmp_str->se_str */ + tmp_str->se_next = NULL; + if (*head_devmapp == NULL) { + *head_devmapp = tail_str = tmp_str; + } else { + tail_str->se_next = tmp_str; + tail_str = tmp_str; + } + } + freedmapent(devmapp); + } + enddmapent(); + + return (rc); +} + +/* + * _write_defattrs + * writes current entries to devalloc_defaults. + */ +static void +_write_defattrs(FILE *fp, strentry_t *head_defent) +{ + strentry_t *tmp_str; + + for (tmp_str = head_defent; tmp_str != NULL; + tmp_str = tmp_str->se_next) { + (void) fputs(tmp_str->se_str, fp); + (void) fputs("\n", fp); + } + +} + +/* + * _write_device_allocate - + * writes current entries in the list to device_allocate. + */ +static void +_write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp) +{ + int is_on = -1; + strentry_t *tmp_str; + struct stat dastat; + + (void) fseek(dafp, (off_t)0, SEEK_SET); + + /* + * if the devalloc on/off string existed before, + * put it back before anything else. + * we need to check for the string only if the file + * exists. + */ + if (stat(odevalloc, &dastat) == 0) { + is_on = da_is_on(); + if (is_on == 0) + (void) fputs(DA_OFF_STR, dafp); + else if (is_on == 1) + (void) fputs(DA_ON_STR, dafp); + } + tmp_str = head_devallocp; + while (tmp_str) { + (void) fputs(tmp_str->se_str, dafp); + (void) fputs("\n", dafp); + tmp_str = tmp_str->se_next; + } +} + +/* + * _write_device_maps - + * writes current entries in the list to device_maps. + */ +static void +_write_device_maps(FILE *dmfp, strentry_t *head_devmapp) +{ + strentry_t *tmp_str; + + (void) fseek(dmfp, (off_t)0, SEEK_SET); + + tmp_str = head_devmapp; + while (tmp_str) { + (void) fputs(tmp_str->se_str, dmfp); + (void) fputs("\n", dmfp); + tmp_str = tmp_str->se_next; + } +} + +/* + * _write_new_defattrs + * writes the new entry to devalloc_defaults. + * returns 0 on success, -1 on error. + */ +static int +_write_new_defattrs(FILE *fp, da_args *dargs) +{ + int count; + char *tok = NULL, *tokp = NULL; + char *lasts; + devinfo_t *devinfo = dargs->devinfo; + + if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) + return (-1); + if (!devinfo->devopts) + return (0); + (void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""), + KV_TOKEN_DELIMIT); + if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) { + (void) strcpy(tokp, devinfo->devopts); + if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) { + (void) fprintf(fp, "%s", tok); + count = 1; + } + while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) { + if (count) + (void) fprintf(fp, "%s", KV_DELIMITER); + (void) fprintf(fp, "%s", tok); + count++; + } + } else { + (void) fprintf(fp, "%s", devinfo->devopts); + } + + return (0); +} + +/* + * _write_new_entry - + * writes the new devalloc_t to device_allocate or the new devmap_t to + * device_maps. + * returns 0 on success, -1 on error. + */ +static int +_write_new_entry(FILE *fp, da_args *dargs, int flag) +{ + int count; + char *tok = NULL, *tokp = NULL; + char *lasts; + devinfo_t *devinfo = dargs->devinfo; + + if (flag & DA_MAPS_ONLY) + goto dmap_only; + + if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) + return (-1); + + (void) fprintf(fp, "%s%s\\\n\t", + (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER); + (void) fprintf(fp, "%s%s\\\n\t", + (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER); + if (devinfo->devopts == NULL) { + (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, + KV_DELIMITER); + } else { + if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) { + (void) strcpy(tokp, devinfo->devopts); + if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) != + NULL) { + (void) fprintf(fp, "%s", tok); + count = 1; + } + while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, + &lasts)) != NULL) { + if (count) + (void) fprintf(fp, "%s", + KV_TOKEN_DELIMIT "\\\n\t"); + (void) fprintf(fp, "%s", tok); + count++; + } + if (count) + (void) fprintf(fp, "%s", + KV_DELIMITER "\\\n\t"); + } else { + (void) fprintf(fp, "%s%s", devinfo->devopts, + KV_DELIMITER "\\\n\t"); + } + } + (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER); + (void) fprintf(fp, "%s%s\\\n\t", + (devinfo->devauths ? devinfo->devauths : DA_ANYUSER), + KV_DELIMITER); + (void) fprintf(fp, "%s\n", + (devinfo->devexec ? devinfo->devexec : KV_DELIMITER)); + +dmap_only: + if (flag & DA_ALLOC_ONLY) + return (0); + + if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1) + return (-1); + + (void) fprintf(fp, "%s%s\\\n", + (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT); + (void) fprintf(fp, "\t%s%s\\\n", + (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT); + (void) fprintf(fp, "\t%s\n", + (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT)); + + return (0); +} + +/* + * _da_lock_devdb - + * locks the database files; lock can be either broken explicitly by + * closing the fd of the lock file, or it expires automatically at process + * termination. + * returns fd of the lock file or -1 on error. + */ +int +_da_lock_devdb(char *rootdir) +{ + int lockfd = -1; + char *lockfile; + char path[MAXPATHLEN]; + int size = sizeof (path); + + if (rootdir == NULL) { + lockfile = DA_DB_LOCK; + } else { + path[0] = '\0'; + if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size) + return (-1); + lockfile = path; + } + + if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) + /* cannot open lock file */ + return (-1); + + (void) fchown(lockfd, DA_UID, DA_GID); + + if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) { + /* cannot position lock file */ + (void) close(lockfd); + return (-1); + } + if (lockf(lockfd, F_TLOCK, 0) == -1) { + /* cannot set lock */ + (void) close(lockfd); + return (-1); + } + (void) utime(lockfile, NULL); + + return (lockfd); +} + +/* + * da_open_devdb - + * opens one or both database files - device_allocate, device_maps - in + * the specified mode. + * locks the database files; lock is either broken explicitly by the + * caller by closing the lock file fd, or it expires automatically at + * process termination. + * writes the file pointer of opened file in the input args - dafp, dmfp. + * returns fd of the lock file on success, -2 if database file does not + * exist, -1 on other errors. + */ +int +da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag) +{ + int oflag = 0; + int fda = -1; + int fdm = -1; + int lockfd = -1; + char *fname; + char *fmode; + char path[MAXPATHLEN]; + FILE *devfile; + + if ((dafp == NULL) && (dmfp == NULL)) + return (-1); + + if (flag & DA_RDWR) { + oflag = DA_RDWR; + fmode = "r+"; + } else if (flag & DA_RDONLY) { + oflag = DA_RDONLY; + fmode = "r"; + } + + if ((lockfd = _da_lock_devdb(rootdir)) == -1) + return (-1); + + if ((dafp == NULL) || (flag & DA_MAPS_ONLY)) + goto dmap_only; + + path[0] = '\0'; + + /* + * open the device allocation file + */ + if (rootdir == NULL) { + fname = DEVALLOC; + } else { + if (snprintf(path, sizeof (path), "%s%s", rootdir, + DEVALLOC) >= sizeof (path)) { + if (lockfd != -1) + (void) close(lockfd); + return (-1); + } + fname = path; + } + if ((fda = open(fname, oflag, DA_DBMODE)) == -1) { + if (lockfd != -1) + (void) close(lockfd); + return ((errno == ENOENT) ? -2 : -1); + } + if ((devfile = fdopen(fda, fmode)) == NULL) { + (void) close(fda); + if (lockfd != -1) + (void) close(lockfd); + return (-1); + } + *dafp = devfile; + (void) fchmod(fda, DA_DBMODE); + + if ((flag & DA_ALLOC_ONLY)) + goto out; + +dmap_only: + path[0] = '\0'; + /* + * open the device map file + */ + if (rootdir == NULL) { + fname = DEVMAP; + } else { + if (snprintf(path, sizeof (path), "%s%s", rootdir, + DEVMAP) >= sizeof (path)) { + (void) close(fda); + if (lockfd != -1) + (void) close(lockfd); + return (-1); + } + fname = path; + } + + if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) { + if (lockfd != -1) + (void) close(lockfd); + return ((errno == ENOENT) ? -2 : -1); + } + + if ((devfile = fdopen(fdm, fmode)) == NULL) { + (void) close(fdm); + (void) close(fda); + if (lockfd != -1) + (void) close(lockfd); + return (-1); + } + *dmfp = devfile; + (void) fchmod(fdm, DA_DBMODE); + +out: + return (lockfd); +} + +/* + * _record_on_off - + * adds either DA_ON_STR or DA_OFF_STR to device_allocate + * returns 0 on success, -1 on error. + */ +static int +_record_on_off(da_args *dargs, FILE *tafp, FILE *dafp) +{ + int dafd; + int nsize; + int nitems = 1; + int actionlen; + int str_found = 0; + int len = 0, nlen = 0, plen = 0; + char *ptr = NULL; + char *actionstr; + char *nbuf = NULL; + char line[MAX_CANON]; + struct stat dastat; + + if (dargs->optflag & DA_ON) + actionstr = DA_ON_STR; + else + actionstr = DA_OFF_STR; + actionlen = strlen(actionstr); + dafd = fileno(dafp); + if (fstat(dafd, &dastat) == -1) + return (-1); + + /* check the old device_allocate for on/off string */ + ptr = fgets(line, MAX_CANON, dafp); + if (ptr != NULL) { + if ((strcmp(line, DA_ON_STR) == 0) || + (strcmp(line, DA_OFF_STR) == 0)) { + str_found = 1; + nsize = dastat.st_size; + } + } + if (!ptr || !str_found) { + /* + * the file never had either the on or the off string; + * make room for it. + */ + str_found = 0; + nsize = dastat.st_size + actionlen + 1; + } + if ((nbuf = (char *)malloc(nsize)) == NULL) + return (-1); + nbuf[0] = '\0'; + /* put the on/off string */ + (void) strcpy(nbuf, actionstr); + nlen = strlen(nbuf); + plen = nlen; + if (ptr && !str_found) { + /* now put the first line that we read in fgets */ + nlen = plen + strlen(line) + 1; + len = snprintf(nbuf + plen, nlen - plen, "%s", line); + if (len >= nsize) { + free(nbuf); + return (-1); + } + plen += len; + } + + /* now get the rest of the old file */ + while (fgets(line, MAX_CANON, dafp) != NULL) { + nlen = plen + strlen(line) + 1; + len = snprintf(nbuf + plen, nlen - plen, "%s", line); + if (len >= nsize) { + free(nbuf); + return (-1); + } + plen += len; + } + len = strlen(nbuf) + 1; + if (len < nsize) + nbuf[len] = '\n'; + + /* write the on/off str + the old device_allocate to the temp file */ + if (fwrite(nbuf, nsize, nitems, tafp) < nitems) { + free(nbuf); + return (-1); + } + + free(nbuf); + + return (0); +} + +/* + * da_update_defattrs - + * writes default attributes to devalloc_defaults + * returns 0 on success, -1 on error. + */ +int +da_update_defattrs(da_args *dargs) +{ + int rc = 0, lockfd = 0, tmpfd = 0; + char *defpath = DEFATTRS; + char *tmpdefpath = TMPATTRS; + FILE *tmpfp = NULL; + struct stat dstat; + strentry_t *head_defent = NULL; + + if (dargs == NULL) + return (0); + if ((lockfd = _da_lock_devdb(NULL)) == -1) + return (-1); + if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { + (void) close(lockfd); + return (-1); + } + (void) fchown(tmpfd, DA_UID, DA_GID); + if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) { + (void) close(tmpfd); + (void) unlink(tmpdefpath); + (void) close(lockfd); + return (-1); + } + /* + * examine all entries, remove an old one if required, check + * if a new one needs to be added. + */ + if (stat(defpath, &dstat) == 0) { + if ((rc = _build_defattrs(dargs, &head_defent)) != 0) { + if (rc == 1) { + (void) close(tmpfd); + (void) unlink(tmpdefpath); + (void) close(lockfd); + return (rc); + } + } + } + /* + * write back any existing entries. + */ + _write_defattrs(tmpfp, head_defent); + + if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { + /* add new entries */ + rc = _write_new_defattrs(tmpfp, dargs); + (void) fclose(tmpfp); + } else { + (void) fclose(tmpfp); + } + if (rename(tmpdefpath, defpath) != 0) { + rc = -1; + (void) unlink(tmpdefpath); + } + (void) close(lockfd); + + return (rc); +} + +/* + * da_update_device - + * writes devices entries to device_allocate and device_maps. + * returns 0 on success, -1 on error. + */ +int +da_update_device(da_args *dargs) +{ + int rc; + int tafd = -1, tmfd = -1; + int lockfd = -1; + char *rootdir = NULL; + char *apathp = NULL, *mpathp = NULL, *dapathp = NULL, + *dmpathp = NULL; + char apath[MAXPATHLEN], mpath[MAXPATHLEN], + dapath[MAXPATHLEN], dmpath[MAXPATHLEN]; + FILE *tafp = NULL, *tmfp = NULL, *dafp = NULL; + struct stat dastat; + devinfo_t *devinfo; + strentry_t *head_devmapp = NULL; + strentry_t *head_devallocp = NULL; + + if (dargs == NULL) + return (0); + + rootdir = dargs->rootdir; + devinfo = dargs->devinfo; + + /* + * adding/removing entries should be done in both + * device_allocate and device_maps. updates can be + * done in both or either of the files. + */ + if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) { + if (dargs->optflag & DA_ALLOC_ONLY || + dargs->optflag & DA_MAPS_ONLY) + return (0); + } + + /* + * name, type and list are required fields for adding a new + * device. + */ + if ((dargs->optflag & DA_ADD) && + ((devinfo->devname == NULL) || + (devinfo->devtype == NULL) || + (devinfo->devlist == NULL))) { + return (-1); + } + + if (rootdir != NULL) { + if (snprintf(apath, sizeof (apath), "%s%s", rootdir, + TMPALLOC) >= sizeof (apath)) + return (-1); + apathp = apath; + if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir, + DEVALLOC) >= sizeof (dapath)) + return (-1); + dapathp = dapath; + if (!(dargs->optflag & DA_ALLOC_ONLY)) { + if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir, + TMPMAP) >= sizeof (mpath)) + return (-1); + mpathp = mpath; + if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir, + DEVMAP) >= sizeof (dmpath)) + return (-1); + dmpathp = dmpath; + } + } else { + apathp = TMPALLOC; + dapathp = DEVALLOC; + mpathp = TMPMAP; + dmpathp = DEVMAP; + } + + if (dargs->optflag & DA_MAPS_ONLY) + goto dmap_only; + + /* + * Check if we are here just to record on/off status of + * device_allocation. + */ + if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) + lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL, + DA_RDONLY|DA_ALLOC_ONLY); + else + lockfd = _da_lock_devdb(rootdir); + if (lockfd == -1) + return (-1); + + if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { + (void) close(lockfd); + (void) fclose(dafp); + return (-1); + } + (void) fchown(tafd, DA_UID, DA_GID); + if ((tafp = fdopen(tafd, "r+")) == NULL) { + (void) close(tafd); + (void) unlink(apathp); + (void) fclose(dafp); + (void) close(lockfd); + return (-1); + } + + /* + * We don't need to parse the file if we are here just to record + * on/off status of device_allocation. + */ + if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) { + if (_record_on_off(dargs, tafp, dafp) == -1) { + (void) close(tafd); + (void) unlink(apathp); + (void) fclose(dafp); + (void) close(lockfd); + return (-1); + } + (void) fclose(dafp); + goto out; + } + + /* + * examine all the entries, remove an old one if forced to, + * and check that they are suitable for updating. + * we need to do this only if the file exists already. + */ + if (stat(dapathp, &dastat) == 0) { + if ((rc = _build_lists(dargs, &head_devallocp, + &head_devmapp)) != 0) { + if (rc != 1) { + (void) close(tafd); + (void) unlink(apathp); + (void) close(lockfd); + return (rc); + } + } + } + + /* + * write back any existing devalloc entries, along with + * the devalloc on/off string. + */ + _write_device_allocate(dapathp, tafp, head_devallocp); + + if (dargs->optflag & DA_ALLOC_ONLY) + goto out; + +dmap_only: + if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) { + (void) close(tafd); + (void) unlink(apathp); + (void) close(lockfd); + return (-1); + } + (void) fchown(tmfd, DA_UID, DA_GID); + if ((tmfp = fdopen(tmfd, "r+")) == NULL) { + (void) close(tafd); + (void) unlink(apathp); + (void) close(tmfd); + (void) unlink(mpathp); + (void) close(lockfd); + return (-1); + } + + /* write back any existing devmap entries */ + if (head_devmapp != NULL) + _write_device_maps(tmfp, head_devmapp); + +out: + if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) { + /* add any new entries */ + rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY); + (void) fclose(tafp); + + if (rc == 0) + rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY); + (void) fclose(tmfp); + } else { + if (tafp) + (void) fclose(tafp); + if (tmfp) + (void) fclose(tmfp); + } + + rc = 0; + if (!(dargs->optflag & DA_MAPS_ONLY)) { + if (rename(apathp, dapathp) != 0) { + rc = -1; + (void) unlink(apathp); + } + } + if (!(dargs->optflag & DA_ALLOC_ONLY)) { + if (rename(mpathp, dmpathp) != 0) { + rc = -1; + (void) unlink(mpathp); + } + } + + (void) close(lockfd); + + return (rc); +} + +/* + * da_add_list - + * adds new /dev link name to the linked list of devices. + * returns 0 if link added successfully, -1 on error. + */ +int +da_add_list(devlist_t *dlist, char *link, int new_instance, int flag) +{ + int instance; + int nlen, plen; + int new_entry = 0; + char *dtype, *dexec, *tname, *kval; + char *minstr = NULL, *maxstr = NULL; + char dname[DA_MAXNAME]; + kva_t *kva; + deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL; + da_defs_t *da_defs; + + if (dlist == NULL || link == NULL) + return (-1); + + dname[0] = '\0'; + if (flag & DA_AUDIO) { + dentry = dlist->audio; + tname = DA_AUDIO_NAME; + dtype = DA_AUDIO_TYPE; + dexec = DA_DEFAULT_AUDIO_CLEAN; + } else if (flag & DA_CD) { + dentry = dlist->cd; + tname = DA_CD_NAME; + dtype = DA_CD_TYPE; + dexec = DA_DEFAULT_DISK_CLEAN; + } else if (flag & DA_FLOPPY) { + dentry = dlist->floppy; + tname = DA_FLOPPY_NAME; + dtype = DA_FLOPPY_TYPE; + dexec = DA_DEFAULT_DISK_CLEAN; + } else if (flag & DA_TAPE) { + dentry = dlist->tape; + tname = DA_TAPE_NAME; + dtype = DA_TAPE_TYPE; + dexec = DA_DEFAULT_TAPE_CLEAN; + } else if (flag & DA_RMDISK) { + dentry = dlist->rmdisk; + tname = DA_RMDISK_NAME; + dtype = DA_RMDISK_TYPE; + dexec = DA_DEFAULT_DISK_CLEAN; + } else { + return (-1); + } + + for (nentry = dentry; nentry != NULL; nentry = nentry->next) { + pentry = nentry; + (void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance); + if (nentry->devinfo.instance == new_instance) + /* + * Add the new link name to the list of links + * that the device 'dname' has. + */ + break; + } + + if (nentry == NULL) { + /* + * Either this is the first entry ever, or no matching entry + * was found. Create a new one and add to the list. + */ + if (dentry == NULL) /* first entry ever */ + instance = 0; + else /* no matching entry */ + instance++; + (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance); + if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) == + NULL) + return (-1); + if (pentry != NULL) + pentry->next = nentry; + new_entry = 1; + nentry->devinfo.devname = strdup(dname); + nentry->devinfo.devtype = dtype; + nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH; + nentry->devinfo.devexec = dexec; + nentry->devinfo.instance = new_instance; + /* + * Look for default label range, authorizations and cleaning + * program in devalloc_defaults. If label range is not + * specified in devalloc_defaults, assume it to be admin_low + * to admin_high. + */ + minstr = DA_DEFAULT_MIN; + maxstr = DA_DEFAULT_MAX; + setdadefent(); + if (da_defs = getdadeftype(nentry->devinfo.devtype)) { + kva = da_defs->devopts; + if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL) + minstr = strdup(kval); + if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL) + maxstr = strdup(kval); + if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL) + nentry->devinfo.devauths = strdup(kval); + if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL) + nentry->devinfo.devexec = strdup(kval); + freedadefent(da_defs); + } + enddadefent(); + kval = NULL; + nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) + + strlen(minstr) + strlen(KV_TOKEN_DELIMIT) + + strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr) + + 1; /* +1 for terminator */ + if (kval = (char *)malloc(nlen)) + (void) snprintf(kval, nlen, "%s%s%s%s%s%s%s", + DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT, + DAOPT_MAXLABEL, KV_ASSIGN, maxstr); + nentry->devinfo.devopts = kval; + + nentry->devinfo.devlist = NULL; + nentry->next = NULL; + } + + nlen = strlen(link) + 1; /* +1 terminator */ + if (nentry->devinfo.devlist) { + plen = strlen(nentry->devinfo.devlist); + nlen = nlen + plen + 1; /* +1 for blank to separate entries */ + } else { + plen = 0; + } + + if ((nentry->devinfo.devlist = + (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) { + if (new_entry) { + nentry->devinfo.devname = NULL; + free(nentry->devinfo.devname); + nentry = NULL; + free(nentry); + if (pentry != NULL) + pentry->next = NULL; + } + return (-1); + } + + if (plen == 0) + (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link); + else + (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen, + " %s", link); + + if (pentry == NULL) { + /* + * This is the first entry of this device type. + */ + if (flag & DA_AUDIO) + dlist->audio = nentry; + else if (flag & DA_CD) + dlist->cd = nentry; + else if (flag & DA_FLOPPY) + dlist->floppy = nentry; + else if (flag & DA_TAPE) + dlist->tape = nentry; + else if (flag & DA_RMDISK) + dlist->rmdisk = nentry; + } + + return (0); +} + +/* + * da_remove_list - + * removes a /dev link name from the linked list of devices. + * returns type of device if link for that device removed + * successfully, else returns -1 on error. + * if all links for a device are removed, stores that device + * name in devname. + */ +int +da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size) +{ + int flag; + int remove_dev = 0; + int nlen, plen, slen; + char *lasts, *lname, *oldlist; + struct stat rmstat; + deventry_t *dentry, *current, *prev; + + if (type != NULL) + flag = type; + else if (link == NULL) + return (-1); + else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME)) + flag = DA_AUDIO; + else if (strstr(link, "dsk") || strstr(link, "rdsk") || + strstr(link, "sr") || strstr(link, "rsr")) + flag = DA_CD; + else if (strstr(link, "fd") || strstr(link, "rfd") || + strstr(link, "diskette") || strstr(link, "rdiskette")) + flag = DA_FLOPPY; + else if (strstr(link, DA_TAPE_NAME)) + flag = DA_TAPE; + else + flag = DA_RMDISK; + + switch (type) { + case DA_AUDIO: + dentry = dlist->audio; + break; + case DA_CD: + dentry = dlist->cd; + break; + case DA_FLOPPY: + dentry = dlist->floppy; + break; + case DA_TAPE: + dentry = dlist->tape; + break; + case DA_RMDISK: + dentry = dlist->rmdisk; + break; + default: + return (-1); + } + + if ((type != NULL) && (link == NULL)) { + for (current = dentry, prev = dentry; current != NULL; + current = current->next) { + oldlist = strdup(current->devinfo.devlist); + for (lname = strtok_r(oldlist, " ", &lasts); + lname != NULL; + lname = strtok_r(NULL, " ", &lasts)) { + if (stat(lname, &rmstat) != 0) { + remove_dev = 1; + goto remove_dev; + } + } + prev = current; + } + return (-1); + } + + for (current = dentry, prev = dentry; current != NULL; + current = current->next) { + plen = strlen(current->devinfo.devlist); + nlen = strlen(link); + if (plen == nlen) { + if (strcmp(current->devinfo.devlist, link) == 0) { + /* last name in the list */ + remove_dev = 1; + break; + } + } + if (strstr(current->devinfo.devlist, link)) { + nlen = plen - nlen + 1; + oldlist = strdup(current->devinfo.devlist); + if ((current->devinfo.devlist = + (char *)realloc(current->devinfo.devlist, + nlen)) == NULL) { + free(oldlist); + return (-1); + } + current->devinfo.devlist[0] = '\0'; + nlen = plen = slen = 0; + for (lname = strtok_r(oldlist, " ", &lasts); + lname != NULL; + lname = strtok_r(NULL, " ", &lasts)) { + if (strcmp(lname, link) == 0) + continue; + nlen = strlen(lname) + plen + 1; + if (plen == 0) { + slen = + snprintf(current->devinfo.devlist, + nlen, "%s", lname); + } else { + slen = + snprintf(current->devinfo.devlist + + plen, nlen - plen, " %s", + lname); + } + plen = plen + slen + 1; + } + free(oldlist); + break; + } + prev = current; + } + +remove_dev: + if (remove_dev == 1) { + (void) strlcpy(devname, current->devinfo.devname, size); + free(current->devinfo.devname); + free(current->devinfo.devlist); + current->devinfo.devname = current->devinfo.devlist = NULL; + prev->next = current->next; + free(current); + current = NULL; + } + if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) { + if (prev->next) { + /* + * what we removed above was the first entry + * in the list. make the next entry to be the + * first. + */ + current = prev->next; + } else { + /* + * the matching entry was the only entry in the list + * for this type. + */ + current = NULL; + } + if (flag & DA_AUDIO) + dlist->audio = current; + else if (flag & DA_CD) + dlist->cd = current; + else if (flag & DA_FLOPPY) + dlist->floppy = current; + else if (flag & DA_TAPE) + dlist->tape = current; + else if (flag & DA_RMDISK) + dlist->rmdisk = current; + } + + return (flag); +} + +/* + * da_is_on - + * checks if device allocation feature is turned on. + * returns 1 if on, 0 if off, -1 if status string not + * found in device_allocate. + */ +int +da_is_on() +{ + return (getdaon()); +} + +/* + * da_print_device - + * debug routine to print device entries. + */ +void +da_print_device(int flag, devlist_t *devlist) +{ + deventry_t *entry, *dentry; + devinfo_t *devinfo; + + if (flag & DA_AUDIO) + dentry = devlist->audio; + else if (flag & DA_CD) + dentry = devlist->cd; + else if (flag & DA_FLOPPY) + dentry = devlist->floppy; + else if (flag & DA_TAPE) + dentry = devlist->tape; + else if (flag & DA_RMDISK) + dentry = devlist->rmdisk; + else + return; + + for (entry = dentry; entry != NULL; entry = entry->next) { + devinfo = &(entry->devinfo); + (void) fprintf(stdout, "name: %s\n", devinfo->devname); + (void) fprintf(stdout, "type: %s\n", devinfo->devtype); + (void) fprintf(stdout, "auth: %s\n", devinfo->devauths); + (void) fprintf(stdout, "exec: %s\n", devinfo->devexec); + (void) fprintf(stdout, "list: %s\n\n", devinfo->devlist); + } +} |