libnwam_files.c revision 6ba597c56d749c61b4f783157f63196d7b2445f0
/*
* 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
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <assert.h>
#include <dirent.h>
#include <ctype.h>
#include <libgen.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include "libnwam_impl.h"
#include <libnwam_priv.h>
#include <libnwam.h>
/*
* Implementation of files backend for libnwam configuration objects.
* /etc/dladm/datalink.conf-like format is used.
*/
#define NWAM_FILE_LINE_MAX 2048
#define NWAM_FILE_PROP_ESCAPE '\\'
#define NWAM_FILE_PROP_DELIMITER ';'
#define NWAM_FILE_PROP_ASSIGN '='
#define NWAM_FILE_VALUE_DELIMITER ','
#define NWAM_FILE_BOOLEAN_TRUE "true"
#define NWAM_FILE_BOOLEAN_FALSE "false"
/*
* strtok_r-like function that takes a string, finds the next unescaped
* delimiter char after in, nullifies it and sets nextp to point to the
* remaining string (if any). Returns in, setting nextp to NULL if no such
* delimiter is found.
*/
char *
{
return (NULL);
if ((*nextp)[0] == NWAM_FILE_PROP_ESCAPE) {
/* Nullify delimiter */
(*nextp)[0] = '\0';
/*
* If more string left to go, nextp points to string
* after delimiter, otherwise NULL.
*/
(*nextp)++;
return (in);
} else {
}
}
return (in);
}
/* Add escape chars to value string */
static void
{
int i, j = 0;
/*
* It is safe to use strlen() as we sanitycheck string length on value
* creation, so no string longer than NWAM_MAX_VALUE_LEN is accepted.
*/
switch (in[i]) {
case NWAM_FILE_PROP_DELIMITER:
case NWAM_FILE_PROP_ESCAPE:
out[j++] = NWAM_FILE_PROP_ESCAPE;
break;
default:
break;
}
}
out[j] = '\0';
}
static char *
value_remove_escapes(char *in)
{
char *out;
int i, j = 0;
return (NULL);
/*
* It is safe to use strlen() as we sanitycheck string length on value
* creation (i.e. before they are written to the file), so no string
* longer than NWAM_MAX_VALUE_LEN is accepted.
*/
if (in[i] == NWAM_FILE_PROP_ESCAPE)
else
}
out[j] = '\0';
return (out);
}
/*
* Parse line into name and object list of properties.
* Each line has the format:
*
* objname [prop=type:val1[,val2..];..]
*/
{
return (err);
== NULL) {
nwam_free_object_list(*((char **)proplist));
return (NWAM_ENTITY_INVALID);
}
/*
* Parse property into name=type,val[,val]
*/
nwam_free_object_list(*((char **)proplist));
return (NWAM_ENTITY_INVALID);
}
nwam_free_object_list(*((char **)proplist));
return (NWAM_ENTITY_INVALID);
}
switch (proptype) {
case NWAM_VALUE_TYPE_BOOLEAN:
sizeof (boolean_t));
break;
case NWAM_VALUE_TYPE_INT64:
sizeof (int64_t));
break;
case NWAM_VALUE_TYPE_UINT64:
sizeof (uint64_t));
break;
case NWAM_VALUE_TYPE_STRING:
sizeof (char *));
break;
default:
nwam_free_object_list(*((char **)proplist));
return (NWAM_ENTITY_INVALID_VALUE);
}
/* Memory allocation failed */
nwam_free_object_list(*((char **)proplist));
return (NWAM_NO_MEMORY);
}
nelem = 0;
nelem++;
switch (proptype) {
case NWAM_VALUE_TYPE_BOOLEAN:
== 0) {
} else {
(*((char **)proplist));
return (NWAM_ENTITY_INVALID_VALUE);
}
break;
case NWAM_VALUE_TYPE_INT64:
break;
case NWAM_VALUE_TYPE_UINT64:
break;
case NWAM_VALUE_TYPE_STRING:
break;
default:
nwam_free_object_list(*((char **)proplist));
return (NWAM_ENTITY_INVALID_VALUE);
}
}
switch (proptype) {
case NWAM_VALUE_TYPE_BOOLEAN:
nwam_free_object_list(*((char **)proplist));
return (NWAM_NO_MEMORY);
}
nwam_free_object_list(*((char **)proplist));
return (err);
}
break;
case NWAM_VALUE_TYPE_INT64:
nwam_free_object_list(*((char **)proplist));
return (NWAM_NO_MEMORY);
}
nwam_free_object_list(*((char **)proplist));
return (err);
}
break;
case NWAM_VALUE_TYPE_UINT64:
nwam_free_object_list(*((char **)proplist));
return (NWAM_NO_MEMORY);
}
nwam_free_object_list(*((char **)proplist));
return (err);
}
break;
case NWAM_VALUE_TYPE_STRING:
nwam_free_object_list(*((char **)proplist));
return (NWAM_NO_MEMORY);
}
for (i = 0; i < nelem; i++)
nwam_free_object_list(*((char **)proplist));
return (err);
}
for (i = 0; i < nelem; i++)
break;
}
}
return (NWAM_SUCCESS);
}
/*
* Create list of NCP files used for walk of NCPs and for case-insensitive
* matching of NCP name to file.
*/
static nwam_error_t
{
uint_t i;
return (NWAM_NO_MEMORY);
*num_filesp = 0;
/*
* Construct NCP list by finding all files in NWAM directory
* that match the NCP filename format.
*/
goto done;
}
/* Ensure filename is valid */
continue;
goto done;
}
(*num_filesp)++;
}
done:
if (err != NWAM_SUCCESS) {
for (i = 0; i < *num_filesp; i++)
} else {
}
return (err);
}
/*
* Read object specified by objname from file, converting it to
* an object list. If filename is NULL, a list of configuration object
* containers is returned, represented as an object lists with elements "enms"
* "locs" and "ncps". Each of these is a list of configuration files for each
* ncp conf files. If objname is NULL, read all objects, and create
* an nvlist with one element - "object-list" - which has as its values
* the names of the objects found. Otherwise obj points to an object list
* of properties for the first object in the file that case-insensitively
* matches objname. We write the found name into objname so that it can be
* returned to the caller (and set in the object handle).
*/
/* ARGSUSED2 */
{
char line[NWAM_FILE_LINE_MAX];
uint_t i = 0, j = 0;
/*
* When the filename is not specified, it signifies a
* request for the list of configuration object containers -
* in this case files.
*
* A list of all object files is returned. For ENMs
* files are used, but for NCPs we need to walk the
* files in the NWAM directory retrieving each one that
* matches the NCP pattern.
*/
return (err);
&enmval)) != NWAM_SUCCESS ||
&locval)) != NWAM_SUCCESS ||
enmval)) != NWAM_SUCCESS ||
locval)) != NWAM_SUCCESS)
goto done_with_containers;
/*
* Construct NCP list by finding all files in NWAM directory
* that match the NCP filename format.
*/
!= NWAM_SUCCESS)
goto done_with_containers;
&ncpval)) == NWAM_SUCCESS) {
}
for (j = 0; j < num_files; j++)
}
if (err != NWAM_SUCCESS)
else
return (err);
}
/* Allocate string array to store object names */
== NULL)
return (NWAM_NO_MEMORY);
}
return (NWAM_ERROR_INTERNAL);
}
/*
* Check NCP file list in case filename passed in was derived
* from a case-insensitive NCP name.
*/
== NWAM_SUCCESS) {
for (j = 0; j < num_files; j++) {
/* Copy real filename back */
ncpfiles[j],
break;
}
}
}
for (j = 0; j < num_files; j++)
}
/* Return NOT_FOUND if file not found */
return (NWAM_ENTITY_NOT_FOUND);
}
}
cp++;
continue;
!= NWAM_SUCCESS)
goto done;
/*
* Is this the specified object? If so set objname and
* obj and bail.
*/
break;
} else {
}
} else {
goto done;
}
i++;
}
}
/*
* Allocate object list with one value named
* NWAM_OBJECT_NAMES_STRING - it's values are the names of
* the objects found.
*/
&objnamesval)) == NWAM_SUCCESS) {
}
}
done:
/*
* We're done, either we have success, and return our object list
* containing object names, or we have failure and we need to free
* the object list.
*/
for (j = 0; j < i; j++)
if (err == NWAM_SUCCESS) {
} else {
}
} else {
/* Check if to-be-read object was not found */
return (NWAM_ENTITY_NOT_FOUND);
}
return (err);
}
{
char **valstr;
== NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
switch (type) {
case NWAM_VALUE_TYPE_BOOLEAN:
!= NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
}
for (i = 0; i < nelem; i++) {
if (valbool[i]) {
} else {
}
}
break;
case NWAM_VALUE_TYPE_INT64:
!= NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
}
for (i = 0; i < nelem; i++) {
}
break;
case NWAM_VALUE_TYPE_UINT64:
!= NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
}
for (i = 0; i < nelem; i++) {
}
break;
case NWAM_VALUE_TYPE_STRING:
!= NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
}
for (i = 0; i < nelem; i++) {
char evalstr[NWAM_MAX_VALUE_LEN];
/* Add escape chars as necessary */
}
break;
default:
return (NWAM_INVALID_ARG);
}
}
return (NWAM_SUCCESS);
}
/*
* Write object specified by objname to file. If objname is NULL, objlist
* must be a list of lists, where each list corresponds to an
* object to write to the file. Otherwise objlist should point to a list of
* properties for the object specified by objname. The write operation is
* first done to filename.new, and if this succeeds, the file is renamed to
* filename. Since rename(2) is atomic, this approach guarantees a complete
* configuration will end up in filename as a result of an aborted operation.
*/
{
void *proplist;
char *dir;
/* Create the directory in case it does not exist. */
return (nwam_errno_to_nwam_error(errno));
return (nwam_errno_to_nwam_error(errno));
}
return (nwam_errno_to_nwam_error(errno));
goto done;
}
/*
* Need to lock filename.new to prevent multiple commits colliding
* at this point.
*/
if (flags & NWAM_FLAG_BLOCKING)
else
return (NWAM_ENTITY_IN_USE);
else
return (NWAM_ERROR_INTERNAL);
}
/* Only one object to write */
} else {
err = NWAM_SUCCESS;
goto done;
}
/* Otherwise, write each object in turn. */
proplist)) != NWAM_SUCCESS)
break;
}
if (err == NWAM_LIST_END)
err = NWAM_SUCCESS;
}
done:
if (err == NWAM_SUCCESS) {
return (NWAM_SUCCESS);
} else {
}
}
(void) unlink(tmpfilename);
return (err);
}
/*
* Read in all objects from file and update object corresponding to objname
* with properties recorded in proplist, and then write results to filename.
* If objname is empty, no object needs to be updated. If proplist is NULL,
* object is to be removed (this is done by simply not adding it to the list
* of objects).
*/
{
void *objlist, *objnamelist;
char **object_names;
uint_t i, num_objects;
/* If we find existing object, fail if creation was specified */
if (flags & NWAM_FLAG_CREATE) {
char discard_objname[NWAM_MAX_NAME_LEN];
void *discard_objlist;
sizeof (discard_objname));
return (NWAM_ENTITY_EXISTS);
}
}
/* Get existing list of object names (if any) */
&objnamelist);
switch (err) {
case NWAM_SUCCESS:
/*
* For each object name on list other than the one to be
* updated, add an object list consisting of its properties.
* The object to be updated (if any) will be added below.
*/
return (err);
}
&num_objects)) != NWAM_SUCCESS) {
return (err);
}
for (i = 0; i < num_objects; i++) {
continue;
!= NWAM_SUCCESS ||
return (err);
}
}
break;
case NWAM_ENTITY_NOT_FOUND:
/*
*/
default:
return (err);
}
/*
* Add the object to be updated to our list of objects if the
* property list is non-NULL (NULL signifies remove the object).
*/
return (err);
}
}
objlist);
return (err);
}
/*
* Remove specified object from file by reading in the list of objects,
* removing objname and writing the remainder.
*/
{
int uerr;
/*
* NULL objname signifies remove file.
*/
if (uerr != 0)
return (nwam_errno_to_nwam_error(errno));
return (NWAM_SUCCESS);
}
NULL));
}