~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/libxl/libxl_exec.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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"
 
19
 
 
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 */
 
29
 
 
30
#include "libxl.h"
 
31
#include "libxl_internal.h"
 
32
 
 
33
static pid_t libxl_fork(struct libxl_ctx *ctx)
 
34
{
 
35
    pid_t pid;
 
36
 
 
37
    pid = fork();
 
38
    if (pid == -1) {
 
39
        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
 
40
        return -1;
 
41
    }
 
42
 
 
43
    return pid;
 
44
}
 
45
 
 
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
}
 
50
 
 
51
void libxl_exec(int stdinfd, int stdoutfd, int stderrfd, char *arg0, char **args)
 
52
     /* call this in the child */
 
53
{
 
54
    int i;
 
55
 
 
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
}
 
67
 
 
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 */
 
73
 
 
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
}
 
99
 
 
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;
 
110
 
 
111
    if (for_spawn) {
 
112
        for_spawn->what = libxl_sprintf(ctx, "%s", what);
 
113
        if (!for_spawn->what) return ERROR_NOMEM;
 
114
    }
 
115
 
 
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
    }
 
126
 
 
127
    /* we are now the intermediate process */
 
128
 
 
129
    child = fork();
 
130
    if (child == -1)
 
131
        exit(255);
 
132
    if (!child)
 
133
        return 0; /* caller runs child code */
 
134
 
 
135
    intermediate_hook(starting, child);
 
136
 
 
137
    if (!for_spawn) _exit(0); /* just detach then */
 
138
 
 
139
    got = call_waitpid(ctx->waitpid_instead, child, &status, 0);
 
140
    assert(got == child);
 
141
 
 
142
    _exit(WIFEXITED(status) ? WEXITSTATUS(status) :
 
143
          WIFSIGNALED(status) && WTERMSIG(status) < 127
 
144
          ? WTERMSIG(status)+128 : -1);
 
145
}
 
146
 
 
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
}
 
160
 
 
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;
 
167
 
 
168
    if (!for_spawn) return 0;
 
169
 
 
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
    }
 
187
 
 
188
    free(for_spawn->what);
 
189
    for_spawn->what = 0;
 
190
 
 
191
    return rc;
 
192
}
 
193
 
 
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;
 
199
 
 
200
    if (!for_spawn) return 0;
 
201
 
 
202
    assert(for_spawn->intermediate);
 
203
    got = call_waitpid(ctx->waitpid_instead, for_spawn->intermediate, &status, WNOHANG);
 
204
    if (!got) return 0;
 
205
 
 
206
    assert(got == for_spawn->intermediate);
 
207
    report_spawn_intermediate_status(ctx, for_spawn, status);
 
208
 
 
209
    for_spawn->intermediate = 0;
 
210
    return ERROR_FAIL;
 
211
}