nut-debian/server/netlist.c
2022-07-10 09:23:45 +02:00

349 lines
6.9 KiB
C

/* netlist.c - LIST handlers for upsd
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2012 Arnaud Quette <arnaud.quette@free.fr>
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 "common.h"
#include "upsd.h"
#include "sstate.h"
#include "state.h"
#include "neterr.h"
#include "netlist.h"
extern upstype_t *firstups; /* for list_ups */
extern nut_ctype_t *firstclient; /* for list_clients */
static int tree_dump(st_tree_t *node, nut_ctype_t *client, const char *ups,
int rw, int fsd)
{
int ret;
if (!node)
return 1; /* not an error */
if (node->left) {
ret = tree_dump(node->left, client, ups, rw, fsd);
if (!ret)
return 0; /* write failed in child */
}
if (rw) {
/* only send this back if it's been flagged RW */
if (node->flags & ST_FLAG_RW) {
ret = sendback(client, "RW %s %s \"%s\"\n",
ups, node->var, node->val);
} else {
ret = 1; /* dummy */
}
} else {
/* normal variable list only */
/* status is always a special case */
if ((fsd == 1) && (!strcasecmp(node->var, "ups.status"))) {
ret = sendback(client, "VAR %s %s \"FSD %s\"\n",
ups, node->var, node->val);
} else {
ret = sendback(client, "VAR %s %s \"%s\"\n",
ups, node->var, node->val);
}
}
if (ret != 1)
return 0;
if (node->right)
return tree_dump(node->right, client, ups, rw, fsd);
return 1;
}
static void list_rw(nut_ctype_t *client, const char *upsname)
{
const upstype_t *ups;
ups = get_ups_ptr(upsname);
if (!ups) {
send_err(client, NUT_ERR_UNKNOWN_UPS);
return;
}
if (!ups_available(ups, client))
return;
if (!sendback(client, "BEGIN LIST RW %s\n", upsname))
return;
if (!tree_dump(ups->inforoot, client, upsname, 1, ups->fsd))
return;
sendback(client, "END LIST RW %s\n", upsname);
}
static void list_var(nut_ctype_t *client, const char *upsname)
{
const upstype_t *ups;
ups = get_ups_ptr(upsname);
if (!ups) {
send_err(client, NUT_ERR_UNKNOWN_UPS);
return;
}
if (!ups_available(ups, client))
return;
if (!sendback(client, "BEGIN LIST VAR %s\n", upsname))
return;
if (!tree_dump(ups->inforoot, client, upsname, 0, ups->fsd))
return;
sendback(client, "END LIST VAR %s\n", upsname);
}
static void list_cmd(nut_ctype_t *client, const char *upsname)
{
const upstype_t *ups;
cmdlist_t *ctmp;
ups = get_ups_ptr(upsname);
if (!ups) {
send_err(client, NUT_ERR_UNKNOWN_UPS);
return;
}
if (!ups_available(ups, client))
return;
if (!sendback(client, "BEGIN LIST CMD %s\n", upsname))
return;
for (ctmp = ups->cmdlist; ctmp != NULL; ctmp = ctmp->next) {
if (!sendback(client, "CMD %s %s\n", upsname, ctmp->name))
return;
}
sendback(client, "END LIST CMD %s\n", upsname);
}
static void list_enum(nut_ctype_t *client, const char *upsname, const char *var)
{
const upstype_t *ups;
const st_tree_t *node;
const enum_t *etmp;
ups = get_ups_ptr(upsname);
if (!ups) {
send_err(client, NUT_ERR_UNKNOWN_UPS);
return;
}
if (!ups_available(ups, client))
return;
node = sstate_getnode(ups, var);
if (!node) {
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
return;
}
if (!sendback(client, "BEGIN LIST ENUM %s %s\n", upsname, var))
return;
for (etmp = node->enum_list; etmp != NULL; etmp = etmp->next) {
if (!sendback(client, "ENUM %s %s \"%s\"\n",
upsname, var, etmp->val))
return;
}
sendback(client, "END LIST ENUM %s %s\n", upsname, var);
}
static void list_range(nut_ctype_t *client, const char *upsname, const char *var)
{
const upstype_t *ups;
const st_tree_t *node;
const range_t *rtmp;
ups = get_ups_ptr(upsname);
if (!ups) {
send_err(client, NUT_ERR_UNKNOWN_UPS);
return;
}
if (!ups_available(ups, client))
return;
node = sstate_getnode(ups, var);
if (!node) {
send_err(client, NUT_ERR_VAR_NOT_SUPPORTED);
return;
}
if (!sendback(client, "BEGIN LIST RANGE %s %s\n", upsname, var))
return;
for (rtmp = node->range_list; rtmp != NULL; rtmp = rtmp->next) {
if (!sendback(client, "RANGE %s %s \"%i\" \"%i\"\n",
upsname, var, rtmp->min, rtmp->max))
return;
}
sendback(client, "END LIST RANGE %s %s\n", upsname, var);
}
static void list_ups(nut_ctype_t *client)
{
upstype_t *utmp;
char esc[SMALLBUF];
if (!sendback(client, "BEGIN LIST UPS\n"))
return;
utmp = firstups;
while (utmp) {
int ret;
if (utmp->desc) {
pconf_encode(utmp->desc, esc, sizeof(esc));
ret = sendback(client, "UPS %s \"%s\"\n",
utmp->name, esc);
} else {
ret = sendback(client, "UPS %s \"Description unavailable\"\n",
utmp->name);
}
if (!ret)
return;
utmp = utmp->next;
}
sendback(client, "END LIST UPS\n");
}
static void list_clients(nut_ctype_t *client, const char *upsname)
{
const upstype_t *ups;
nut_ctype_t *c, *cnext;
ups = get_ups_ptr(upsname);
if (!ups) {
send_err(client, NUT_ERR_UNKNOWN_UPS);
return;
}
if (!sendback(client, "BEGIN LIST CLIENT %s\n", upsname))
return;
if (firstclient) {
int ret;
/* show connected clients */
for (c = firstclient; c; c = cnext) {
if (c->loginups && (!ups || !strcasecmp(c->loginups, ups->name))) {
ret = sendback(client, "CLIENT %s %s\n", c->loginups, c->addr);
if (!ret)
return;
}
cnext = c->next;
}
}
sendback(client, "END LIST CLIENT %s\n", upsname);
}
void net_list(nut_ctype_t *client, size_t numarg, const char **arg)
{
if (numarg < 1) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
/* LIST UPS */
if (!strcasecmp(arg[0], "UPS")) {
list_ups(client);
return;
}
if (numarg < 2) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
/* LIST VAR UPS */
if (!strcasecmp(arg[0], "VAR")) {
list_var(client, arg[1]);
return;
}
/* LIST RW UPS */
if (!strcasecmp(arg[0], "RW")) {
list_rw(client, arg[1]);
return;
}
/* LIST CMD UPS */
if (!strcasecmp(arg[0], "CMD")) {
list_cmd(client, arg[1]);
return;
}
/* LIST CLIENT UPS */
if (!strcasecmp(arg[0], "CLIENT")) {
list_clients(client, arg[1]);
return;
}
if (numarg < 3) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
/* LIST ENUM UPS VARNAME */
if (!strcasecmp(arg[0], "ENUM")) {
list_enum(client, arg[1], arg[2]);
return;
}
/* LIST RANGE UPS VARNAME */
if (!strcasecmp(arg[0], "RANGE")) {
list_range(client, arg[1], arg[2]);
return;
}
send_err(client, NUT_ERR_INVALID_ARGUMENT);
}