#include #ifdef __GNUG__ #pragma implementation #endif #include #include #include #include #include #include #include #include "debug.h" #include "syscall.h" #include "syscontr.h" #include "support/lstrings.h" Systemcalls::Systemcalls() { pid = 0; // No child yet } Systemcalls::Systemcalls(Starttype how, string const & what, Callbackfct cback) { start = how; command = what; cbk = cback; pid = (pid_t) 0; retval = 0; startscript(); } Systemcalls::~Systemcalls() { #if 0 // If the child is alive, we have to brutally kill it if (getpid() != 0) { ::kill(getpid(), SIGKILL); } #endif } // Start a childprocess // // if child runs in background, add information to global controller. int Systemcalls::startscript() { retval = 0; switch (start) { case System: retval = system(command.c_str()); callback(); break; case Wait: pid = fork(); if (pid>0) { // Fork succesful. Wait for child waitForChild(); callback(); } else retval = 1; break; case DontWait: pid = fork(); if (pid>0) { // Now integrate into Controller SystemcallsSingletoncontroller::Startcontroller starter; SystemcallsSingletoncontroller * contr = starter.getController(); // Add this to controller contr->addCall(*this); } else retval = 1; break; } return retval; } void Systemcalls::kill(int tolerance) { if (getpid() == 0) { lyxerr << "LyX: Can't kill non-existing process." << endl; return; } int ret = ::kill(getpid(), SIGHUP); bool wait_for_death = true; if (ret != 0) { if (errno == ESRCH) { // The process is already dead! wait_for_death = false; } else { // Something is rotten - maybe we lost permissions? } } if (wait_for_death) { // Here, we should add the PID to a list of // waiting processes to kill if they are not // dead without tolerance seconds #ifdef WITH_WARNINGS #warning Implement this using the timer of the singleton systemcontroller (Asger) #endif } } // Wait for child process to finish. Returns returncode from child. void Systemcalls::waitForChild() { // We'll pretend that the child returns 1 on all errorconditions. retval = 1; int status; bool wait = true; while (wait) { pid_t waitrpid = waitpid(pid, &status, WUNTRACED); if (waitrpid == -1) { lyxerr << "LyX: Error waiting for child:" << strerror(errno) << endl; wait = false; } else if (WIFEXITED(status)) { // Child exited normally. Update return value. retval = WEXITSTATUS(status); wait = false; } else if (WIFSIGNALED(status)) { lyxerr << "LyX: Child didn't catch signal " << WTERMSIG(status) << "and died. Too bad." << endl; wait = false; } else if (WIFSTOPPED(status)) { lyxerr << "LyX: Child (pid: " << pid << ") stopped on signal " << WSTOPSIG(status) << ". Waiting for child to finish." << endl; } else { lyxerr << "LyX: Something rotten happened while " "waiting for child " << pid << endl; wait = false; } } } // generate child in background pid_t Systemcalls::fork() { pid_t cpid= ::fork(); if (cpid == 0) { // child string childcommand(command); // copy string rest = split(command, childcommand, ' '); const int MAX_ARGV = 255; char *syscmd = 0; char *argv[MAX_ARGV]; int index = 0; bool more; do { if (syscmd == 0) { syscmd = new char[childcommand.length() + 1]; childcommand.copy(syscmd, childcommand.length()); syscmd[childcommand.length()] = '\0'; } char * tmp = new char[childcommand.length() + 1]; childcommand.copy(tmp, childcommand.length()); tmp[childcommand.length()] = '\0'; argv[index++] = tmp; // reinit more = !rest.empty(); if (more) rest = split(rest, childcommand, ' '); } while (more); argv[index] = 0; // replace by command. Expand using PATH-environment-var. execvp(syscmd, argv); // If something goes wrong, we end up here: lyxerr << "LyX: execvp failed: " << strerror(errno) << endl; } else if (cpid < 0) { // error lyxerr << "LyX: Could not fork: " << strerror(errno) << endl; } else { // parent return cpid; } return 0; } // Reuse of instance int Systemcalls::startscript(Starttype how, string const & what, Callbackfct cback) { start = how; command = what; cbk = cback; pid = (pid_t) 0; // yet no child retval = 0; return startscript(); } // // Mini-Test-environment for script-classes // #ifdef TEST_MAIN #include int SimulateTimer; void back(string cmd, int retval) { printf("Done: %s gave %d\n", cmd.c_str(), retval); SimulateTimer = 0; } int main(int, char**) { SystemcallsSingletoncontroller::Startcontroller starter; SystemcallsSingletoncontroller *contr=starter.GetController(); Systemcalls one(Systemcalls::System, "ls -ltag", back); Systemcalls two(Systemcalls::Wait, "ls -ltag", back); SimulateTimer = 1; Systemcalls three(Systemcalls::DontWait , "ls -ltag", back); // Simulation of timer while (SimulateTimer) { sleep(1); contr->Timer(); } } #endif