/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.0 (the 'License'). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ /* * nilib2 ± more NetInfo library routines. * Written by Marc Majka * * Copyright 1994, NeXT Computer Inc. */ //#include #include #include #include #include #include static unsigned long ni_connect_timeout = 300; enum ni_parse_status ni_parse_server_tag(char *str, struct sockaddr_in *server, char **t) { /* utility to parse a server/tag string */ int len, i; char *host, *tag, *slash; struct hostent *hent; len = strlen(str); /* find the "/" character */ slash = index(str, '/'); /* check to see if the "/" is missing */ if (slash == NULL) return NI_PARSE_BADFORMAT; /* find the location of the '/' */ i = slash - str; /* check if host string is empty */ if (i == 0) return NI_PARSE_NOHOST; /* check if tag string is empty */ if (i == (len - 1)) return NI_PARSE_NOTAG; /* allocate some space for the host and tag */ host = (char *)malloc(i + 1); *t = (char *)malloc(len - i); tag = *t; /* copy out the host */ strncpy(host, str, i); host[i] = '\0'; /* copy out the tag */ strcpy(tag, slash + 1); /* try interpreting the host portion as an address */ server->sin_addr.s_addr = inet_addr(host); if (server->sin_addr.s_addr == -1) { /* This isn't a valid address. Is it a known hostname? */ hent = gethostbyname(host); if (hent != NULL) { /* found a host with that name */ bcopy(hent->h_addr, &server->sin_addr, hent->h_length); } else { fprintf(stderr, "Can't find address for %s\n", host); free(host); free(tag); return NI_PARSE_HOSTNOTFOUND; } } free(host); return NI_PARSE_OK; } const char * ni_parse_error_string(enum ni_parse_status status) { switch (status) { case NI_PARSE_OK: return("Operation succeeded"); case NI_PARSE_BADFORMAT: return("Bad format"); case NI_PARSE_NOHOST: return("No host"); case NI_PARSE_NOTAG: return("No tag"); case NI_PARSE_BADADDR: return("Bad address"); case NI_PARSE_HOSTNOTFOUND: return("Host not found"); } return NULL; } int do_open(char *tool, char *name, void **domain, bool bytag, int timeout, char *user, char *passwd) { /* do an ni_open or an ni_connect, as appropriate */ char *tag; enum ni_parse_status pstatus; ni_status status; struct sockaddr_in server; ni_id rootdir; if (bytag) { /* connect by tag */ /* call a function to parse the input arg */ pstatus = ni_parse_server_tag(name, &server, &tag); if (pstatus != NI_PARSE_OK) { fprintf(stderr, "%s: incorrect format for domain %s (%s)\n", tool, name, ni_parse_error_string(pstatus)); fprintf(stderr, "usage: -t /\n"); fprintf(stderr, " can be a host name or IP address\n"); return NI_FAILED + 1 + pstatus; } /* connect to the specified server */ *domain = ni_connect(&server, tag); free(tag); if (*domain == NULL) { fprintf(stderr, "%s: can't connect to server %s\n", tool, name); return NI_FAILED + 1; } } else { status = ni_open(NULL, name, domain); if (status != NI_OK) { fprintf(stderr, "%s: can't connect to server for domain %s\n", tool, name); return status; } } /* abort on errors */ ni_setabort(*domain, 1); /* set timeouts */ ni_setreadtimeout(*domain, timeout); ni_setwritetimeout(*domain, timeout); /* authentication */ if (user != NULL) { ni_setuser(*domain, user); if (passwd != NULL) ni_setpassword(*domain, passwd); } /* get the root directory to see if the connection is alive */ status = ni_root(*domain, &rootdir); if (status != NI_OK) { if (bytag) fprintf(stderr, "%s: can't connect to server %s: %s\n", tool, name, ni_error(status)); else fprintf(stderr, "%s: can't connect to server for domain %s: %s\n", tool, name, ni_error(status)); return status; } return 0; } ni_status ni2_create(void *domain, char *pathname) { /* make a directory with the given pathname */ /* do nothing if the directory already exists */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if it already exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret == NI_OK) return NI_OK; /* doesn't exist: create it */ ret = ni_root(domain, &dir); if (ret != NI_OK) return ret; if (pathname[0] == '/') ret = ni2_createpath(domain, &dir, pathname+1); else ret = ni2_createpath(domain, &dir, pathname); return ret; } ni_status ni2_createprop(void *domain, char *pathname, const ni_name key, ni_namelist values) { /* create a new property with a given key and list of values */ /* replaces an existing property if it already exists */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory already exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_createdirprop(domain, &dir, key, values); } ni_status ni2_createdirprop(void *domain, ni_id *dir, const ni_name key, ni_namelist values) { /* createprop given a directory rather than a pathname */ ni_status ret; ni_property p; ni_namelist nl; ni_index where; /* need to be talking to the master */ ni_needwrite(domain, 1); /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* check for existing property with this key */ where = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, create it */ if (where == NI_INDEX_NULL) { NI_INIT(&p); p.nip_name = ni_name_dup(key); p.nip_val = ni_namelist_dup(values); ret = ni_createprop(domain, dir, p, NI_INDEX_NULL); ni_prop_free(&p); return ret; } /* property exists: replace the existing values */ ret = ni_writeprop(domain, dir, where, values); return ret; } ni_status ni2_appendprop(void *domain, char *pathname, const ni_name key, ni_namelist values) { /* append a list of values to a property */ /* a new property is created if it doesn't exist */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory already exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_appenddirprop(domain, &dir, key, values); } ni_status ni2_appenddirprop(void *domain, ni_id *dir, const ni_name key, ni_namelist values) { /* appendprop given a directory rather than a pathname */ ni_status ret; ni_property p; ni_namelist nl; ni_index where; int i; /* need to be talking to the master */ ni_needwrite(domain, 1); /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) { return ret; } /* check for existing property with this key */ where = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, create it */ if (where == NI_INDEX_NULL) { NI_INIT(&p); p.nip_name = ni_name_dup(key); p.nip_val = ni_namelist_dup(values); ret = ni_createprop(domain, dir, p, NI_INDEX_NULL); ni_prop_free(&p); return ret; } /* property exists: replace the existing values */ /* fetch existing namelist for this property */ NI_INIT(&nl); ret = ni_readprop(domain, dir, where, &nl); if (ret != NI_OK) { return ret; } /* append new values */ for (i = 0; i < values.ni_namelist_len; i++) { ni_namelist_insert(&nl, values.ni_namelist_val[i], NI_INDEX_NULL); } /* write the new list back */ ret = ni_writeprop(domain, dir, where, nl); ni_namelist_free(&nl); return ret; } ni_status ni2_insertval(void *domain, char *pathname, const ni_name key, const ni_name value, ni_index where) { /* insert a new value into a property */ /* the property is created if it doesn't exist */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_insertdirval(domain, &dir, key, value, where); } ni_status ni2_insertdirval(void *domain, ni_id *dir, const ni_name key, const ni_name value, ni_index whereval) { /* insertval given a directory rather than a pathname */ ni_status ret; ni_property p; ni_namelist nl; ni_index where; /* need to be talking to the master */ ni_needwrite(domain, 1); /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* check for existing property with this key */ where = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, create it */ if (where == NI_INDEX_NULL) { NI_INIT(&nl); ni_namelist_insert(&nl, value, NI_INDEX_NULL); NI_INIT(&p); p.nip_name = ni_name_dup(key); p.nip_val = ni_namelist_dup(nl); ret = ni_createprop(domain, dir, p, NI_INDEX_NULL); ni_namelist_free(&nl); ni_prop_free(&p); return ret; } /* property exists: replace the existing values */ /* fetch existing namelist for this property */ NI_INIT(&nl); ret = ni_readprop(domain, dir, where, &nl); if (ret != NI_OK) return ret; /* insert new value */ ni_namelist_insert(&nl, value, whereval); /* write the new list back */ ret = ni_writeprop(domain, dir, where, nl); ni_namelist_free(&nl); return ret; } ni_status ni2_mergeprop(void *domain, char *pathname, const ni_name key, ni_namelist values) { /* merge a list of values into a property (to prevent duplicates) */ /* creates the property if it doesn't already exist */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory already exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_mergedirprop(domain, &dir, key, values); } ni_status ni2_mergedirprop(void *domain, ni_id *dir, const ni_name key, ni_namelist values) { /* mergeprop given a directory rather than a pathname */ ni_status ret; ni_property p; ni_namelist nl; ni_index where, whereval; int i; /* need to be talking to the master */ ni_needwrite(domain, 1); /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* check for existing property with this key */ where = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, create it */ if (where == NI_INDEX_NULL) { NI_INIT(&p); p.nip_name = ni_name_dup(key); p.nip_val = ni_namelist_dup(values); ret = ni_createprop(domain, dir, p, NI_INDEX_NULL); ni_prop_free(&p); return ret; } /* property exists: replace the existing values */ /* fetch existing namelist for this property */ NI_INIT(&nl); ret = ni_readprop(domain, dir, where, &nl); if (ret != NI_OK) return ret; /* merge new values */ for (i = 0; i < values.ni_namelist_len; i++) { whereval = ni_namelist_match(nl, values.ni_namelist_val[i]); if (whereval == NI_INDEX_NULL) { ni_namelist_insert(&nl, values.ni_namelist_val[i], NI_INDEX_NULL); } } /* write the new list back */ ret = ni_writeprop(domain, dir, where, nl); ni_namelist_free(&nl); return ret; } ni_status ni2_destroy(void *domain, char *pathname) { /* destroy a directory */ /* this version recursively destroys all subdirectories as well */ ni_status ret; ni_id dir, parent; ni_index pi; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; /* get the parent directory index (nii_object) */ ret = ni_parent(domain, &dir, &pi); if (ret != NI_OK) return ret; /* get the parent directory id */ parent.nii_object = pi; ret = ni_self(domain, &parent); if (ret != NI_OK) return ret; return ni2_destroydir(domain, &dir, &parent); } ni_status ni2_destroydir(void *domain, ni_id *dir, ni_id *parent) { /* destroy a directory and all it's subdirectories */ /* this is the recursive workhorse */ ni_status ret; int i; ni_idlist children; ni_id child; /* need to be talking to the master */ ni_needwrite(domain, 1); /* get a list of all my children */ NI_INIT(&children); ret = ni_children(domain, dir, &children); if (ret != NI_OK) return ret; /* destroy each child */ for (i = 0; i < children.ni_idlist_len; i++) { child.nii_object = children.ni_idlist_val[i]; ret = ni_self(domain, &child); if (ret != NI_OK) return ret; ret = ni2_destroydir(domain, &child, dir); if (ret != NI_OK) return ret; } /* free list of child ids */ ni_idlist_free(&children); /* destroy myself */ return ni_destroy(domain, parent, *dir); } ni_status ni2_destroyprop(void *domain, char *pathname, ni_namelist keys) { /* destroy a property */ /* destroys all properties with the same key */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_destroydirprop(domain, &dir, keys); } ni_status ni2_destroydirprop(void *domain, ni_id *dir, ni_namelist keys) { /* destroyprop given a directory rather than a pathname */ ni_status ret; ni_index where; ni_namelist nl; int i; /* need to be talking to the master */ ni_needwrite(domain, 1); /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* destroy all occurrences of each key */ for (i = 0; i < keys.ni_namelist_len; i++) { where = ni_namelist_match(nl, keys.ni_namelist_val[i]); /* keep looking for all occurrences */ while (where != NI_INDEX_NULL) { ret = ni_destroyprop(domain, dir, where); if (ret != NI_OK) { ni_namelist_free(&nl); return ret; } /* update the namelist */ ni_namelist_delete(&nl, where); where = ni_namelist_match(nl, keys.ni_namelist_val[i]); } } ni_namelist_free(&nl); return NI_OK; } ni_status ni2_destroyval(void *domain, char *pathname, const ni_name key, ni_namelist values) { /* destroy all occurances of a value in a property */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_destroydirval(domain, &dir, key, values); } ni_status ni2_destroydirval(void *domain, ni_id *dir, const ni_name key, ni_namelist values) { /* destroyval given a directory rather than a pathname */ ni_status ret; ni_namelist nl; ni_index where, whereval; int i; /* need to be talking to the master */ ni_needwrite(domain, 1); /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK)return ret; /* check for existing property with this key */ where = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, nothing to do */ if (where == NI_INDEX_NULL) return NI_OK; /* fetch existing namelist for this property */ NI_INIT(&nl); ret = ni_readprop(domain, dir, where, &nl); if (ret != NI_OK) return ret; /* delete values */ for (i = 0; i < values.ni_namelist_len; i++) { whereval = ni_namelist_match(nl, values.ni_namelist_val[i]); while (whereval != NI_INDEX_NULL) { ni_namelist_delete(&nl, whereval); whereval = ni_namelist_match(nl, values.ni_namelist_val[i]); } } /* write the new list back */ ret = ni_writeprop(domain, dir, where, nl); ni_namelist_free(&nl); return ret; } ni_status ni2_renameprop(void *domain, char *pathname, const ni_name oldname, const ni_name newname) { /* rename a property */ ni_status ret; ni_id dir; /* need to be talking to the master */ ni_needwrite(domain, 1); /* see if the directory already exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_renamedirprop(domain, &dir, oldname, newname); } ni_status ni2_renamedirprop(void *domain, ni_id *dir, const ni_name oldname, const ni_name newname) { /* renameprop given a directory rather than a pathname */ ni_status ret; ni_index where; ni_namelist nl; /* need to be talking to the master */ ni_needwrite(domain, 1); /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* look up old name */ where = ni_namelist_match(nl, oldname); ni_namelist_free(&nl); /* if it's not there, return an error */ if (where == NI_INDEX_NULL) return NI_NOPROP; return ni_renameprop(domain, dir, where, newname); } ni_status ni2_pathsearch(void *domain, ni_id *dir, char *pathname) { /* same as pathsearch, but if pathname is an integer */ /* then use it as a directory id */ int i, len; bool is_id; len = strlen(pathname); is_id = true; for (i = 0; i < len && is_id; i++) if (!isdigit(pathname[i])) is_id = false; if (is_id) { dir->nii_object = (unsigned long)atoi(pathname); return ni_self(domain, dir); } else { return ni_pathsearch(domain, dir, pathname); } } ni_status ni2_createpath(void *domain, ni_id *dir, char *pathname) { /* make a directory with the given pathname */ ni_status ret; ni_id checkdir; int i, j, len; char *dirname = NULL; bool simple; /* pull out every pathname component and create the directory */ i = 0; while (pathname[i] != '\0') { /* search forward for a path component (a directory) */ simple = true; for (j = i; pathname[j] != '\0' && simple; j++) { if (pathname[j] == '\\' && pathname[j+1] == '/') j+=2; if (pathname[j] == '/') simple = false; } len = j - i; if (!simple) len--; dirname = malloc(len + 1); strncpy(dirname, pathname+i, len); dirname[len] = '\0'; /* advance the pointer */ i = j; /* does this directory exist? */ checkdir = *dir; ret = ni_pathsearch(domain, dir, dirname); /* if it doesn't exist, create it */ if (ret == NI_NODIR) { *dir = checkdir; ret = ni2_createchild(domain, dir, dirname); if (ret != NI_OK) return ret; } free(dirname); } return NI_OK; } ni_status ni2_createchild(void *domain, ni_id *dir, const ni_name dirname) { /* make a child directory with the given name */ ni_status ret; ni_proplist p; ni_id child; int i, j, k, len; char *key = NULL; char *value = NULL; /* if the name contains "=", then we've got "foo=bar" */ /* property key is "foo", not "name" */ len = 0; for (i = 0; dirname[i] != '\0' && dirname[i] != '='; i++); if (dirname[i] == '=') len = i; if (len > 0) { key = malloc(len + 1); /* check for backslashes in property key */ for (i = 0, j = 0; i < len; i++, j++) { if (dirname[i] == '\\' && dirname[i+1] == '/') i++; key[j] = dirname[i]; } key[j] = '\0'; i = len + 1; } else { key = malloc(5); strcpy(key, "name"); i = 0; } /* compress out backslashes in value */ j = strlen(dirname); len = j - i; value = malloc(len + 1); for (k = 0; i < j; k++, i++) { if (dirname[i] == '\\' && dirname[i+1] == '/') i++; value[k] = dirname[i]; } value[k] = '\0'; /* set up the new directory */ NI_INIT(&p); nipl_createprop(&p, key); nipl_appendprop(&p, key, value); /* create it */ ret = ni_create(domain, dir, p, &child, NI_INDEX_NULL); if (ret != NI_OK) { ni_proplist_free(&p); return ret; } ni_proplist_free(&p); free(key); free(value); *dir = child; return NI_OK; } void nipl_createprop(ni_proplist *l, const ni_name n) { /* property list utility */ /* add a name property to a property list */ ni_property p; NI_INIT(&p); p.nip_name = ni_name_dup(n); p.nip_val.ninl_len = 0; p.nip_val.ninl_val = NULL; ni_proplist_insert(l, p, NI_INDEX_NULL); ni_prop_free(&p); } void nipl_appendprop(ni_proplist *l, const ni_name n, const ni_name v) { /* property list utility */ /* append a value to a property in a property list */ ni_index where; where = ni_proplist_match(*l, n, NULL); if (where == NI_INDEX_NULL) { nipl_createprop(l, n); where = ni_proplist_match(*l, n, NULL); } ni_namelist_insert(&(l->nipl_val[where].nip_val), v, NI_INDEX_NULL); } void nipl_mergeprop(ni_proplist *l, const ni_name n, const ni_name v) { /* property list utility */ /* merge a value into a property in a property list */ ni_index where; where = ni_proplist_match(*l, n, NULL); if (where == NI_INDEX_NULL) { nipl_createprop(l, n); where = ni_proplist_match(*l, n, NULL); } where = ni_namelist_match(l->nipl_val[where].nip_val, v); if (where == NI_INDEX_NULL) { ni_namelist_insert(&(l->nipl_val[where].nip_val), v, NI_INDEX_NULL); } } ni_status ni2_statprop(void *domain, char *pathname, const ni_name key, ni_index *where) { /* match a property in a given property in a given directory */ ni_status ret; ni_id dir; /* assume there's no match */ *where = NI_INDEX_NULL; /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_statpropdir(domain, &dir, key, where); } ni_status ni2_statpropdir(void *domain, ni_id *dir, const ni_name key, ni_index *where) { /* statprop given a directory rather than a pathname */ ni_status ret; ni_namelist nl; /* assume there's no match */ *where = NI_INDEX_NULL; /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* check for property with this key */ *where = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, no match */ if (*where == NI_INDEX_NULL) return NI_NOPROP; return NI_OK; } ni_status ni2_statval(void *domain, char *pathname, const ni_name key, const ni_name value, ni_index *where) { /* match a value in a given property in a given directory */ ni_status ret; ni_id dir; /* assume there's no match */ *where = NI_INDEX_NULL; /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_statvaldir(domain, &dir, key, value, where); } ni_status ni2_statvaldir(void *domain, ni_id *dir, const ni_name key, const ni_name value, ni_index *where) { /* statval given a directory rather than a pathname */ ni_status ret; ni_namelist nl; ni_index wh; /* assume there's no match */ *where = NI_INDEX_NULL; /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* check for property with this key */ wh = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, no match */ if (wh == NI_INDEX_NULL) return NI_NOPROP; /* fetch existing namelist for this property */ NI_INIT(&nl); ret = ni_readprop(domain, dir, wh, &nl); if (ret != NI_OK) return ret; /* check for this value */ wh = ni_namelist_match(nl, value); ni_namelist_free(&nl); /* if value doesn't exist, no match */ if (wh == NI_INDEX_NULL) return NI_NONAME; *where = wh; return NI_OK; } ni_status ni2_reapprop(void *domain, char *pathname, const ni_name key) { /* remove a property in a given directory if the property is empty */ ni_status ret; ni_id dir; /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni2_reappropdir(domain, &dir, key); } ni_status ni2_reappropdir(void *domain, ni_id *dir, const ni_name key) { /* reapprop given a directory rather than a pathname */ ni_status ret; ni_namelist nl; ni_index where; /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, dir, &nl); if (ret != NI_OK) return ret; /* check for property with this key */ where = ni_namelist_match(nl, key); ni_namelist_free(&nl); /* if property doesn't exist, return */ if (where == NI_INDEX_NULL) return NI_OK; /* fetch existing namelist for this property */ NI_INIT(&nl); ret = ni_readprop(domain, dir, where, &nl); if (ret != NI_OK) return ret; /* if the property contains any values, leave it alone */ if (nl.ni_namelist_len > 0) { ni_namelist_free(&nl); return NI_OK; } /* property is empty, delete it */ ni_namelist_free(&nl); return ni_destroyprop(domain, dir, where); } ni_status ni2_reapdir(void *domain, char *pathname) { /* destroy a directory if it has nothing but a name */ ni_status ret; ni_id dir; ni_namelist nl; /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; /* fetch list of property keys from directory */ NI_INIT(&nl); ret = ni_listprops(domain, &dir, &nl); if (ret != NI_OK) return ret; /* if more than one property, leave it alone */ if (nl.ni_namelist_len > 1) { ni_namelist_free(&nl); return NI_OK; } /* directory is empty (except for name), delete it */ ni_namelist_free(&nl); return ni2_destroy(domain, pathname); } ni_status ni2_copy(void *srcdomain, char *path, void*dstdomain, bool recursive) { /* copy a directory from src to dst */ ni_status ret; ni_id srcdir, dstdir; /* see if src directory exists */ ret = ni2_pathsearch(srcdomain, &srcdir, path); if (ret != NI_OK) return ret; /* create dstdir if necessary */ ret = ni2_create(dstdomain, path); if (ret != NI_OK) return ret; /* get dstdir */ ret = ni2_pathsearch(dstdomain, &dstdir, path); if (ret != NI_OK) return ret; return ni2_copydir(srcdomain, &srcdir, dstdomain, &dstdir, recursive); } ni_status ni2_copydir(void *srcdomain, ni_id *srcdir, void*dstdomain, ni_id *dstdir , bool recursive) { ni_status ret; ni_idlist children; int i, len; ni_proplist p; ni_id dir; NI_INIT(&p); /* get proplist from src dir */ ret = ni_read(srcdomain, srcdir, &p); if (ret != NI_OK) return ret; /* write the property list to the dst dir */ ret = ni_write(dstdomain, dstdir, p); if (ret != NI_OK) { ni_proplist_free(&p); return ret; } ni_proplist_free(&p); if (recursive) { NI_INIT(&children); /* get list of children */ ret = ni_children(srcdomain, srcdir, &children); if (ret != NI_OK) return ret; len = children.ni_idlist_len; for (i = 0; i < len; i++) { dir.nii_object = children.ni_idlist_val[i]; ret = ni_self(srcdomain, &dir); if (ret != NI_OK) { ni_idlist_free(&children); return ret; } ret = ni2_copydirtoparentdir(srcdomain,&dir,dstdomain,dstdir,recursive); } ni_idlist_free(&children); } return NI_OK; } ni_status ni2_copydirtoparentdir(void *srcdomain, ni_id *srcdir, void*dstdomain, ni_id *dstdir , bool recursive) { ni_status ret; ni_idlist children; int i, len; ni_proplist p; ni_id dir, newdstdir; NI_INIT(&p); /* get proplist from src dir */ ret = ni_read(srcdomain, srcdir, &p); if (ret != NI_OK) return ret; /* create the destination dir */ ret = ni_create(dstdomain, dstdir, p, &newdstdir, NI_INDEX_NULL); if (ret != NI_OK) { ni_proplist_free(&p); return ret; } ni_proplist_free(&p); if (recursive) { NI_INIT(&children); /* get list of children */ ret = ni_children(srcdomain, srcdir, &children); if (ret != NI_OK) return ret; len = children.ni_idlist_len; for (i = 0; i < len; i++) { dir.nii_object = children.ni_idlist_val[i]; ret = ni_self(srcdomain, &dir); if (ret != NI_OK) { ni_idlist_free(&children); return ret; } ret = ni2_copydirtoparentdir(srcdomain,&dir,dstdomain, &newdstdir,recursive); } ni_idlist_free(&children); } return NI_OK; } ni_status ni2_lookupprop(void *domain, char *pathname, const ni_name key, ni_namelist *values) { /* read a property */ ni_status ret; ni_id dir; /* see if the directory exists */ ret = ni2_pathsearch(domain, &dir, pathname); if (ret != NI_OK) return ret; return ni_lookupprop(domain, &dir, key, values); } ni_index ni_namelist_insert_sorted(ni_namelist *values, const ni_name newvalue) { int i, len; len = values->ni_namelist_len; for (i = 0; i < len; i++) { if (strcmp(newvalue, values->ni_namelist_val[i]) <= 0) { ni_namelist_insert(values, newvalue, (ni_index)i); return (ni_index)i; } } ni_namelist_insert(values, newvalue, NI_INDEX_NULL); return NI_INDEX_NULL; } void * niHandleForTag(char *tag, struct sockaddr_in *addr) { void *domain; int a; unsigned long t; ni_status status; ni_id root; if (tag == NULL) return NULL; if (addr == NULL) return NULL; if (addr->sin_addr.s_addr == -1) return NULL; domain = ni_connect(addr, tag); if (domain == NULL) return NULL; a = 1; t = ni_connect_timeout; if (!strcmp(tag, "local") && (addr->sin_addr.s_addr == htonl(INADDR_LOOPBACK))) { a = 0; t = 0; } ni_setabort(domain, a); ni_setreadtimeout(domain, t); root.nii_object = 0; status = ni_self(domain, &root); if (status != NI_OK) { system_log(LOG_ALERT, "NetInfo open failed for %s@%s (%s)", tag, inet_ntoa(addr->sin_addr), ni_error(status)); ni_free(domain); return NULL; } ni_setabort(domain, 1); ni_setreadtimeout(domain, ni_connect_timeout); return domain; } void * niHandleForPath(char *path, struct sockaddr_in *addr) { void *d0, *d1; ni_status status; char **parts; int a, i; unsigned long t; ni_id root; if (path == NULL) return NULL; if (addr == NULL) return NULL; if (addr->sin_addr.s_addr == -1) return NULL; root.nii_object = 0; d0 = ni_connect(addr, "local"); if (d0 == NULL) return NULL; a = 1; t = ni_connect_timeout; if (!strcmp(path, ".") && (addr->sin_addr.s_addr == htonl(INADDR_LOOPBACK))) { a = 0; t = 0; } ni_setabort(d0, a); ni_setreadtimeout(d0, t); status = ni_self(d0, &root); if (status != NI_OK) { system_log(LOG_ALERT, "NetInfo open failed for local@%s (%s)", inet_ntoa(addr->sin_addr), ni_error(status)); ni_free(d0); return NULL; } ni_setabort(d0, 1); ni_setreadtimeout(d0, ni_connect_timeout); if (!strcmp(path, ".")) return d0; status = NI_OK; while (status == NI_OK) { status = ni_open(d0, "..", &d1); if (status == NI_OK) status = ni_self(d1, &root); if (status == NI_OK) { ni_free(d0); d0 = d1; } if (!strcmp(path, "..")) return d0; } if (!strcmp(path, "/")) return d0; parts = explode(path+1, "/"); for (i = 0; parts[i] != NULL; i++) { status = ni_open(d0, parts[i], &d1); if (status == NI_OK) status = ni_self(d1, &root); if (status != NI_OK) { system_log(LOG_ALERT, "NetInfo open failed for domain component %s at address %s (%s)", parts[i], inet_ntoa(addr->sin_addr), ni_error(status)); freeList(parts); return NULL; } ni_free(d0); d0 = d1; } freeList(parts); return d0; } void * niHandleForName(char *name) { void *domain; char *p_colon, *p_at; struct sockaddr_in server; if (name == NULL) return NULL; /* * names may be of the following formats: * * path -> domain with given pathname * tag@address -> connect by tag to given address * path@address -> path relative to local domain at host * * niserver:tag -> connect by tag, localhost * niserver:tag@address -> connect by tag * nidomain:path -> domain with given pathname * nidomain:path@address -> path relative to local domain at host */ domain = NULL; p_colon = strchr(name, ':'); p_at = strchr(name, '@'); memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (p_at != NULL) { *p_at = '\0'; server.sin_addr.s_addr = inet_addr(p_at + 1); } if (p_colon != NULL) { if (!strncmp(name, "niserver:", 9)) domain = niHandleForTag(name+9, &server); if (!strncmp(name, "nidomain:", 9)) domain = niHandleForPath(name+9, &server); } else { if ((name[0] == '/') || (name[0] == '.')) domain = niHandleForPath(name, &server); else domain = niHandleForTag(name, &server); } if (domain == NULL) { system_log(LOG_ALERT, "NetInfo open failed for %s", name); } if (p_at != NULL) *p_at = '@'; return domain; }