From 499899d405779959b9c614b8c89025def35fc52a Mon Sep 17 00:00:00 2001 From: Thulinma Date: Wed, 12 Oct 2011 23:30:42 +0200 Subject: [PATCH] Added piped process support to Util::Procs --- spawntest/main.cpp | 6 +-- spawntest/testpipein.sh | 5 ++ spawntest/testpipeout.sh | 6 +++ util/proc.cpp | 105 +++++++++++++++++++++++++++++++-------- util/proc.h | 2 + 5 files changed, 101 insertions(+), 23 deletions(-) create mode 100755 spawntest/testpipein.sh create mode 100755 spawntest/testpipeout.sh diff --git a/spawntest/main.cpp b/spawntest/main.cpp index 255a2354..c622bdba 100644 --- a/spawntest/main.cpp +++ b/spawntest/main.cpp @@ -8,8 +8,8 @@ /// Testing program for Util::Proc utility class. int main(){ Util::Procs::Start("number1", "./test.sh Koekjes"); - while (true){ - sleep(1); - } + sleep(1); sleep(1); sleep(1); sleep(1); sleep(1); + Util::Procs::Start("number2", "./testpipein.sh", "./testpipeout.sh"); + sleep(1); sleep(1); sleep(1); sleep(1); sleep(1); return 0; }//main diff --git a/spawntest/testpipein.sh b/spawntest/testpipein.sh new file mode 100755 index 00000000..bd54fdd1 --- /dev/null +++ b/spawntest/testpipein.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +echo "Sending something through the pipe..." 1>&2 +echo "something" +echo "Exiting pipewriter" 1>&2 diff --git a/spawntest/testpipeout.sh b/spawntest/testpipeout.sh new file mode 100755 index 00000000..7c7c6cec --- /dev/null +++ b/spawntest/testpipeout.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "Reading stdin..." +read meh +echo "I read $meh" +echo "Exiting pipereader now..." diff --git a/util/proc.cpp b/util/proc.cpp index 0e891be5..db004d0d 100644 --- a/util/proc.cpp +++ b/util/proc.cpp @@ -24,6 +24,33 @@ void Util::Procs::childsig_handler(int signum){ plist.erase(ret); } +/// Attempts to run the command cmd. +/// Replaces the current process - use after forking first! +/// This function will never return - it will either run the given +/// command or kill itself with return code 42. +void Util::Procs::runCmd(std::string & cmd){ + //split cmd into arguments + //supports a maximum of 20 arguments + char * tmp = (char*)cmd.c_str(); + char * tmp2 = 0; + char * args[21]; + int i = 0; + tmp2 = strtok(tmp, " "); + args[0] = tmp2; + while (tmp2 != 0 && (i < 20)){ + tmp2 = strtok(0, " "); + ++i; + args[i] = tmp2; + } + if (i == 20){args[20] = 0;} + //execute the command + execvp(args[0], args); + #if DEBUG >= 1 + std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl; + #endif + _exit(42); +} + /// Starts a new process if the name is not already active. /// \return 0 if process was not started, process PID otherwise. /// \arg name Name for this process - only used internally. @@ -40,26 +67,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){ } pid_t ret = fork(); if (ret == 0){ - //split cmd into arguments - //supports a maximum of 20 arguments - char * tmp = (char*)cmd.c_str(); - char * tmp2 = 0; - char * args[21]; - int i = 0; - tmp2 = strtok(tmp, " "); - args[0] = tmp2; - while (tmp2 != 0 && (i < 20)){ - tmp2 = strtok(0, " "); - ++i; - args[i] = tmp2; - } - if (i == 20){args[20] = 0;} - //execute the command - execvp(args[0], args); - #if DEBUG >= 1 - std::cerr << "Error: " << strerror(errno) << std::endl; - #endif - _exit(42); + runCmd(cmd); }else{ if (ret > 0){ #if DEBUG >= 1 @@ -76,6 +84,63 @@ pid_t Util::Procs::Start(std::string name, std::string cmd){ return ret; } +/// Starts two piped processes if the name is not already active. +/// \return 0 if process was not started, main (receiving) process PID otherwise. +/// \arg name Name for this process - only used internally. +/// \arg cmd Commandline for sub (sending) process. +/// \arg cmd2 Commandline for main (receiving) process. +pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ + if (isActive(name)){return getPid(name);} + if (!handler_set){ + struct sigaction new_action; + new_action.sa_handler = Util::Procs::childsig_handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = 0; + sigaction(SIGCHLD, &new_action, NULL); + handler_set = true; + } + pid_t ret = fork(); + if (ret == 0){ + int pfildes[2]; + if (pipe(pfildes) == -1){ + #if DEBUG >= 1 + std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl; + #endif + _exit(41); + } + pid_t pid; + if ((pid = fork()) == -1){ + #if DEBUG >= 1 + std::cerr << "Process " << name << " could not be started. Second fork() failed." << std::endl; + #endif + _exit(41); + }else if (pid == 0){ + close(pfildes[0]); + dup2(pfildes[1],1); + close(pfildes[1]); + runCmd(cmd); + }else{ + close(pfildes[1]); + dup2(pfildes[0],0); + close(pfildes[0]); + runCmd(cmd2); + } + }else{ + if (ret > 0){ + #if DEBUG >= 1 + std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << " | " << cmd2 << std::endl; + #endif + plist.insert(std::pair(ret, name)); + }else{ + #if DEBUG >= 1 + std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; + #endif + return 0; + } + } + return ret; +} + /// Stops the named process, if running. /// \arg name (Internal) name of process to stop void Util::Procs::Stop(std::string name){ diff --git a/util/proc.h b/util/proc.h index a2c10ec0..a74d75bd 100644 --- a/util/proc.h +++ b/util/proc.h @@ -14,8 +14,10 @@ namespace Util{ static std::map plist; ///< Holds active processes static bool handler_set; ///< If true, the sigchld handler has been setup. static void childsig_handler(int signum); + static void runCmd(std::string & cmd); public: static pid_t Start(std::string name, std::string cmd); + static pid_t Start(std::string name, std::string cmd, std::string cmd2); static void Stop(std::string name); static void Stop(pid_t name); static void StopAll();