From 99f92a51e51351e3f514a61d457ab030efa1dd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Thu, 21 Feb 2008 21:11:09 +0000 Subject: [PATCH] Add some functions for dealing with fork(), executing childs and reaping them. --- Makefile | 2 +- spawn.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ spawn.h | 26 ++++++++ 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 spawn.c create mode 100644 spawn.h diff --git a/Makefile b/Makefile index fd260a7c..66759ee4 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c \ subscriptions.c mux.c tsdemux.c buffer.c tcp.c \ - resolver.c tsmux.c parsers.c bitstream.c parser_h264.c + resolver.c tsmux.c parsers.c bitstream.c parser_h264.c spawn.c SRCS += http.c htmlui.c diff --git a/spawn.c b/spawn.c new file mode 100644 index 00000000..c692c563 --- /dev/null +++ b/spawn.c @@ -0,0 +1,198 @@ +/* + * Process spawn functions + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tvhead.h" +#include "dispatch.h" +#include "spawn.h" + +static dtimer_t reaper_timer; + +pthread_mutex_t spawn_mutex = PTHREAD_MUTEX_INITIALIZER; + +static LIST_HEAD(, spawn) spawns; + +typedef struct spawn { + LIST_ENTRY(spawn) link; + pid_t pid; + const char *name; +} spawn_t; + + +static void +reaper(void *opaque, int64_t now) +{ + pid_t pid; + int status; + char txt[100]; + spawn_t *s; + + dtimer_arm(&reaper_timer, reaper, NULL, 1); + + while(1) { + pid = waitpid(-1, &status, WNOHANG); + if(pid < 1) + break; + + pthread_mutex_lock(&spawn_mutex); + LIST_FOREACH(s, &spawns, link) + if(s->pid == pid) + break; + + if (WIFEXITED(status)) { + snprintf(txt, sizeof(txt), + "exited, status=%d\n", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + snprintf(txt, sizeof(txt), + "killed by signal %d\n", WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { + snprintf(txt, sizeof(txt), + "stopped by signal %d\n", WSTOPSIG(status)); + } else if (WIFCONTINUED(status)) { + snprintf(txt, sizeof(txt), + "continued\n"); + } else { + snprintf(txt, sizeof(txt), + "unknown status\n"); + } + + syslog(LOG_INFO, "spawn: \"%s\" %s", s ? s->name : "", txt); + + LIST_REMOVE(s, link); + free((void *)s->name); + free(s); + pthread_mutex_unlock(&spawn_mutex); + } +} + + +void +spawn_init(void) +{ + dtimer_arm(&reaper_timer, reaper, NULL, 1); +} + + + +static spawn_t * +spawn_enq(const char *name, int pid) +{ + spawn_t *s = calloc(1, sizeof(spawn_t)); + s->name = strdup(name); + s->pid = pid; + pthread_mutex_lock(&spawn_mutex); + LIST_INSERT_HEAD(&spawns, s, link); + pthread_mutex_unlock(&spawn_mutex); + return s; +} + + + + + +TAILQ_HEAD(spawn_output_buf_queue, spawn_output_buf); + +#define MAX_SOB_SIZE 4000 + +typedef struct spawn_output_buf { + TAILQ_ENTRY(spawn_output_buf) sob_link; + int sob_size; + char sob_buf[MAX_SOB_SIZE]; +} spawn_output_buf_t; + + + +int +spawn_and_store_stdout(const char *prog, char **outp) +{ + pid_t p; + int fd[2], r, totalsize = 0; + char *outbuf; + + struct spawn_output_buf_queue bufs; + spawn_output_buf_t *b = NULL; + + if(pipe(fd) == -1) + return -1; + + p = fork(); + + if(p == -1) + return -1; + + if(p == 0) { + close(0); + close(2); + close(fd[0]); + dup2(fd[1], 1); + close(fd[1]); + syslog(LOG_INFO, "spawn: Executing \"%s\"", prog); + execl(prog, prog, NULL); + syslog(LOG_ERR, "spawn: pid %d cannot execute %s -- %s", + getpid(), prog, strerror(errno)); + close(1); + exit(1); + } + + spawn_enq(prog, p); + + close(fd[1]); + + TAILQ_INIT(&bufs); + while(1) { + if(b == NULL) { + b = malloc(sizeof(spawn_output_buf_t)); + b->sob_size = 0; + TAILQ_INSERT_TAIL(&bufs, b, sob_link); + } + + r = read(fd[0], b->sob_buf + b->sob_size, MAX_SOB_SIZE - b->sob_size); + if(r < 1) + break; + b->sob_size += r; + totalsize += r; + if(b->sob_size == MAX_SOB_SIZE) + b = NULL; + } + + if(totalsize == 0) { + free(b); + *outp = NULL; + return 0; + } + + outbuf = malloc(totalsize); + r = 0; + while((b = TAILQ_FIRST(&bufs)) != NULL) { + memcpy(outbuf + r, b->sob_buf, b->sob_size); + r+= b->sob_size; + TAILQ_REMOVE(&bufs, b, sob_link); + free(b); + } + assert(r == totalsize); + *outp = outbuf; + return totalsize; +} diff --git a/spawn.h b/spawn.h new file mode 100644 index 00000000..3ba957b5 --- /dev/null +++ b/spawn.h @@ -0,0 +1,26 @@ +/* + * Process spawn functions + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SPAWN_H +#define SPAWN_H + +int spawn_and_store_stdout(const char *prog, char **outp); + +void spawn_init(void); + +#endif /* SPAWN_H */