3
* Copyright (C) 2009 Citrix Ltd.
4
* Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
5
* Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
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.
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.
18
#include "libxl_osdeps.h"
26
#include <sys/types.h>
28
#include <signal.h> /* for SIGKILL */
31
#include "libxl_internal.h"
33
static pid_t libxl_fork(struct libxl_ctx *ctx)
39
XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
46
static int call_waitpid(pid_t (*waitpid_cb)(pid_t, int *, int), pid_t pid, int *status, int options)
48
return (waitpid_cb) ? waitpid_cb(pid, status, options) : waitpid(pid, status, options);
51
void libxl_exec(int stdinfd, int stdoutfd, int stderrfd, char *arg0, char **args)
52
/* call this in the child */
57
dup2(stdinfd, STDIN_FILENO);
59
dup2(stdoutfd, STDOUT_FILENO);
61
dup2(stderrfd, STDERR_FILENO);
62
for (i = 4; i < 256; i++)
68
void libxl_report_child_exitstatus(struct libxl_ctx *ctx,
69
const char *what, pid_t pid, int status)
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);
77
XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] exited"
78
" with error status %d", what, (unsigned long)pid, st);
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)" : "";
87
XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to"
88
" fatal signal %s%s", what, (unsigned long)pid,
91
XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to unknown"
92
" fatal signal number %d%s", what, (unsigned long)pid,
95
XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] gave unknown"
96
" wait status 0x%x", what, (unsigned long)pid, status);
100
int libxl_spawn_spawn(struct libxl_ctx *ctx,
101
libxl_device_model_starting *starting,
103
void (*intermediate_hook)(void *for_spawn,
109
struct libxl_spawn_starting *for_spawn = starting->for_spawn;
112
for_spawn->what = libxl_sprintf(ctx, "%s", what);
113
if (!for_spawn->what) return ERROR_NOMEM;
116
intermediate = libxl_fork(ctx);
117
if (intermediate ==-1) {
118
if (for_spawn) free(for_spawn->what);
123
if (for_spawn) for_spawn->intermediate = intermediate;
127
/* we are now the intermediate process */
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);
147
static void report_spawn_intermediate_status(struct libxl_ctx *ctx,
148
struct libxl_spawn_starting *for_spawn,
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)",
156
libxl_report_child_exitstatus(ctx, intermediate_what,
157
for_spawn->intermediate, status);
161
int libxl_spawn_detach(struct libxl_ctx *ctx,
162
struct libxl_spawn_starting *for_spawn)
168
if (!for_spawn) return 0;
170
if (for_spawn->intermediate) {
171
r = kill(for_spawn->intermediate, SIGKILL);
173
XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
174
"could not kill %s intermediate process [%ld]",
176
(unsigned long)for_spawn->intermediate);
177
abort(); /* things are very wrong */
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);
185
for_spawn->intermediate = 0;
188
free(for_spawn->what);
194
int libxl_spawn_check(struct libxl_ctx *ctx, void *for_spawn_void)
196
struct libxl_spawn_starting *for_spawn = for_spawn_void;
200
if (!for_spawn) return 0;
202
assert(for_spawn->intermediate);
203
got = call_waitpid(ctx->waitpid_instead, for_spawn->intermediate, &status, WNOHANG);
206
assert(got == for_spawn->intermediate);
207
report_spawn_intermediate_status(ctx, for_spawn, status);
209
for_spawn->intermediate = 0;