1 /* $NetBSD: xenbackendd.c,v 1.1.1.1 2008/08/07 20:26:57 cegger Exp $ */
2 /*
3 * Copyright (C) 2006 Manuel Bouyer <bouyer@netbsd.org>
4 * Copyright (C) 2009 Christoph Egger <Christoph.Egger@amd.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; under version 2 of the License.
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 <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <syslog.h>
29
30 #include <xenstore.h>
31
32 #include "_paths.h"
33
34 #define DEVTYPE_UNKNOWN 0
35 #define DEVTYPE_VIF 1
36 #define DEVTYPE_VBD 2
37 #define DISABLE_EXEC "libxl/disable_udev"
38
39 #define DOMAIN_PATH "/local/domain/0"
40
41 #ifndef XEN_SCRIPT_DIR
42 #error XEN_SCRIPT_DIR not defined
43 #endif
44
45 #ifndef VBD_SCRIPT
46 #define VBD_SCRIPT XEN_SCRIPT_DIR"/block"
47 #endif
48 #ifndef LOG_FILE
49 #define LOG_FILE XEN_LOG_DIR "xenbackendd.log"
50 #endif
51 #ifndef PID_FILE
52 #define PID_FILE XEN_RUN_DIR "xenbackendd.pid"
53 #endif
54
55
56 struct xs_handle *xs;
57
58 int fflag = 0;
59 int dflag = 0;
60
61 const char *vbd_script = NULL;
62 const char *log_file = NULL;
63 const char *pidfile = NULL;
64
65 static void
dolog(int pri,const char * fmt,...)66 dolog(int pri, const char *fmt, ...)
67 {
68 va_list ap;
69 va_start(ap, fmt);
70 vfprintf(stderr, fmt, ap);
71 va_end(ap);
72 fprintf(stderr, "\n");
73 fflush(stderr);
74 va_start(ap, fmt);
75 vsyslog(pri, fmt, ap);
76 va_end(ap);
77 }
78
79 static void
dodebug(const char * fmt,...)80 dodebug(const char *fmt, ...)
81 {
82 va_list ap;
83
84 if (dflag == 0)
85 return;
86 va_start(ap, fmt);
87 vfprintf(stdout, fmt, ap);
88 va_end(ap);
89 printf("\n");
90 fflush(stdout);
91 }
92
93 static void
doexec(const char * cmd,const char * arg1,const char * arg2)94 doexec(const char *cmd, const char *arg1, const char *arg2)
95 {
96 dodebug("exec %s %s %s", cmd, arg1, arg2);
97 switch(vfork()) {
98 case -1:
99 dolog(LOG_ERR, "can't vfork: %s", strerror(errno));
100 break;
101 case 0:
102 execl(cmd, cmd, arg1, arg2, NULL);
103 dolog(LOG_ERR, "can't exec %s: %s", cmd, strerror(errno));
104 exit(EXIT_FAILURE);
105 /* NOTREACHED */
106 break;
107 default:
108 wait(NULL);
109 break;
110 }
111 }
112
113 static void
usage(void)114 usage(void)
115 {
116 fprintf(stderr,
117 "usage: %s [-d] [-f] [-l log_file] [-p pif_file] [-s vbd_script]\n",
118 getprogname());
119 exit(EXIT_FAILURE);
120 }
121
122 static int
xen_setup(void)123 xen_setup(void)
124 {
125 xs = xs_daemon_open();
126 if (xs == NULL) {
127 dolog(LOG_ERR,
128 "Failed to contact xenstore (%s). Is it running?",
129 strerror(errno));
130 goto out;
131 }
132
133 if (!xs_watch(xs, DOMAIN_PATH, "backend")) {
134 dolog(LOG_ERR, "xenstore watch on backend fails.");
135 goto out;
136 }
137 return 0;
138
139 out:
140 if (xs) {
141 xs_daemon_close(xs);
142 xs = NULL;
143 }
144 return -1;
145 }
146
147 int
main(int argc,char * const argv[])148 main(int argc, char * const argv[])
149 {
150 char **vec;
151 unsigned int num;
152 char *s;
153 int state;
154 char *sstate, *sdisable;
155 char *p;
156 char buf[80];
157 int type;
158 int ch;
159 int debug_fd;
160 FILE *pidfile_f;
161
162 while ((ch = getopt(argc, argv, "dfl:p:s:")) != -1) {
163 switch (ch) {
164 case 'd':
165 dflag = 1;
166 break;
167 case 'f':
168 fflag = 1;
169 break;
170 case 'l':
171 log_file = optarg;
172 break;
173 case 'p':
174 pidfile = optarg;
175 case 's':
176 vbd_script = optarg;
177 break;
178 default:
179 usage();
180 }
181 }
182
183 if (vbd_script == NULL)
184 vbd_script = VBD_SCRIPT;
185 if (pidfile == NULL)
186 pidfile = PID_FILE;
187 if (log_file == NULL)
188 log_file = LOG_FILE;
189
190 openlog("xenbackendd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
191
192 if (fflag == 0) {
193 /* open log file */
194 debug_fd = open(log_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
195 if (debug_fd == -1) {
196 dolog(LOG_ERR, "can't open %s: %s",
197 log_file, strerror(errno));
198 exit(EXIT_FAILURE);
199 }
200 }
201
202 if (fflag == 0) {
203 /* daemonize */
204 pidfile_f = fopen(pidfile, "w");
205 if (pidfile_f == NULL) {
206 dolog(LOG_ERR, "can't open %s: %s",
207 pidfile, strerror(errno));
208 exit(EXIT_FAILURE);
209 }
210 if (daemon(0, 0) < 0) {
211 dolog(LOG_ERR, "can't daemonize: %s",
212 strerror(errno));
213 exit(EXIT_FAILURE);
214 }
215 fprintf(pidfile_f, "%d\n", (int)getpid());
216 fclose(pidfile_f);
217
218 /* redirect stderr to log file */
219 if (dup2(debug_fd, STDERR_FILENO) < 0) {
220 dolog(LOG_ERR, "can't redirect stderr to %s: %s\n",
221 log_file, strerror(errno));
222 exit(EXIT_FAILURE);
223 }
224
225 /* also redirect stdout if we're in debug mode */
226 if (dflag) {
227 if (dup2(debug_fd, STDOUT_FILENO) < 0) {
228 dolog(LOG_ERR,
229 "can't redirect stdout to %s: %s\n",
230 log_file, strerror(errno));
231 exit(EXIT_FAILURE);
232 }
233 }
234
235 close(debug_fd);
236 debug_fd = -1;
237 }
238
239 if (xen_setup() < 0)
240 exit(EXIT_FAILURE);
241
242 for (;;) {
243 vec = xs_read_watch(xs, &num);
244 dodebug("read from xen watch: %s", *vec);
245 if (!vec) {
246 dolog(LOG_ERR, "xs_read_watch: NULL\n");
247 continue;
248 }
249
250 sdisable = xs_read(xs, XBT_NULL, DISABLE_EXEC, 0);
251 if (sdisable)
252 goto next1;
253
254 if (strlen(vec[XS_WATCH_PATH]) < sizeof("state"))
255 goto next1;
256
257 /* find last component of path, check if it's "state" */
258 p = &vec[XS_WATCH_PATH][
259 strlen(vec[XS_WATCH_PATH]) - sizeof("state")];
260 if (p[0] != '/')
261 goto next1;
262 p[0] = '\0';
263 p++;
264 if (strcmp(p, "state") != 0)
265 goto next1;
266
267 snprintf(buf, sizeof(buf), "%s/state", vec[XS_WATCH_PATH]);
268 sstate = xs_read(xs, XBT_NULL, buf, 0);
269 if (sstate == NULL) {
270 dolog(LOG_ERR,
271 "Failed to read %s (%s)", buf, strerror(errno));
272 goto next1;
273 }
274
275 state = atoi(sstate);
276 snprintf(buf, sizeof(buf), "%s/hotplug-status",
277 vec[XS_WATCH_PATH]);
278 s = xs_read(xs, XBT_NULL, buf, 0);
279 if (s != NULL && state != 6 /* XenbusStateClosed */)
280 goto next2;
281
282 type = DEVTYPE_UNKNOWN;
283 if (strncmp(vec[XS_WATCH_PATH],
284 DOMAIN_PATH "/backend/vif",
285 strlen(DOMAIN_PATH "/backend/vif")) == 0)
286 type = DEVTYPE_VIF;
287
288 if (strncmp(vec[XS_WATCH_PATH],
289 DOMAIN_PATH "/backend/vbd",
290 strlen(DOMAIN_PATH "/backend/vbd")) == 0)
291 type = DEVTYPE_VBD;
292
293 switch(type) {
294 case DEVTYPE_VIF:
295 free(s);
296 snprintf(buf, sizeof(buf), "%s/script",
297 vec[XS_WATCH_PATH]);
298 s = xs_read(xs, XBT_NULL, buf, 0);
299 if (s == NULL) {
300 dolog(LOG_ERR,
301 "Failed to read %s (%s)", buf,
302 strerror(errno));
303 goto next2;
304 }
305 doexec(s, vec[XS_WATCH_PATH], sstate);
306 break;
307
308 case DEVTYPE_VBD:
309 doexec(vbd_script, vec[XS_WATCH_PATH], sstate);
310 break;
311
312 default:
313 break;
314 }
315
316 next2:
317 free(s);
318 free(sstate);
319
320 next1:
321 free(sdisable);
322 free(vec);
323 }
324
325 return 0;
326 }
327