~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/roken/simple_exec.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
 
3
 * (Royal Institute of Technology, Stockholm, Sweden).
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 * 1. Redistributions of source code must retain the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer.
 
12
 *
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 *
 
17
 * 3. Neither the name of the Institute nor the names of its contributors
 
18
 *    may be used to endorse or promote products derived from this software
 
19
 *    without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
#ifdef HAVE_CONFIG_H
 
35
#include <config.h>
 
36
RCSID("$Id$");
 
37
#endif
 
38
 
 
39
#include <stdarg.h>
 
40
#include <stdlib.h>
 
41
#ifdef HAVE_SYS_TYPES_H
 
42
#include <sys/types.h>
 
43
#endif
 
44
#ifdef HAVE_SYS_WAIT_H
 
45
#include <sys/wait.h>
 
46
#endif
 
47
#ifdef HAVE_UNISTD_H
 
48
#include <unistd.h>
 
49
#endif
 
50
#include <errno.h>
 
51
 
 
52
#include "roken.h"
 
53
 
 
54
#if !HAVE_DECL_ENVIRON
 
55
extern char **environ;
 
56
#endif
 
57
 
 
58
#define EX_NOEXEC       126
 
59
#define EX_NOTFOUND     127
 
60
 
 
61
/* return values:
 
62
   -1   on `unspecified' system errors
 
63
   -2   on fork failures
 
64
   -3   on waitpid errors
 
65
   -4   exec timeout
 
66
   0-   is return value from subprocess
 
67
   126  if the program couldn't be executed
 
68
   127  if the program couldn't be found
 
69
   128- is 128 + signal that killed subprocess
 
70
 
 
71
   possible values `func' can return:
 
72
   ((time_t)-2)         exit loop w/o killing child and return
 
73
                        `exec timeout'/-4 from simple_exec
 
74
   ((time_t)-1)         kill child with SIGTERM and wait for child to exit
 
75
   0                    don't timeout again
 
76
   n                    seconds to next timeout
 
77
   */
 
78
 
 
79
static int sig_alarm;
 
80
 
 
81
static RETSIGTYPE
 
82
sigtimeout(int sig)
 
83
{
 
84
    sig_alarm = 1;
 
85
    SIGRETURN(0);
 
86
}
 
87
 
 
88
int ROKEN_LIB_FUNCTION
 
89
wait_for_process_timed(pid_t pid, time_t (*func)(void *),
 
90
                       void *ptr, time_t timeout)
 
91
{
 
92
    RETSIGTYPE (*old_func)(int sig) = NULL;
 
93
    unsigned int oldtime = 0;
 
94
    int ret;
 
95
 
 
96
    sig_alarm = 0;
 
97
 
 
98
    if (func) {
 
99
        old_func = signal(SIGALRM, sigtimeout);
 
100
        oldtime = alarm(timeout);
 
101
    }
 
102
 
 
103
    while(1) {
 
104
        int status;
 
105
 
 
106
        while(waitpid(pid, &status, 0) < 0) {
 
107
            if (errno != EINTR) {
 
108
                ret = -3;
 
109
                goto out;
 
110
            }
 
111
            if (func == NULL)
 
112
                continue;
 
113
            if (sig_alarm == 0)
 
114
                continue;
 
115
            timeout = (*func)(ptr);
 
116
            if (timeout == (time_t)-1) {
 
117
                kill(pid, SIGTERM);
 
118
                continue;
 
119
            } else if (timeout == (time_t)-2) {
 
120
                ret = -4;
 
121
                goto out;
 
122
            }
 
123
            alarm(timeout);
 
124
        }
 
125
        if(WIFSTOPPED(status))
 
126
            continue;
 
127
        if(WIFEXITED(status)) {
 
128
            ret = WEXITSTATUS(status);
 
129
            break;
 
130
        }
 
131
        if(WIFSIGNALED(status)) {
 
132
            ret = WTERMSIG(status) + 128;
 
133
            break;
 
134
        }
 
135
    }
 
136
 out:
 
137
    if (func) {
 
138
        signal(SIGALRM, old_func);
 
139
        alarm(oldtime);
 
140
    }
 
141
    return ret;
 
142
}
 
143
 
 
144
int ROKEN_LIB_FUNCTION
 
145
wait_for_process(pid_t pid)
 
146
{
 
147
    return wait_for_process_timed(pid, NULL, NULL, 0);
 
148
}
 
149
 
 
150
int ROKEN_LIB_FUNCTION
 
151
pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
 
152
           const char *file, ...)
 
153
{
 
154
    int in_fd[2], out_fd[2], err_fd[2];
 
155
    pid_t pid;
 
156
    va_list ap;
 
157
    char **argv;
 
158
 
 
159
    if(stdin_fd != NULL)
 
160
        pipe(in_fd);
 
161
    if(stdout_fd != NULL)
 
162
        pipe(out_fd);
 
163
    if(stderr_fd != NULL)
 
164
        pipe(err_fd);
 
165
    pid = fork();
 
166
    switch(pid) {
 
167
    case 0:
 
168
        va_start(ap, file);
 
169
        argv = vstrcollect(&ap);
 
170
        va_end(ap);
 
171
        if(argv == NULL)
 
172
            exit(-1);
 
173
 
 
174
        /* close pipes we're not interested in */
 
175
        if(stdin_fd != NULL)
 
176
            close(in_fd[1]);
 
177
        if(stdout_fd != NULL)
 
178
            close(out_fd[0]);
 
179
        if(stderr_fd != NULL)
 
180
            close(err_fd[0]);
 
181
 
 
182
        /* pipe everything caller doesn't care about to /dev/null */
 
183
        if(stdin_fd == NULL)
 
184
            in_fd[0] = open(_PATH_DEVNULL, O_RDONLY);
 
185
        if(stdout_fd == NULL)
 
186
            out_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
 
187
        if(stderr_fd == NULL)
 
188
            err_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
 
189
 
 
190
        /* move to proper descriptors */
 
191
        if(in_fd[0] != STDIN_FILENO) {
 
192
            dup2(in_fd[0], STDIN_FILENO);
 
193
            close(in_fd[0]);
 
194
        }
 
195
        if(out_fd[1] != STDOUT_FILENO) {
 
196
            dup2(out_fd[1], STDOUT_FILENO);
 
197
            close(out_fd[1]);
 
198
        }
 
199
        if(err_fd[1] != STDERR_FILENO) {
 
200
            dup2(err_fd[1], STDERR_FILENO);
 
201
            close(err_fd[1]);
 
202
        }
 
203
 
 
204
        closefrom(3);
 
205
 
 
206
        execv(file, argv);
 
207
        exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
 
208
    case -1:
 
209
        if(stdin_fd != NULL) {
 
210
            close(in_fd[0]);
 
211
            close(in_fd[1]);
 
212
        }
 
213
        if(stdout_fd != NULL) {
 
214
            close(out_fd[0]);
 
215
            close(out_fd[1]);
 
216
        }
 
217
        if(stderr_fd != NULL) {
 
218
            close(err_fd[0]);
 
219
            close(err_fd[1]);
 
220
        }
 
221
        return -2;
 
222
    default:
 
223
        if(stdin_fd != NULL) {
 
224
            close(in_fd[0]);
 
225
            *stdin_fd = fdopen(in_fd[1], "w");
 
226
        }
 
227
        if(stdout_fd != NULL) {
 
228
            close(out_fd[1]);
 
229
            *stdout_fd = fdopen(out_fd[0], "r");
 
230
        }
 
231
        if(stderr_fd != NULL) {
 
232
            close(err_fd[1]);
 
233
            *stderr_fd = fdopen(err_fd[0], "r");
 
234
        }
 
235
    }
 
236
    return pid;
 
237
}
 
238
 
 
239
int ROKEN_LIB_FUNCTION
 
240
simple_execvp_timed(const char *file, char *const args[],
 
241
                    time_t (*func)(void *), void *ptr, time_t timeout)
 
242
{
 
243
    pid_t pid = fork();
 
244
    switch(pid){
 
245
    case -1:
 
246
        return -2;
 
247
    case 0:
 
248
        execvp(file, args);
 
249
        exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
 
250
    default:
 
251
        return wait_for_process_timed(pid, func, ptr, timeout);
 
252
    }
 
253
}
 
254
 
 
255
int ROKEN_LIB_FUNCTION
 
256
simple_execvp(const char *file, char *const args[])
 
257
{
 
258
    return simple_execvp_timed(file, args, NULL, NULL, 0);
 
259
}
 
260
 
 
261
/* gee, I'd like a execvpe */
 
262
int ROKEN_LIB_FUNCTION
 
263
simple_execve_timed(const char *file, char *const args[], char *const envp[],
 
264
                    time_t (*func)(void *), void *ptr, time_t timeout)
 
265
{
 
266
    pid_t pid = fork();
 
267
    switch(pid){
 
268
    case -1:
 
269
        return -2;
 
270
    case 0:
 
271
        execve(file, args, envp);
 
272
        exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
 
273
    default:
 
274
        return wait_for_process_timed(pid, func, ptr, timeout);
 
275
    }
 
276
}
 
277
 
 
278
int ROKEN_LIB_FUNCTION
 
279
simple_execve(const char *file, char *const args[], char *const envp[])
 
280
{
 
281
    return simple_execve_timed(file, args, envp, NULL, NULL, 0);
 
282
}
 
283
 
 
284
int ROKEN_LIB_FUNCTION
 
285
simple_execlp(const char *file, ...)
 
286
{
 
287
    va_list ap;
 
288
    char **argv;
 
289
    int ret;
 
290
 
 
291
    va_start(ap, file);
 
292
    argv = vstrcollect(&ap);
 
293
    va_end(ap);
 
294
    if(argv == NULL)
 
295
        return -1;
 
296
    ret = simple_execvp(file, argv);
 
297
    free(argv);
 
298
    return ret;
 
299
}
 
300
 
 
301
int ROKEN_LIB_FUNCTION
 
302
simple_execle(const char *file, ... /* ,char *const envp[] */)
 
303
{
 
304
    va_list ap;
 
305
    char **argv;
 
306
    char *const* envp;
 
307
    int ret;
 
308
 
 
309
    va_start(ap, file);
 
310
    argv = vstrcollect(&ap);
 
311
    envp = va_arg(ap, char **);
 
312
    va_end(ap);
 
313
    if(argv == NULL)
 
314
        return -1;
 
315
    ret = simple_execve(file, argv, envp);
 
316
    free(argv);
 
317
    return ret;
 
318
}
 
319
 
 
320
int ROKEN_LIB_FUNCTION
 
321
simple_execl(const char *file, ...)
 
322
{
 
323
    va_list ap;
 
324
    char **argv;
 
325
    int ret;
 
326
 
 
327
    va_start(ap, file);
 
328
    argv = vstrcollect(&ap);
 
329
    va_end(ap);
 
330
    if(argv == NULL)
 
331
        return -1;
 
332
    ret = simple_execve(file, argv, environ);
 
333
    free(argv);
 
334
    return ret;
 
335
}