2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <errno.h>
2N/A#include <ctype.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/dld.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <libdladm_impl.h>
2N/A#include <libdlflow_impl.h>
2N/A
2N/A/*
2N/A * XXX duplicate defines
2N/A */
2N/A#define DLADM_PROP_VAL_MAX 32
2N/A#define DLADM_MAX_PROPS 32
2N/A
2N/Astatic void
2N/Afree_props(prop_db_info_t *lip)
2N/A{
2N/A prop_db_info_t *lip_next;
2N/A prop_val_t *lvp, *lvp_next;
2N/A
2N/A for (; lip != NULL; lip = lip_next) {
2N/A lip_next = lip->li_nextprop;
2N/A for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
2N/A lvp_next = lvp->lv_nextval;
2N/A free(lvp);
2N/A }
2N/A free(lip);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Generate an entry in the property database.
2N/A * Each entry has this format:
2N/A * <name> <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
2N/A */
2N/Astatic void
2N/Agenerate_prop_line(const char *name, char *buf,
2N/A prop_db_info_t *listp, dladm_status_t *statusp)
2N/A{
2N/A char tmpbuf[MAXLINELEN];
2N/A char *ptr, *lim = tmpbuf + MAXLINELEN;
2N/A prop_db_info_t *lip = listp;
2N/A prop_val_t *lvp = NULL;
2N/A
2N/A /*
2N/A * Delete line if there are no properties left.
2N/A */
2N/A if (lip == NULL ||
2N/A (lip->li_val == NULL && lip->li_nextprop == NULL)) {
2N/A buf[0] = '\0';
2N/A return;
2N/A }
2N/A ptr = tmpbuf;
2N/A ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", name);
2N/A for (; lip != NULL; lip = lip->li_nextprop) {
2N/A /*
2N/A * Skip properties without values.
2N/A */
2N/A if (lip->li_val == NULL)
2N/A continue;
2N/A
2N/A ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name);
2N/A for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
2N/A ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c",
2N/A lvp->lv_name,
2N/A ((lvp->lv_nextval == NULL) ? ';' : ','));
2N/A }
2N/A }
2N/A if (ptr > lim) {
2N/A *statusp = DLADM_STATUS_TOOSMALL;
2N/A return;
2N/A }
2N/A (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
2N/A}
2N/A
2N/A/*
2N/A * This function is used to update or create an entry in the persistent db.
2N/A * process_prop_db() will first scan the db for an entry matching the
2N/A * specified name. If a match is found, this function is invoked with the
2N/A * entry's contents (buf) and its linked-list representation (listp). lsp
2N/A * holds the name and values of the property to be added or updated; this
2N/A * information will be merged with listp. Subsequently, an updated entry
2N/A * will be written to buf, which will in turn be written to disk by
2N/A * process_prop_db(). If no entry matches the specified name, listp
2N/A * will be NULL; a new entry will be generated in this case and it will
2N/A * contain only the property information in lsp.
2N/A */
2N/A/* ARGSUSED */
2N/Aboolean_t
2N/Aprocess_prop_set(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
2N/A prop_db_info_t *listp, dladm_status_t *statusp)
2N/A{
2N/A dladm_status_t status;
2N/A prop_db_info_t *lastp = NULL, *lip = listp, *nlip = NULL;
2N/A prop_val_t **lvpp;
2N/A int i;
2N/A
2N/A if (lsp->ls_propname == NULL) {
2N/A buf[0] = '\0';
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A /*
2N/A * Find the prop we want to change.
2N/A */
2N/A for (; lip != NULL; lip = lip->li_nextprop) {
2N/A if (strcmp(lip->li_name, lsp->ls_propname) == 0)
2N/A break;
2N/A
2N/A lastp = lip;
2N/A }
2N/A
2N/A if (lip == NULL) {
2N/A /*
2N/A * If the prop is not found, append it to the list.
2N/A */
2N/A if ((nlip = malloc(sizeof (prop_db_info_t))) == NULL) {
2N/A status = DLADM_STATUS_NOMEM;
2N/A goto fail;
2N/A }
2N/A /*
2N/A * nlip will need to be freed later if there is no list to
2N/A * append to.
2N/A */
2N/A if (lastp != NULL)
2N/A lastp->li_nextprop = nlip;
2N/A nlip->li_name = lsp->ls_propname;
2N/A nlip->li_nextprop = NULL;
2N/A nlip->li_val = NULL;
2N/A lvpp = &nlip->li_val;
2N/A } else {
2N/A prop_val_t *lvp, *lvp_next;
2N/A
2N/A /*
2N/A * If the prop is found, delete the existing values from it.
2N/A */
2N/A for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
2N/A lvp_next = lvp->lv_nextval;
2N/A free(lvp);
2N/A }
2N/A lip->li_val = NULL;
2N/A lvpp = &lip->li_val;
2N/A }
2N/A
2N/A /*
2N/A * Fill our prop with the specified values.
2N/A */
2N/A for (i = 0; i < *lsp->ls_valcntp; i++) {
2N/A if ((*lvpp = malloc(sizeof (prop_val_t))) == NULL) {
2N/A status = DLADM_STATUS_NOMEM;
2N/A goto fail;
2N/A }
2N/A (*lvpp)->lv_name = lsp->ls_propval[i];
2N/A (*lvpp)->lv_nextval = NULL;
2N/A lvpp = &(*lvpp)->lv_nextval;
2N/A }
2N/A
2N/A if (listp != NULL) {
2N/A generate_prop_line(lsp->ls_name, buf, listp, statusp);
2N/A } else {
2N/A generate_prop_line(lsp->ls_name, buf, nlip, statusp);
2N/A free_props(nlip);
2N/A }
2N/A return (B_FALSE);
2N/A
2N/Afail:
2N/A *statusp = status;
2N/A if (listp == NULL)
2N/A free_props(nlip);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * This function is used for retrieving the values for a specific property.
2N/A * It gets called if an entry matching the specified name exists in the db.
2N/A * The entry is converted into a linked-list listp. This list is then scanned
2N/A * for the specified property name; if a matching property exists, its
2N/A * associated values are copied to the array lsp->ls_propval.
2N/A */
2N/A/* ARGSUSED */
2N/Aboolean_t
2N/Aprocess_prop_get(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
2N/A prop_db_info_t *listp, dladm_status_t *statusp)
2N/A{
2N/A prop_db_info_t *lip = listp;
2N/A prop_val_t *lvp;
2N/A uint_t valcnt = 0;
2N/A
2N/A /*
2N/A * Find the prop we want to get.
2N/A */
2N/A for (; lip != NULL; lip = lip->li_nextprop) {
2N/A if (strcmp(lip->li_name, lsp->ls_propname) == 0)
2N/A break;
2N/A }
2N/A if (lip == NULL) {
2N/A *statusp = DLADM_STATUS_NOTFOUND;
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
2N/A (void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name,
2N/A DLADM_PROP_VAL_MAX);
2N/A
2N/A if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) {
2N/A *statusp = DLADM_STATUS_TOOSMALL;
2N/A return (B_FALSE);
2N/A }
2N/A }
2N/A /*
2N/A * This function is meant to be called at most once for each call
2N/A * to process_prop_db(). For this reason, it's ok to overwrite
2N/A * the caller's valcnt array size with the actual number of values
2N/A * returned.
2N/A */
2N/A *lsp->ls_valcntp = valcnt;
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * This is used for initializing properties.
2N/A * Unlike the other routines, this gets called for every entry in the
2N/A * database. lsp->ls_name is not user-specified but instead is set to
2N/A * the current name being processed.
2N/A */
2N/A/* ARGSUSED */
2N/Aboolean_t
2N/Aprocess_prop_init(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
2N/A prop_db_info_t *listp, dladm_status_t *statusp)
2N/A{
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A prop_db_info_t *lip = listp;
2N/A prop_val_t *lvp;
2N/A uint_t valcnt, i;
2N/A char **propval;
2N/A
2N/A for (; lip != NULL; lip = lip->li_nextprop) {
2N/A /*
2N/A * Construct the propval array and fill it with
2N/A * values from listp.
2N/A */
2N/A for (lvp = lip->li_val, valcnt = 0;
2N/A lvp != NULL; lvp = lvp->lv_nextval, valcnt++) {
2N/A }
2N/A
2N/A propval = malloc(sizeof (char *) * valcnt);
2N/A if (propval == NULL) {
2N/A *statusp = DLADM_STATUS_NOMEM;
2N/A break;
2N/A }
2N/A lvp = lip->li_val;
2N/A for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval)
2N/A propval[i] = (char *)lvp->lv_name;
2N/A
2N/A status = (*lsp->ls_initop)(handle, lsp->ls_name, lip->li_name,
2N/A propval, valcnt, DLADM_OPT_ACTIVE, NULL);
2N/A
2N/A /*
2N/A * We continue with initializing other properties even
2N/A * after encountering an error. This error will be
2N/A * propagated to the caller via 'statusp'.
2N/A */
2N/A if (status != DLADM_STATUS_OK)
2N/A *statusp = status;
2N/A
2N/A free(propval);
2N/A }
2N/A return (B_TRUE);
2N/A}
2N/A
2N/Astatic int
2N/Aparse_props(char *buf, prop_db_info_t **lipp)
2N/A{
2N/A int i, len;
2N/A char *curr;
2N/A prop_db_info_t *lip = NULL;
2N/A prop_db_info_t **tailp = lipp;
2N/A prop_val_t *lvp = NULL;
2N/A prop_val_t **vtailp = NULL;
2N/A
2N/A curr = buf;
2N/A len = strlen(buf);
2N/A for (i = 0; i < len; i++) {
2N/A char c = buf[i];
2N/A boolean_t match = (c == '=' || c == ',' || c == ';');
2N/A
2N/A /*
2N/A * Move to the next character if there is no match and
2N/A * if we have not reached the last character.
2N/A */
2N/A if (!match && i != len - 1)
2N/A continue;
2N/A
2N/A if (match) {
2N/A /*
2N/A * Nul-terminate the string pointed to by 'curr'.
2N/A */
2N/A buf[i] = '\0';
2N/A if (*curr == '\0')
2N/A goto fail;
2N/A }
2N/A
2N/A if (lip != NULL) {
2N/A /*
2N/A * We get here after we have processed the "<prop>="
2N/A * pattern. The pattern we are now interested in is
2N/A * "<val0>,<val1>,...,<valn>;". For each value we
2N/A * find, a prop_val_t will be allocated and
2N/A * added to the current 'lip'.
2N/A */
2N/A if (c == '=')
2N/A goto fail;
2N/A
2N/A lvp = malloc(sizeof (*lvp));
2N/A if (lvp == NULL)
2N/A goto fail;
2N/A
2N/A lvp->lv_name = curr;
2N/A lvp->lv_nextval = NULL;
2N/A *vtailp = lvp;
2N/A vtailp = &lvp->lv_nextval;
2N/A
2N/A if (c == ';') {
2N/A tailp = &lip->li_nextprop;
2N/A vtailp = NULL;
2N/A lip = NULL;
2N/A }
2N/A } else {
2N/A /*
2N/A * lip == NULL indicates that 'curr' must be refering
2N/A * to a property name. We allocate a new prop_db_info_t
2N/A * append it to the list given by the caller.
2N/A */
2N/A if (c != '=')
2N/A goto fail;
2N/A
2N/A lip = malloc(sizeof (*lip));
2N/A if (lip == NULL)
2N/A goto fail;
2N/A
2N/A lip->li_name = curr;
2N/A lip->li_val = NULL;
2N/A lip->li_nextprop = NULL;
2N/A *tailp = lip;
2N/A vtailp = &lip->li_val;
2N/A }
2N/A curr = buf + i + 1;
2N/A }
2N/A /*
2N/A * The list must be non-empty and the last character must be ';'.
2N/A */
2N/A if (*lipp == NULL || lip != NULL)
2N/A goto fail;
2N/A
2N/A return (0);
2N/A
2N/Afail:
2N/A free_props(*lipp);
2N/A *lipp = NULL;
2N/A return (-1);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Aprocess_prop_line(dladm_handle_t handle, prop_db_state_t *lsp, char *buf,
2N/A dladm_status_t *statusp)
2N/A{
2N/A prop_db_info_t *lip = NULL;
2N/A int i, len, llen;
2N/A char *str, *lasts;
2N/A boolean_t cont, noname = B_FALSE;
2N/A
2N/A /*
2N/A * Skip leading spaces, blank lines, and comments.
2N/A */
2N/A len = strlen(buf);
2N/A for (i = 0; i < len; i++) {
2N/A if (!isspace(buf[i]))
2N/A break;
2N/A }
2N/A if (i == len || buf[i] == '#')
2N/A return (B_TRUE);
2N/A
2N/A str = buf + i;
2N/A if (lsp->ls_name != NULL) {
2N/A /*
2N/A * Skip names we're not interested in.
2N/A * Note that strncmp() and isspace() are used here
2N/A * instead of strtok() and strcmp() because we don't
2N/A * want to modify buf in case it does not contain the
2N/A * specified name.
2N/A */
2N/A llen = strlen(lsp->ls_name);
2N/A if (strncmp(str, lsp->ls_name, llen) != 0 ||
2N/A !isspace(str[llen]))
2N/A return (B_TRUE);
2N/A } else {
2N/A /*
2N/A * If a name is not specified, find the name
2N/A * and assign it to lsp->ls_name.
2N/A */
2N/A if (strtok_r(str, " \n\t", &lasts) == NULL)
2N/A goto fail;
2N/A
2N/A llen = strlen(str);
2N/A lsp->ls_name = str;
2N/A noname = B_TRUE;
2N/A }
2N/A str += llen + 1;
2N/A if (str >= buf + len)
2N/A goto fail;
2N/A
2N/A /*
2N/A * Now find the list of properties.
2N/A */
2N/A if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
2N/A goto fail;
2N/A
2N/A if (parse_props(str, &lip) < 0)
2N/A goto fail;
2N/A
2N/A cont = (*lsp->ls_op)(handle, lsp, buf, lip, statusp);
2N/A free_props(lip);
2N/A if (noname)
2N/A lsp->ls_name = NULL;
2N/A return (cont);
2N/A
2N/Afail:
2N/A free_props(lip);
2N/A if (noname)
2N/A lsp->ls_name = NULL;
2N/A
2N/A /*
2N/A * Delete corrupted line.
2N/A */
2N/A buf[0] = '\0';
2N/A return (B_TRUE);
2N/A}
2N/A
2N/Adladm_status_t
2N/Aprocess_prop_db(dladm_handle_t handle, void *arg, FILE *fp, FILE *nfp)
2N/A{
2N/A prop_db_state_t *lsp = arg;
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A char buf[MAXLINELEN];
2N/A boolean_t cont = B_TRUE;
2N/A
2N/A /*
2N/A * This loop processes each line of the configuration file.
2N/A * buf can potentially be modified by process_prop_line().
2N/A * If this is a write operation and buf is not truncated, buf will
2N/A * be written to disk. process_prop_line() will no longer be
2N/A * called after it returns B_FALSE; at which point the remainder
2N/A * of the file will continue to be read and, if necessary, written
2N/A * to disk as well.
2N/A */
2N/A while (fgets(buf, MAXLINELEN, fp) != NULL) {
2N/A if (cont)
2N/A cont = process_prop_line(handle, lsp, buf, &status);
2N/A
2N/A if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
2N/A status = dladm_errno2status(errno);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (status != DLADM_STATUS_OK || !cont)
2N/A return (status);
2N/A
2N/A if (lsp->ls_op == process_prop_set) {
2N/A /*
2N/A * If the specified name is not found above, we add the
2N/A * name and its properties to the configuration file.
2N/A */
2N/A (void) (*lsp->ls_op)(handle, lsp, buf, NULL, &status);
2N/A if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF)
2N/A status = dladm_errno2status(errno);
2N/A }
2N/A
2N/A if (lsp->ls_op == process_prop_get)
2N/A status = DLADM_STATUS_NOTFOUND;
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Ai_dladm_get_prop_temp(dladm_handle_t handle, const char *name,
2N/A dladm_prop_type_t type, const char *prop_name, char **prop_val,
2N/A uint_t *val_cntp, prop_table_t *prop_tbl)
2N/A{
2N/A int i;
2N/A dladm_status_t status;
2N/A uint_t cnt;
2N/A fprop_desc_t *pdp;
2N/A
2N/A if (name == NULL || prop_name == NULL || prop_val == NULL ||
2N/A val_cntp == NULL || *val_cntp == 0)
2N/A return (DLADM_STATUS_BADARG);
2N/A
2N/A for (i = 0; i < prop_tbl->pt_size; i++)
2N/A if (strcasecmp(prop_name, prop_tbl->pt_table[i].pd_name) == 0)
2N/A break;
2N/A
2N/A if (i == prop_tbl->pt_size)
2N/A return (DLADM_STATUS_NOTFOUND);
2N/A
2N/A pdp = &prop_tbl->pt_table[i];
2N/A status = DLADM_STATUS_OK;
2N/A
2N/A switch (type) {
2N/A case DLADM_PROP_VAL_CURRENT:
2N/A status = pdp->pd_get(handle, name, prop_val, val_cntp);
2N/A break;
2N/A case DLADM_PROP_VAL_DEFAULT:
2N/A if (pdp->pd_defval.vd_name == NULL) {
2N/A status = DLADM_STATUS_NOTSUP;
2N/A break;
2N/A }
2N/A (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
2N/A *val_cntp = 1;
2N/A break;
2N/A
2N/A case DLADM_PROP_VAL_MODIFIABLE:
2N/A if (pdp->pd_getmod != NULL) {
2N/A status = pdp->pd_getmod(handle, name, prop_val,
2N/A val_cntp);
2N/A break;
2N/A }
2N/A cnt = pdp->pd_nmodval;
2N/A if (cnt == 0) {
2N/A status = DLADM_STATUS_NOTSUP;
2N/A } else if (cnt > *val_cntp) {
2N/A status = DLADM_STATUS_TOOSMALL;
2N/A } else {
2N/A for (i = 0; i < cnt; i++) {
2N/A (void) strcpy(prop_val[i],
2N/A pdp->pd_modval[i].vd_name);
2N/A }
2N/A *val_cntp = cnt;
2N/A }
2N/A break;
2N/A default:
2N/A status = DLADM_STATUS_BADARG;
2N/A break;
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Astatic dladm_status_t
2N/Ai_dladm_set_one_prop_temp(dladm_handle_t handle, const char *name,
2N/A fprop_desc_t *pdp, char **prop_val, uint_t val_cnt, uint_t flags)
2N/A{
2N/A dladm_status_t status;
2N/A val_desc_t *vdp = NULL;
2N/A uint_t cnt;
2N/A
2N/A if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0)
2N/A return (DLADM_STATUS_TEMPONLY);
2N/A
2N/A if (pdp->pd_set == NULL)
2N/A return (DLADM_STATUS_PROPRDONLY);
2N/A
2N/A if (prop_val != NULL) {
2N/A if (pdp->pd_check != NULL)
2N/A status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp);
2N/A else
2N/A status = DLADM_STATUS_BADARG;
2N/A
2N/A if (status != DLADM_STATUS_OK)
2N/A return (status);
2N/A
2N/A cnt = val_cnt;
2N/A } else {
2N/A if (pdp->pd_defval.vd_name == NULL)
2N/A return (DLADM_STATUS_NOTSUP);
2N/A
2N/A if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
2N/A return (DLADM_STATUS_NOMEM);
2N/A
2N/A (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
2N/A cnt = 1;
2N/A }
2N/A
2N/A status = pdp->pd_set(handle, name, vdp, cnt);
2N/A
2N/A free(vdp);
2N/A return (status);
2N/A}
2N/A
2N/Adladm_status_t
2N/Ai_dladm_set_prop_temp(dladm_handle_t handle, const char *name,
2N/A const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags,
2N/A char **errprop, prop_table_t *prop_tbl)
2N/A{
2N/A int i;
2N/A dladm_status_t status = DLADM_STATUS_OK;
2N/A boolean_t found = B_FALSE;
2N/A
2N/A for (i = 0; i < prop_tbl->pt_size; i++) {
2N/A fprop_desc_t *pdp = &prop_tbl->pt_table[i];
2N/A dladm_status_t s;
2N/A
2N/A if (prop_name != NULL &&
2N/A (strcasecmp(prop_name, pdp->pd_name) != 0))
2N/A continue;
2N/A
2N/A found = B_TRUE;
2N/A s = i_dladm_set_one_prop_temp(handle, name, pdp, prop_val,
2N/A val_cnt, flags);
2N/A
2N/A if (prop_name != NULL) {
2N/A status = s;
2N/A break;
2N/A } else {
2N/A if (s != DLADM_STATUS_OK &&
2N/A s != DLADM_STATUS_NOTSUP) {
2N/A if (errprop != NULL)
2N/A *errprop = pdp->pd_name;
2N/A status = s;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (!found)
2N/A status = DLADM_STATUS_NOTFOUND;
2N/A
2N/A return (status);
2N/A}
2N/A
2N/Aboolean_t
2N/Ai_dladm_is_prop_temponly(const char *prop_name, char **errprop,
2N/A prop_table_t *prop_tbl)
2N/A{
2N/A int i;
2N/A
2N/A if (prop_name == NULL)
2N/A return (B_FALSE);
2N/A
2N/A for (i = 0; i < prop_tbl->pt_size; i++) {
2N/A fprop_desc_t *pdp = &prop_tbl->pt_table[i];
2N/A
2N/A if (strcasecmp(prop_name, pdp->pd_name) != 0)
2N/A continue;
2N/A
2N/A if (errprop != NULL)
2N/A *errprop = pdp->pd_name;
2N/A
2N/A if (pdp->pd_temponly)
2N/A return (B_TRUE);
2N/A }
2N/A
2N/A return (B_FALSE);
2N/A}
2N/Avoid
2N/Adladm_free_props(dladm_arg_list_t *list)
2N/A{
2N/A dladm_free_args(list);
2N/A}
2N/A
2N/Adladm_status_t
2N/Adladm_parse_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
2N/A{
2N/A if (dladm_parse_args(str, listp, novalues) != DLADM_STATUS_OK)
2N/A goto fail;
2N/A
2N/A return (DLADM_STATUS_OK);
2N/A
2N/Afail:
2N/A dladm_free_args(*listp);
2N/A return (DLADM_STATUS_PROP_PARSE_ERR);
2N/A}