From 66c2537197a79b1c6fd44112015b96f2353ccd42 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Mon, 30 May 2011 22:52:37 +0000 Subject: initial release --- src/sysexec.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 src/sysexec.c (limited to 'src/sysexec.c') diff --git a/src/sysexec.c b/src/sysexec.c new file mode 100644 index 0000000..55c9830 --- /dev/null +++ b/src/sysexec.c @@ -0,0 +1,220 @@ +/* + * gstdvbbackend + * + * gstdvbbackend is a small programm which captures a given set of dvb + * channels from one dvb device and provides the streams via minimal http. + * + * + * Copyright (C) 2011 Christian Pointner + * + * This file is part of gstdvbbackend. + * + * gstdvbbackend 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 + * any later version. + * + * gstdvbbackend 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 gstdvbbackend. If not, see . + */ + +#include "datatypes.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysexec.h" +#include "log.h" + +char** dup_ptrptr(char* const ptrptr[]) +{ + if(!ptrptr) + return NULL; + + int n = 0; + while(ptrptr[n]) + n++; + + char** my_ptrptr; + my_ptrptr = malloc((n+1)*sizeof(char*)); + if(!my_ptrptr) + return NULL; + + int i; + for(i = 0; i < n; ++i) { + my_ptrptr[i] = strdup(ptrptr[i]); + if(!my_ptrptr[i]) { + i--; + for(; i >= 0; --i) + free(my_ptrptr[i]); + + free(my_ptrptr); + return NULL; + } + } + + my_ptrptr[n] = NULL; + + return my_ptrptr; +} + +void free_ptrptr(char** ptrptr) +{ + if(!ptrptr) + return; + + int i; + for(i = 0; ptrptr[i]; ++i) + free(ptrptr[i]); + + free(ptrptr); +} + +child_t* new_child(const char* script, char* const argv[], char* const evp[]) +{ + child_t* new_child; + + new_child = malloc(sizeof(child_t)); + if(!new_child) + return NULL; + + new_child->pid_ = -1; + new_child->err_fd_ = -1; + new_child->script_ = strdup(script); + if(!new_child->script_) { + free(new_child); + return NULL; + } + + new_child->argv_ = dup_ptrptr(argv); + if(!new_child->argv_) { + free(new_child->script_); + free(new_child); + return NULL; + + } + + new_child->evp_ = dup_ptrptr(evp); + if(!new_child->evp_) { + free_ptrptr(new_child->argv_); + free(new_child->script_); + free(new_child); + return NULL; + } + return new_child; +} + +void free_child(child_t* child) +{ + if(!child) + return; + + free_ptrptr(child->argv_); + free_ptrptr(child->evp_); + if(child->script_) + free(child->script_); + if(child->err_fd_ >= 0) close(child->err_fd_); + free(child); +} + +child_t* rh_exec(const char* script, char* const argv[], char* const evp[]) +{ + if(!script) + return NULL; + + child_t* child = new_child(script, argv, evp); + if(!child) + return NULL; + + int pipefd[2]; + if(pipe(pipefd) == -1) { + log_printf(ERROR, "executing script '%s' failed: pipe() error: %s", child->script_, strerror(errno)); // TODO: thread safe strerror + free_child(child); + return NULL; + } + + pid_t pid; + pid = fork(); + if(pid == -1) { + log_printf(ERROR, "executing script '%s' failed: fork() error: %s", child->script_, strerror(errno)); // TODO: thread safe strerror + close(pipefd[0]); + close(pipefd[1]); + free_child(child); + return NULL; + } + + if(!pid) { + int fd; + for (fd=getdtablesize();fd>=0;--fd) // close all file descriptors + if(fd != pipefd[1]) close(fd); + + fd = open("/dev/null",O_RDWR); // stdin + if(fd == -1) + log_printf(WARNING, "can't open stdin"); + else { + if(dup(fd) == -1) // stdout + log_printf(WARNING, "can't open stdout"); + if(dup(fd) == -1) // stderr + log_printf(WARNING, "can't open stderr"); + } + execve(child->script_, child->argv_, child->evp_); + // if execve returns, an error occurred, but logging doesn't work + // because we closed all file descriptors, so just write errno to + // pipe and call exit + write(pipefd[1], (void*)(&errno), sizeof(errno)); + exit(-1); + } + close(pipefd[1]); + + child->pid_ = pid; + child->err_fd_ = pipefd[0]; + + log_printf(INFO, "called script '%s' with pid %d", child->script_, child->pid_); + + return child; +} + +int rh_waitpid(child_t* child, int* status_return) +{ + int status = 0; + pid_t pid = waitpid(child->pid_, &status, WNOHANG); + if(!pid || (pid < 0 && errno == ECHILD)) + return 0; + if(pid < 0) { + log_printf(ERROR, "waitpid returned with error: %s", strerror(errno)); // TODO: thread safe strerror + return pid; + } + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(child->err_fd_, &rfds); + struct timeval tv = { 0 , 0 }; + if(select(child->err_fd_+1, &rfds, NULL, NULL, &tv) == 1) { + int err = 0; + if(read(child->err_fd_, (void*)(&err), sizeof(err)) >= sizeof(err)) { + log_printf(INFO, "script '%s' exec() error: %s", child->script_, strerror(err)); // TODO: thread safe strerror + return -1; + } + } + if(WIFEXITED(status)) + log_printf(INFO, "script '%s' (pid %d) returned %d", child->script_, child->pid_, WEXITSTATUS(status)); + else if(WIFSIGNALED(status)) + log_printf(INFO, "script '%s' (pid %d) terminated after signal %d", child->script_, child->pid_, WTERMSIG(status)); + else + log_printf(INFO, "executing script '%s' (pid %d): unkown error", child->script_, child->pid_); + + if(status_return) *status_return = status; + + return 1; +} -- cgit v1.2.3