1
2 /*
3 * Copyright (C) 2009 Citrix Ltd.
4 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
5 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; version 2.1 only. with the special
10 * exception on linking described in file LICENSE.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 */
17
18 #include "libxl_osdeps.h" /* must come before any other headers */
19
20 #include "libxl_internal.h"
21
check_open_fds(const char * what)22 static void check_open_fds(const char *what)
23 {
24 const char *env_debug;
25 int debug;
26 int i, flags, badness = 0;
27
28 env_debug = getenv("_LIBXL_DEBUG_EXEC_FDS");
29 if (!env_debug) return;
30
31 debug = strtol(env_debug, (char **) NULL, 10);
32 if (debug <= 0) return;
33
34 for (i = 4; i < 256; i++) {
35 #ifdef __linux__
36 ssize_t len;
37 char path[PATH_MAX];
38 char linkpath[PATH_MAX+1];
39 #endif
40 flags = fcntl(i, F_GETFD);
41 if ( flags == -1 ) {
42 if ( errno != EBADF )
43 fprintf(stderr, "libxl: execing %s: fd %d flags returned %s (%d)\n",
44 what, i, strerror(errno), errno);
45 continue;
46 }
47
48 if ( flags & FD_CLOEXEC )
49 continue;
50
51 badness++;
52
53 #ifdef __linux__
54 snprintf(path, PATH_MAX, "/proc/%d/fd/%d", getpid(), i);
55 len = readlink(path, linkpath, PATH_MAX);
56 if (len > 0) {
57 linkpath[len] = '\0';
58 fprintf(stderr, "libxl: execing %s: fd %d is open to %s with flags %#x\n",
59 what, i, linkpath, flags);
60 } else
61 #endif
62 fprintf(stderr, "libxl: execing %s: fd %d is open with flags %#x\n",
63 what, i, flags);
64 }
65 if (debug < 2) return;
66 if (badness) abort();
67 }
68
libxl__exec(libxl__gc * gc,int stdinfd,int stdoutfd,int stderrfd,const char * arg0,char * const args[],char * const env[])69 void libxl__exec(libxl__gc *gc, int stdinfd, int stdoutfd, int stderrfd,
70 const char *arg0, char *const args[], char *const env[])
71 /* call this in the child */
72 {
73 if (stdinfd != -1)
74 dup2(stdinfd, STDIN_FILENO);
75 if (stdoutfd != -1)
76 dup2(stdoutfd, STDOUT_FILENO);
77 if (stderrfd != -1)
78 dup2(stderrfd, STDERR_FILENO);
79
80 if (stdinfd > 2)
81 close(stdinfd);
82 if (stdoutfd > 2 && stdoutfd != stdinfd)
83 close(stdoutfd);
84 if (stderrfd > 2 && stderrfd != stdinfd && stderrfd != stdoutfd)
85 close(stderrfd);
86
87 check_open_fds(arg0);
88
89 signal(SIGPIPE, SIG_DFL);
90 /* in case our caller set it to IGN. subprocesses are entitled
91 * to assume they got DFL. */
92
93 if (env != NULL) {
94 for (int i = 0; env[i] != NULL && env[i+1] != NULL; i += 2) {
95 if (setenv(env[i], env[i+1], 1) < 0) {
96 LOGEV(ERROR, errno, "setting env vars (%s = %s)",
97 env[i], env[i+1]);
98 goto out;
99 }
100 }
101 }
102 execvp(arg0, args);
103
104 out:
105 fprintf(stderr, "libxl: cannot execute %s: %s\n", arg0, strerror(errno));
106 _exit(-1);
107 }
108
libxl_report_child_exitstatus(libxl_ctx * ctx,xentoollog_level level,const char * what,pid_t pid,int status)109 void libxl_report_child_exitstatus(libxl_ctx *ctx,
110 xentoollog_level level,
111 const char *what, pid_t pid, int status)
112 {
113
114 if (WIFEXITED(status)) {
115 int st = WEXITSTATUS(status);
116 if (st)
117 LIBXL__LOG(ctx, level, "%s [%ld] exited"
118 " with error status %d", what, (unsigned long)pid, st);
119 else
120 LIBXL__LOG(ctx, level, "%s [%ld] unexpectedly"
121 " exited status zero", what, (unsigned long)pid);
122 } else if (WIFSIGNALED(status)) {
123 int sig = WTERMSIG(status);
124 const char *str = strsignal(sig);
125 const char *coredump = WCOREDUMP(status) ? " (core dumped)" : "";
126 if (str)
127 LIBXL__LOG(ctx, level, "%s [%ld] died due to"
128 " fatal signal %s%s", what, (unsigned long)pid,
129 str, coredump);
130 else
131 LIBXL__LOG(ctx, level, "%s [%ld] died due to unknown"
132 " fatal signal number %d%s", what, (unsigned long)pid,
133 sig, coredump);
134 } else {
135 LIBXL__LOG(ctx, level, "%s [%ld] gave unknown"
136 " wait status 0x%x", what, (unsigned long)pid, status);
137 }
138 }
139
libxl__spawn_record_pid(libxl__gc * gc,libxl__spawn_state * spawn,pid_t pid)140 int libxl__spawn_record_pid(libxl__gc *gc, libxl__spawn_state *spawn, pid_t pid)
141 {
142 int r, rc;
143
144 rc = libxl__ev_child_xenstore_reopen(gc, spawn->what);
145 if (rc) goto out;
146
147 r = libxl__xs_printf(gc, XBT_NULL, spawn->pidpath, "%d", pid);
148 if (r) {
149 LOGE(ERROR,
150 "write %s = %d: xenstore write failed", spawn->pidpath, pid);
151 rc = ERROR_FAIL; goto out;
152 }
153
154 rc = 0;
155
156 out:
157 return rc ? SIGTERM : 0;
158 }
159
libxl__xenstore_child_wait_deprecated(libxl__gc * gc,uint32_t domid,uint32_t timeout,char * what,char * path,char * state,libxl__spawn_starting * spawning,int (* check_callback)(libxl__gc * gc,uint32_t domid,const char * state,void * userdata),void * check_callback_userdata)160 int libxl__xenstore_child_wait_deprecated(libxl__gc *gc,
161 uint32_t domid,
162 uint32_t timeout, char *what,
163 char *path, char *state,
164 libxl__spawn_starting *spawning,
165 int (*check_callback)(libxl__gc *gc,
166 uint32_t domid,
167 const char *state,
168 void *userdata),
169 void *check_callback_userdata)
170 {
171 char *p;
172 unsigned int len;
173 int rc = 0;
174 struct xs_handle *xsh;
175 int nfds;
176 fd_set rfds;
177 struct timeval tv;
178 unsigned int num;
179 char **l = NULL;
180
181 xsh = xs_daemon_open();
182 if (xsh == NULL) {
183 LOG(ERROR, "Unable to open xenstore connection");
184 goto err;
185 }
186
187 xs_watch(xsh, path, path);
188 tv.tv_sec = timeout;
189 tv.tv_usec = 0;
190 nfds = xs_fileno(xsh) + 1;
191 assert(!spawning);
192
193 while (rc > 0 || (!rc && tv.tv_sec > 0)) {
194 p = xs_read(xsh, XBT_NULL, path, &len);
195 if ( NULL == p )
196 goto again;
197
198 if ( NULL != state && strcmp(p, state) )
199 goto again;
200
201 if ( NULL != check_callback ) {
202 rc = (*check_callback)(gc, domid, p, check_callback_userdata);
203 if ( rc > 0 )
204 goto again;
205 }
206
207 free(p);
208 xs_unwatch(xsh, path, path);
209 xs_daemon_close(xsh);
210 return rc;
211 again:
212 free(p);
213 FD_ZERO(&rfds);
214 FD_SET(xs_fileno(xsh), &rfds);
215 rc = select(nfds, &rfds, NULL, NULL, &tv);
216 if (rc > 0) {
217 if (FD_ISSET(xs_fileno(xsh), &rfds)) {
218 l = xs_read_watch(xsh, &num);
219 if (l != NULL)
220 free(l);
221 else
222 goto again;
223 }
224 }
225 }
226 LOG(ERROR, "%s not ready", what);
227
228 xs_unwatch(xsh, path, path);
229 xs_daemon_close(xsh);
230 err:
231 return -1;
232 }
233
234
235 /*----- spawn implementation -----*/
236
237 /*
238 * Full set of possible states of a libxl__spawn_state and its _detachable:
239 *
240 * detaching rc mid timeout xswatch
241 * - Undefined undef undef - undef undef
242 * - Idle any any Idle Idle Idle
243 * - Attached OK 0 0 Active Active Active
244 * - Attached Failed 0 non-0 Active Idle Idle
245 * - Detaching 1 maybe Active Idle Idle
246 * - Partial any any Idle Active/Idle Active/Idle
247 *
248 * When in states Detaching or Attached Failed, the middle process has
249 * been sent a SIGKILL.
250 *
251 * The difference between Attached OK and Attached Failed is not
252 * directly visible to callers - callers see these two the same,
253 * although of course Attached OK will hopefully eventually result in
254 * a call to detached_cb, whereas Attached Failed will end up
255 * in a call to failure_cb.
256 */
257
258 /* Event callbacks. */
259 static void spawn_watch_event(libxl__egc *egc, libxl__xswait_state *xswa,
260 int rc, const char *xsdata);
261 static void spawn_middle_death(libxl__egc *egc, libxl__ev_child *childw,
262 pid_t pid, int status);
263
264 /* Precondition: Partial. Results: Idle. */
265 static void spawn_cleanup(libxl__gc *gc, libxl__spawn_state *ss);
266
267 /* Precondition: Attached or Detaching; caller has logged failure reason.
268 * Results: Detaching, or Attached Failed */
269 static void spawn_fail(libxl__egc *egc, libxl__spawn_state *ss, int rc);
270
libxl__spawn_init(libxl__spawn_state * ss)271 void libxl__spawn_init(libxl__spawn_state *ss)
272 {
273 libxl__ev_child_init(&ss->mid);
274 libxl__xswait_init(&ss->xswait);
275 }
276
libxl__spawn_spawn(libxl__egc * egc,libxl__spawn_state * ss)277 int libxl__spawn_spawn(libxl__egc *egc, libxl__spawn_state *ss)
278 {
279 STATE_AO_GC(ss->ao);
280 int r;
281 pid_t child;
282 int status, rc;
283
284 libxl__spawn_init(ss);
285 ss->rc = ss->detaching = 0;
286
287 ss->xswait.ao = ao;
288 ss->xswait.what = GCSPRINTF("%s startup", ss->what);
289 ss->xswait.path = ss->xspath;
290 ss->xswait.timeout_ms = ss->timeout_ms;
291 ss->xswait.callback = spawn_watch_event;
292 rc = libxl__xswait_start(gc, &ss->xswait);
293 if (rc) goto out_err;
294
295 pid_t middle = libxl__ev_child_fork(gc, &ss->mid, spawn_middle_death);
296 if (middle ==-1) { rc = ERROR_FAIL; goto out_err; }
297
298 if (middle) {
299 /* parent */
300 return 1;
301 }
302
303 /* we are now the middle process */
304
305 pid_t (*fork_replacement)(void*) =
306 CTX->childproc_hooks
307 ? CTX->childproc_hooks->fork_replacement
308 : 0;
309 child =
310 fork_replacement
311 ? fork_replacement(CTX->childproc_user)
312 : fork();
313
314 if (child == -1)
315 exit(255);
316 if (!child) {
317 return 0; /* caller runs child code */
318 }
319
320 int failsig = ss->midproc_cb(gc, ss, child);
321 if (failsig) {
322 kill(child, failsig);
323 _exit(127);
324 }
325
326 for (;;) {
327 pid_t got = waitpid(child, &status, 0);
328 if (got == -1) {
329 assert(errno == EINTR);
330 continue;
331 }
332 assert(got == child);
333 break;
334 }
335
336 r = (WIFEXITED(status) && WEXITSTATUS(status) <= 127 ? WEXITSTATUS(status) :
337 WIFSIGNALED(status) && WTERMSIG(status) < 127 ? WTERMSIG(status)+128 :
338 -1);
339 _exit(r);
340
341 out_err:
342 spawn_cleanup(gc, ss);
343 return rc;
344 }
345
spawn_cleanup(libxl__gc * gc,libxl__spawn_state * ss)346 static void spawn_cleanup(libxl__gc *gc, libxl__spawn_state *ss)
347 {
348 assert(!libxl__ev_child_inuse(&ss->mid));
349 libxl__xswait_stop(gc, &ss->xswait);
350 }
351
spawn_detach(libxl__gc * gc,libxl__spawn_state * ss)352 static void spawn_detach(libxl__gc *gc, libxl__spawn_state *ss)
353 /* Precondition: Attached or Detaching, but caller must have just set
354 * at least one of detaching or rc.
355 * Results: Detaching or Attached Failed */
356 {
357 int r;
358
359 assert(libxl__ev_child_inuse(&ss->mid));
360 assert(ss->detaching || ss->rc);
361 libxl__xswait_stop(gc, &ss->xswait);
362
363 pid_t child = ss->mid.pid;
364 r = kill(child, SIGKILL);
365 if (r && errno != ESRCH)
366 LOGE(WARN, "%s: failed to kill intermediate child (pid=%lu)",
367 ss->what, (unsigned long)child);
368 }
369
libxl__spawn_initiate_detach(libxl__gc * gc,libxl__spawn_state * ss)370 void libxl__spawn_initiate_detach(libxl__gc *gc, libxl__spawn_state *ss)
371 {
372 ss->detaching = 1;
373 spawn_detach(gc, ss);
374 }
375
libxl__spawn_initiate_failure(libxl__egc * egc,libxl__spawn_state * ss,int rc)376 void libxl__spawn_initiate_failure(libxl__egc *egc, libxl__spawn_state *ss,
377 int rc)
378 /* The spawn state must be Attached on entry and will be Attached Failed
379 * on return. */
380 {
381 spawn_fail(egc, ss, rc);
382 }
383
spawn_fail(libxl__egc * egc,libxl__spawn_state * ss,int rc)384 static void spawn_fail(libxl__egc *egc, libxl__spawn_state *ss, int rc)
385 /* Caller must have logged. Must be last thing in calling function,
386 * as it may make the callback. Precondition: Attached or Detaching. */
387 {
388 EGC_GC;
389 assert(rc);
390 if (!ss->rc)
391 ss->rc = rc;
392 spawn_detach(gc, ss);
393 }
394
spawn_watch_event(libxl__egc * egc,libxl__xswait_state * xswa,int rc,const char * p)395 static void spawn_watch_event(libxl__egc *egc, libxl__xswait_state *xswa,
396 int rc, const char *p)
397 {
398 /* On entry, is Attached. */
399 EGC_GC;
400 libxl__spawn_state *ss = CONTAINER_OF(xswa, *ss, xswait);
401 if (rc) {
402 if (rc == ERROR_TIMEDOUT)
403 LOG(ERROR, "%s: startup timed out", ss->what);
404 spawn_fail(egc, ss, rc); /* must be last */
405 return;
406 }
407 LOG(DEBUG, "%s: spawn watch p=%s", ss->what, p);
408 ss->confirm_cb(egc, ss, p); /* must be last */
409 }
410
spawn_middle_death(libxl__egc * egc,libxl__ev_child * childw,pid_t pid,int status)411 static void spawn_middle_death(libxl__egc *egc, libxl__ev_child *childw,
412 pid_t pid, int status)
413 /* On entry, is Attached or Detaching */
414 {
415 EGC_GC;
416 libxl__spawn_state *ss = CONTAINER_OF(childw, *ss, mid);
417
418 if ((ss->rc || ss->detaching) &&
419 ((WIFEXITED(status) && WEXITSTATUS(status)==0) ||
420 (WIFSIGNALED(status) && WTERMSIG(status)==SIGKILL))) {
421 /* as expected */
422 const char *what = GCSPRINTF("%s (dying as expected)", ss->what);
423 libxl_report_child_exitstatus(CTX, XTL_DEBUG, what, pid, status);
424 } else if (!WIFEXITED(status)) {
425 int loglevel = ss->detaching ? XTL_WARN : XTL_ERROR;
426 const char *what =
427 GCSPRINTF("%s intermediate process (startup monitor)", ss->what);
428 libxl_report_child_exitstatus(CTX, loglevel, what, pid, status);
429 ss->rc = ERROR_FAIL;
430 } else {
431 if (!status)
432 LOG(ERROR, "%s [%ld]: unexpectedly exited with exit status 0,"
433 " when we were waiting for it to confirm startup",
434 ss->what, (unsigned long)pid);
435 else if (status <= 127)
436 LOG(ERROR, "%s [%ld]: failed startup with non-zero exit status %d",
437 ss->what, (unsigned long)pid, status);
438 else if (status < 255) {
439 int sig = status - 128;
440 const char *str = strsignal(sig);
441 if (str)
442 LOG(ERROR, "%s [%ld]: died during startup due to fatal"
443 " signal %s", ss->what, (unsigned long)pid, str);
444 else
445 LOG(ERROR, "%s [%ld]: died during startup due to unknown fatal"
446 " signal number %d", ss->what, (unsigned long)pid, sig);
447 }
448 ss->rc = ERROR_FAIL;
449 }
450
451 spawn_cleanup(gc, ss);
452
453 if (ss->rc && !ss->detaching) {
454 ss->failure_cb(egc, ss, ss->rc); /* must be last */
455 return;
456 }
457
458 if (ss->rc && ss->detaching)
459 LOG(WARN,"%s underlying machinery seemed to fail (%d),"
460 " but its function seems to have been successful",
461 ss->what, ss->rc);
462
463 assert(ss->detaching);
464 ss->detached_cb(egc, ss);
465 }
466
467 /*
468 * Local variables:
469 * mode: C
470 * c-basic-offset: 4
471 * indent-tabs-mode: nil
472 * End:
473 */
474