libnetcfg.c revision 2
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/*
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <assert.h>
2N/A#include <auth_attr.h>
2N/A#include <door.h>
2N/A#include <errno.h>
2N/A#include <fcntl.h>
2N/A#include <libintl.h>
2N/A#include <libscf.h>
2N/A#include <pthread.h>
2N/A#include <pwd.h>
2N/A#include <strings.h>
2N/A#include <s10_brand.h>
2N/A#include <sys/mman.h>
2N/A#include <unistd.h>
2N/A#include <zone.h>
2N/A
2N/A#include "libnetcfg.h"
2N/A#include "libnetcfg_impl.h"
2N/A
2N/A/*
2N/A * Communicate with the backend daemon (running in netcfgd) to retrieve or
2N/A * change configuration.
2N/A */
2N/Astatic int netcfgd_door_fd = -1;
2N/Apthread_mutex_t door_mutex = PTHREAD_MUTEX_INITIALIZER;
2N/A
2N/A#define NP_FMRI "svc:/network/physical:default"
2N/A#define NP_NETCFG_PG "netcfg"
2N/A#define NP_ACTIVE_NCP_PROP "active_ncp"
2N/A
2N/A/* error codes and text description */
2N/Astatic struct netcfg_error_info {
2N/A netcfg_error_t error_code;
2N/A const char *error_desc;
2N/A} netcfg_errors[] = {
2N/A { NETCFG_SUCCESS, "no error" },
2N/A { NETCFG_EPERM, "permission denied" },
2N/A { NETCFG_INVALID_ARG, "invalid argument" },
2N/A { NETCFG_EXISTS, "object exists" },
2N/A { NETCFG_NOT_FOUND, "object not found" },
2N/A { NETCFG_WALK_HALTED, "callback function halted walk" },
2N/A { NETCFG_ERROR_BIND, "could not bind to daemon" },
2N/A { NETCFG_NO_MEMORY, "insufficient memory" },
2N/A { NETCFG_FAILURE, "failure" }
2N/A};
2N/A
2N/A#define NETCFG_NUM_ERRORS (sizeof (netcfg_errors) / sizeof (*netcfg_errors))
2N/A
2N/A/*
2N/A * Returns a message string for the given libnetcfg error code.
2N/A */
2N/Aconst char *
2N/Anetcfg_strerror(netcfg_error_t code)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < NETCFG_NUM_ERRORS; i++) {
2N/A if (code == netcfg_errors[i].error_code) {
2N/A return (dgettext(TEXT_DOMAIN,
2N/A netcfg_errors[i].error_desc));
2N/A }
2N/A }
2N/A return (dgettext(TEXT_DOMAIN, "<unknown error>"));
2N/A}
2N/A
2N/Anetcfg_error_t
2N/Anetcfg_errno2error(int error)
2N/A{
2N/A switch (error) {
2N/A case 0:
2N/A return (NETCFG_SUCCESS);
2N/A case ENOMEM:
2N/A case ENOSPC:
2N/A return (NETCFG_NO_MEMORY);
2N/A case EFAULT:
2N/A case EINVAL:
2N/A return (NETCFG_INVALID_ARG);
2N/A
2N/A case EEXIST:
2N/A return (NETCFG_EXISTS);
2N/A case ENOENT:
2N/A case ENOTDIR:
2N/A return (NETCFG_NOT_FOUND);
2N/A case EACCES:
2N/A case EPERM:
2N/A return (NETCFG_EPERM);
2N/A case EBADF:
2N/A return (NETCFG_ERROR_BIND);
2N/A default:
2N/A return (NETCFG_FAILURE);
2N/A }
2N/A}
2N/A
2N/Aint
2N/Anetcfg_error2errno(netcfg_error_t code)
2N/A{
2N/A int err;
2N/A
2N/A switch (code) {
2N/A case NETCFG_SUCCESS:
2N/A err = 0;
2N/A break;
2N/A case NETCFG_EPERM:
2N/A err = EACCES;
2N/A break;
2N/A case NETCFG_INVALID_ARG:
2N/A err = EINVAL;
2N/A break;
2N/A case NETCFG_EXISTS:
2N/A err = EEXIST;
2N/A break;
2N/A case NETCFG_NOT_FOUND:
2N/A err = ENOENT;
2N/A break;
2N/A case NETCFG_WALK_HALTED:
2N/A err = ECANCELED;
2N/A break;
2N/A case NETCFG_NO_MEMORY:
2N/A err = ENOMEM;
2N/A break;
2N/A case NETCFG_ERROR_BIND:
2N/A case NETCFG_FAILURE:
2N/A default:
2N/A /* no good analog for these */
2N/A err = EINVAL;
2N/A break;
2N/A }
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Read the "netcfg/active_ncp" property from svc:/network/physical:default
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_active_profile(char *profile, size_t pbuflen)
2N/A{
2N/A zoneid_t zoneid = getzoneid();
2N/A char brand[MAXNAMELEN];
2N/A scf_simple_prop_t *prop;
2N/A
2N/A *profile = NULL;
2N/A /* Need to skip if we're in an S10-branded zone */
2N/A if (zoneid != GLOBAL_ZONEID) {
2N/A if (zone_getattr(zoneid, ZONE_ATTR_BRAND, brand,
2N/A sizeof (brand)) < 0) {
2N/A return (netcfg_errno2error(errno));
2N/A }
2N/A if (strcmp(brand, S10_BRANDNAME) == 0) {
2N/A (void) strlcpy(profile, S10_BRAND_DUMMY_PROFILE,
2N/A pbuflen);
2N/A return (NETCFG_SUCCESS);
2N/A }
2N/A }
2N/A
2N/A prop = scf_simple_prop_get(NULL, NP_FMRI, NP_NETCFG_PG,
2N/A NP_ACTIVE_NCP_PROP);
2N/A if (prop == NULL)
2N/A return (NETCFG_FAILURE);
2N/A
2N/A if (scf_simple_prop_numvalues(prop) > 0) {
2N/A (void) strlcpy(profile, scf_simple_prop_next_astring(prop),
2N/A pbuflen);
2N/A }
2N/A scf_simple_prop_free(prop);
2N/A
2N/A return (NETCFG_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Read nvlists from the door argument that is returned by the door call to
2N/A * netcfgd. If the arg datalen is non-zero, unpack the object nvlist.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_read_lists_from_door_arg(netcfgd_door_arg_t *arg, nvlist_t **idlist,
2N/A nvlist_t **objp)
2N/A{
2N/A caddr_t idptr, dataptr;
2N/A int nverr;
2N/A
2N/A if (arg->nda_result != NETCFG_SUCCESS)
2N/A return (arg->nda_result);
2N/A
2N/A idptr = (caddr_t)arg + sizeof (netcfgd_door_arg_t);
2N/A if ((nverr = nvlist_unpack((char *)idptr, arg->nda_idlen, idlist, 0))
2N/A != 0)
2N/A return (netcfg_errno2error(nverr));
2N/A
2N/A if (arg->nda_datalen > 0) {
2N/A dataptr = idptr + arg->nda_idlen;
2N/A if ((nverr = nvlist_unpack((char *)dataptr, arg->nda_datalen,
2N/A objp, 0)) != 0)
2N/A return (netcfg_errno2error(nverr));
2N/A }
2N/A
2N/A return (NETCFG_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Set up door arguments and make the door_call().
2N/A */
2N/Astatic int
2N/Anetcfg_make_door_call(void *arg, size_t asize, void **rbufp)
2N/A{
2N/A door_arg_t door_args;
2N/A struct door_info dinfo;
2N/A int err;
2N/A
2N/A door_args.data_ptr = arg;
2N/A door_args.data_size = asize;
2N/A door_args.desc_ptr = NULL;
2N/A door_args.desc_num = 0;
2N/A /*
2N/A * Don't pass in a return buffer. The door server will allocate the
2N/A * return buffer. The rsize must be > 0, however, else the door acts
2N/A * as if no response was expected and doesn't pass back anything.
2N/A */
2N/A door_args.rbuf = NULL;
2N/A door_args.rsize = 1;
2N/A
2N/A (void) pthread_mutex_lock(&door_mutex);
2N/A
2N/A if (netcfgd_door_fd != -1) {
2N/A /* Check door fd is not old (from previous netcfgd) */
2N/A if (door_info(netcfgd_door_fd, &dinfo) != 0 ||
2N/A (dinfo.di_attributes & DOOR_REVOKED) != 0) {
2N/A (void) close(netcfgd_door_fd);
2N/A netcfgd_door_fd = -1;
2N/A }
2N/A }
2N/A
2N/A if (netcfgd_door_fd == -1) {
2N/A if ((netcfgd_door_fd = open(NETCFGD_DOOR_FILE, O_RDONLY))
2N/A == -1) {
2N/A err = errno;
2N/A (void) pthread_mutex_unlock(&door_mutex);
2N/A return (err);
2N/A }
2N/A }
2N/A
2N/A (void) pthread_mutex_unlock(&door_mutex);
2N/A
2N/A if ((err = door_call(netcfgd_door_fd, &door_args)) == -1)
2N/A return (errno);
2N/A
2N/A if (door_args.rbuf != NULL) {
2N/A /*
2N/A * The size of *rbufp was not big enough and the door itself
2N/A * rellocated the return buffer. Reallocate *rbufp and copy
2N/A * the contents to the new buffer.
2N/A */
2N/A if ((*rbufp = malloc(door_args.rsize)) == NULL)
2N/A err = ENOMEM;
2N/A else
2N/A (void) memcpy(*rbufp, door_args.rbuf, door_args.rsize);
2N/A
2N/A /* munmap() the door buffer */
2N/A (void) munmap(door_args.rbuf, door_args.rsize);
2N/A }
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Set up arguments for the door call and read in results returned from the
2N/A * door call.
2N/A */
2N/Astatic netcfg_error_t
2N/Anetcfg_door_call(netcfgd_door_cmd_t cmd, nvlist_t **idlist, uint64_t flags,
2N/A nvlist_t **obj)
2N/A{
2N/A netcfgd_door_arg_t *dargp, *rargp = NULL;
2N/A char *buf = NULL, *idnvlbuf = NULL, *nvlbuf = NULL;
2N/A char *idp, *datap;
2N/A size_t bufsize, idnvlsize, nvlsize = 0;
2N/A netcfg_error_t err = NETCFG_SUCCESS;
2N/A int nverr, ierr;
2N/A
2N/A /* pack the nvlist of identifiers */
2N/A nverr = nvlist_pack(*idlist, &idnvlbuf, &idnvlsize, NV_ENCODE_XDR, 0);
2N/A if (nverr != 0) {
2N/A err = netcfg_errno2error(nverr);
2N/A goto done;
2N/A }
2N/A
2N/A /* For the commands that pass object data as well, pack the objlist */
2N/A if (cmd == NETCFGD_DOOR_CMD_UPDATE_REQ ||
2N/A cmd == NETCFGD_DOOR_CMD_RENAME_REQ ||
2N/A cmd == NETCFGD_DOOR_CMD_GETPROP_REQ ||
2N/A cmd == NETCFGD_DOOR_CMD_DBCREATE_REQ) {
2N/A nverr = nvlist_pack(*obj, &nvlbuf, &nvlsize, NV_ENCODE_XDR, 0);
2N/A if (nverr != 0) {
2N/A err = netcfg_errno2error(nverr);
2N/A goto done;
2N/A }
2N/A
2N/A /* obj will be filled in when the returned nvlist is unpacked */
2N/A if (cmd == NETCFGD_DOOR_CMD_GETPROP_REQ) {
2N/A nvlist_free(*obj);
2N/A *obj = NULL;
2N/A }
2N/A }
2N/A
2N/A bufsize = sizeof (netcfgd_door_arg_t) + idnvlsize + nvlsize;
2N/A if ((buf = calloc(1, bufsize)) == NULL) {
2N/A err = netcfg_errno2error(errno);
2N/A goto done;
2N/A }
2N/A
2N/A /* populate the door call argument structure */
2N/A dargp = (void *)buf;
2N/A dargp->nda_cmd = cmd;
2N/A dargp->nda_idlen = idnvlsize;
2N/A dargp->nda_datalen = nvlsize;
2N/A dargp->nda_result = NETCFG_SUCCESS;
2N/A dargp->nda_flags = flags;
2N/A
2N/A /* add the packed id nvlist */
2N/A idp = buf + sizeof (netcfgd_door_arg_t);
2N/A (void) bcopy(idnvlbuf, idp, idnvlsize);
2N/A
2N/A /* and the packed data nvlist for updates */
2N/A datap = idp + idnvlsize;
2N/A if (nvlsize > 0)
2N/A (void) bcopy(nvlbuf, datap, nvlsize);
2N/A
2N/A ierr = netcfg_make_door_call(dargp, bufsize, (void **)&rargp);
2N/A if (ierr != 0) {
2N/A err = netcfg_errno2error(ierr);
2N/A goto done;
2N/A }
2N/A
2N/A /* Check for an error return */
2N/A if (rargp != NULL && rargp->nda_result != NETCFG_SUCCESS) {
2N/A err = rargp->nda_result;
2N/A goto done;
2N/A }
2N/A
2N/A /* If reading from file, parse out the return buffer */
2N/A if ((cmd == NETCFGD_DOOR_CMD_READ_REQ ||
2N/A cmd == NETCFGD_DOOR_CMD_GETPROP_REQ) && rargp != NULL) {
2N/A nvlist_free(*idlist);
2N/A *idlist = NULL;
2N/A err = netcfg_read_lists_from_door_arg(rargp, idlist, obj);
2N/A }
2N/A
2N/Adone:
2N/A free(idnvlbuf);
2N/A free(nvlbuf);
2N/A free(buf);
2N/A free(rargp);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Read object specified by the passed-in idlist, retrieving an object
2N/A * list representation.
2N/A *
2N/A * If idlist is NULL, obj is a list of string arrays consisting of the list
2N/A * of DBs.
2N/A *
2N/A * If object-db-name is specified, but no object identifiers are included
2N/A * in idlist, read all objects in the specified dbname and create an object
2N/A * list containing a string array which represents each object.
2N/A *
2N/A * Otherwise, obj will point to a list of the properties for the object
2N/A * specified by idlist.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_read_object(nvlist_t **idlist, uint64_t flags, nvlist_t **obj)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_READ_REQ, idlist, flags,
2N/A obj));
2N/A}
2N/A
2N/A/*
2N/A * Read in all objects from the DB and object specified by idlist and update
2N/A * with the properties recorded in obj, writing the results to the DB.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_update_object(nvlist_t **idlist, uint64_t flags, nvlist_t **obj)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_UPDATE_REQ, idlist, flags,
2N/A obj));
2N/A}
2N/A
2N/A/*
2N/A * Remove the object specified by cur_idlist from the DB, and create a new
2N/A * entry with the read-in property list and the passed-in new_idlist.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_rename_object(nvlist_t **cur_idlist, uint64_t flags,
2N/A nvlist_t **new_idlist)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_RENAME_REQ, cur_idlist,
2N/A flags, new_idlist));
2N/A}
2N/A
2N/A/*
2N/A * Remove specified object from the DB by reading in the list of objects,
2N/A * removing the object identified by idlist, and writing the remainder.
2N/A *
2N/A * If idlist only identifies the DB, remove the DB altogether.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_remove_object(nvlist_t **idlist, uint64_t flags)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_REMOVE_REQ, idlist, flags,
2N/A NULL));
2N/A}
2N/A
2N/A/*
2N/A * Read the specified object, then fill in appropriate values for the
2N/A * properties passed in in objlist. If a passed-in property is not present
2N/A * in the db entry, remove it from the list before returning.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_get_object_props(nvlist_t **idlist, uint64_t flags, nvlist_t **objlist)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_GETPROP_REQ, idlist, flags,
2N/A objlist));
2N/A}
2N/A
2N/A/*
2N/A * Call the provided callback for each object in DB (specified by a dbname
2N/A * pair in the idlist), passing in the object and the provided argument.
2N/A *
2N/A * If selcb is specified, it will be called first for each entry, and will
2N/A * be passed both the idlist and objlist, as well as the flags. It should
2N/A * return 0 or non-zero to signify whether or not cb should be called for
2N/A * that particular entry; it may optionally return an alternate object arg
2N/A * to be passed to cb instead of the objlist. This allows libraries which
2N/A * consume this generic interface to implement library-specific filtering
2N/A * for walk functions which they in turn export.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_walk_db(nvlist_t **idlist, uint64_t flags, netcfg_walkcb_t *cb,
2N/A void *arg, netcfg_selectcb_t *selcb, netcfg_freecb_t *freecb, int *retp)
2N/A{
2N/A netcfg_error_t nerr;
2N/A int nverr, i;
2N/A uint_t objcnt;
2N/A nvlist_t *nvlist, *objp;
2N/A nvpair_t *objlist;
2N/A nvlist_t **objids;
2N/A boolean_t xzoneop;
2N/A zoneid_t dbzoneid, myzoneid = getzoneid();
2N/A
2N/A assert(cb != NULL);
2N/A
2N/A /*
2N/A * Calling netcfg_read_object() with an idlist containing just a
2N/A * dbname pair (and optional zoneid pair) returns an nvlist with
2N/A * one member: the NETCFG_OBJECT_ID_LIST; this object's value is
2N/A * an array of nvlists, where each nvlist is the list of
2N/A * identifiers for an object in the db.
2N/A */
2N/A if ((nerr = netcfg_read_object(idlist, flags, &nvlist))
2N/A != NETCFG_SUCCESS)
2N/A return (nerr);
2N/A
2N/A if ((nverr = nvlist_lookup_nvpair(nvlist, NETCFG_OBJECT_ID_LIST,
2N/A &objlist)) != 0 || (nverr = nvpair_value_nvlist_array(objlist,
2N/A &objids, &objcnt)) != 0) {
2N/A nvlist_free(nvlist);
2N/A return (netcfg_errno2error(nverr));
2N/A }
2N/A
2N/A dbzoneid = zoneid_from_idlist(*idlist);
2N/A xzoneop = (dbzoneid <= MAX_ZONEID && dbzoneid != myzoneid);
2N/A if (xzoneop && myzoneid != GLOBAL_ZONEID) {
2N/A nvlist_free(nvlist);
2N/A return (NETCFG_INVALID_ARG);
2N/A }
2N/A
2N/A for (i = 0; i < objcnt; i++) {
2N/A int cbret;
2N/A void *cbobjp = NULL;
2N/A
2N/A if (xzoneop) {
2N/A nverr = nvlist_add_int64(objids[i],
2N/A NETCFG_OBJECT_DB_ZONE, dbzoneid);
2N/A if (nverr != 0)
2N/A goto done;
2N/A }
2N/A
2N/A nerr = netcfg_read_object(&objids[i], flags, &objp);
2N/A if (nerr == NETCFG_NOT_FOUND)
2N/A continue;
2N/A if (nerr != NETCFG_SUCCESS)
2N/A goto done;
2N/A
2N/A if (selcb == NULL ||
2N/A selcb(objids[i], objp, flags, &cbobjp) == 0) {
2N/A cbret = cb(cbobjp == NULL ? objp : cbobjp, arg);
2N/A /* now call the freecb() routine */
2N/A if (freecb != NULL)
2N/A freecb(&cbobjp);
2N/A if (cbret != 0) {
2N/A if (retp != NULL)
2N/A *retp = cbret;
2N/A nerr = NETCFG_WALK_HALTED;
2N/A nvlist_free(objp);
2N/A goto done;
2N/A }
2N/A }
2N/A nvlist_free(objp);
2N/A }
2N/A
2N/Adone:
2N/A nvlist_free(nvlist);
2N/A return (nerr);
2N/A}
2N/A
2N/A/*
2N/A * Walk a db, calling the provided callback for each link in the file.
2N/A * Passes the raw data string representing the current line to the
2N/A * callback, as well as a caller-specified argument.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_walk_db_raw(nvlist_t **idlist, uint64_t flags, netcfg_rawcb_t cb,
2N/A void *arg)
2N/A{
2N/A netcfg_error_t nerr;
2N/A int nverr, i;
2N/A uint_t bufcnt;
2N/A nvlist_t *nvlist;
2N/A nvpair_t *objlist;
2N/A char **bufs;
2N/A netcfg_error_t retval = NETCFG_SUCCESS;
2N/A
2N/A assert(cb != NULL);
2N/A
2N/A /*
2N/A * Calling netcfg_read_object() with an idlist containing just a
2N/A * dbname pair and NETCFG_DB_RAW_FLAG set returns an nvlist with
2N/A * one member: the NETCFG_OBJECT_RAW_BUFS; this object's value is
2N/A * an array of strings, where each string in the array maps to a
2N/A * single line from the file.
2N/A */
2N/A flags |= NETCFG_DB_RAW_FLAG;
2N/A if ((nerr = netcfg_read_object(idlist, flags, &nvlist))
2N/A != NETCFG_SUCCESS) {
2N/A if (nerr == NETCFG_NOT_FOUND) {
2N/A /*
2N/A * The dbname container is not present; this is not
2N/A * an error case, it just means the db is empty, so
2N/A * there is nothing to walk.
2N/A */
2N/A return (NETCFG_SUCCESS);
2N/A }
2N/A return (nerr);
2N/A }
2N/A
2N/A if (((nverr = nvlist_lookup_nvpair(nvlist, NETCFG_OBJECT_RAW_BUFS,
2N/A &objlist)) != 0) || ((nverr = nvpair_value_string_array(objlist,
2N/A &bufs, &bufcnt)) != 0)) {
2N/A nvlist_free(nvlist);
2N/A return (netcfg_errno2error(nverr));
2N/A }
2N/A
2N/A for (i = 0; i < bufcnt; i++) {
2N/A int cbret;
2N/A
2N/A cbret = cb(bufs[i], arg);
2N/A if (cbret != 0) {
2N/A retval = NETCFG_WALK_HALTED;
2N/A break;
2N/A }
2N/A }
2N/A
2N/Adone:
2N/A nvlist_free(nvlist);
2N/A return (retval);
2N/A}
2N/A
2N/A/*
2N/A * Create a new (or replace an existing) database. The new db is identified
2N/A * by the passed-in idlist; its contents are specified in the dblist param.
2N/A * This nvlist should contain an nvpair for each db entry; the name should
2N/A * be the string representation of the entry's idlist (the output of
2N/A * netcfg_idl2idstr()), the value should be an nvlist containing the entry
2N/A * properties.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_create_db(nvlist_t **idlist, uint64_t flags, nvlist_t **dblist)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_DBCREATE_REQ, idlist, flags,
2N/A dblist));
2N/A}
2N/A
2N/A/*
2N/A * Destroy the database specified by the passed-in idlist.
2N/A */
2N/Anetcfg_error_t
2N/Anetcfg_destroy_db(nvlist_t **idlist)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_DBDESTROY_REQ, idlist, 0,
2N/A NULL));
2N/A}
2N/A
2N/Anetcfg_error_t
2N/Anetcfg_backup_db(nvlist_t **idlist)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_DBBACKUP_REQ, idlist, 0,
2N/A NULL));
2N/A}
2N/A
2N/Anetcfg_error_t
2N/Anetcfg_restore_db(nvlist_t **idlist)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_DBRESTORE_REQ, idlist, 0,
2N/A NULL));
2N/A}
2N/A
2N/Anetcfg_error_t
2N/Anetcfg_destroy_backup_db(nvlist_t **idlist)
2N/A{
2N/A return (netcfg_door_call(NETCFGD_DOOR_CMD_DBDESTROYBACKUP_REQ, idlist,
2N/A 0, NULL));
2N/A}