logo

Manual Pages


Table of Contents

NAME

registry_impl - adding new implementations to the registry

SYNOPSIS

  #include 
  #include 

  /*
   * API's to handle forwarding of a key prefix
   * to a particular registry implementation (regImpl)
   */

  boolean_t registry_forward(
                      regCred a,
                      const char* prefix,
                      regImpl* implementation);
  boolean_t registry_notify(
                      regCred a,
                      const char* key,
                      regNotifyClient func);
  regRawInfo registry_rawinfo(
                      regCred a,
                      const char* key);

  /* Supporting declarations */

  typedef struct regImpl {
          ushort          flags;
          void            (*init)(
                                  struct regImpl*,
                                  regCred a
                                  );
          void            (*load)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* password
                                  );
          boolean_t       (*commit)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* password
                                  );
          const char*     (*get)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* key,
                                  char* valuebuff,
                                  int buffleng
                                  );
          boolean_t       (*set)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* key,
                                  const char* value
                                  );
          boolean_t       (*delete)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* key
                                  );
          const char*     (*walkinit)(
                                  struct regImpl*,
                                  regCred a,
                                  const char*prefix,
                                  regWalkType t
                                  );
          const char*     (*walknext)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* cookie,
                                  char* keybuff,
                                  int buffleng
                                  );
          void            (*walkend)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* cookie
                                  );
          boolean_t       (*forward)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* prefix,
                                  struct regImpl* forwardto
                                  );
          regRawInfo      (*rawinfo)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* key
                                  );
          boolean_t       (*notify)(
                                  struct regImpl*,
                                  regCred a,
                                  const char* prefix,
                                  regNotifyClient f
                                  );
          boolean_t       (*validate)(
                                  struct regImpl*,
                                  regCred a,
                                  regOpType o,
                                  const char *key,
                                  const char *val,
                                  errors_t** errs
                                  );
          boolean_t       (*commitx)(
                                  struct regImpl*,
                                  regTransaction* t,
                                  const char* password,
                                  errors_t** errs
                                  );
          const char*     prefix;
          int             lock[NHOSTS];
          regCookieList   cookies[NHOSTS];
          void*           private[NHOSTS];
  } regImpl;

  typedef struct regRawInfo {
          ushort type;
          union regRawValueUnion {
                  long *l;
                  int *i;
                  int4 *i4;
                  double *d;
          } u;
  } regRawInfo;

  typedef boolean_t (*regNotifyClient)(regCred a, const char* key, const char* value);

DESCRIPTION

The registry_forward function allows you to add a new implementation to the registry, so that any reference to a registry key that starts with the specified prefix will be forwarded to that implementation. This essentially allows you to add a new "sub-tree" to the registry namespace. This can be used to provide registry access to dynamically-changing data, or values that are already stored in other data structures, and for which you don't want to duplicate the storage in the registry, or for which you don't want to change the existing code.

To use registry_forward, you need to create an instance of the regImpl structure, and fill it with pointers to functions that implement some subset of the registry functions. (The one value you don't have to explicitly provide is prefix, which is set by the registry infrastructure.) An example is the best explanation, so here is code that implements read-only access to two of the global variables in the kernel - sk_tics and sk_busy_tics.

  static boolean_t
  stats_registry_get(regCred a, regImpl* impl, const char* key, char* valbuff, int leng)
  {
          char buff[16];  /* enough for an int4 */
          int4 val;

          /* This would be table-driven if there were lots of variables. */
          if ( strcmp(key,"sk_tics") == 0 )
                  val = sk_tics;
          else if ( strcmp(key,"sk_busy_tics") == 0 )
                  val = sk_busy_tics;
          else {
                  errno = ENOENT;
                  return B_FALSE;
          }
          sprintf(buff,"%d",val);
          /*
           * registry_returnbuff is a utility function for helping to
           * copy the result
           * into valbuff.
           */
          return registry_returnbuff(buff,valbuff,leng);
  }

  regImpl regStatsImpl = {
          0,              /* flags */
          0,              /* init */
          0,              /* load */
          0,              /* commit */
          stats_registry_get,
          0,              /* set */
          0,              /* delete */
          0,              /* walkinit */
          0,              /* walknext */
          0,              /* walkend */
          0,              /* forward */
          0,              /* rawinfo */
          0,              /* notify */
          0,              /* prefix */
          { 0,0 }         /* lock */
          { NULL,NULL }   /* cookies */
          0               /* private */
  };

The following line would then make use of this implementation, so that all registry references to keys beginning with "stats." would be forwarded to it:

registry_forward("stats.",&regStatsImpl);

After this line was executed, those variables would be accessible through the registry with the names "stats.sk_tics" and "stats.sk_busy_tics".

DETAILS

When registry_forward is called, it will result in an immediate call to the init element of the registry implementation, which can then do any initialization required.

The flags value in the regImpl structure contains bit flags that indicate what type of "walks" are supported by the walkinit/walknext/walkend functions (if any) of the registry implementation. If the flags value is WALK_ALL, you are saying that your registry implementation (i.e. walkinit function) supports a WALK_ALL walking type, which should return all the keys in your part of the namespace. If the flags value contains the WALK_DEFAULTPERSISTENCE bit, you are saying that your registry implementation wants to make use of the default registry persistence (i.e. the /etc/registry file), and that a walk of type WALK_DEFAULTPERSISTENCE will return the keys that you want to save in that file. For further discussion of this, see the functional spec of the registry transaction APIs in the design depot (at http://web.netapp.com/engineering/design-depot/appliance-mgmt/registry_trans/fs.html ).

The private value in the regImpl structure can be used for any purpose, by a particular registry implementation. Note that it is an array, containing private values for each host. Note that each function in the regImpl structure has, as its first argument, a pointer to a regImpl this argument will be a pointer to the regImpl that triggered the function's invocation. This pointer can then be used to access the private element, which would then typically point to some larger data structure containing information that controls the operation of that registry implementation. This mechanism allows a single set of registry implementation functions to be shared by different forwarding prefixes. For example, to extend the example above, there could be two instances of regImpl (say, regStats1Impl and regStats2Impl ) which both contained a pointer to stats_registry_get as the value of their get function, but which contained pointers to different private values. You could then set up forwarding to two different prefixes:

registry_forward("stats1.",&regStats1Impl);
registry_forward("stats2.",&regStats2Impl);

When stats_registry_get was called, it would use the value of private to determine which of the two implementations had triggered its use.

The delete method, if implemented in a regImpl structure, should return B_FALSE if the item does not already exist.

NOTIFICATION OF CHANGES

You can be notified of changes to the registry (i.e. whenever the registry_set or registry_delete functions are used) by making use of the registry_notify API. The key argument to this API is key of the registry item that you want to monitor, and every time that value is set or deleted, func (the second argument to registry_notify) will be called, providing the key name and the new value. Actually, the key argument is interpreted as a prefix, so that if you want to get notification on a while subtree (say, everything under "options.nfs."), just use "options.nfs." as the argument to registry_notify, and your notify function will be called for any modifications to any keys containing that prefix. Only one notification function will be called for any given change to the registry - it will be the first one whose prefix matches the key being changed, and the prefixes are searched in order.

RAWINFO ACCESS

For more efficient access to things in the registry, a registry implementation can provide an implementation for the rawinfo function in the regImpl structure. This function will return a regRawInfo structure that allows someone to get direct access to the underlying values (as ints, longs, whatever) rather than being forced to convert to and from strings (through the normal registry_get() and registry_set() functions.

An example is again the best explanation, so here is a function that adds raw access to the two global variables used in the previous example, and the value of regStatsImpl that would include it.

  static regRawInfo
  stats_registry_rawinfo(regImpl* impl, const char* name)
  {
          regRawInfo v;

          v.type = 0;     /* Not used, in this example */
          /*
           * This would be table-driven if there were lots of variables.
           */
          if ( strcmp(key,"sk_tics") == 0 )
                  v.u.i4 = &sk_tics;
          else if ( strcmp(key,"sk_busy_tics") == 0 )
                  v.u.i4 = &sk_busy_tics;
          else
                  v.u = NULL;
          return v;
  }

  regImpl regStatsImpl = {
          0,              /* flags */
          0,              /* init */
          0,              /* load */
          0,              /* commit */
          stats_registry_get,
          0,              /* set */
          0,              /* delete */
          0,              /* walkinit */
          0,              /* walknext */
          0,              /* walkend */
          0,              /* forward */
          stats_registry_rawinfo,
          0,              /* notify */
          0,              /* prefix */
          { 0,0 }         /* lock */
          { NULL,NULL }   /* cookies */
          {0,0}           /* private */
  };

The following code shows how this implementation would be used, from C code that needed raw access to these registry values:

  regRawinfo raw;
  raw = registry_rawinfo("raw.sk_tics");
  /*
   * raw.u.i4 is now the pointer value you can use.
   */
  dbg_printf("registry test: raw value is %d0,*(raw.u.i4));

You may wonder "why not just access these global variables directly?" The goal here is to provided consistent access (from things like servlets, the command-line interface, and other external APIs) to named configuration values. The names provide a way for non-C code (e.g. Java, or APIs from other machines) to access the same values. The names can actually be dynamically interpreted - for example the name "raw.sk_tics" could refer to two different global variables, depending on the current value of SK_GETHOST(). In this case, the information returned by registry_rawinfo() would also be dynamically determined.

SEE ALSO

registry(3)


Table of Contents