Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: dict_ni.c,v 1.2 2026/05/09 18:49:22 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	dict_ni 3
      6 /* SUMMARY
      7 /*	dictionary manager interface to NetInfo
      8 /* SYNOPSIS
      9 /*	#include <dict_ni.h>
     10 /*
     11 /*	DICT	*dict_ni_open(path, dummy, dict_flags)
     12 /*	char	*path;
     13 /*	int	dummy;
     14 /*	int	dict_flags;
     15 /* DESCRIPTION
     16 /*	dict_ni_open() `opens' the named NetInfo database. The result is
     17 /*	a pointer to a structure that can be used to access the dictionary
     18 /*	using the generic methods documented in dict_open(3).
     19 /* DIAGNOSTICS
     20 /*	dict_ni_register() returns 0 in case of success, -1 in case
     21 /*	of problems.
     22 /*	Fatal errors: NetInfo errors, out of memory.
     23 /* SEE ALSO
     24 /*	dict(3) generic dictionary manager
     25 /*	netinfo(3N) data base subroutines
     26 /* AUTHOR(S)
     27 /*	Pieter Schoenmakers
     28 /*	Eindhoven University of Technology
     29 /*	P.O. Box 513
     30 /*	5600 MB Eindhoven
     31 /*	The Netherlands
     32 /*--*/
     33 
     34 #include "sys_defs.h"
     35 
     36 #ifdef HAS_NETINFO
     37 
     38 /* System library. */
     39 
     40 #include <stdio.h>
     41 #include <netinfo/ni.h>
     42 
     43 /* Utility library. */
     44 
     45 #include "dict.h"
     46 #include "dict_ni.h"
     47 #include "msg.h"
     48 #include "mymalloc.h"
     49 #include "stringops.h"
     50 
     51 typedef struct {
     52     DICT    dict;			/* my super */
     53     char   *path;			/* directory path */
     54 } DICT_NI;
     55 
     56  /*
     57   * We'd like other possibilities, but that is not possible in the current
     58   * dictionary setup...  An example of a different setup: use `members' for
     59   * multi-valued lookups (to be compatible with /aliases), and `value' for
     60   * single-valued tables.
     61   */
     62 #define NETINFO_PROP_KEY	"name"
     63 #define NETINFO_PROP_VALUE	"members"
     64 #define NETINFO_VALUE_SEP	 ","
     65 
     66 #define NETINFO_MAX_DOMAIN_DEPTH	100
     67 
     68 /* Hard worker doing lookups.	Returned value is statically allocated and
     69    reused each call.  */
     70 static const char *dict_ni_do_lookup(char *path, char *key_prop,
     71 			              const char *key_value, char *val_prop)
     72 {
     73     unsigned int result_cap = 0;
     74     static char *result = 0;
     75 
     76     char   *return_val = 0;
     77     ni_namelist values;
     78     int     depth = 0;
     79     void   *domain;
     80     void   *next_domain;
     81     char   *query;
     82     ni_status r;
     83     ni_id   dir;
     84 
     85     if (msg_verbose)
     86 	msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);
     87 
     88     r = ni_open(NULL, ".", &domain);
     89     if (r != NI_OK) {
     90 	msg_warn("ni_open `.': %d", r);
     91 	return NULL;
     92     }
     93     query = mymalloc(strlen(path) + strlen(key_prop) + 3 + strlen(key_value));
     94     sprintf(query, "%s/%s=%s", path, key_prop, key_value);
     95 
     96     for (;;) {
     97 
     98 	/*
     99 	 * What does it _mean_ if we find the directory but not the value?
    100 	 */
    101 	if (ni_pathsearch(domain, &dir, query) == NI_OK
    102 	    && ni_lookupprop(domain, &dir, val_prop, &values) == NI_OK)
    103 	    if (values.ni_namelist_len <= 0)
    104 		ni_namelist_free(&values);
    105 	    else {
    106 		unsigned int i, l, n;
    107 
    108 		for (i = l = 0; i < values.ni_namelist_len; i++)
    109 		    l += 1 + strlen(values.ni_namelist_val[i]);
    110 		if (result_cap < l) {
    111 		    if (result)
    112 			myfree(result);
    113 		    result_cap = l + 100;
    114 		    result = mymalloc(result_cap);
    115 		}
    116 		for (i = l = 0; i < values.ni_namelist_len; i++) {
    117 		    n = strlen(values.ni_namelist_val[i]);
    118 		    memcpy(result + l, values.ni_namelist_val[i], n);
    119 		    l += n;
    120 		    if (i < values.ni_namelist_len - 1)
    121 			result[l++] = ',';
    122 		}
    123 		result[l] = '\0';
    124 		return_val = result;
    125 		break;
    126 	    }
    127 
    128 	if (++depth >= NETINFO_MAX_DOMAIN_DEPTH) {
    129 	    msg_warn("ni_open: domain depth limit");
    130 	    break;
    131 	}
    132 	r = ni_open(domain, "..", &next_domain);
    133 	if (r != NI_OK) {
    134 	    if (r != NI_FAILED)
    135 		msg_warn("ni_open `..': %d", r);
    136 	    break;
    137 	}
    138 	ni_free(domain);
    139 	domain = next_domain;
    140     }
    141 
    142     ni_free(domain);
    143     myfree(query);
    144 
    145     return return_val;
    146 }
    147 
    148 /* dict_ni_lookup - find table entry */
    149 
    150 static const char *dict_ni_lookup(DICT *dict, const char *key)
    151 {
    152     DICT_NI *d = (DICT_NI *) dict;
    153 
    154     dict->error = 0;
    155 
    156     /*
    157      * Optionally fold the key.
    158      */
    159     if (dict->flags & DICT_FLAG_FOLD_FIX) {
    160 	if (dict->fold_buf == 0)
    161 	    dict->fold_buf = vstring_alloc(10);
    162 	vstring_strcpy(dict->fold_buf, key);
    163 	key = lowercase(vstring_str(dict->fold_buf));
    164     }
    165     return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
    166 			     key, NETINFO_PROP_VALUE);
    167 }
    168 
    169 /* dict_ni_close - disassociate from NetInfo map */
    170 
    171 static void dict_ni_close(DICT *dict)
    172 {
    173     DICT_NI *d = (DICT_NI *) dict;
    174 
    175     if (dict->fold_buf)
    176 	vstring_free(dict->fold_buf);
    177     dict_free(dict);
    178 }
    179 
    180 /* dict_ni_open - create association with NetInfo map */
    181 
    182 DICT   *dict_ni_open(const char *path, int unused_flags, int dict_flags)
    183 {
    184     DICT_NI *d = (void *) dict_alloc(DICT_TYPE_NETINFO, path, sizeof(*d));
    185 
    186     d->dict.lookup = dict_ni_lookup;
    187     d->dict.close = dict_ni_close;
    188     d->dict.flags = dict_flags | DICT_FLAG_FIXED;
    189     if (dict_flags & DICT_FLAG_FOLD_FIX)
    190 	d->dict.fold_buf = vstring_alloc(10);
    191     d->dict.owner.status = DICT_OWNER_TRUSTED;
    192 
    193     return (&d->dict);
    194 }
    195 
    196 #endif
    197