~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to lib/process.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include "dynamic-string.h"
29
29
#include "fatal-signal.h"
30
30
#include "list.h"
 
31
#include "ovs-thread.h"
31
32
#include "poll-loop.h"
32
33
#include "signals.h"
33
34
#include "socket-util.h"
36
37
 
37
38
VLOG_DEFINE_THIS_MODULE(process);
38
39
 
39
 
COVERAGE_DEFINE(process_run);
40
 
COVERAGE_DEFINE(process_run_capture);
41
40
COVERAGE_DEFINE(process_sigchld);
42
41
COVERAGE_DEFINE(process_start);
43
42
 
46
45
    char *name;
47
46
    pid_t pid;
48
47
 
49
 
    /* Modified by signal handler. */
50
 
    volatile bool exited;
51
 
    volatile int status;
 
48
    /* State. */
 
49
    bool exited;
 
50
    int status;
52
51
};
53
52
 
54
53
/* Pipe used to signal child termination. */
57
56
/* All processes. */
58
57
static struct list all_processes = LIST_INITIALIZER(&all_processes);
59
58
 
60
 
static bool sigchld_is_blocked(void);
61
 
static void block_sigchld(sigset_t *);
62
 
static void unblock_sigchld(const sigset_t *);
63
59
static void sigchld_handler(int signr OVS_UNUSED);
64
 
static bool is_member(int x, const int *array, size_t);
65
60
 
66
61
/* Initializes the process subsystem (if it is not already initialized).  Calls
67
62
 * exit() if initialization fails.
68
63
 *
 
64
 * This function may not be called after creating any additional threads.
 
65
 *
69
66
 * Calling this function is optional; it will be called automatically by
70
67
 * process_start() if necessary.  Calling it explicitly allows the client to
71
68
 * prevent the process from exiting at an unexpected time. */
75
72
    static bool inited;
76
73
    struct sigaction sa;
77
74
 
 
75
    assert_single_threaded();
78
76
    if (inited) {
79
77
        return;
80
78
    }
148
146
}
149
147
 
150
148
/* Creates and returns a new struct process with the specified 'name' and
151
 
 * 'pid'.
152
 
 *
153
 
 * This is racy unless SIGCHLD is blocked (and has been blocked since before
154
 
 * the fork()) that created the subprocess.  */
 
149
 * 'pid'. */
155
150
static struct process *
156
151
process_register(const char *name, pid_t pid)
157
152
{
158
153
    struct process *p;
159
154
    const char *slash;
160
155
 
161
 
    ovs_assert(sigchld_is_blocked());
162
 
 
163
156
    p = xzalloc(sizeof *p);
164
157
    p->pid = pid;
165
158
    slash = strrchr(name, '/');
175
168
 * argv[0] is used as the name of the process.  Searches the PATH environment
176
169
 * variable to find the program to execute.
177
170
 *
 
171
 * This function may not be called after creating any additional threads.
 
172
 *
178
173
 * All file descriptors are closed before executing the subprocess, except for
179
 
 * fds 0, 1, and 2 and the 'n_keep_fds' fds listed in 'keep_fds'.  Also, any of
180
 
 * the 'n_null_fds' fds listed in 'null_fds' are replaced by /dev/null.
 
174
 * fds 0, 1, and 2.
181
175
 *
182
176
 * Returns 0 if successful, otherwise a positive errno value indicating the
183
177
 * error.  If successful, '*pp' is assigned a new struct process that may be
184
178
 * used to query the process's status.  On failure, '*pp' is set to NULL. */
185
179
int
186
 
process_start(char **argv,
187
 
              const int keep_fds[], size_t n_keep_fds,
188
 
              const int null_fds[], size_t n_null_fds,
189
 
              struct process **pp)
 
180
process_start(char **argv, struct process **pp)
190
181
{
191
 
    sigset_t oldsigs;
192
 
    int nullfd;
193
182
    pid_t pid;
194
183
    int error;
195
184
 
 
185
    assert_single_threaded();
 
186
 
196
187
    *pp = NULL;
197
188
    COVERAGE_INC(process_start);
198
189
    error = process_prestart(argv);
200
191
        return error;
201
192
    }
202
193
 
203
 
    if (n_null_fds) {
204
 
        nullfd = get_null_fd();
205
 
        if (nullfd < 0) {
206
 
            return -nullfd;
207
 
        }
208
 
    } else {
209
 
        nullfd = -1;
210
 
    }
211
 
 
212
 
    block_sigchld(&oldsigs);
213
194
    pid = fork();
214
195
    if (pid < 0) {
215
 
        unblock_sigchld(&oldsigs);
216
 
        VLOG_WARN("fork failed: %s", strerror(errno));
 
196
        VLOG_WARN("fork failed: %s", ovs_strerror(errno));
217
197
        return errno;
218
198
    } else if (pid) {
219
199
        /* Running in parent process. */
220
200
        *pp = process_register(argv[0], pid);
221
 
        unblock_sigchld(&oldsigs);
222
201
        return 0;
223
202
    } else {
224
203
        /* Running in child process. */
226
205
        int fd;
227
206
 
228
207
        fatal_signal_fork();
229
 
        unblock_sigchld(&oldsigs);
230
 
        for (fd = 0; fd < fd_max; fd++) {
231
 
            if (is_member(fd, null_fds, n_null_fds)) {
232
 
                dup2(nullfd, fd);
233
 
            } else if (fd >= 3 && fd != nullfd
234
 
                       && !is_member(fd, keep_fds, n_keep_fds)) {
235
 
                close(fd);
236
 
            }
237
 
        }
238
 
        if (nullfd >= 0
239
 
            && !is_member(nullfd, keep_fds, n_keep_fds)
240
 
            && !is_member(nullfd, null_fds, n_null_fds)) {
241
 
            close(nullfd);
 
208
        for (fd = 3; fd < fd_max; fd++) {
 
209
            close(fd);
242
210
        }
243
211
        execvp(argv[0], argv);
244
212
        fprintf(stderr, "execvp(\"%s\") failed: %s\n",
245
 
                argv[0], strerror(errno));
 
213
                argv[0], ovs_strerror(errno));
246
214
        _exit(1);
247
215
    }
248
216
}
252
220
process_destroy(struct process *p)
253
221
{
254
222
    if (p) {
255
 
        sigset_t oldsigs;
256
 
 
257
 
        block_sigchld(&oldsigs);
258
223
        list_remove(&p->node);
259
 
        unblock_sigchld(&oldsigs);
260
 
 
261
224
        free(p->name);
262
225
        free(p);
263
226
    }
292
255
bool
293
256
process_exited(struct process *p)
294
257
{
295
 
    if (p->exited) {
296
 
        return true;
297
 
    } else {
298
 
        char buf[_POSIX_PIPE_BUF];
299
 
        ignore(read(fds[0], buf, sizeof buf));
300
 
        return false;
301
 
    }
 
258
    return p->exited;
302
259
}
303
260
 
304
261
/* Returns process 'p''s exit status, as reported by waitpid(2).
311
268
    return p->status;
312
269
}
313
270
 
314
 
int
315
 
process_run(char **argv,
316
 
            const int keep_fds[], size_t n_keep_fds,
317
 
            const int null_fds[], size_t n_null_fds,
318
 
            int *status)
319
 
{
320
 
    struct process *p;
321
 
    int retval;
322
 
 
323
 
    COVERAGE_INC(process_run);
324
 
    retval = process_start(argv, keep_fds, n_keep_fds, null_fds, n_null_fds,
325
 
                           &p);
326
 
    if (retval) {
327
 
        *status = 0;
328
 
        return retval;
329
 
    }
330
 
 
331
 
    while (!process_exited(p)) {
332
 
        process_wait(p);
333
 
        poll_block();
334
 
    }
335
 
    *status = process_status(p);
336
 
    process_destroy(p);
337
 
    return 0;
338
 
}
339
 
 
340
271
/* Given 'status', which is a process status in the form reported by waitpid(2)
341
272
 * and returned by process_status(), returns a string describing how the
342
273
 * process terminated.  The caller is responsible for freeing the string when
348
279
    if (WIFEXITED(status)) {
349
280
        ds_put_format(&ds, "exit status %d", WEXITSTATUS(status));
350
281
    } else if (WIFSIGNALED(status)) {
351
 
        ds_put_format(&ds, "killed (%s)", signal_name(WTERMSIG(status)));
 
282
        char namebuf[SIGNAL_NAME_BUFSIZE];
 
283
 
 
284
        ds_put_format(&ds, "killed (%s)",
 
285
                      signal_name(WTERMSIG(status), namebuf, sizeof namebuf));
352
286
    } else if (WIFSTOPPED(status)) {
353
 
        ds_put_format(&ds, "stopped (%s)", signal_name(WSTOPSIG(status)));
 
287
        char namebuf[SIGNAL_NAME_BUFSIZE];
 
288
 
 
289
        ds_put_format(&ds, "stopped (%s)",
 
290
                      signal_name(WSTOPSIG(status), namebuf, sizeof namebuf));
354
291
    } else {
355
292
        ds_put_format(&ds, "terminated abnormally (%x)", status);
356
293
    }
360
297
    return ds_cstr(&ds);
361
298
}
362
299
 
 
300
/* Executes periodic maintenance activities required by the process module. */
 
301
void
 
302
process_run(void)
 
303
{
 
304
    char buf[_POSIX_PIPE_BUF];
 
305
 
 
306
    if (!list_is_empty(&all_processes) && read(fds[0], buf, sizeof buf) > 0) {
 
307
        struct process *p;
 
308
 
 
309
        LIST_FOR_EACH (p, node, &all_processes) {
 
310
            if (!p->exited) {
 
311
                int retval, status;
 
312
                do {
 
313
                    retval = waitpid(p->pid, &status, WNOHANG);
 
314
                } while (retval == -1 && errno == EINTR);
 
315
                if (retval == p->pid) {
 
316
                    p->exited = true;
 
317
                    p->status = status;
 
318
                } else if (retval < 0) {
 
319
                    VLOG_WARN("waitpid: %s", ovs_strerror(errno));
 
320
                    p->exited = true;
 
321
                    p->status = -1;
 
322
                }
 
323
            }
 
324
        }
 
325
    }
 
326
}
 
327
 
 
328
 
363
329
/* Causes the next call to poll_block() to wake up when process 'p' has
364
330
 * exited. */
365
331
void
397
363
    return NULL;
398
364
}
399
365
 
400
 
/* process_run_capture() and supporting functions. */
401
 
 
402
 
struct stream {
403
 
    size_t max_size;
404
 
    struct ds log;
405
 
    int fds[2];
406
 
};
407
 
 
408
 
static int
409
 
stream_open(struct stream *s, size_t max_size)
410
 
{
411
 
    int error;
412
 
 
413
 
    s->max_size = max_size;
414
 
    ds_init(&s->log);
415
 
    if (pipe(s->fds)) {
416
 
        VLOG_WARN("failed to create pipe: %s", strerror(errno));
417
 
        return errno;
418
 
    }
419
 
    error = set_nonblocking(s->fds[0]);
420
 
    if (error) {
421
 
        close(s->fds[0]);
422
 
        close(s->fds[1]);
423
 
    }
424
 
    return error;
425
 
}
426
 
 
427
 
static void
428
 
stream_read(struct stream *s)
429
 
{
430
 
    if (s->fds[0] < 0) {
431
 
        return;
432
 
    }
433
 
 
434
 
    for (;;) {
435
 
        char buffer[512];
436
 
        int error;
437
 
        size_t n;
438
 
 
439
 
        error = read_fully(s->fds[0], buffer, sizeof buffer, &n);
440
 
        ds_put_buffer(&s->log, buffer, n);
441
 
        if (error) {
442
 
            if (error == EAGAIN || error == EWOULDBLOCK) {
443
 
                return;
444
 
            } else {
445
 
                if (error != EOF) {
446
 
                    VLOG_WARN("error reading subprocess pipe: %s",
447
 
                              strerror(error));
448
 
                }
449
 
                break;
450
 
            }
451
 
        } else if (s->log.length > s->max_size) {
452
 
            VLOG_WARN("subprocess output overflowed %zu-byte buffer",
453
 
                      s->max_size);
454
 
            break;
455
 
        }
456
 
    }
457
 
    close(s->fds[0]);
458
 
    s->fds[0] = -1;
459
 
}
460
 
 
461
 
static void
462
 
stream_wait(struct stream *s)
463
 
{
464
 
    if (s->fds[0] >= 0) {
465
 
        poll_fd_wait(s->fds[0], POLLIN);
466
 
    }
467
 
}
468
 
 
469
 
static void
470
 
stream_close(struct stream *s)
471
 
{
472
 
    ds_destroy(&s->log);
473
 
    if (s->fds[0] >= 0) {
474
 
        close(s->fds[0]);
475
 
    }
476
 
    if (s->fds[1] >= 0) {
477
 
        close(s->fds[1]);
478
 
    }
479
 
}
480
 
 
481
 
/* Starts the process whose arguments are given in the null-terminated array
482
 
 * 'argv' and waits for it to exit.  On success returns 0 and stores the
483
 
 * process exit value (suitable for passing to process_status_msg()) in
484
 
 * '*status'.  On failure, returns a positive errno value and stores 0 in
485
 
 * '*status'.
486
 
 *
487
 
 * If 'stdout_log' is nonnull, then the subprocess's output to stdout (up to a
488
 
 * limit of 'log_max' bytes) is captured in a memory buffer, which
489
 
 * when this function returns 0 is stored as a null-terminated string in
490
 
 * '*stdout_log'.  The caller is responsible for freeing '*stdout_log' (by
491
 
 * passing it to free()).  When this function returns an error, '*stdout_log'
492
 
 * is set to NULL.
493
 
 *
494
 
 * If 'stderr_log' is nonnull, then it is treated like 'stdout_log' except
495
 
 * that it captures the subprocess's output to stderr. */
496
 
int
497
 
process_run_capture(char **argv, char **stdout_log, char **stderr_log,
498
 
                    size_t max_log, int *status)
499
 
{
500
 
    struct stream s_stdout, s_stderr;
501
 
    sigset_t oldsigs;
502
 
    pid_t pid;
503
 
    int error;
504
 
 
505
 
    COVERAGE_INC(process_run_capture);
506
 
    if (stdout_log) {
507
 
        *stdout_log = NULL;
508
 
    }
509
 
    if (stderr_log) {
510
 
        *stderr_log = NULL;
511
 
    }
512
 
    *status = 0;
513
 
    error = process_prestart(argv);
514
 
    if (error) {
515
 
        return error;
516
 
    }
517
 
 
518
 
    error = stream_open(&s_stdout, max_log);
519
 
    if (error) {
520
 
        return error;
521
 
    }
522
 
 
523
 
    error = stream_open(&s_stderr, max_log);
524
 
    if (error) {
525
 
        stream_close(&s_stdout);
526
 
        return error;
527
 
    }
528
 
 
529
 
    block_sigchld(&oldsigs);
530
 
    pid = fork();
531
 
    if (pid < 0) {
532
 
        error = errno;
533
 
 
534
 
        unblock_sigchld(&oldsigs);
535
 
        VLOG_WARN("fork failed: %s", strerror(error));
536
 
 
537
 
        stream_close(&s_stdout);
538
 
        stream_close(&s_stderr);
539
 
        *status = 0;
540
 
        return error;
541
 
    } else if (pid) {
542
 
        /* Running in parent process. */
543
 
        struct process *p;
544
 
 
545
 
        p = process_register(argv[0], pid);
546
 
        unblock_sigchld(&oldsigs);
547
 
 
548
 
        close(s_stdout.fds[1]);
549
 
        close(s_stderr.fds[1]);
550
 
        while (!process_exited(p)) {
551
 
            stream_read(&s_stdout);
552
 
            stream_read(&s_stderr);
553
 
 
554
 
            stream_wait(&s_stdout);
555
 
            stream_wait(&s_stderr);
556
 
            process_wait(p);
557
 
            poll_block();
558
 
        }
559
 
        stream_read(&s_stdout);
560
 
        stream_read(&s_stderr);
561
 
 
562
 
        if (stdout_log) {
563
 
            *stdout_log = ds_steal_cstr(&s_stdout.log);
564
 
        }
565
 
        if (stderr_log) {
566
 
            *stderr_log = ds_steal_cstr(&s_stderr.log);
567
 
        }
568
 
 
569
 
        stream_close(&s_stdout);
570
 
        stream_close(&s_stderr);
571
 
 
572
 
        *status = process_status(p);
573
 
        process_destroy(p);
574
 
        return 0;
575
 
    } else {
576
 
        /* Running in child process. */
577
 
        int max_fds;
578
 
        int i;
579
 
 
580
 
        fatal_signal_fork();
581
 
        unblock_sigchld(&oldsigs);
582
 
 
583
 
        dup2(get_null_fd(), 0);
584
 
        dup2(s_stdout.fds[1], 1);
585
 
        dup2(s_stderr.fds[1], 2);
586
 
 
587
 
        max_fds = get_max_fds();
588
 
        for (i = 3; i < max_fds; i++) {
589
 
            close(i);
590
 
        }
591
 
 
592
 
        execvp(argv[0], argv);
593
 
        fprintf(stderr, "execvp(\"%s\") failed: %s\n",
594
 
                argv[0], strerror(errno));
595
 
        exit(EXIT_FAILURE);
596
 
    }
597
 
}
598
 
 
599
366
static void
600
367
sigchld_handler(int signr OVS_UNUSED)
601
368
{
602
 
    struct process *p;
603
 
 
604
 
    COVERAGE_INC(process_sigchld);
605
 
    LIST_FOR_EACH (p, node, &all_processes) {
606
 
        if (!p->exited) {
607
 
            int retval, status;
608
 
            do {
609
 
                retval = waitpid(p->pid, &status, WNOHANG);
610
 
            } while (retval == -1 && errno == EINTR);
611
 
            if (retval == p->pid) {
612
 
                p->exited = true;
613
 
                p->status = status;
614
 
            } else if (retval < 0) {
615
 
                /* XXX We want to log something but we're in a signal
616
 
                 * handler. */
617
 
                p->exited = true;
618
 
                p->status = -1;
619
 
            }
620
 
        }
621
 
    }
622
369
    ignore(write(fds[1], "", 1));
623
370
}
624
 
 
625
 
static bool
626
 
is_member(int x, const int *array, size_t n)
627
 
{
628
 
    size_t i;
629
 
 
630
 
    for (i = 0; i < n; i++) {
631
 
        if (array[i] == x) {
632
 
            return true;
633
 
        }
634
 
    }
635
 
    return false;
636
 
}
637
 
 
638
 
static bool
639
 
sigchld_is_blocked(void)
640
 
{
641
 
    sigset_t sigs;
642
 
 
643
 
    xsigprocmask(SIG_SETMASK, NULL, &sigs);
644
 
    return sigismember(&sigs, SIGCHLD);
645
 
}
646
 
 
647
 
static void
648
 
block_sigchld(sigset_t *oldsigs)
649
 
{
650
 
    sigset_t sigchld;
651
 
 
652
 
    sigemptyset(&sigchld);
653
 
    sigaddset(&sigchld, SIGCHLD);
654
 
    xsigprocmask(SIG_BLOCK, &sigchld, oldsigs);
655
 
}
656
 
 
657
 
static void
658
 
unblock_sigchld(const sigset_t *oldsigs)
659
 
{
660
 
    xsigprocmask(SIG_SETMASK, oldsigs, NULL);
661
 
}