/* * 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 * or http://www.opensolaris.org/os/licensing. * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "libnwam_impl.h" #include #include /* * 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 * nwam_tokenize_by_unescaped_delim(char *in, char delim, char **nextp) { boolean_t escaped = B_FALSE; size_t totlen; if (in == NULL) return (NULL); totlen = strlen(in); for (*nextp = in; (*nextp - in) < strlen(in); (*nextp)++) { if ((*nextp)[0] == NWAM_FILE_PROP_ESCAPE) { escaped = !escaped; } else if (!escaped && (*nextp)[0] == delim) { /* Nullify delimiter */ (*nextp)[0] = '\0'; /* * If more string left to go, nextp points to string * after delimiter, otherwise NULL. */ (*nextp)++; *nextp = ((*nextp - in) < totlen) ? (*nextp) : NULL; return (in); } else { escaped = B_FALSE; } } *nextp = NULL; return (in); } /* Add escape chars to value string */ static void value_add_escapes(char *in, char *out) { 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. */ for (i = 0; i < strlen(in); i++) { switch (in[i]) { case NWAM_FILE_VALUE_DELIMITER: case NWAM_FILE_PROP_DELIMITER: case NWAM_FILE_PROP_ESCAPE: out[j++] = NWAM_FILE_PROP_ESCAPE; out[j++] = in[i]; break; default: out[j++] = in[i]; break; } } out[j] = '\0'; } static char * value_remove_escapes(char *in) { char *out; int i, j = 0; if ((out = strdup(in)) == NULL) 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. */ for (i = 0; i < strlen(in); i++) { if (in[i] == NWAM_FILE_PROP_ESCAPE) out[j++] = in[++i]; else out[j++] = in[i]; } out[j] = '\0'; return (out); } /* * Parse line into name and object list of properties. * Each line has the format: * * objname [prop=type:val1[,val2..];..] */ nwam_error_t nwam_line_to_object(char *line, char **objname, void *proplist) { char *next = line, *prop, *nextprop, *propname, *proptypestr, *nextval; char **valstr, **newvalstr; boolean_t *valbool, *newvalbool; int64_t *valint, *newvalint; uint64_t *valuint, *newvaluint; uint_t nelem, i; nwam_value_type_t proptype; nwam_value_t val = NULL; nwam_error_t err; if ((err = nwam_alloc_object_list(proplist)) != NWAM_SUCCESS) return (err); *objname = line; if ((*objname = nwam_tokenize_by_unescaped_delim(line, '\t', &prop)) == NULL) { nwam_free_object_list(*((char **)proplist)); return (NWAM_ENTITY_INVALID); } while ((prop = nwam_tokenize_by_unescaped_delim(prop, NWAM_FILE_PROP_DELIMITER, &nextprop)) != NULL) { /* * Parse property into name=type,val[,val] */ if ((propname = nwam_tokenize_by_unescaped_delim(prop, NWAM_FILE_PROP_ASSIGN, &next)) == NULL || (proptypestr = nwam_tokenize_by_unescaped_delim(next, NWAM_FILE_VALUE_DELIMITER, &next)) == NULL) { nwam_free_object_list(*((char **)proplist)); return (NWAM_ENTITY_INVALID); } if ((proptype = nwam_string_to_value_type(proptypestr)) == NWAM_VALUE_TYPE_UNKNOWN) { nwam_free_object_list(*((char **)proplist)); return (NWAM_ENTITY_INVALID); } valbool = NULL; valint = NULL; valstr = NULL; switch (proptype) { case NWAM_VALUE_TYPE_BOOLEAN: valbool = calloc(NWAM_MAX_NUM_VALUES, sizeof (boolean_t)); break; case NWAM_VALUE_TYPE_INT64: valint = calloc(NWAM_MAX_NUM_VALUES, sizeof (int64_t)); break; case NWAM_VALUE_TYPE_UINT64: valuint = calloc(NWAM_MAX_NUM_VALUES, sizeof (uint64_t)); break; case NWAM_VALUE_TYPE_STRING: valstr = calloc(NWAM_MAX_NUM_VALUES, sizeof (char *)); break; default: nwam_free_object_list(*((char **)proplist)); return (NWAM_ENTITY_INVALID_VALUE); } if (valbool == NULL && valint == NULL && valuint == NULL && valstr == NULL) { /* Memory allocation failed */ nwam_free_object_list(*((char **)proplist)); return (NWAM_NO_MEMORY); } nelem = 0; while ((nextval = nwam_tokenize_by_unescaped_delim(next, NWAM_FILE_VALUE_DELIMITER, &next)) != NULL) { nelem++; switch (proptype) { case NWAM_VALUE_TYPE_BOOLEAN: if (strncmp(nextval, NWAM_FILE_BOOLEAN_TRUE, strlen(nextval)) == 0) { valbool[nelem - 1] = B_TRUE; } else if (strncmp(nextval, NWAM_FILE_BOOLEAN_FALSE, strlen(nextval)) == 0) { valbool[nelem - 1] = B_FALSE; } else { nwam_free_object_list (*((char **)proplist)); return (NWAM_ENTITY_INVALID_VALUE); } break; case NWAM_VALUE_TYPE_INT64: valint[nelem - 1] = (int64_t)atoll(nextval); break; case NWAM_VALUE_TYPE_UINT64: valuint[nelem - 1] = (uint64_t)atoll(nextval); break; case NWAM_VALUE_TYPE_STRING: valstr[nelem - 1] = value_remove_escapes(nextval); break; default: nwam_free_object_list(*((char **)proplist)); return (NWAM_ENTITY_INVALID_VALUE); } } switch (proptype) { case NWAM_VALUE_TYPE_BOOLEAN: if ((newvalbool = realloc(valbool, nelem * sizeof (boolean_t))) == NULL) { nwam_free_object_list(*((char **)proplist)); return (NWAM_NO_MEMORY); } if ((err = nwam_value_create_boolean_array(newvalbool, nelem, &val)) != NWAM_SUCCESS || (err = nwam_set_prop_value(*((char **)proplist), propname, val)) != NWAM_SUCCESS) { free(newvalbool); nwam_value_free(val); nwam_free_object_list(*((char **)proplist)); return (err); } free(newvalbool); nwam_value_free(val); break; case NWAM_VALUE_TYPE_INT64: if ((newvalint = realloc(valint, nelem * sizeof (int64_t))) == NULL) { nwam_free_object_list(*((char **)proplist)); return (NWAM_NO_MEMORY); } if ((err = nwam_value_create_int64_array(newvalint, nelem, &val)) != NWAM_SUCCESS || (err = nwam_set_prop_value(*((char **)proplist), propname, val)) != NWAM_SUCCESS) { free(newvalint); nwam_value_free(val); nwam_free_object_list(*((char **)proplist)); return (err); } free(newvalint); nwam_value_free(val); break; case NWAM_VALUE_TYPE_UINT64: if ((newvaluint = realloc(valuint, nelem * sizeof (uint64_t))) == NULL) { nwam_free_object_list(*((char **)proplist)); return (NWAM_NO_MEMORY); } if ((err = nwam_value_create_uint64_array(newvaluint, nelem, &val)) != NWAM_SUCCESS || (err = nwam_set_prop_value(*((char **)proplist), propname, val)) != NWAM_SUCCESS) { free(newvaluint); nwam_value_free(val); nwam_free_object_list(*((char **)proplist)); return (err); } free(newvaluint); nwam_value_free(val); break; case NWAM_VALUE_TYPE_STRING: if ((newvalstr = realloc(valstr, nelem * sizeof (char *))) == NULL) { nwam_free_object_list(*((char **)proplist)); return (NWAM_NO_MEMORY); } if ((err = nwam_value_create_string_array(newvalstr, nelem, &val)) != NWAM_SUCCESS || (err = nwam_set_prop_value(*((char **)proplist), propname, val)) != NWAM_SUCCESS) { for (i = 0; i < nelem; i++) free(newvalstr[i]); free(newvalstr); nwam_value_free(val); nwam_free_object_list(*((char **)proplist)); return (err); } for (i = 0; i < nelem; i++) free(newvalstr[i]); free(newvalstr); nwam_value_free(val); break; } prop = nextprop; } 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 create_ncp_file_list(char ***ncpfilesp, uint_t *num_filesp) { DIR *dirp = NULL; struct dirent *dp; char *ncpname, **ncpfiles = NULL; nwam_error_t err = NWAM_SUCCESS; uint_t i; ncpfiles = calloc(NWAM_MAX_NUM_OBJECTS, sizeof (char *)); if (ncpfiles == NULL) return (NWAM_NO_MEMORY); *num_filesp = 0; /* * Construct NCP list by finding all files in NWAM directory * that match the NCP filename format. */ if ((dirp = opendir(NWAM_CONF_DIR)) == NULL) { err = nwam_errno_to_nwam_error(errno); goto done; } while ((dp = readdir(dirp)) != NULL) { uint_t filenamelen; /* Ensure filename is valid */ if (nwam_ncp_file_to_name(dp->d_name, &ncpname) != NWAM_SUCCESS) continue; free(ncpname); filenamelen = strlen(NWAM_CONF_DIR) + strlen(dp->d_name) + 1; if ((ncpfiles[*num_filesp] = malloc(filenamelen)) == NULL) { err = NWAM_NO_MEMORY; goto done; } (void) strlcpy(ncpfiles[*num_filesp], NWAM_CONF_DIR, strlen(NWAM_CONF_DIR) + 1); (void) strlcpy(ncpfiles[*num_filesp] + strlen(NWAM_CONF_DIR), dp->d_name, filenamelen - strlen(NWAM_CONF_DIR)); (*num_filesp)++; } done: if (dirp != NULL) (void) closedir(dirp); if (err != NWAM_SUCCESS) { for (i = 0; i < *num_filesp; i++) free(ncpfiles[i]); free(ncpfiles); } else { *ncpfilesp = realloc(ncpfiles, sizeof (char *) * (*num_filesp)); if (*ncpfilesp == NULL) err = NWAM_NO_MEMORY; } 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 * object. This corresponds to the enm.conf file, loc.conf file and list of * 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 */ nwam_error_t nwam_read_object_from_files_backend(char *filename, char *objname, uint64_t flags, void *obj) { char line[NWAM_FILE_LINE_MAX]; char *cp, *foundobjname, **objnames = NULL, **ncpfiles = NULL; uint_t num_files = 0; FILE *fp = NULL; nwam_error_t err; void *objlist = NULL, *proplist = NULL; uint_t i = 0, j = 0; nwam_value_t objnamesval = NULL; assert(obj != NULL); *((char **)obj) = NULL; if (filename == NULL) { nwam_value_t enmval = NULL, locval = NULL, ncpval = NULL; /* * 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 * and locations, only the default loc.conf and enm.conf * files are used, but for NCPs we need to walk the * files in the NWAM directory retrieving each one that * matches the NCP pattern. */ if ((err = nwam_alloc_object_list(&objlist)) != NWAM_SUCCESS) return (err); if ((err = nwam_value_create_string(NWAM_ENM_CONF_FILE, &enmval)) != NWAM_SUCCESS || (err = nwam_value_create_string(NWAM_LOC_CONF_FILE, &locval)) != NWAM_SUCCESS || (err = nwam_set_prop_value(objlist, NWAM_ENM_OBJECT_STRING, enmval)) != NWAM_SUCCESS || (err = nwam_set_prop_value(objlist, NWAM_LOC_OBJECT_STRING, locval)) != NWAM_SUCCESS) goto done_with_containers; /* * Construct NCP list by finding all files in NWAM directory * that match the NCP filename format. */ if ((err = create_ncp_file_list(&ncpfiles, &num_files)) != NWAM_SUCCESS) goto done_with_containers; if ((err = nwam_value_create_string_array(ncpfiles, num_files, &ncpval)) == NWAM_SUCCESS) { err = nwam_set_prop_value(objlist, NWAM_NCP_OBJECT_STRING, ncpval); } done_with_containers: nwam_value_free(enmval); nwam_value_free(locval); nwam_value_free(ncpval); if (ncpfiles != NULL) { for (j = 0; j < num_files; j++) free(ncpfiles[j]); free(ncpfiles); } if (err != NWAM_SUCCESS) nwam_free_object_list(objlist); else *((char **)obj) = objlist; return (err); } if (objname == NULL) { /* Allocate string array to store object names */ if ((objnames = calloc(NWAM_MAX_NUM_OBJECTS, sizeof (char *))) == NULL) return (NWAM_NO_MEMORY); } fp = fopen(filename, "r"); if (fp == NULL) { if (errno != ENOENT) { if (objname == NULL) free(objnames); return (NWAM_ERROR_INTERNAL); } /* * Check NCP file list in case filename passed in was derived * from a case-insensitive NCP name. */ if ((err = create_ncp_file_list(&ncpfiles, &num_files)) == NWAM_SUCCESS) { for (j = 0; j < num_files; j++) { if (strcasecmp(ncpfiles[j], filename) == 0) { fp = fopen(ncpfiles[j], "r"); if (fp != NULL) { /* Copy real filename back */ (void) strlcpy(filename, ncpfiles[j], strlen(filename) + 1); break; } } } for (j = 0; j < num_files; j++) free(ncpfiles[j]); free(ncpfiles); } /* Return NOT_FOUND if file not found */ if (fp == NULL) { if (objname == NULL) free(objnames); return (NWAM_ENTITY_NOT_FOUND); } } while (fgets(line, sizeof (line), fp) != NULL) { if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; cp = line; while (isspace(*cp)) cp++; if (*cp == '#' || *cp == '\0') continue; if ((err = nwam_line_to_object(cp, &foundobjname, &proplist)) != NWAM_SUCCESS) goto done; if (objname != NULL) { /* * Is this the specified object? If so set objname and * obj and bail. */ if (strcasecmp(objname, foundobjname) == 0) { *((char **)obj) = proplist; (void) strlcpy(objname, foundobjname, NWAM_MAX_NAME_LEN); break; } else { nwam_free_object_list(proplist); } } else { objnames[i] = strdup(foundobjname); nwam_free_object_list(proplist); if (objnames[i] == NULL) { err = NWAM_NO_MEMORY; goto done; } i++; } } if (objname == NULL) { /* * Allocate object list with one value named * NWAM_OBJECT_NAMES_STRING - it's values are the names of * the objects found. */ if ((err = nwam_alloc_object_list(&objlist)) == NWAM_SUCCESS && (err = nwam_value_create_string_array(objnames, i, &objnamesval)) == NWAM_SUCCESS) { err = nwam_set_prop_value(objlist, NWAM_OBJECT_NAMES_STRING, objnamesval); } } done: if (fp != NULL) (void) fclose(fp); /* * 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. */ if (objname == NULL) { for (j = 0; j < i; j++) free(objnames[j]); free(objnames); nwam_value_free(objnamesval); if (err == NWAM_SUCCESS) { *((char **)obj) = objlist; } else { *((char **)obj) = NULL; nwam_free_object_list(objlist); } } else { /* Check if to-be-read object was not found */ if (*((char **)obj) == NULL && err == NWAM_SUCCESS) return (NWAM_ENTITY_NOT_FOUND); } return (err); } nwam_error_t nwam_object_to_line(FILE *fp, const char *objname, void *proplist) { char *propname, *lastpropname = NULL; boolean_t *valbool; int64_t *valint; uint64_t *valuint; char **valstr; uint_t nelem, i; nwam_value_t val; nwam_value_type_t type; (void) fprintf(fp, "%s\t", objname); while (nwam_next_object_prop(proplist, lastpropname, &propname, &val) == NWAM_SUCCESS) { (void) fprintf(fp, "%s%c", propname, NWAM_FILE_PROP_ASSIGN); if (nwam_value_get_type(val, &type) != NWAM_SUCCESS) return (NWAM_INVALID_ARG); switch (type) { case NWAM_VALUE_TYPE_BOOLEAN: (void) fprintf(fp, "%s", nwam_value_type_to_string(NWAM_VALUE_TYPE_BOOLEAN)); if (nwam_value_get_boolean_array(val, &valbool, &nelem) != NWAM_SUCCESS) { nwam_value_free(val); return (NWAM_INVALID_ARG); } for (i = 0; i < nelem; i++) { (void) fprintf(fp, "%c", NWAM_FILE_VALUE_DELIMITER); if (valbool[i]) { (void) fprintf(fp, NWAM_FILE_BOOLEAN_TRUE); } else { (void) fprintf(fp, NWAM_FILE_BOOLEAN_FALSE); } } break; case NWAM_VALUE_TYPE_INT64: (void) fprintf(fp, "%s", nwam_value_type_to_string(NWAM_VALUE_TYPE_INT64)); if (nwam_value_get_int64_array(val, &valint, &nelem) != NWAM_SUCCESS) { nwam_value_free(val); return (NWAM_INVALID_ARG); } for (i = 0; i < nelem; i++) { (void) fprintf(fp, "%c%lld", NWAM_FILE_VALUE_DELIMITER, valint[i]); } break; case NWAM_VALUE_TYPE_UINT64: (void) fprintf(fp, "%s", nwam_value_type_to_string(NWAM_VALUE_TYPE_UINT64)); if (nwam_value_get_uint64_array(val, &valuint, &nelem) != NWAM_SUCCESS) { nwam_value_free(val); return (NWAM_INVALID_ARG); } for (i = 0; i < nelem; i++) { (void) fprintf(fp, "%c%lld", NWAM_FILE_VALUE_DELIMITER, valuint[i]); } break; case NWAM_VALUE_TYPE_STRING: (void) fprintf(fp, "%s", nwam_value_type_to_string(NWAM_VALUE_TYPE_STRING)); if (nwam_value_get_string_array(val, &valstr, &nelem) != NWAM_SUCCESS) { nwam_value_free(val); return (NWAM_INVALID_ARG); } for (i = 0; i < nelem; i++) { char evalstr[NWAM_MAX_VALUE_LEN]; /* Add escape chars as necessary */ value_add_escapes(valstr[i], evalstr); (void) fprintf(fp, "%c%s", NWAM_FILE_VALUE_DELIMITER, evalstr); } break; default: nwam_value_free(val); return (NWAM_INVALID_ARG); } nwam_value_free(val); (void) fprintf(fp, "%c", NWAM_FILE_PROP_DELIMITER); lastpropname = propname; } (void) fprintf(fp, "\n"); 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. */ nwam_error_t nwam_write_object_to_files_backend(const char *filename, const char *objname, uint64_t flags, void *objlist) { void *proplist; char *currobjname, *lastobjname = NULL; int fd, cmd; nwam_error_t err = NWAM_SUCCESS; char *dir; char tmpfilename[MAXPATHLEN], filename_copy[MAXPATHLEN]; FILE *fp; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; struct flock fl = { F_WRLCK, SEEK_SET, 0, 0, 0}; struct flock fu = { F_UNLCK, SEEK_SET, 0, 0, 0}; assert(filename != NULL); /* Create the directory in case it does not exist. */ (void) strlcpy(filename_copy, filename, MAXPATHLEN); if ((dir = dirname(filename_copy)) == NULL) return (nwam_errno_to_nwam_error(errno)); if (mkdir(dir, dirmode) != 0) { if (errno != EEXIST) return (nwam_errno_to_nwam_error(errno)); } (void) snprintf(tmpfilename, MAXPATHLEN, "%s.new", filename); if ((fd = open(tmpfilename, O_RDWR | O_CREAT | O_TRUNC, mode)) < 0) return (nwam_errno_to_nwam_error(errno)); if ((fp = fdopen(fd, "w")) == NULL) { err = 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) cmd = F_SETLKW; else cmd = F_SETLK; if (fcntl(fd, cmd, &fl) != 0) { if (errno == EAGAIN) return (NWAM_ENTITY_IN_USE); else return (NWAM_ERROR_INTERNAL); } if (objname != NULL) { /* Only one object to write */ err = nwam_object_to_line(fp, objname, objlist); } else { if (objlist == NULL) { err = NWAM_SUCCESS; goto done; } /* Otherwise, write each object in turn. */ while ((err = nwam_next_object_list(objlist, lastobjname, &currobjname, &proplist)) == NWAM_SUCCESS) { if ((err = nwam_object_to_line(fp, currobjname, proplist)) != NWAM_SUCCESS) break; lastobjname = currobjname; } if (err == NWAM_LIST_END) err = NWAM_SUCCESS; } done: if (err == NWAM_SUCCESS) { if (rename(tmpfilename, filename) == 0) { (void) fcntl(fd, F_SETLKW, &fu); (void) fclose(fp); return (NWAM_SUCCESS); } else { err = nwam_errno_to_nwam_error(errno); } } (void) fcntl(fd, F_SETLKW, &fu); (void) fclose(fp); (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). */ nwam_error_t nwam_update_object_in_files_backend(char *filename, char *objname, uint64_t flags, void *proplist) { nwam_error_t err; void *objlist, *objnamelist; char **object_names; nwam_value_t value = NULL; uint_t i, num_objects; assert(filename != NULL); /* 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; (void) strlcpy(discard_objname, objname, sizeof (discard_objname)); if ((err = nwam_read_object_from_files_backend(filename, discard_objname, 0, &discard_objlist)) == NWAM_SUCCESS) { nwam_free_object_list(discard_objlist); return (NWAM_ENTITY_EXISTS); } } /* Get existing list of object names (if any) */ err = nwam_read_object_from_files_backend(filename, NULL, flags, &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. */ if ((err = nwam_alloc_object_list(&objlist)) != NWAM_SUCCESS) { nwam_free_object_list(objnamelist); return (err); } if ((err = nwam_get_prop_value(objnamelist, NWAM_OBJECT_NAMES_STRING, &value)) != NWAM_SUCCESS || (err = nwam_value_get_string_array(value, &object_names, &num_objects)) != NWAM_SUCCESS) { nwam_value_free(value); nwam_free_object_list(objnamelist); nwam_free_object_list(objlist); return (err); } nwam_free_object_list(objnamelist); for (i = 0; i < num_objects; i++) { void *oproplist = NULL; if (objname != NULL && strcmp(objname, object_names[i]) == 0) continue; if ((err = nwam_read_object_from_files_backend(filename, object_names[i], flags, &oproplist)) != NWAM_SUCCESS || (err = nwam_object_list_add_object_list(objlist, object_names[i], oproplist)) != NWAM_SUCCESS) { nwam_free_object_list(oproplist); nwam_free_object_list(objlist); nwam_value_free(value); return (err); } nwam_free_object_list(oproplist); } nwam_value_free(value); break; case NWAM_ENTITY_NOT_FOUND: /* * Just need to write/remove this single object. */ return (nwam_write_object_to_files_backend(filename, objname, flags, proplist)); 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). */ if (objname != NULL && proplist != NULL) { if ((err = nwam_object_list_add_object_list(objlist, (char *)objname, proplist)) != NWAM_SUCCESS) { nwam_free_object_list(objlist); return (err); } } err = nwam_write_object_to_files_backend(filename, NULL, flags, objlist); nwam_free_object_list(objlist); return (err); } /* * Remove specified object from file by reading in the list of objects, * removing objname and writing the remainder. */ nwam_error_t nwam_remove_object_from_files_backend(char *filename, char *objname, uint64_t flags) { int uerr; assert(filename != NULL); if (objname == NULL) { /* * NULL objname signifies remove file. */ uerr = unlink(filename); if (uerr != 0) return (nwam_errno_to_nwam_error(errno)); return (NWAM_SUCCESS); } return (nwam_update_object_in_files_backend(filename, objname, flags, NULL)); }