10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * 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.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*4893Stz204579 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
281676Sjpk #include <ctype.h>
291676Sjpk #include <string.h>
301676Sjpk #include <stdlib.h>
311676Sjpk #include <tsol/label.h>
321676Sjpk #include <bsm/devices.h>
331676Sjpk #include <bsm/devalloc.h>
341676Sjpk
351676Sjpk extern char *_strdup_null(char *);
360Sstevel@tonic-gate
370Sstevel@tonic-gate static struct _dabuff {
381676Sjpk FILE *_daf; /* pointer into /etc/security/device_allocate */
391676Sjpk devalloc_t _interpdevalloc;
401676Sjpk char _interpdaline[DA_BUFSIZE + 1];
411676Sjpk char *_DEVALLOC;
420Sstevel@tonic-gate } *__dabuff;
430Sstevel@tonic-gate
441676Sjpk #define daf (_da->_daf)
451676Sjpk #define interpdevalloc (_da->_interpdevalloc)
461676Sjpk #define interpdaline (_da->_interpdaline)
471676Sjpk #define DEVALLOC_FILE (_da->_DEVALLOC)
481676Sjpk static devalloc_t *da_interpret(char *);
491676Sjpk
501676Sjpk int da_matchname(devalloc_t *, char *);
511676Sjpk int da_matchtype(devalloc_t *, char *);
521676Sjpk
531676Sjpk static int system_labeled = 0;
540Sstevel@tonic-gate
550Sstevel@tonic-gate /*
561676Sjpk * trim_white -
571676Sjpk * trims off leading and trailing white space from input string.
581676Sjpk * The leading white space is skipped by moving the pointer forward.
591676Sjpk * The trailing white space is removed by nulling the white space
601676Sjpk * characters.
611676Sjpk * returns pointer to non-white string, else returns NULL if input string
621676Sjpk * is null or if the resulting string has zero length.
630Sstevel@tonic-gate */
641676Sjpk char *
trim_white(char * ptr)651676Sjpk trim_white(char *ptr)
660Sstevel@tonic-gate {
671676Sjpk char *tptr;
681676Sjpk
690Sstevel@tonic-gate if (ptr == NULL)
700Sstevel@tonic-gate return (NULL);
711676Sjpk while (isspace(*ptr))
720Sstevel@tonic-gate ptr++;
731676Sjpk tptr = ptr + strlen(ptr);
741676Sjpk while (tptr != ptr && isspace(tptr[-1]))
751676Sjpk --tptr;
761676Sjpk *tptr = '\0';
771676Sjpk if (*ptr == '\0')
780Sstevel@tonic-gate return (NULL);
791676Sjpk
800Sstevel@tonic-gate return (ptr);
810Sstevel@tonic-gate }
820Sstevel@tonic-gate
830Sstevel@tonic-gate /*
841676Sjpk * pack_white -
851676Sjpk * trims off multiple occurrences of white space from input string.
861676Sjpk * returns the number of spaces retained
870Sstevel@tonic-gate */
881676Sjpk int
pack_white(char * ptr)891676Sjpk pack_white(char *ptr)
900Sstevel@tonic-gate {
911676Sjpk int cnt = 0;
921676Sjpk char *tptr, ch;
931676Sjpk
941676Sjpk if (ptr == NULL)
951676Sjpk return (0);
961676Sjpk tptr = ptr;
971676Sjpk while (isspace(*tptr))
981676Sjpk tptr++;
991676Sjpk for (;;) {
1001676Sjpk while ((ch = *tptr) != '\0' && !isspace(ch)) {
1011676Sjpk *ptr++ = ch;
1021676Sjpk tptr++;
1031676Sjpk }
1041676Sjpk while (isspace(*tptr))
1051676Sjpk tptr++;
1061676Sjpk if (*tptr == '\0')
1071676Sjpk break;
1081676Sjpk *ptr++ = ' ';
1091676Sjpk cnt++;
1101676Sjpk }
1111676Sjpk *ptr = '\0';
1121676Sjpk
1131676Sjpk return (cnt);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate /*
1171676Sjpk * getdadmline -
1181676Sjpk * reads one device_alloc/device_maps line from stream into buff of len
1191676Sjpk * bytes. Continued lines from stream are concatenated into one line in
1201676Sjpk * buff. Comments are removed from buff.
1211676Sjpk * returns the number of characters in buff, else returns 0 if no
1221676Sjpk * characters are read or an error occurred.
1230Sstevel@tonic-gate */
1241676Sjpk int
getdadmline(char * buff,int len,FILE * stream)1251676Sjpk getdadmline(char *buff, int len, FILE *stream)
1260Sstevel@tonic-gate {
1271676Sjpk int tmpcnt;
1281676Sjpk int charcnt = 0;
1291676Sjpk int fileerr = 0;
1301676Sjpk int contline = 0;
1311676Sjpk char *cp;
1321676Sjpk char *ccp;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate do {
1350Sstevel@tonic-gate cp = buff;
1360Sstevel@tonic-gate *cp = NULL;
1370Sstevel@tonic-gate do {
1381676Sjpk contline = 0;
1390Sstevel@tonic-gate if (fgets(cp, len - charcnt, stream) == NULL) {
1400Sstevel@tonic-gate fileerr = 1;
1410Sstevel@tonic-gate break;
1420Sstevel@tonic-gate }
1431676Sjpk ccp = strchr(cp, '\n');
1440Sstevel@tonic-gate if (ccp != NULL) {
1451676Sjpk if (ccp != cp && ccp[-1] == '\\') {
1461676Sjpk ccp--;
1470Sstevel@tonic-gate contline = 1;
1481676Sjpk }
1491676Sjpk else
1500Sstevel@tonic-gate contline = 0;
1510Sstevel@tonic-gate *ccp = NULL;
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate tmpcnt = strlen(cp);
1541676Sjpk cp += tmpcnt;
1551676Sjpk charcnt += tmpcnt;
1560Sstevel@tonic-gate } while ((contline) || (charcnt == 0));
1570Sstevel@tonic-gate ccp = strpbrk(buff, "#");
1580Sstevel@tonic-gate if (ccp != NULL)
1590Sstevel@tonic-gate *ccp = NULL;
1600Sstevel@tonic-gate charcnt = strlen(buff);
1610Sstevel@tonic-gate } while ((fileerr == 0) && (charcnt == 0));
1621676Sjpk
1631676Sjpk if (fileerr && !charcnt)
1640Sstevel@tonic-gate return (0);
1651676Sjpk else
1660Sstevel@tonic-gate return (charcnt);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1691676Sjpk /*
1701676Sjpk * _daalloc -
1711676Sjpk * allocates common buffers and structures.
1721676Sjpk * returns pointer to the new structure, else returns NULL on error.
1731676Sjpk */
1741676Sjpk static struct _dabuff *
_daalloc(void)1751676Sjpk _daalloc(void)
1760Sstevel@tonic-gate {
1771676Sjpk struct _dabuff *_da = __dabuff;
1780Sstevel@tonic-gate
1791676Sjpk if (_da == NULL) {
1801676Sjpk _da = (struct _dabuff *)calloc((unsigned)1,
1811676Sjpk (unsigned)sizeof (*__dabuff));
1821676Sjpk if (_da == NULL)
1831676Sjpk return (NULL);
1841676Sjpk DEVALLOC_FILE = "/etc/security/device_allocate";
1851676Sjpk daf = NULL;
1861676Sjpk __dabuff = _da;
1871676Sjpk system_labeled = is_system_labeled();
1880Sstevel@tonic-gate }
1891676Sjpk
1901676Sjpk return (__dabuff);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /*
1941676Sjpk * getdadmfield -
1951676Sjpk * gets individual fields separated by skip in ptr.
1960Sstevel@tonic-gate */
1971676Sjpk char *
getdadmfield(char * ptr,char * skip)1981676Sjpk getdadmfield(char *ptr, char *skip)
1990Sstevel@tonic-gate {
2001676Sjpk static char *tptr = NULL;
2011676Sjpk char *pend;
2020Sstevel@tonic-gate
2031676Sjpk /* check for a continuing search */
2041676Sjpk if (ptr == NULL)
2051676Sjpk ptr = tptr;
2061676Sjpk /* check for source end */
2071676Sjpk if (ptr == NULL || *ptr == '\0')
2081676Sjpk return (NULL);
2091676Sjpk /* find terminator */
2101676Sjpk pend = strpbrk(ptr, skip);
2111676Sjpk /* terminate and set continuation pointer */
2121676Sjpk if (pend != NULL) {
2131676Sjpk *pend++ = '\0';
2141676Sjpk tptr = pend;
2151676Sjpk } else
2161676Sjpk tptr = NULL;
2171676Sjpk /*
2181676Sjpk * trim off any surrounding white space, return what's left
2191676Sjpk */
2201676Sjpk
2211676Sjpk return (trim_white(ptr));
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /*
2251676Sjpk * setdaent -
2261676Sjpk * rewinds the device_allocate file to the begining.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate void
setdaent(void)2301676Sjpk setdaent(void)
2310Sstevel@tonic-gate {
2321676Sjpk struct _dabuff *_da = _daalloc();
2330Sstevel@tonic-gate
2341676Sjpk if (_da == NULL)
2350Sstevel@tonic-gate return;
2361676Sjpk if (daf == NULL)
2371914Scasper daf = fopen(DEVALLOC_FILE, "rF");
2381676Sjpk else
2390Sstevel@tonic-gate rewind(daf);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate /*
2431676Sjpk * enddaent -
2441676Sjpk * closes device_allocate file.
2450Sstevel@tonic-gate */
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate void
enddaent(void)2481676Sjpk enddaent(void)
2490Sstevel@tonic-gate {
2501676Sjpk struct _dabuff *_da = _daalloc();
2510Sstevel@tonic-gate
2521676Sjpk if (_da == NULL)
2530Sstevel@tonic-gate return;
2540Sstevel@tonic-gate if (daf != NULL) {
2550Sstevel@tonic-gate (void) fclose(daf);
2560Sstevel@tonic-gate daf = NULL;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate /*
2611676Sjpk * setdafile -
2621676Sjpk * changes the default device_allocate file to the one specified.
2631676Sjpk * It does not close the previous file. If this is desired, enddaent
2641676Sjpk * should be called prior to setdafile.
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate void
setdafile(char * file)2671676Sjpk setdafile(char *file)
2680Sstevel@tonic-gate {
2691676Sjpk struct _dabuff *_da = _daalloc();
2700Sstevel@tonic-gate
2711676Sjpk if (_da == NULL)
2720Sstevel@tonic-gate return;
2730Sstevel@tonic-gate if (daf != NULL) {
2740Sstevel@tonic-gate (void) fclose(daf);
2750Sstevel@tonic-gate daf = NULL;
2760Sstevel@tonic-gate }
2771676Sjpk DEVALLOC_FILE = file;
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2801676Sjpk void
freedaent(devalloc_t * dap)2811676Sjpk freedaent(devalloc_t *dap)
2821676Sjpk {
2831676Sjpk if (dap == NULL)
2841676Sjpk return;
2851676Sjpk _kva_free(dap->da_devopts);
2861676Sjpk dap->da_devopts = NULL;
2871676Sjpk }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate /*
2901676Sjpk * getdaon -
2911676Sjpk * checks if device_allocate has string DEVICE_ALLOCATION=ON or
2921676Sjpk * DEVICE_ALLOCATION=OFF string in it.
2931676Sjpk * returns 1 if the string is DEVICE_ALLOCATION=ON, 0 if it is
2941676Sjpk * DEVICE_ALLOCATION=OFF, -1 if neither string present.
2951676Sjpk */
2961676Sjpk int
getdaon()2971676Sjpk getdaon()
2981676Sjpk {
2991676Sjpk int is_on = -1;
3001676Sjpk char line1[DA_BUFSIZE + 1];
3011676Sjpk struct _dabuff *_da = _daalloc();
3021676Sjpk
3031676Sjpk setdaent();
3041676Sjpk if ((_da == NULL) || (daf == NULL)) {
3051676Sjpk enddaent();
3061676Sjpk return (is_on);
3071676Sjpk }
3081676Sjpk while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
3091676Sjpk if (strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) {
3101676Sjpk is_on = 1;
3111676Sjpk break;
3121676Sjpk } else if (strncmp(line1, DA_OFF_STR,
3131676Sjpk (strlen(DA_OFF_STR) - 1)) == 0) {
3141676Sjpk is_on = 0;
3151676Sjpk break;
3161676Sjpk }
3171676Sjpk }
3181676Sjpk enddaent();
3191676Sjpk
3201676Sjpk return (is_on);
3211676Sjpk }
3221676Sjpk
3231676Sjpk /*
3241676Sjpk * getdaent -
3251676Sjpk * When first called, returns a pointer to the first devalloc_t
3261676Sjpk * structure in device_allocate; thereafter, it returns a pointer to the
3271676Sjpk * next devalloc_t structure in the file. Thus, successive calls can be
3281676Sjpk * used to search the entire file.
3291676Sjpk * call to getdaent should be bracketed by setdaent and enddaent.
3301676Sjpk * returns NULL on error.
3310Sstevel@tonic-gate */
3320Sstevel@tonic-gate devalloc_t *
getdaent(void)3331676Sjpk getdaent(void)
3340Sstevel@tonic-gate {
3351676Sjpk char line1[DA_BUFSIZE + 1];
3361676Sjpk devalloc_t *da;
3371676Sjpk struct _dabuff *_da = _daalloc();
3381676Sjpk
3391676Sjpk if ((_da == 0) || (daf == NULL))
3401676Sjpk return (NULL);
3410Sstevel@tonic-gate
3421676Sjpk while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
3431676Sjpk if ((strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) ||
3441676Sjpk (strncmp(line1, DA_OFF_STR, (strlen(DA_OFF_STR) - 1)) == 0))
3451676Sjpk continue;
3461676Sjpk if ((da = da_interpret(line1)) == NULL)
3471676Sjpk continue;
3481676Sjpk return (da);
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate
3511676Sjpk return (NULL);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3551676Sjpk * getdanam
3561676Sjpk * searches from the beginning of device_allocate for the device specified
3571676Sjpk * by its name.
3581676Sjpk * call to getdanam should be bracketed by setdaent and enddaent.
3591676Sjpk * returns pointer to devalloc_t for the device if it is found, else
3601676Sjpk * returns NULL if device not found or in case of error.
3610Sstevel@tonic-gate */
3620Sstevel@tonic-gate devalloc_t *
getdanam(char * name)3631676Sjpk getdanam(char *name)
3640Sstevel@tonic-gate {
3651676Sjpk char line[DA_BUFSIZE + 1];
3661676Sjpk devalloc_t *da;
3671676Sjpk struct _dabuff *_da = _daalloc();
3680Sstevel@tonic-gate
3691676Sjpk if ((name == NULL) || (_da == 0) || (daf == NULL))
3700Sstevel@tonic-gate return (NULL);
3710Sstevel@tonic-gate
3721676Sjpk while (getdadmline(line, (int)sizeof (line), daf) != 0) {
3731676Sjpk if (strstr(line, name) == NULL)
3741676Sjpk continue;
3751676Sjpk if ((da = da_interpret(line)) == NULL)
3761676Sjpk continue;
3771676Sjpk if (da_matchname(da, name)) {
3781676Sjpk enddaent();
3791676Sjpk return (da);
3801676Sjpk }
3811676Sjpk freedaent(da);
3821676Sjpk }
3831676Sjpk
3841676Sjpk return (NULL);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate /*
3881676Sjpk * getdatype -
3891676Sjpk * searches from the beginning of device_allocate for the device specified
3901676Sjpk * by its type.
3911676Sjpk * call to getdatype should be bracketed by setdaent and enddaent.
3921676Sjpk * returns pointer to devalloc_t for the device if it is found, else
3931676Sjpk * returns NULL if device not found or in case of error.
3940Sstevel@tonic-gate */
3951676Sjpk devalloc_t *
getdatype(char * type)3961676Sjpk getdatype(char *type)
3970Sstevel@tonic-gate {
3981676Sjpk char line1[DA_BUFSIZE + 1];
3991676Sjpk devalloc_t *da;
4001676Sjpk struct _dabuff *_da = _daalloc();
4011676Sjpk
4021676Sjpk if ((type == NULL) || (_da == NULL) || (daf == NULL))
4031676Sjpk return (NULL);
4040Sstevel@tonic-gate
4051676Sjpk while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
4061676Sjpk if (strstr(line1, type) == NULL)
4071676Sjpk continue;
4081676Sjpk if ((da = da_interpret(line1)) == NULL)
4091676Sjpk continue;
4101676Sjpk if (da_matchtype(da, type))
4111676Sjpk return (da);
4121676Sjpk freedaent(da);
4131676Sjpk }
4141676Sjpk
4151676Sjpk return (NULL);
4161676Sjpk }
4171676Sjpk
4181676Sjpk /*
4191676Sjpk * da_matchname -
4201676Sjpk * checks if the specified devalloc_t is for the device specified.
4211676Sjpk * returns 1 if it is, else returns 0.
4221676Sjpk */
4231676Sjpk int
da_matchname(devalloc_t * dap,char * name)4241676Sjpk da_matchname(devalloc_t *dap, char *name)
4251676Sjpk {
4261676Sjpk if (dap->da_devname == NULL)
4270Sstevel@tonic-gate return (0);
4281676Sjpk
4291676Sjpk return ((strcmp(dap->da_devname, name) == 0));
4301676Sjpk }
4311676Sjpk
4321676Sjpk /*
4331676Sjpk * da_matchtype -
4341676Sjpk * checks if the specified devalloc_t is for the device type specified.
4351676Sjpk * returns 1 if match found, else, returns 0.
4361676Sjpk */
4371676Sjpk int
da_matchtype(devalloc_t * da,char * type)4381676Sjpk da_matchtype(devalloc_t *da, char *type)
4391676Sjpk {
4401676Sjpk if (da->da_devtype == NULL)
4410Sstevel@tonic-gate return (0);
4421676Sjpk
4431676Sjpk return ((strcmp(da->da_devtype, type) == 0));
4441676Sjpk }
4451676Sjpk
4461676Sjpk /*
4471676Sjpk * da_match -
4481676Sjpk * calls da_matchname or da_matchdev as appropriate.
4491676Sjpk */
4501676Sjpk int
da_match(devalloc_t * dap,da_args * dargs)4511676Sjpk da_match(devalloc_t *dap, da_args *dargs)
4521676Sjpk {
4531676Sjpk if (dargs->devinfo->devname)
4541676Sjpk return (da_matchname(dap, dargs->devinfo->devname));
4551676Sjpk else if (dargs->devinfo->devtype)
4561676Sjpk return (da_matchtype(dap, dargs->devinfo->devtype));
4571676Sjpk
4580Sstevel@tonic-gate return (0);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate /*
4621676Sjpk * da_interpret -
4631676Sjpk * parses val and initializes pointers in devalloc_t.
4641676Sjpk * returns pointer to parsed devalloc_t entry, else returns NULL on error.
4650Sstevel@tonic-gate */
4660Sstevel@tonic-gate static devalloc_t *
da_interpret(char * val)4671676Sjpk da_interpret(char *val)
4680Sstevel@tonic-gate {
4691676Sjpk struct _dabuff *_da = _daalloc();
4701676Sjpk char *opts;
4711676Sjpk int i;
4721676Sjpk kva_t *kvap;
4731676Sjpk kv_t *kvp;
4741676Sjpk
4751676Sjpk if (_da == NULL)
4761676Sjpk return (NULL);
4771676Sjpk
4781676Sjpk (void) strcpy(interpdaline, val);
4791676Sjpk interpdevalloc.da_devname = getdadmfield(interpdaline, KV_DELIMITER);
4801676Sjpk interpdevalloc.da_devtype = getdadmfield(NULL, KV_DELIMITER);
4811676Sjpk opts = getdadmfield(NULL, KV_DELIMITER);
4821676Sjpk (void) getdadmfield(NULL, KV_DELIMITER); /* reserved field */
4831676Sjpk interpdevalloc.da_devauth = getdadmfield(NULL, KV_DELIMITER);
4841676Sjpk interpdevalloc.da_devexec = getdadmfield(NULL, KV_DELIMITER);
4851676Sjpk interpdevalloc.da_devopts = NULL;
4861676Sjpk if (interpdevalloc.da_devname == NULL ||
4871676Sjpk interpdevalloc.da_devtype == NULL)
4881676Sjpk return (NULL);
4891676Sjpk if ((opts != NULL) &&
4901676Sjpk (strncmp(opts, DA_RESERVED, strlen(DA_RESERVED)) != 0)) {
4911676Sjpk interpdevalloc.da_devopts =
4921676Sjpk _str2kva(opts, KV_ASSIGN, KV_TOKEN_DELIMIT);
4931676Sjpk }
4941676Sjpk /* remove any extraneous whitespace in the options */
4951676Sjpk if ((kvap = interpdevalloc.da_devopts) != NULL) {
4961676Sjpk for (i = 0, kvp = kvap->data; i < kvap->length; i++, kvp++) {
4971676Sjpk (void) pack_white(kvp->key);
4981676Sjpk (void) pack_white(kvp->value);
4991676Sjpk }
5001676Sjpk }
5010Sstevel@tonic-gate
5021676Sjpk if (system_labeled) {
5031676Sjpk /* if label range is not defined, use the default range. */
5041676Sjpk int i = 0, nlen = 0;
5051676Sjpk char *minstr = NULL, *maxstr = NULL;
5061676Sjpk kva_t *nkvap = NULL;
5071676Sjpk kv_t *ndata = NULL, *odata = NULL;
5080Sstevel@tonic-gate
5091676Sjpk if (kvap == NULL) {
5101676Sjpk nlen = 2; /* minlabel, maxlabel */
5111676Sjpk } else {
5121676Sjpk nlen += kvap->length;
5131676Sjpk if ((minstr = kva_match(kvap, DAOPT_MINLABEL)) == NULL)
5141676Sjpk nlen++;
5151676Sjpk if ((maxstr = kva_match(kvap, DAOPT_MAXLABEL)) == NULL)
5161676Sjpk nlen++;
5171676Sjpk }
5181676Sjpk if ((minstr != NULL) && (maxstr != NULL))
5191676Sjpk /*
5201676Sjpk * label range provided; we don't need to construct
5211676Sjpk * default range.
5221676Sjpk */
5231676Sjpk goto out;
5241676Sjpk nkvap = _new_kva(nlen);
5251676Sjpk ndata = nkvap->data;
5261676Sjpk if (kvap != NULL) {
5271676Sjpk for (i = 0; i < kvap->length; i++) {
5281676Sjpk odata = kvap->data;
5291676Sjpk ndata[i].key = _strdup_null(odata[i].key);
5301676Sjpk ndata[i].value = _strdup_null(odata[i].value);
5311676Sjpk nkvap->length++;
5321676Sjpk }
5331676Sjpk }
5341676Sjpk if (minstr == NULL) {
5351676Sjpk ndata[i].key = strdup(DAOPT_MINLABEL);
5361676Sjpk ndata[i].value = strdup(DA_DEFAULT_MIN);
5371676Sjpk nkvap->length++;
5381676Sjpk i++;
5391676Sjpk }
5401676Sjpk if (maxstr == NULL) {
5411676Sjpk ndata[i].key = strdup(DAOPT_MAXLABEL);
5421676Sjpk ndata[i].value = strdup(DA_DEFAULT_MAX);
5431676Sjpk nkvap->length++;
5441676Sjpk }
5451676Sjpk interpdevalloc.da_devopts = nkvap;
5461676Sjpk }
5471676Sjpk
5481676Sjpk out:
5490Sstevel@tonic-gate return (&interpdevalloc);
5500Sstevel@tonic-gate }
551