Logo Search packages:      
Sourcecode: nut version File versions

state.c

/* state.c - Network UPS Tools common state management functions

   Copyright (C) 2003  Russell Kroll <rkroll@exploits.org>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <stdio.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include "common.h"
#include "state.h"
#include "parseconf.h"

static void val_escape(struct st_tree_t *node)
{
      char  etmp[ST_MAX_VALUE_LEN];

      /* escape any tricky stuff like \ and " */
      pconf_encode(node->val, etmp, sizeof(etmp));

      /* if nothing was escaped, we don't need to do anything else */
      if (!strcmp(node->raw, etmp)) {
            node->val = node->raw;
            return;
      }

      /* first time: set a good starting place */
      if (node->safesize == 0) {
            node->safesize = strlen(etmp) + 1;
            node->safe = xmalloc(node->safesize);
      }

      /* if the escaped value grew, deal with it */
      if (strlen(etmp) > (node->safesize - 1)) {
            node->safesize = strlen(etmp) + 1;
            node->safe = xrealloc(node->safe, node->safesize);
      }

      snprintf(node->safe, node->safesize, "%s", etmp);
      node->val = node->safe;
}

static void st_tree_enum_free(struct enum_t *list)
{
      if (!list)
            return;

      st_tree_enum_free(list->next);

      free(list->val);
      free(list);
}

/* free all memory associated with a node */
static void st_tree_node_free(struct st_tree_t *node)
{
      if (node->var)
            free(node->var);
      if (node->raw)
            free(node->raw);
      if (node->safe)
            free(node->safe);

      /* never free node->val, since it's just a pointer to raw or safe */

      /* blow away the list of enums */
      st_tree_enum_free(node->enum_list);

      /* now finally kill the node itself */
      free(node);
}

/* add a subtree to another subtree */
static void st_tree_node_add(struct st_tree_t **nptr, struct st_tree_t *sptr)
{
      struct      st_tree_t   *node = *nptr;

      if (!sptr)
            return;

      if (!node) {
            *nptr = sptr;
            return;
      }

      if (strcmp(sptr->var, node->var) < 0)
            st_tree_node_add(&node->left, sptr);
      else
            st_tree_node_add(&node->right, sptr);
}

/* remove a variable from a tree */
int state_delinfo(struct st_tree_t **nptr, const char *var)
{
      struct      st_tree_t   *node = *nptr;

      if (!node)
            return 0;   /* variable not found! */

      if (strcasecmp(var, node->var) < 0)
            return state_delinfo(&node->left, var);

      if (strcasecmp(var, node->var) > 0)
            return state_delinfo(&node->right, var);

      /* apparently, we've found it! */

      /* whatever is on the left, hang it off current right */
      st_tree_node_add(&node->right, node->left);

      /* now point the parent at the old right child */
      *nptr = node->right;

      st_tree_node_free(node);

      return 1;
}     

/* interface */

int state_setinfo(struct st_tree_t **nptr, const char *var, const char *val)
{
      struct      st_tree_t   *node = *nptr;

      if (!node) {
            node = xmalloc(sizeof(struct st_tree_t));

            node->var = xstrdup(var);

            node->rawsize = strlen(val) + 1;
            node->raw = xmalloc(node->rawsize);
            snprintf(node->raw, node->rawsize, "%s", val);

            /* this is usually sufficient if nothing gets escaped */
            node->val = node->raw;
            node->safesize = 0;
            node->safe = NULL;

            /* but see if it needs escaping anyway */
            val_escape(node);

            /* these are updated by other functions */
            node->flags = 0;
            node->aux = 0;
            node->enum_list = NULL;

            node->left = NULL;
            node->right = NULL;

            /* now we're done with creating a new node, add it to the tree */
            *nptr = node;

            return 1;   /* added */
      }

      if (strcasecmp(var, node->var) < 0)
            return state_setinfo(&node->left, var, val);

      if (strcasecmp(var, node->var) > 0)
            return state_setinfo(&node->right, var, val);

      /* var must equal node->var - updating an existing entry */

      if (!strcasecmp(node->raw, val))
            return 0;         /* no change */

      /* expand the buffer if the value grows */
      if (strlen(val) > (node->rawsize - 1)) {
            node->rawsize = strlen(val) + 1;
            node->raw = xrealloc(node->raw, node->rawsize);
            node->val = node->raw;
      }

      /* store the literal value for later comparisons */
      snprintf(node->raw, node->rawsize, "%s", val);

      val_escape(node);

      return 1;   /* changed */
}

static void st_tree_enum_add(struct enum_t **list, const char *enc)
{
      struct      enum_t      *item = *list;

      if (!item) {      /* end of list reached */
            item = xmalloc(sizeof(struct enum_t));
            item->val = xstrdup(enc);
            item->next = NULL;

            /* now we're done creating it, add it to the list */
            *list = item;

            return;
      }

      /* don't add duplicates - silently ignore them */
      if (!strcmp(item->val, enc))
            return;

      st_tree_enum_add(&item->next, enc);
}

int state_addenum(struct st_tree_t *root, const char *var, const char *value)
{
      struct      st_tree_t   *sttmp;
      char  enc[ST_MAX_VALUE_LEN];

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp) {
            upslogx(LOG_ERR, "state_addenum: base variable (%s) "
                  "does not exist", var);
            return 0;   /* failed */
      }

      /* smooth over any oddities in the enum value */
      pconf_encode(value, enc, sizeof(enc));

      st_tree_enum_add(&sttmp->enum_list, enc);

      return 1;
}

int state_setaux(struct st_tree_t *root, const char *var, const char *auxs)
{
      struct      st_tree_t   *sttmp;
      int   aux;

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp) {
            upslogx(LOG_ERR, "state_addenum: base variable (%s) "
                  "does not exist", var);
            return -1;  /* failed */
      }

      aux = strtol(auxs, (char **) NULL, 10);

      /* silently ignore matches */
      if (sttmp->aux == aux)
            return 0;

      sttmp->aux = aux;

      return 1;
}

const char *state_getinfo(struct st_tree_t *root, const char *var)
{
      struct      st_tree_t   *sttmp;

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp)
            return NULL;

      return sttmp->val;
}

int state_getflags(struct st_tree_t *root, const char *var)
{
      struct      st_tree_t   *sttmp;

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp)
            return -1;

      return sttmp->flags;
}

int state_getaux(struct st_tree_t *root, const char *var)
{
      struct      st_tree_t   *sttmp;

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp)
            return -1;

      return sttmp->aux;
}

const struct enum_t *state_getenumlist(struct st_tree_t *root, const char *var)
{
      struct      st_tree_t   *sttmp;

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp)
            return NULL;

      return sttmp->enum_list;
}

void state_setflags(struct st_tree_t *root, const char *var, int numflags,
      char **flag)
{     
      int   i;
      struct      st_tree_t   *sttmp;

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp) {
            upslogx(LOG_ERR, "state_setflags: base variable (%s) "
                  "does not exist", var);
            return;
      }

      sttmp->flags = 0;

      for (i = 0; i < numflags; i++) {

            if (!strcasecmp(flag[i], "RW")) {
                  sttmp->flags |= ST_FLAG_RW;
                  continue;
            }

            if (!strcasecmp(flag[i], "STRING")) {
                  sttmp->flags |= ST_FLAG_STRING;
                  continue;
            }

            upsdebugx(2, "Unrecognized flag [%s]", flag[i]);
      }
}

int state_addcmd(struct cmdlist_t **list, const char *cmdname)
{
      struct      cmdlist_t   *item = *list;

      if (!item) {      /* end of list reached */
            item = xmalloc(sizeof(struct cmdlist_t));
            item->name = xstrdup(cmdname);
            item->next = NULL;

            /* now we're done creating it, add it to the list */
            *list = item;

            return 1;
      }

      /* don't add duplicates - silently ignore them */
      if (!strcasecmp(item->name, cmdname))
            return 0;

      return state_addcmd(&item->next, cmdname);
}

void state_infofree(struct st_tree_t *node)
{
      if (!node)
            return;

      state_infofree(node->left);

      state_infofree(node->right);

      st_tree_node_free(node);
}

void state_cmdfree(struct cmdlist_t *list)
{
      if (!list)
            return;

      state_cmdfree(list->next);

      free(list->name);
      free(list);
}

int state_delcmd(struct cmdlist_t **list, const char *cmd)
{
      struct      cmdlist_t   *item = *list;

      if (!item)  /* not found */
            return 0;

      /* if this is not the right command, go on to the next */
      if (strcmp(item->name, cmd))
            return state_delcmd(&item->next, cmd);

      /* we found it! */

      *list = item->next;

      free(item->name);
      free(item);

      return 1;   /* deleted */
}

static int st_tree_del_enum(struct enum_t **list, const char *val)
{
      struct      enum_t      *item = *list;

      if (!item)        /* not found */
            return 0;

      /* if this is not the right value, go on to the next */
      if (strcmp(item->val, val))
            return st_tree_del_enum(&item->next, val);

      /* we found it! */

      *list = item->next;

      free(item->val);
      free(item);

      return 1;   /* deleted */
}

int state_delenum(struct st_tree_t *root, const char *var, const char *val)
{
      struct      st_tree_t   *sttmp;

      /* find the tree node for var */
      sttmp = state_tree_find(root, var);

      if (!sttmp)
            return 0;

      return st_tree_del_enum(&sttmp->enum_list, val);
}

struct st_tree_t *state_tree_find(struct st_tree_t *node, const char *var)
{
      if (!node)
            return NULL;

      if (strcasecmp(var, node->var) < 0)
            return state_tree_find(node->left, var);

      if (strcasecmp(var, node->var) > 0)
            return state_tree_find(node->right, var);

      return node;
}

Generated by  Doxygen 1.6.0   Back to index