1 /*
2 Interactive commands for Xen Store Daemon.
3 Copyright (C) 2017 Juergen Gross, SUSE Linux GmbH
4
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.
9
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.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "utils.h"
25 #include "talloc.h"
26 #include "xenstored_core.h"
27 #include "xenstored_control.h"
28
29 struct cmd_s {
30 char *cmd;
31 int (*func)(void *, struct connection *, char **, int);
32 char *pars;
33 };
34
do_control_check(void * ctx,struct connection * conn,char ** vec,int num)35 static int do_control_check(void *ctx, struct connection *conn,
36 char **vec, int num)
37 {
38 if (num)
39 return EINVAL;
40
41 check_store();
42
43 send_ack(conn, XS_CONTROL);
44 return 0;
45 }
46
do_control_log(void * ctx,struct connection * conn,char ** vec,int num)47 static int do_control_log(void *ctx, struct connection *conn,
48 char **vec, int num)
49 {
50 if (num != 1)
51 return EINVAL;
52
53 if (!strcmp(vec[0], "on"))
54 reopen_log();
55 else if (!strcmp(vec[0], "off"))
56 close_log();
57 else
58 return EINVAL;
59
60 send_ack(conn, XS_CONTROL);
61 return 0;
62 }
63
64 #ifdef __MINIOS__
do_control_memreport(void * ctx,struct connection * conn,char ** vec,int num)65 static int do_control_memreport(void *ctx, struct connection *conn,
66 char **vec, int num)
67 {
68 if (num)
69 return EINVAL;
70
71 talloc_report_full(NULL, stdout);
72
73 send_ack(conn, XS_CONTROL);
74 return 0;
75 }
76 #else
do_control_logfile(void * ctx,struct connection * conn,char ** vec,int num)77 static int do_control_logfile(void *ctx, struct connection *conn,
78 char **vec, int num)
79 {
80 if (num != 1)
81 return EINVAL;
82
83 close_log();
84 talloc_free(tracefile);
85 tracefile = talloc_strdup(NULL, vec[0]);
86 reopen_log();
87
88 send_ack(conn, XS_CONTROL);
89 return 0;
90 }
91
do_control_memreport(void * ctx,struct connection * conn,char ** vec,int num)92 static int do_control_memreport(void *ctx, struct connection *conn,
93 char **vec, int num)
94 {
95 FILE *fp;
96 int fd;
97
98 if (num > 1)
99 return EINVAL;
100
101 if (num == 0) {
102 if (tracefd < 0) {
103 if (!tracefile)
104 return EBADF;
105 fp = fopen(tracefile, "a");
106 } else {
107 /*
108 * Use dup() in order to avoid closing the file later
109 * with fclose() which will release stream resources.
110 */
111 fd = dup(tracefd);
112 if (fd < 0)
113 return EBADF;
114 fp = fdopen(fd, "a");
115 if (!fp)
116 close(fd);
117 }
118 } else
119 fp = fopen(vec[0], "a");
120
121 if (!fp)
122 return EBADF;
123
124 talloc_report_full(NULL, fp);
125 fclose(fp);
126
127 send_ack(conn, XS_CONTROL);
128 return 0;
129 }
130 #endif
131
do_control_print(void * ctx,struct connection * conn,char ** vec,int num)132 static int do_control_print(void *ctx, struct connection *conn,
133 char **vec, int num)
134 {
135 if (num != 1)
136 return EINVAL;
137
138 xprintf("control: %s", vec[0]);
139
140 send_ack(conn, XS_CONTROL);
141 return 0;
142 }
143
144 static int do_control_help(void *, struct connection *, char **, int);
145
146 static struct cmd_s cmds[] = {
147 { "check", do_control_check, "" },
148 { "log", do_control_log, "on|off" },
149 #ifdef __MINIOS__
150 { "memreport", do_control_memreport, "" },
151 #else
152 { "logfile", do_control_logfile, "<file>" },
153 { "memreport", do_control_memreport, "[<file>]" },
154 #endif
155 { "print", do_control_print, "<string>" },
156 { "help", do_control_help, "" },
157 };
158
do_control_help(void * ctx,struct connection * conn,char ** vec,int num)159 static int do_control_help(void *ctx, struct connection *conn,
160 char **vec, int num)
161 {
162 int cmd, len = 0;
163 char *resp;
164
165 if (num)
166 return EINVAL;
167
168 for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++) {
169 len += strlen(cmds[cmd].cmd) + 1;
170 len += strlen(cmds[cmd].pars) + 1;
171 }
172 len++;
173
174 resp = talloc_array(ctx, char, len);
175 if (!resp)
176 return ENOMEM;
177
178 len = 0;
179 for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++) {
180 strcpy(resp + len, cmds[cmd].cmd);
181 len += strlen(cmds[cmd].cmd);
182 resp[len] = '\t';
183 len++;
184 strcpy(resp + len, cmds[cmd].pars);
185 len += strlen(cmds[cmd].pars);
186 resp[len] = '\n';
187 len++;
188 }
189 resp[len] = 0;
190
191 send_reply(conn, XS_CONTROL, resp, len);
192 return 0;
193 }
194
do_control(struct connection * conn,struct buffered_data * in)195 int do_control(struct connection *conn, struct buffered_data *in)
196 {
197 int num;
198 int cmd;
199 char **vec;
200
201 if (conn->id != 0)
202 return EACCES;
203
204 num = xs_count_strings(in->buffer, in->used);
205 if (num < 1)
206 return EINVAL;
207 vec = talloc_array(in, char *, num);
208 if (!vec)
209 return ENOMEM;
210 if (get_strings(in, vec, num) != num)
211 return EIO;
212
213 for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++)
214 if (streq(vec[0], cmds[cmd].cmd))
215 return cmds[cmd].func(in, conn, vec + 1, num - 1);
216
217 return EINVAL;
218 }
219