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