debuggers.hg

view tools/libxl/libxl_exec.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents 675443b02c53
children 86e82ab8d4de
line source
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 */
18 #include "libxl_osdeps.h"
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <assert.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <signal.h> /* for SIGKILL */
30 #include "libxl.h"
31 #include "libxl_internal.h"
33 static pid_t libxl_fork(struct libxl_ctx *ctx)
34 {
35 pid_t pid;
37 pid = fork();
38 if (pid == -1) {
39 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
40 return -1;
41 }
43 return pid;
44 }
46 static int call_waitpid(pid_t (*waitpid_cb)(pid_t, int *, int), pid_t pid, int *status, int options)
47 {
48 return (waitpid_cb) ? waitpid_cb(pid, status, options) : waitpid(pid, status, options);
49 }
51 void libxl_exec(int stdinfd, int stdoutfd, int stderrfd, char *arg0, char **args)
52 /* call this in the child */
53 {
54 int i;
56 if (stdinfd != -1)
57 dup2(stdinfd, STDIN_FILENO);
58 if (stdoutfd != -1)
59 dup2(stdoutfd, STDOUT_FILENO);
60 if (stderrfd != -1)
61 dup2(stderrfd, STDERR_FILENO);
62 for (i = 4; i < 256; i++)
63 close(i);
64 execv(arg0, args);
65 _exit(-1);
66 }
68 void libxl_report_child_exitstatus(struct libxl_ctx *ctx,
69 const char *what, pid_t pid, int status)
70 {
71 /* treats all exit statuses as errors; if that's not what you want,
72 * check status yourself first */
74 if (WIFEXITED(status)) {
75 int st = WEXITSTATUS(status);
76 if (st)
77 XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] exited"
78 " with error status %d", what, (unsigned long)pid, st);
79 else
80 XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] unexpectedly"
81 " exited status zero", what, (unsigned long)pid);
82 } else if (WIFSIGNALED(status)) {
83 int sig = WTERMSIG(status);
84 const char *str = strsignal(sig);
85 const char *coredump = WCOREDUMP(status) ? " (core dumped)" : "";
86 if (str)
87 XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to"
88 " fatal signal %s%s", what, (unsigned long)pid,
89 str, coredump);
90 else
91 XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to unknown"
92 " fatal signal number %d%s", what, (unsigned long)pid,
93 sig, coredump);
94 } else {
95 XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] gave unknown"
96 " wait status 0x%x", what, (unsigned long)pid, status);
97 }
98 }
100 int libxl_spawn_spawn(struct libxl_ctx *ctx,
101 libxl_device_model_starting *starting,
102 const char *what,
103 void (*intermediate_hook)(void *for_spawn,
104 pid_t innerchild))
105 {
106 pid_t child, got;
107 int status;
108 pid_t intermediate;
109 struct libxl_spawn_starting *for_spawn = starting->for_spawn;
111 if (for_spawn) {
112 for_spawn->what = libxl_sprintf(ctx, "%s", what);
113 if (!for_spawn->what) return ERROR_NOMEM;
114 }
116 intermediate = libxl_fork(ctx);
117 if (intermediate ==-1) {
118 if (for_spawn) free(for_spawn->what);
119 return ERROR_FAIL;
120 }
121 if (intermediate) {
122 /* parent */
123 if (for_spawn) for_spawn->intermediate = intermediate;
124 return 1;
125 }
127 /* we are now the intermediate process */
129 child = fork();
130 if (child == -1)
131 exit(255);
132 if (!child)
133 return 0; /* caller runs child code */
135 intermediate_hook(starting, child);
137 if (!for_spawn) _exit(0); /* just detach then */
139 got = call_waitpid(ctx->waitpid_instead, child, &status, 0);
140 assert(got == child);
142 _exit(WIFEXITED(status) ? WEXITSTATUS(status) :
143 WIFSIGNALED(status) && WTERMSIG(status) < 127
144 ? WTERMSIG(status)+128 : -1);
145 }
147 static void report_spawn_intermediate_status(struct libxl_ctx *ctx,
148 struct libxl_spawn_starting *for_spawn,
149 int status)
150 {
151 if (!WIFEXITED(status)) {
152 /* intermediate process did the logging itself if it exited */
153 char *intermediate_what = libxl_sprintf(ctx,
154 "%s intermediate process (startup monitor)",
155 for_spawn->what);
156 libxl_report_child_exitstatus(ctx, intermediate_what,
157 for_spawn->intermediate, status);
158 }
159 }
161 int libxl_spawn_detach(struct libxl_ctx *ctx,
162 struct libxl_spawn_starting *for_spawn)
163 {
164 int r, status;
165 pid_t got;
166 int rc = 0;
168 if (!for_spawn) return 0;
170 if (for_spawn->intermediate) {
171 r = kill(for_spawn->intermediate, SIGKILL);
172 if (r) {
173 XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
174 "could not kill %s intermediate process [%ld]",
175 for_spawn->what,
176 (unsigned long)for_spawn->intermediate);
177 abort(); /* things are very wrong */
178 }
179 got = call_waitpid(ctx->waitpid_instead, for_spawn->intermediate, &status, 0);
180 assert(got == for_spawn->intermediate);
181 if (!(WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL)) {
182 report_spawn_intermediate_status(ctx, for_spawn, status);
183 rc = ERROR_FAIL;
184 }
185 for_spawn->intermediate = 0;
186 }
188 free(for_spawn->what);
189 for_spawn->what = 0;
191 return rc;
192 }
194 int libxl_spawn_check(struct libxl_ctx *ctx, void *for_spawn_void)
195 {
196 struct libxl_spawn_starting *for_spawn = for_spawn_void;
197 pid_t got;
198 int status;
200 if (!for_spawn) return 0;
202 assert(for_spawn->intermediate);
203 got = call_waitpid(ctx->waitpid_instead, for_spawn->intermediate, &status, WNOHANG);
204 if (!got) return 0;
206 assert(got == for_spawn->intermediate);
207 report_spawn_intermediate_status(ctx, for_spawn, status);
209 for_spawn->intermediate = 0;
210 return ERROR_FAIL;
211 }