1999-09-27 18:44:28 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#ifdef __GNUG__
|
|
|
|
#pragma implementation
|
|
|
|
#endif
|
|
|
|
|
1999-12-13 00:05:34 +00:00
|
|
|
#include <cerrno>
|
1999-09-27 18:44:28 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
1999-12-13 00:05:34 +00:00
|
|
|
#include <csignal>
|
1999-10-02 16:21:10 +00:00
|
|
|
#include <cstdlib>
|
1999-09-27 18:44:28 +00:00
|
|
|
#include <unistd.h>
|
1999-10-12 21:37:10 +00:00
|
|
|
#include "debug.h"
|
1999-09-27 18:44:28 +00:00
|
|
|
#include "syscall.h"
|
|
|
|
#include "syscontr.h"
|
1999-10-02 16:21:10 +00:00
|
|
|
#include "support/lstrings.h"
|
2000-01-17 21:01:30 +00:00
|
|
|
#include "support/lyxlib.h"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2000-03-28 02:18:55 +00:00
|
|
|
using std::endl;
|
|
|
|
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
Systemcalls::Systemcalls() {
|
1999-11-04 01:40:20 +00:00
|
|
|
pid = 0; // No child yet
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
Systemcalls::Systemcalls(Starttype how, string const & what, Callbackfct cback)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
|
|
|
start = how;
|
|
|
|
command = what;
|
|
|
|
cbk = cback;
|
1999-12-13 00:05:34 +00:00
|
|
|
pid = static_cast<pid_t>(0);
|
1999-09-27 18:44:28 +00:00
|
|
|
retval = 0;
|
1999-10-12 21:37:10 +00:00
|
|
|
startscript();
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
Systemcalls::~Systemcalls() {
|
|
|
|
#if 0
|
|
|
|
// If the child is alive, we have to brutally kill it
|
|
|
|
if (getpid() != 0) {
|
2000-01-17 21:01:30 +00:00
|
|
|
lyx::kill(getpid(), SIGKILL);
|
1999-10-12 21:37:10 +00:00
|
|
|
}
|
|
|
|
#endif
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Start a childprocess
|
|
|
|
//
|
|
|
|
// if child runs in background, add information to global controller.
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
int Systemcalls::startscript() {
|
1999-09-27 18:44:28 +00:00
|
|
|
retval = 0;
|
|
|
|
switch (start) {
|
|
|
|
case System:
|
2000-09-05 13:16:19 +00:00
|
|
|
case SystemDontWait:
|
1999-09-27 18:44:28 +00:00
|
|
|
retval = system(command.c_str());
|
1999-10-12 21:37:10 +00:00
|
|
|
callback();
|
1999-09-27 18:44:28 +00:00
|
|
|
break;
|
|
|
|
case Wait:
|
1999-10-12 21:37:10 +00:00
|
|
|
pid = fork();
|
1999-09-27 18:44:28 +00:00
|
|
|
if (pid>0) { // Fork succesful. Wait for child
|
|
|
|
waitForChild();
|
1999-10-12 21:37:10 +00:00
|
|
|
callback();
|
1999-09-27 18:44:28 +00:00
|
|
|
} else
|
|
|
|
retval = 1;
|
|
|
|
break;
|
|
|
|
case DontWait:
|
1999-10-12 21:37:10 +00:00
|
|
|
pid = fork();
|
1999-09-27 18:44:28 +00:00
|
|
|
if (pid>0) {
|
|
|
|
// Now integrate into Controller
|
|
|
|
SystemcallsSingletoncontroller::Startcontroller starter;
|
1999-10-12 21:37:10 +00:00
|
|
|
SystemcallsSingletoncontroller * contr = starter.getController();
|
|
|
|
// Add this to controller
|
|
|
|
contr->addCall(*this);
|
1999-09-27 18:44:28 +00:00
|
|
|
} else
|
|
|
|
retval = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
1999-12-13 21:59:26 +00:00
|
|
|
void Systemcalls::kill(int /*tolerance*/) {
|
1999-10-12 21:37:10 +00:00
|
|
|
if (getpid() == 0) {
|
|
|
|
lyxerr << "LyX: Can't kill non-existing process." << endl;
|
|
|
|
return;
|
|
|
|
}
|
2000-01-17 21:01:30 +00:00
|
|
|
int ret = lyx::kill(getpid(), SIGHUP);
|
1999-10-12 21:37:10 +00:00
|
|
|
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
|
2000-04-26 13:57:28 +00:00
|
|
|
|
|
|
|
// CHECK Implement this using the timer of
|
|
|
|
// the singleton systemcontroller (Asger)
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
// Wait for child process to finish. Returns returncode from child.
|
1999-10-12 21:37:10 +00:00
|
|
|
void Systemcalls::waitForChild() {
|
1999-09-27 18:44:28 +00:00
|
|
|
// 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) {
|
1999-10-12 21:37:10 +00:00
|
|
|
lyxerr << "LyX: Error waiting for child:" << strerror(errno) << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
wait = false;
|
|
|
|
} else if (WIFEXITED(status)) {
|
|
|
|
// Child exited normally. Update return value.
|
|
|
|
retval = WEXITSTATUS(status);
|
|
|
|
wait = false;
|
|
|
|
} else if (WIFSIGNALED(status)) {
|
1999-10-07 18:44:17 +00:00
|
|
|
lyxerr << "LyX: Child didn't catch signal "
|
1999-10-12 21:37:10 +00:00
|
|
|
<< WTERMSIG(status)
|
|
|
|
<< "and died. Too bad." << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
wait = false;
|
|
|
|
} else if (WIFSTOPPED(status)) {
|
1999-10-12 21:37:10 +00:00
|
|
|
lyxerr << "LyX: Child (pid: " << pid
|
1999-10-07 18:44:17 +00:00
|
|
|
<< ") stopped on signal "
|
1999-10-12 21:37:10 +00:00
|
|
|
<< WSTOPSIG(status)
|
1999-10-07 18:44:17 +00:00
|
|
|
<< ". Waiting for child to finish." << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
} else {
|
1999-10-07 18:44:17 +00:00
|
|
|
lyxerr << "LyX: Something rotten happened while "
|
1999-10-12 21:37:10 +00:00
|
|
|
"waiting for child " << pid << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
wait = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// generate child in background
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
pid_t Systemcalls::fork()
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
1999-10-12 21:37:10 +00:00
|
|
|
pid_t cpid= ::fork();
|
1999-09-27 18:44:28 +00:00
|
|
|
if (cpid == 0) { // child
|
1999-10-02 16:21:10 +00:00
|
|
|
string childcommand(command); // copy
|
|
|
|
string rest = split(command, childcommand, ' ');
|
1999-09-27 18:44:28 +00:00
|
|
|
const int MAX_ARGV = 255;
|
1999-10-02 16:21:10 +00:00
|
|
|
char *syscmd = 0;
|
1999-09-27 18:44:28 +00:00
|
|
|
char *argv[MAX_ARGV];
|
|
|
|
int index = 0;
|
1999-10-12 21:37:10 +00:00
|
|
|
bool more;
|
1999-09-27 18:44:28 +00:00
|
|
|
do {
|
2000-06-12 11:27:15 +00:00
|
|
|
childcommand = frontStrip(childcommand);
|
1999-10-02 16:21:10 +00:00
|
|
|
if (syscmd == 0) {
|
|
|
|
syscmd = new char[childcommand.length() + 1];
|
|
|
|
childcommand.copy(syscmd, childcommand.length());
|
|
|
|
syscmd[childcommand.length()] = '\0';
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
2000-06-12 11:27:15 +00:00
|
|
|
if (!childcommand.empty()) {
|
1999-10-02 16:21:10 +00:00
|
|
|
char * tmp = new char[childcommand.length() + 1];
|
|
|
|
childcommand.copy(tmp, childcommand.length());
|
|
|
|
tmp[childcommand.length()] = '\0';
|
|
|
|
argv[index++] = tmp;
|
2000-06-12 11:27:15 +00:00
|
|
|
}
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
// reinit
|
1999-10-12 21:37:10 +00:00
|
|
|
more = !rest.empty();
|
|
|
|
if (more)
|
1999-10-02 16:21:10 +00:00
|
|
|
rest = split(rest, childcommand, ' ');
|
1999-10-12 21:37:10 +00:00
|
|
|
} while (more);
|
1999-10-02 16:21:10 +00:00
|
|
|
argv[index] = 0;
|
1999-09-27 18:44:28 +00:00
|
|
|
// replace by command. Expand using PATH-environment-var.
|
|
|
|
execvp(syscmd, argv);
|
|
|
|
// If something goes wrong, we end up here:
|
1999-10-12 21:37:10 +00:00
|
|
|
lyxerr << "LyX: execvp failed: " << strerror(errno) << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
} else if (cpid < 0) { // error
|
1999-10-12 21:37:10 +00:00
|
|
|
lyxerr << "LyX: Could not fork: " << strerror(errno) << endl;
|
1999-09-27 18:44:28 +00:00
|
|
|
} else { // parent
|
|
|
|
return cpid;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Reuse of instance
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
int Systemcalls::startscript(Starttype how, string const & what,
|
|
|
|
Callbackfct cback)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
|
|
|
start = how;
|
|
|
|
command = what;
|
|
|
|
cbk = cback;
|
1999-12-13 00:05:34 +00:00
|
|
|
pid = static_cast<pid_t>(0); // yet no child
|
1999-09-27 18:44:28 +00:00
|
|
|
retval = 0;
|
2000-09-05 13:16:19 +00:00
|
|
|
|
|
|
|
if (how == SystemDontWait) {
|
|
|
|
#ifndef __EMX__
|
|
|
|
command += " &";
|
|
|
|
#else
|
|
|
|
// OS/2 cmd.exe has another use for '&'
|
|
|
|
// This is not NLS safe, but it's OK, I think.
|
|
|
|
string sh = OnlyFilename(GetEnvPath("EMXSHELL"));
|
|
|
|
if (sh.empty()) {
|
|
|
|
// COMSPEC is set, unless user unsets
|
|
|
|
sh = OnlyFilename(GetEnvPath("COMSPEC"));
|
|
|
|
if (sh.empty())
|
|
|
|
sh = "cmd.exe";
|
|
|
|
}
|
|
|
|
sh = lowercase(sh);
|
|
|
|
if (contains(sh, "cmd.exe")
|
|
|
|
|| contains(sh, "4os2.exe"))
|
|
|
|
command = "start /min/n " + command;
|
|
|
|
else
|
|
|
|
command += " &";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1999-10-12 21:37:10 +00:00
|
|
|
return startscript();
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Mini-Test-environment for script-classes
|
|
|
|
//
|
|
|
|
#ifdef TEST_MAIN
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
|
|
int SimulateTimer;
|
1999-10-02 16:21:10 +00:00
|
|
|
void back(string cmd, int retval)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
|
|
|
printf("Done: %s gave %d\n", cmd.c_str(), retval);
|
|
|
|
SimulateTimer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-02-29 02:19:17 +00:00
|
|
|
int main(int, char **)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
SystemcallsSingletoncontroller::Startcontroller starter;
|
1999-11-15 10:54:16 +00:00
|
|
|
SystemcallsSingletoncontroller *contr= starter.GetController();
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
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
|