1
/* state.c - Network UPS Tools common state management functions
3
Copyright (C) 2003 Russell Kroll <rkroll@exploits.org>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
#include <sys/types.h>
24
#include <sys/socket.h>
29
#include "parseconf.h"
31
static void val_escape(struct st_tree_t *node)
33
char etmp[ST_MAX_VALUE_LEN];
35
/* escape any tricky stuff like \ and " */
36
pconf_encode(node->val, etmp, sizeof(etmp));
38
/* if nothing was escaped, we don't need to do anything else */
39
if (!strcmp(node->raw, etmp)) {
40
node->val = node->raw;
44
/* first time: set a good starting place */
45
if (node->safesize == 0) {
46
node->safesize = strlen(etmp) + 1;
47
node->safe = xmalloc(node->safesize);
50
/* if the escaped value grew, deal with it */
51
if (strlen(etmp) > (node->safesize - 1)) {
52
node->safesize = strlen(etmp) + 1;
53
node->safe = xrealloc(node->safe, node->safesize);
56
snprintf(node->safe, node->safesize, "%s", etmp);
57
node->val = node->safe;
60
/* free all memory associated with a node */
61
static void st_tree_node_free(struct st_tree_t *node)
63
struct enum_t *tmp, *next;
72
/* never free node->val, since it's just a pointer to raw or safe */
74
/* blow away the list of enums */
75
tmp = node->enum_list;
85
/* now finally kill the node itself */
89
/* add a subtree to another subtree */
90
static void st_tree_node_add(struct st_tree_t **rptr, struct st_tree_t *node)
92
struct st_tree_t *root = *rptr;
99
if (strcmp(node->var, root->var) < 0) {
100
st_tree_node_add(&root->left, node);
104
st_tree_node_add(&root->right, node);
107
static int st_tree_delete(struct st_tree_t **nptr, struct st_tree_t **lptr,
111
struct st_tree_t *node, *last;
126
cmp = strcasecmp(var, node->var);
128
if (cmp == 0) { /* found the right one */
130
/* deleting the root? */
133
/* root with two children? */
134
if ((node->left) && (node->right)) {
136
/* hang current left off current right */
137
st_tree_node_add(&node->right, node->left);
139
/* now point the root at the old right child */
142
st_tree_node_free(node);
146
/* root with one child (left) */
149
/* point root at left child */
152
st_tree_node_free(node);
156
/* root with one child (right) */
159
/* point root at right child */
162
st_tree_node_free(node);
166
/* root with no children */
168
/* point root at an empty tree */
171
st_tree_node_free(node);
176
if ((!node->left) && (!node->right)) {
178
if (last->right == node)
183
st_tree_node_free(node);
187
/* node with two children */
188
if ((node->left) && (node->right)) {
190
/* hang the current left off the current right */
191
st_tree_node_add(&node->right, node->left);
193
if (last->left == node)
194
last->left = node->right;
196
last->right = node->right;
199
st_tree_node_free(node);
203
/* node with one child (left) */
206
if (last->right == node)
207
last->right = node->left;
209
last->left = node->left;
211
st_tree_node_free(node);
215
/* node with one child (right) */
217
if (last->right == node)
218
last->right = node->right;
220
last->left = node->right;
222
st_tree_node_free(node);
227
ret = st_tree_delete(&node->left, nptr, var);
233
return st_tree_delete(&node->right, nptr, var);
238
int state_setinfo(struct st_tree_t **nptr, const char *var, const char *val)
240
struct st_tree_t *node = *nptr;
243
*nptr = xmalloc(sizeof(struct st_tree_t));
246
node->var = xstrdup(var);
248
node->rawsize = strlen(val) + 1;
249
node->raw = xmalloc(node->rawsize);
250
snprintf(node->raw, node->rawsize, "%s", val);
252
/* this is usually sufficient if nothing gets escaped */
253
node->val = node->raw;
257
/* but see if it needs escaping anyway */
260
/* these are updated by other functions */
263
node->enum_list = NULL;
268
return 1; /* added */
271
if (strcasecmp(var, node->var) < 0)
272
return state_setinfo(&node->left, var, val);
274
if (strcasecmp(var, node->var) > 0)
275
return state_setinfo(&node->right, var, val);
277
/* var must equal node->var - updating an existing entry */
279
if (!strcasecmp(node->raw, val))
280
return 0; /* no change */
282
/* expand the buffer if the value grows */
283
if (strlen(val) > (node->rawsize - 1)) {
284
node->rawsize = strlen(val) + 1;
285
node->raw = xrealloc(node->raw, node->rawsize);
286
node->val = node->raw;
289
/* store the literal value for later comparisons */
290
snprintf(node->raw, node->rawsize, "%s", val);
294
return 1; /* added */
297
int state_addenum(struct st_tree_t *root, const char *var, const char *value)
299
struct st_tree_t *sttmp;
300
struct enum_t *etmp, *elast;
301
char enc[ST_MAX_VALUE_LEN];
303
/* find the tree node for var */
304
sttmp = state_tree_find(root, var);
307
upslogx(LOG_ERR, "dstate_addenum: base variable (%s) "
308
"does not exist", var);
309
return 0; /* failed */
312
/* smooth over any oddities in the enum value */
313
pconf_encode(value, enc, sizeof(enc));
315
etmp = sttmp->enum_list;
321
/* don't add duplicates - silently ignore them */
322
if (!strcmp(etmp->val, enc))
328
etmp = xmalloc(sizeof(struct enum_t));
329
etmp->val = xstrdup(enc);
333
sttmp->enum_list = etmp;
340
int state_setaux(struct st_tree_t *root, const char *var, const char *auxs)
342
struct st_tree_t *sttmp;
345
/* find the tree node for var */
346
sttmp = state_tree_find(root, var);
349
upslogx(LOG_ERR, "dstate_addenum: base variable (%s) "
350
"does not exist", var);
351
return -1; /* failed */
354
aux = strtol(auxs, (char **) NULL, 10);
356
/* silently ignore matches */
357
if (sttmp->aux == aux)
365
const char *state_getinfo(struct st_tree_t *root, const char *var)
367
struct st_tree_t *sttmp;
369
/* find the tree node for var */
370
sttmp = state_tree_find(root, var);
378
int state_getflags(struct st_tree_t *root, const char *var)
380
struct st_tree_t *sttmp;
382
/* find the tree node for var */
383
sttmp = state_tree_find(root, var);
391
int state_getaux(struct st_tree_t *root, const char *var)
393
struct st_tree_t *sttmp;
395
/* find the tree node for var */
396
sttmp = state_tree_find(root, var);
404
const struct enum_t *state_getenumlist(struct st_tree_t *root, const char *var)
406
struct st_tree_t *sttmp;
408
/* find the tree node for var */
409
sttmp = state_tree_find(root, var);
414
return sttmp->enum_list;
417
void state_setflags(struct st_tree_t *root, const char *var, int numflags,
421
struct st_tree_t *sttmp;
423
/* find the tree node for var */
424
sttmp = state_tree_find(root, var);
427
upslogx(LOG_ERR, "dstate_setflags: base variable (%s) "
428
"does not exist", var);
434
for (i = 0; i < numflags; i++) {
436
if (!strcasecmp(flag[i], "RW")) {
437
sttmp->flags |= ST_FLAG_RW;
441
if (!strcasecmp(flag[i], "STRING")) {
442
sttmp->flags |= ST_FLAG_STRING;
446
upsdebugx(2, "Unrecognized flag [%s]", flag[i]);
450
void state_addcmd(struct cmdlist_t **list, const char *cmdname)
452
struct cmdlist_t *tmp, *last;
459
/* ignore duplicates */
460
if (!strcasecmp(tmp->name, cmdname))
466
tmp = xmalloc(sizeof(struct cmdlist_t));
467
tmp->name = xstrdup(cmdname);
476
void state_infofree(struct st_tree_t *node)
482
state_infofree(node->left);
485
state_infofree(node->right);
487
st_tree_node_free(node);
490
int state_delcmd(struct cmdlist_t **list, const char *cmd)
492
struct cmdlist_t *tmp, *last;
498
if (!strcmp(tmp->name, cmd)) {
501
last->next = tmp->next;
508
return 1; /* deleted */
514
return 0; /* not found */
517
int state_delinfo(struct st_tree_t **root, const char *var)
519
return st_tree_delete(root, NULL, var);
522
int state_delenum(struct st_tree_t *root, const char *var, const char *val)
524
struct st_tree_t *sttmp;
525
struct enum_t *etmp, *elast;
527
/* find the tree node for var */
528
sttmp = state_tree_find(root, var);
533
/* look for val in enum_list */
534
etmp = sttmp->enum_list;
538
if (!strcmp(etmp->val, val)) {
541
elast->next = etmp->next;
543
sttmp->enum_list = etmp->next;
548
return 1; /* deleted */
555
return 0; /* not found */
558
struct st_tree_t *state_tree_find(struct st_tree_t *node, const char *var)
565
cmp = strcasecmp(var, node->var);
571
return state_tree_find(node->left, var);
573
return state_tree_find(node->right, var);