/*
Interactive commands for Xen Store Daemon.
Copyright (C) 2017 Juergen Gross, SUSE Linux GmbH
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, see .
*/
#include
#include
#include
#include
#include "utils.h"
#include "talloc.h"
#include "xenstored_core.h"
#include "xenstored_control.h"
struct cmd_s {
char *cmd;
int (*func)(void *, struct connection *, char **, int);
char *pars;
};
static int do_control_check(void *ctx, struct connection *conn,
char **vec, int num)
{
if (num)
return EINVAL;
check_store();
send_ack(conn, XS_CONTROL);
return 0;
}
static int do_control_log(void *ctx, struct connection *conn,
char **vec, int num)
{
if (num != 1)
return EINVAL;
if (!strcmp(vec[0], "on"))
reopen_log();
else if (!strcmp(vec[0], "off"))
close_log();
else
return EINVAL;
send_ack(conn, XS_CONTROL);
return 0;
}
static int do_control_logfile(void *ctx, struct connection *conn,
char **vec, int num)
{
if (num != 1)
return EINVAL;
close_log();
talloc_free(tracefile);
tracefile = talloc_strdup(NULL, vec[0]);
reopen_log();
send_ack(conn, XS_CONTROL);
return 0;
}
static int do_control_memreport(void *ctx, struct connection *conn,
char **vec, int num)
{
FILE *fp;
int fd;
if (num > 1)
return EINVAL;
if (num == 0) {
if (tracefd < 0) {
if (!tracefile)
return EBADF;
fp = fopen(tracefile, "a");
} else {
/*
* Use dup() in order to avoid closing the file later
* with fclose() which will release stream resources.
*/
fd = dup(tracefd);
if (fd < 0)
return EBADF;
fp = fdopen(fd, "a");
if (!fp)
close(fd);
}
} else
fp = fopen(vec[0], "a");
if (!fp)
return EBADF;
talloc_report_full(NULL, fp);
fclose(fp);
send_ack(conn, XS_CONTROL);
return 0;
}
static int do_control_print(void *ctx, struct connection *conn,
char **vec, int num)
{
if (num != 1)
return EINVAL;
xprintf("control: %s", vec[0]);
send_ack(conn, XS_CONTROL);
return 0;
}
static int do_control_help(void *, struct connection *, char **, int);
static struct cmd_s cmds[] = {
{ "check", do_control_check, "" },
{ "log", do_control_log, "on|off" },
{ "logfile", do_control_logfile, "" },
{ "memreport", do_control_memreport, "[]" },
{ "print", do_control_print, "" },
{ "help", do_control_help, "" },
};
static int do_control_help(void *ctx, struct connection *conn,
char **vec, int num)
{
int cmd, len = 0;
char *resp;
if (num)
return EINVAL;
for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++) {
len += strlen(cmds[cmd].cmd) + 1;
len += strlen(cmds[cmd].pars) + 1;
}
len++;
resp = talloc_array(ctx, char, len);
if (!resp)
return ENOMEM;
len = 0;
for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++) {
strcpy(resp + len, cmds[cmd].cmd);
len += strlen(cmds[cmd].cmd);
resp[len] = '\t';
len++;
strcpy(resp + len, cmds[cmd].pars);
len += strlen(cmds[cmd].pars);
resp[len] = '\n';
len++;
}
resp[len] = 0;
send_reply(conn, XS_CONTROL, resp, len);
return 0;
}
int do_control(struct connection *conn, struct buffered_data *in)
{
int num;
int cmd;
char **vec;
if (conn->id != 0)
return EACCES;
num = xs_count_strings(in->buffer, in->used);
if (num < 1)
return EINVAL;
vec = talloc_array(in, char *, num);
if (!vec)
return ENOMEM;
if (get_strings(in, vec, num) != num)
return EIO;
for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++)
if (streq(vec[0], cmds[cmd].cmd))
return cmds[cmd].func(in, conn, vec + 1, num - 1);
return EINVAL;
}