/*
* 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
* 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
*/
/*
*/
#include <assert.h>
#include <auth_attr.h>
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <libintl.h>
#include <libscf.h>
#include <pthread.h>
#include <pwd.h>
#include <strings.h>
#include <s10_brand.h>
#include <unistd.h>
#include <zone.h>
#include "libnetcfg.h"
#include "libnetcfg_impl.h"
/*
* Communicate with the backend daemon (running in netcfgd) to retrieve or
* change configuration.
*/
/* error codes and text description */
static struct netcfg_error_info {
const char *error_desc;
} netcfg_errors[] = {
{ NETCFG_SUCCESS, "no error" },
{ NETCFG_EPERM, "permission denied" },
{ NETCFG_INVALID_ARG, "invalid argument" },
{ NETCFG_EXISTS, "object exists" },
{ NETCFG_NOT_FOUND, "object not found" },
{ NETCFG_WALK_HALTED, "callback function halted walk" },
{ NETCFG_ERROR_BIND, "could not bind to daemon" },
{ NETCFG_NO_MEMORY, "insufficient memory" },
{ NETCFG_FAILURE, "failure" }
};
/*
* Returns a message string for the given libnetcfg error code.
*/
const char *
{
int i;
for (i = 0; i < NETCFG_NUM_ERRORS; i++) {
return (dgettext(TEXT_DOMAIN,
netcfg_errors[i].error_desc));
}
}
}
{
switch (error) {
case 0:
return (NETCFG_SUCCESS);
case ENOMEM:
case ENOSPC:
return (NETCFG_NO_MEMORY);
case EFAULT:
case EINVAL:
return (NETCFG_INVALID_ARG);
case EEXIST:
return (NETCFG_EXISTS);
case ENOENT:
case ENOTDIR:
return (NETCFG_NOT_FOUND);
case EACCES:
case EPERM:
return (NETCFG_EPERM);
case EBADF:
return (NETCFG_ERROR_BIND);
default:
return (NETCFG_FAILURE);
}
}
int
{
int err;
switch (code) {
case NETCFG_SUCCESS:
err = 0;
break;
case NETCFG_EPERM:
break;
case NETCFG_INVALID_ARG:
break;
case NETCFG_EXISTS:
break;
case NETCFG_NOT_FOUND:
break;
case NETCFG_WALK_HALTED:
break;
case NETCFG_NO_MEMORY:
break;
case NETCFG_ERROR_BIND:
case NETCFG_FAILURE:
default:
/* no good analog for these */
break;
}
return (err);
}
/*
* Read the "netcfg/active_ncp" property from svc:/network/physical:default
*/
{
/* Need to skip if we're in an S10-branded zone */
if (zoneid != GLOBAL_ZONEID) {
sizeof (brand)) < 0) {
return (netcfg_errno2error(errno));
}
pbuflen);
return (NETCFG_SUCCESS);
}
}
return (NETCFG_FAILURE);
if (scf_simple_prop_numvalues(prop) > 0) {
pbuflen);
}
return (NETCFG_SUCCESS);
}
/*
* Read nvlists from the door argument that is returned by the door call to
* netcfgd. If the arg datalen is non-zero, unpack the object nvlist.
*/
{
int nverr;
return (arg->nda_result);
!= 0)
return (netcfg_errno2error(nverr));
if (arg->nda_datalen > 0) {
objp, 0)) != 0)
return (netcfg_errno2error(nverr));
}
return (NETCFG_SUCCESS);
}
/*
* Set up door arguments and make the door_call().
*/
static int
{
int err;
/*
* Don't pass in a return buffer. The door server will allocate the
* return buffer. The rsize must be > 0, however, else the door acts
* as if no response was expected and doesn't pass back anything.
*/
(void) pthread_mutex_lock(&door_mutex);
if (netcfgd_door_fd != -1) {
/* Check door fd is not old (from previous netcfgd) */
(void) close(netcfgd_door_fd);
netcfgd_door_fd = -1;
}
}
if (netcfgd_door_fd == -1) {
== -1) {
(void) pthread_mutex_unlock(&door_mutex);
return (err);
}
}
(void) pthread_mutex_unlock(&door_mutex);
return (errno);
/*
* The size of *rbufp was not big enough and the door itself
* rellocated the return buffer. Reallocate *rbufp and copy
* the contents to the new buffer.
*/
else
/* munmap() the door buffer */
}
return (err);
}
/*
* Set up arguments for the door call and read in results returned from the
* door call.
*/
static netcfg_error_t
{
/* pack the nvlist of identifiers */
if (nverr != 0) {
goto done;
}
/* For the commands that pass object data as well, pack the objlist */
if (cmd == NETCFGD_DOOR_CMD_UPDATE_REQ ||
if (nverr != 0) {
goto done;
}
/* obj will be filled in when the returned nvlist is unpacked */
if (cmd == NETCFGD_DOOR_CMD_GETPROP_REQ) {
nvlist_free(*obj);
}
}
goto done;
}
/* populate the door call argument structure */
/* add the packed id nvlist */
/* and the packed data nvlist for updates */
if (nvlsize > 0)
if (ierr != 0) {
goto done;
}
/* Check for an error return */
goto done;
}
/* If reading from file, parse out the return buffer */
if ((cmd == NETCFGD_DOOR_CMD_READ_REQ ||
}
done:
return (err);
}
/*
* Read object specified by the passed-in idlist, retrieving an object
* list representation.
*
* If idlist is NULL, obj is a list of string arrays consisting of the list
* of DBs.
*
* If object-db-name is specified, but no object identifiers are included
* in idlist, read all objects in the specified dbname and create an object
* list containing a string array which represents each object.
*
* Otherwise, obj will point to a list of the properties for the object
* specified by idlist.
*/
{
obj));
}
/*
* Read in all objects from the DB and object specified by idlist and update
* with the properties recorded in obj, writing the results to the DB.
*/
{
obj));
}
/*
* Remove the object specified by cur_idlist from the DB, and create a new
* entry with the read-in property list and the passed-in new_idlist.
*/
{
flags, new_idlist));
}
/*
* Remove specified object from the DB by reading in the list of objects,
* removing the object identified by idlist, and writing the remainder.
*
* If idlist only identifies the DB, remove the DB altogether.
*/
{
NULL));
}
/*
* Read the specified object, then fill in appropriate values for the
* properties passed in in objlist. If a passed-in property is not present
* in the db entry, remove it from the list before returning.
*/
{
objlist));
}
/*
* Call the provided callback for each object in DB (specified by a dbname
* pair in the idlist), passing in the object and the provided argument.
*
* If selcb is specified, it will be called first for each entry, and will
* be passed both the idlist and objlist, as well as the flags. It should
* return 0 or non-zero to signify whether or not cb should be called for
* that particular entry; it may optionally return an alternate object arg
* to be passed to cb instead of the objlist. This allows libraries which
* consume this generic interface to implement library-specific filtering
* for walk functions which they in turn export.
*/
{
int nverr, i;
/*
* Calling netcfg_read_object() with an idlist containing just a
* dbname pair (and optional zoneid pair) returns an nvlist with
* one member: the NETCFG_OBJECT_ID_LIST; this object's value is
* an array of nvlists, where each nvlist is the list of
* identifiers for an object in the db.
*/
!= NETCFG_SUCCESS)
return (nerr);
return (netcfg_errno2error(nverr));
}
return (NETCFG_INVALID_ARG);
}
for (i = 0; i < objcnt; i++) {
int cbret;
if (xzoneop) {
if (nverr != 0)
goto done;
}
if (nerr == NETCFG_NOT_FOUND)
continue;
if (nerr != NETCFG_SUCCESS)
goto done;
/* now call the freecb() routine */
if (cbret != 0) {
goto done;
}
}
}
done:
return (nerr);
}
/*
* Walk a db, calling the provided callback for each link in the file.
* Passes the raw data string representing the current line to the
* callback, as well as a caller-specified argument.
*/
void *arg)
{
int nverr, i;
char **bufs;
/*
* Calling netcfg_read_object() with an idlist containing just a
* dbname pair and NETCFG_DB_RAW_FLAG set returns an nvlist with
* one member: the NETCFG_OBJECT_RAW_BUFS; this object's value is
* an array of strings, where each string in the array maps to a
* single line from the file.
*/
!= NETCFG_SUCCESS) {
if (nerr == NETCFG_NOT_FOUND) {
/*
* The dbname container is not present; this is not
* an error case, it just means the db is empty, so
* there is nothing to walk.
*/
return (NETCFG_SUCCESS);
}
return (nerr);
}
return (netcfg_errno2error(nverr));
}
for (i = 0; i < bufcnt; i++) {
int cbret;
if (cbret != 0) {
break;
}
}
done:
return (retval);
}
/*
* Create a new (or replace an existing) database. The new db is identified
* by the passed-in idlist; its contents are specified in the dblist param.
* This nvlist should contain an nvpair for each db entry; the name should
* be the string representation of the entry's idlist (the output of
* netcfg_idl2idstr()), the value should be an nvlist containing the entry
* properties.
*/
{
dblist));
}
/*
* Destroy the database specified by the passed-in idlist.
*/
{
NULL));
}
{
NULL));
}
{
NULL));
}
{
0, NULL));
}