/*
* processes.cc
*
* This file is part of NEST.
*
* Copyright (C) 2004 The NEST Initiative
*
* NEST 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 2 of the License, or
* (at your option) any later version.
*
* NEST 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 NEST. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <climits>
#include <cstdlib>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <iostream>
#include <string>
// sstream has functions std::?stringstream
// strstream has functions std::?strstream
// HEP 2002-10-06
#ifdef HAVE_SSTREAM
#include <sstream>
#else
#include <strstream>
#endif
#ifdef HAVE_ALPHA_CXX_STD_BUG
#undef __PURE_CNAME
#include <cerrno>
#define __PURE_CNAME
#else
#include <cerrno>
#endif
#include <vector>
#include "processes.h"
#include "integerdatum.h" // Include the data-types we use!
#include "arraydatum.h"
#include "stringdatum.h"
#include "namedatum.h"
#include "booldatum.h"
#include "dictdatum.h" // for signaldict
#include "iostreamdatum.h"
#include "dictutils.h"
#include "tokenutils.h"
#include "interpret.h" // for SLI Interpreter and messaging mechanism
#include "dict.h" // for TokenMap
#include "sliexceptions.h"
#include "fdstream.h"
#ifndef _POSIX_SOURCE
#define _SYNOD__SET_POSIX_SOURCE
#define _POSIX_SOURCE
#endif
// definition of static variables and functions declared in processes.h:
pid_t Processes::children_group = 0;
// The following concernes the new module: -----------------------
// This will be used to produce systemerror-messages
const std::string Processes::systemerror(SLIInterpreter * i)
{
Token errordict_t(i->baselookup(i->errordict_name));
assert(errordict_t.datum() != NULL);
DictionaryDatum errordict_d= *dynamic_cast<DictionaryDatum *>(errordict_t.datum());
std::string ErrorMessage(std::strerror(errno));
errordict_d->insert (Name("sys_errname"), new LiteralDatum (ErrorMessage) );
errordict_d->insert (Name("sys_errno") , new IntegerDatum (errno) );
return "SystemError";
}
int Processes::fd(std::istream *s)
{
if (s == &std::cin)
{
return STDIN_FILENO;
}
else
{
ifdstream * fs = dynamic_cast<ifdstream*>(s);
assert (fs != NULL);
return fs->rdbuf()->fd();
}
}
int Processes::fd(std::ostream *s)
{
if (s == &std::cout)
{
return STDOUT_FILENO;
}
else if ( (s == &std::cerr) || (s == &std::clog) )
{
return STDERR_FILENO;
}
else
{
ofdstream * fs = dynamic_cast<ofdstream*>(s);
assert (fs != NULL);
return fs->rdbuf()->fd();
}
}
// end of definition of static variables and functions
const std::string Processes::name(void) const
{
return std::string("basic process management"); // Return name of the module
}
const std::string Processes::commandstring(void) const
{
return std::string("/processes /C++ ($Revision: 10020 $) provide-component /processes /SLI (1.7) require-component");
}
void Processes::init(SLIInterpreter *i)
{
//Create Dictionary "signaldict", which will contain the system's signal values:
Dictionary * signaldict = new Dictionary; //get a new dictionary from the heap
signaldict->insert( SIGABRT_name, new IntegerDatum(SIGABRT) ); //There is a typeconversion operator Datum<->Token !
signaldict->insert( SIGALRM_name, new IntegerDatum(SIGALRM) );
signaldict->insert( SIGFPE_name, new IntegerDatum(SIGFPE) );
signaldict->insert( SIGHUP_name, new IntegerDatum(SIGHUP) );
signaldict->insert( SIGILL_name, new IntegerDatum(SIGILL) );
signaldict->insert( SIGINT_name, new IntegerDatum(SIGINT) );
signaldict->insert( SIGKILL_name, new IntegerDatum(SIGKILL) );
signaldict->insert( SIGPIPE_name, new IntegerDatum(SIGPIPE) );
signaldict->insert( SIGQUIT_name, new IntegerDatum(SIGQUIT) );
signaldict->insert( SIGSEGV_name, new IntegerDatum(SIGSEGV) );
signaldict->insert( SIGTERM_name, new IntegerDatum(SIGTERM) );
signaldict->insert( SIGUSR1_name, new IntegerDatum(SIGUSR1) );
signaldict->insert( SIGUSR2_name, new IntegerDatum(SIGUSR2) );
signaldict->insert( SIGCHLD_name, new IntegerDatum(SIGCHLD) );
signaldict->insert( SIGCONT_name, new IntegerDatum(SIGCONT) );
signaldict->insert( SIGSTOP_name, new IntegerDatum(SIGSTOP) );
signaldict->insert( SIGTSTP_name, new IntegerDatum(SIGTSTP) );
signaldict->insert( SIGTTIN_name, new IntegerDatum(SIGTTIN) );
signaldict->insert( SIGTTOU_name, new IntegerDatum(SIGTTOU) );
i->def( signaldict_name, new DictionaryDatum(signaldict) );
//DictionaryDatum(signaldict) makes a lockPTR from the ordinary pointer.
// The datum stored in the signaldict-token will thus be a lockPTR to a dictionary
// create variables "sys_errname" and "sys_errno"
// and all needed errornumbers in errordict
Token errordict_t(i->baselookup(i->errordict_name));
assert(errordict_t.datum() != NULL);
DictionaryDatum errordict_d= *dynamic_cast<DictionaryDatum *>(errordict_t.datum());
errordict_d->insert (sys_errname, new LiteralDatum ("") );
errordict_d->insert (sys_errno , new IntegerDatum (0) );
errordict_d->insert (E2BIG_name, new IntegerDatum (E2BIG) );
errordict_d->insert (EACCES_name, new IntegerDatum (EACCES) );
errordict_d->insert (EAGAIN_name, new IntegerDatum (EAGAIN) );
errordict_d->insert (EBADF_name, new IntegerDatum (EBADF) );
errordict_d->insert (EBUSY_name, new IntegerDatum (EBUSY) );
errordict_d->insert (ECHILD_name, new IntegerDatum (ECHILD) );
errordict_d->insert (EDEADLK_name, new IntegerDatum (EDEADLK) );
errordict_d->insert (EDOM_name, new IntegerDatum (EDOM) );
errordict_d->insert (EEXIST_name, new IntegerDatum (EEXIST) );
errordict_d->insert (EFAULT_name, new IntegerDatum (EFAULT) );
errordict_d->insert (EFBIG_name, new IntegerDatum (EFBIG) );
errordict_d->insert (EINTR_name, new IntegerDatum (EINTR) );
errordict_d->insert (EINVAL_name, new IntegerDatum (EINVAL) );
errordict_d->insert (EIO_name, new IntegerDatum (EIO) );
errordict_d->insert (EISDIR_name, new IntegerDatum (EISDIR) );
errordict_d->insert (EMFILE_name, new IntegerDatum (EMFILE) );
errordict_d->insert (EMLINK_name, new IntegerDatum (EMLINK) );
errordict_d->insert (ENAMETOOLONG_name, new IntegerDatum (ENAMETOOLONG) );
errordict_d->insert (ENFILE_name, new IntegerDatum (ENFILE) );
errordict_d->insert (ENODEV_name, new IntegerDatum (ENODEV) );
errordict_d->insert (ENOENT_name, new IntegerDatum (ENOENT) );
errordict_d->insert (ENOEXEC_name, new IntegerDatum (ENOEXEC) );
errordict_d->insert (ENOLCK_name, new IntegerDatum (ENOLCK) );
errordict_d->insert (ENOMEM_name, new IntegerDatum (ENOMEM) );
errordict_d->insert (ENOSPC_name, new IntegerDatum (ENOSPC) );
errordict_d->insert (ENOSYS_name, new IntegerDatum (ENOSYS) );
errordict_d->insert (ENOTDIR_name, new IntegerDatum (ENOTDIR) );
errordict_d->insert (ENOTEMPTY_name, new IntegerDatum (ENOTEMPTY) );
errordict_d->insert (ENOTTY_name, new IntegerDatum (ENOTTY) );
errordict_d->insert (ENXIO_name, new IntegerDatum (ENXIO) );
errordict_d->insert (EPERM_name, new IntegerDatum (EPERM) );
errordict_d->insert (EPIPE_name, new IntegerDatum (EPIPE) );
errordict_d->insert (ERANGE_name, new IntegerDatum (ERANGE) );
errordict_d->insert (EROFS_name, new IntegerDatum (EROFS) );
errordict_d->insert (ESPIPE_name, new IntegerDatum (ESPIPE) );
errordict_d->insert (ESRCH_name, new IntegerDatum (ESRCH) );
errordict_d->insert (EXDEV_name, new IntegerDatum (EXDEV) );
// ...don't forget to create the new SLI-commands!
i->createcommand("fork",& forkfunction);
i->createcommand("sysexec_a",& sysexec_afunction);
i->createcommand("waitPID",& waitPIDfunction);
i->createcommand("kill",& killfunction);
i->createcommand("pipe",& pipefunction);
i->createcommand("dup2_is_is",& dup2_is_isfunction);
i->createcommand("dup2_os_os",& dup2_os_osfunction);
i->createcommand("dup2_is_os",& dup2_is_osfunction);
i->createcommand("dup2_os_is",& dup2_os_isfunction);
i->createcommand("available",& availablefunction);
i->createcommand("getPID",& getpidfunction);
i->createcommand("getPPID",& getppidfunction);
i->createcommand("getPGRP",& getpgrpfunction);
i->createcommand("mkfifo",& mkfifofunction);
i->createcommand("setNONBLOCK",& setnonblockfunction);
i->createcommand("ctermid",& ctermidfunction);
i->createcommand("isatty_os",& isatty_osfunction);
i->createcommand("isatty_is",& isatty_isfunction);
}
Processes::~Processes()
{}
// ---------------------------------------------------------------
// The following concernes the new command(s): -------------------
void Processes::ForkFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
pid_t pid;
pid = fork();
if (pid < 0)
i->raiseerror(systemerror(i)); // ehemals:i->raiseerror ("CannotFork");
else
{
if (pid != 0)
{// I am the parent. pid is the PID of the new child.
#ifdef HAVE_SSTREAM
std::stringstream s;
s << "Child PID: " << pid << "\n";
i->message(SLIInterpreter::M_DEBUG, "fork",s.str().c_str());
#endif
// if (Processes::children_group == 0)
// {
// std::cerr << "Parent: Creating and putting child into new process group ";
// int result = setpgid(pid,pid);
// if (result < 0) i->raiseerror(systemerror(i));
// Processes::children_group = pid;
// std::cerr << Processes::children_group << std::endl;
// }
// else
// {
// std::cerr << "Parent: Putting child into process group " << Processes::children_group << std::endl;
// int result = setpgid(pid,Processes::children_group);
// if (result < 0) i->raiseerror(systemerror(i));
// }
}
else // for the child
{
// In case we are in debug_mode, we need to switch it off
// Otherwise the debug prompt will disturb further processing.
i->debug_mode_off();
}
i->EStack.pop(); // Don't forget to pop yourself...
Token result_token( new IntegerDatum(pid) ); // Make Token, containing IntegerDatum, which is initialized to pid;
i->OStack.push_move(result_token);
}
}
void Processes::Sysexec_aFunction::execute(SLIInterpreter *i) const
{
assert( i->OStack.load() != 0 );
Token array_token;
i->OStack.pop_move(array_token); // move topmost Token into namearray_token
ArrayDatum *array = dynamic_cast<ArrayDatum *> (array_token.datum()); // this is an array of tokens (to names)
assert (array != NULL);
assert (array->size() > 0); // need at least the commandname
// The following array is needed to supply the function execvp with a C
// string array. Thus, the supplied array of SLI strings must be converted.
// argv is deleted right after the call to execvp(command, const_cast<char * const *> (argv) );
//
// **argv denotes an pointer to an array which is allocated dynamically
// the old formulation char *argv[array->size() + 1]; is no longer legal c++ (Ruediger!!)
char **argv= new char*[array->size() + 1];
for (unsigned int j=0; j < array->size(); j++) // forall in array
{
StringDatum * nd = dynamic_cast<StringDatum *> ( (*array)[j].datum() );
assert( nd != NULL);
argv[j] = const_cast<char *>(nd->c_str()); // StringDatum is derived from class string.
}
char * command = argv[0];
argv[array->size()] = NULL;
int result = execvp(command, argv );
// int result = execvp(command, const_cast<char * const *> (argv) );
delete [] argv;
if (result == -1)
{// an error occured!
i->OStack.push_move(array_token); // restore operand stack
i->raiseerror(systemerror(i));
}
}// auto-destroy namearray_token and free its datum.
void Processes::WaitPIDFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
assert( i->OStack.load() >= 2 ); // waitPID takes 2 arguments
// Read arguments from operand Stack, but leave tokens on stack:
IntegerDatum * pidin_d = dynamic_cast<IntegerDatum *> ( i->OStack.pick(1).datum() );
assert( pidin_d != NULL);
BoolDatum * nohangflag_d = dynamic_cast<BoolDatum *> ( i->OStack.top().datum() );
assert( nohangflag_d != NULL);
// call waitpid()
int stat_value;
int options=0;
if (*nohangflag_d)
options=WNOHANG;
pid_t pidout=waitpid(pidin_d->get(), &stat_value, options);
// Check for error
if (pidout == -1) // an Error occured
{
i->raiseerror(systemerror(i));
}
else if (pidout == 0) // NoHangFlag was set, and no information was ready
{
i->EStack.pop();
i->OStack.pop();
i->OStack.pop(); // We will oly leave one result on stack: 0
i->OStack.push(0); // Push 0 on stack.
}
else // child exited
{
// push result
Token pidout_t( new IntegerDatum(pidout) ); // Make Token, containing IntegerDatum, which is initialized to pidout;
i->OStack.push_move(pidout_t); // Push on stack by moving the contents of this token.
// Ostack is now: pidin(int) nohangflag(bool) pidout(int)
// first 2 Tokens will be reused: status(int) normalexitflag(bool) pidout(int)
IntegerDatum * status_d = pidin_d; // This is meant to produce clearity, not confusion!
BoolDatum * normalexitflag_d = nohangflag_d; // just a renaming of variables!
// check status
if WIFEXITED(stat_value) // child exited normally
{
i->EStack.pop();
(*normalexitflag_d) = true;
(*status_d) = WEXITSTATUS(stat_value); // return exit status
}
else if WIFSIGNALED(stat_value) // child terminated due to a sgnal that was not caught
{
i->EStack.pop();
(*normalexitflag_d) = false;
(*status_d) = WTERMSIG(stat_value); // return number of terminating signal
}
else
{
i->OStack.pop(); //restore OStack before raising an error
i->raiseerror ("UnhandledExitOfChild");
}
}
}
void Processes::KillFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
assert( i->OStack.load() >= 2 ); // kill takes 2 arguments
// Read arguments from operand Stack, but leave tokens on stack:
IntegerDatum * pid_d = dynamic_cast<IntegerDatum *> ( i->OStack.pick(1).datum() );
assert( pid_d != NULL);
IntegerDatum * signal_d = dynamic_cast<IntegerDatum *> ( i->OStack.top().datum() );
assert( signal_d != NULL);
// call kill()
int result = kill( pid_d->get(), signal_d->get() );
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
i->EStack.pop(); //pop command from execution stack
i->OStack.pop(2); //pop arguments from operand stack
}
}
void Processes::PipeFunction::execute(SLIInterpreter *i) const
{
// call pipe()
int filedes[2];
int result = pipe( filedes );
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
ifdstream *in = new ifdstream(filedes[0]);
ofdstream *out = new ofdstream(filedes[1]);
Token in_t(new IstreamDatum(in ));
Token out_t(new OstreamDatum(out));
i->OStack.push_move( in_t );
i->OStack.push_move( out_t );
i->EStack.pop(); //pop command from execution stack
}
}
void Processes::Dup2_is_isFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
assert( i->OStack.load() >= 2 ); // dup2 takes 2 arguments
// Read arguments from operand Stack, but leave tokens on stack:
IstreamDatum * s_d1 = dynamic_cast<IstreamDatum *>( i->OStack.pick(1).datum() );
assert( s_d1 != NULL);
IstreamDatum * s_d2 = dynamic_cast<IstreamDatum *>( i->OStack.top().datum() );
assert( s_d2 != NULL);
// call dup2();
//int result = dup2( fd(s_d1->get()) , fd(s_d2->get()) );//using get() on a LockPTR will lock the PointerObject!
//This would result in a failed assertion at the next operation on that Datum
// (if we don not unlock it explicitely again)
int result = dup2( fd(**s_d1) , fd(**s_d2) );//so we use operator* instead
//LockPTRs can be used like ordinary pointers!!! (*s_d1 is a LockPTR on an istream)
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
i->EStack.pop(); //pop command from execution stack
i->OStack.pop(2); //pop operands from operand stack
}
}
void Processes::Dup2_os_osFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
assert( i->OStack.load() >= 2 ); // dup2 takes 2 arguments
// Read arguments from operand Stack, but leave tokens on stack:
OstreamDatum * s_d1 = dynamic_cast<OstreamDatum *>( i->OStack.pick(1).datum() );
assert( s_d1 != NULL);
OstreamDatum * s_d2 = dynamic_cast<OstreamDatum *>( i->OStack.top().datum() );
assert( s_d2 != NULL);
// call dup2();
int result = dup2( fd(**s_d1) , fd(**s_d2) );//for comments on LockPTRs see Dup2_is_isFunction::execute
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
i->EStack.pop(); //pop command from execution stack
i->OStack.pop(2); //pop operands from operand stack
}
}
void Processes::Dup2_is_osFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
assert( i->OStack.load() >= 2 ); // dup2 takes 2 arguments
// Read arguments from operand Stack, but leave tokens on stack:
IstreamDatum * s_d1 = dynamic_cast<IstreamDatum *>( i->OStack.pick(1).datum() );
assert( s_d1 != NULL);
OstreamDatum * s_d2 = dynamic_cast<OstreamDatum *>( i->OStack.top().datum() );
assert( s_d2 != NULL);
// call dup2();
//int result = dup2( fd(s_d1->get()) , fd(s_d2->get()) );//using get() on a LockPTR will lock the PointerObject!
//This would result in a failed assertion at the next operation on that Datum
// (if we don not unlock it explicitely again)
int result = dup2( fd(**s_d1) , fd(**s_d2) );//so we use operator* instead
//LockPTRs can be used like ordinary pointers!!! (*s_d1 is a LockPTR on an istream)
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
i->EStack.pop(); //pop command from execution stack
i->OStack.pop(2); //pop operands from operand stack
}
}
void Processes::Dup2_os_isFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
assert( i->OStack.load() >= 2 ); // dup2 takes 2 arguments
// Read arguments from operand Stack, but leave tokens on stack:
OstreamDatum * s_d1 = dynamic_cast<OstreamDatum *>( i->OStack.pick(1).datum() );
assert( s_d1 != NULL);
IstreamDatum * s_d2 = dynamic_cast<IstreamDatum *>( i->OStack.top().datum() );
assert( s_d2 != NULL);
// call dup2();
int result = dup2( fd(**s_d1) , fd(**s_d2) );//for comments on LockPTRs see Dup2_is_isFunction::execute
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
i->EStack.pop(); //pop command from execution stack
i->OStack.pop(2); //pop operands from operand stack
}
}
void Processes::AvailableFunction::execute(SLIInterpreter *i) const
{
assert( i->OStack.load() >= 1 ); // available takes 1 argument
IstreamDatum *istreamdatum=
dynamic_cast<IstreamDatum *>(i->OStack.top().datum());
assert(istreamdatum != 0); assert(istreamdatum->valid());
if ( !(**istreamdatum).good() )
{// istream not good. Do nothing. Return false.
i->EStack.pop();
i->OStack.push(false);
}
else
{// istream is good. Try to read from it.
// istreamdatum is a pointer to a LockPTR
// get filedescriptor: -
int fd = Processes::fd(**istreamdatum) ; //Get FileDescriptor
//-------------------------------
// Set Non-Blocking-Flag on this fd:
int flags=fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,flags|O_NONBLOCK);
// ------------------------------
// Start read attempt on this FILE:
// ---- Version 1: using errno to detect errors - not portable?? ----
// int peekchar = (**istreamdatum).peek();
// // Reset Fileflags --------------
// fcntl(fd,F_SETFL,flags); //reset to old value
// // ------------------------------
// if ( (peekchar==-1) && (errno!=EAGAIN) && (errno!=ESPIPE) )
// {// some unexpected error occured!
// i->raiseerror(systemerror(i));
// }
// else
// {// no error or EAGAIN or ESPIPE occured
// i->EStack.pop();
// bool result;
// if ( peekchar==-1 ) // errno==EAGAIN or errno==ESPIPE
// {// no data is currently available
// result = false; // no data is available
// (**istreamdatum).clear(); // Lower eof and error Flag
// }
// else
// {// the read attempt was successful.
// result = true; // data can be read
// }
// // leave result on OStack ---------
// if (result == true)
// {
// Token result_t = new BoolDatum( i->true_name);
// i->OStack.push_move(result_t);
// }
// else
// {
// Token result_t = new BoolDatum( i->false_name);
// i->OStack.push_move(result_t);
// }
// }
// }
// ----- End Version 1 ----
// ---- Version 2: Using .good() to detect errors. Pure C++ (apart from fcntl) ------
(**istreamdatum).peek();
// Reset Fileflags --------------
fcntl(fd,F_SETFL,flags); //reset to old value
// ------------------------------
bool result;
if ( !(**istreamdatum).good() )
{// an error occured. No data can be read.
// no data is currently available
result = false; // no data is available
(**istreamdatum).clear(); // Lower eof and error Flag
}
else
{// the read attempt was successful.
result = true; // data can be read
}
// leave result on OStack ---------
i->EStack.pop();
i->OStack.push(result);
}
// ----- End Version 2 ----
}
// ---------------------------------------------------------------
void Processes::GetPIDFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
pid_t pid;
pid = getpid();
if (pid < 0) i->raiseerror(systemerror(i)); // ehemals:i->raiseerror ("CannotFork");
else
{
i->EStack.pop(); // Don't forget to pop yourself...
Token result_token( new IntegerDatum(pid) ); // Make Token, containing IntegerDatum, which is initialized to pid;
i->OStack.push_move(result_token);
}
}
void Processes::GetPPIDFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
pid_t ppid;
ppid = getppid();
if (ppid < 0) i->raiseerror(systemerror(i)); // ehemals:i->raiseerror ("CannotFork");
else
{
i->EStack.pop(); // Don't forget to pop yourself...
Token result_token( new IntegerDatum(ppid) ); // Make Token, containing IntegerDatum, which is initialized to ppid;
i->OStack.push_move(result_token);
}
}
void Processes::GetPGRPFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
pid_t pgrp;
pgrp = getpgrp();
if (pgrp < 0) i->raiseerror(systemerror(i)); // ehemals:i->raiseerror ("CannotFork");
else
{
i->EStack.pop(); // Don't forget to pop yourself...
Token result_token( new IntegerDatum(pgrp) ); // Make Token, containing IntegerDatum, which is initialized to pgrp;
i->OStack.push_move(result_token);
}
}
void Processes::MkfifoFunction::execute(SLIInterpreter *i) const
{
// This is what happens, when the SLI-command is called:
assert( i->OStack.load() >= 1 ); // mkfifo takes 1 arguments
// Read arguments from operand Stack, but leave tokens on stack:
StringDatum * s_d = dynamic_cast<StringDatum *>( i->OStack.top().datum() );
assert( s_d != NULL);
// call mkfifo();
mode_t mode=S_IRWXU|S_IRWXG|S_IRWXO; // Try to give all permissions, modified only by the user`s umask.
int result = mkfifo( s_d->c_str() , mode );//StringDatum is derived from string
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
i->EStack.pop(); //pop command from execution stack
i->OStack.pop(); //pop operand from operand stack
}
}
void Processes::SetNonblockFunction::execute(SLIInterpreter *i) const
{
assert( i->OStack.load() >= 2 ); // setNONBLOCK takes 2 arguments
IstreamDatum *istreamdatum = dynamic_cast<IstreamDatum *>(i->OStack.pick(1).datum());
assert(istreamdatum != 0); assert(istreamdatum->valid());
BoolDatum * newflag_d = dynamic_cast<BoolDatum *> ( i->OStack.top().datum() );
assert( newflag_d != NULL);
// get filedescriptor:
// istreamdatum is a pointer to a LockPTR
int fd = Processes::fd(**istreamdatum) ; //Get FileDescriptor
//-------------------------------
// Get filestatus-flags on this fd:
int flags=fcntl(fd,F_GETFL);
if (flags == -1)
i->raiseerror(systemerror(i)); // an error occured!
// modify flags to the new value:
if (*newflag_d)
flags |= O_NONBLOCK; // set the flag
else
flags &= ~O_NONBLOCK; // erase the flag
// Set new filestatus-flags:
int result = fcntl(fd,F_SETFL,flags);
// ------------------------------
if (result == -1)
{// an error occured!
i->raiseerror(systemerror(i));
}
else
{// no error
// leave the istream on OStack
i->EStack.pop();
i->OStack.pop();
}
}
void Processes::CtermidFunction::execute(SLIInterpreter *i) const
{
char term[] = "\0";
std::string termid = ctermid(term);
i->OStack.push(Token(termid));
i->EStack.pop();
}
void Processes::Isatty_osFunction::execute(SLIInterpreter *i) const
{
assert( i->OStack.load() >= 1 );
// Read arguments from operand Stack, but leave tokens on stack:
OstreamDatum * s_d1 = dynamic_cast<OstreamDatum *>( i->OStack.pick(0).datum() );
assert(s_d1 != NULL);
int fd = Processes::fd(**s_d1) ; //Get FileDescriptor
i->OStack.pop();
if (isatty(fd))
{
i->OStack.push(Token(BoolDatum(true)));
}
else
{
i->OStack.push(Token(BoolDatum(false)));
}
i->EStack.pop();
}
void Processes::Isatty_isFunction::execute(SLIInterpreter *i) const
{
assert( i->OStack.load() >= 1 );
// Read arguments from operand Stack, but leave tokens on stack:
IstreamDatum * s_d1 = dynamic_cast<IstreamDatum *>( i->OStack.pick(0).datum() );
assert(s_d1 != NULL);
int fd = Processes::fd(**s_d1) ; //Get FileDescriptor
i->OStack.pop();
if (isatty(fd))
{
i->OStack.push(Token(BoolDatum(true)));
}
else
{
i->OStack.push(Token(BoolDatum(false)));
}
i->EStack.pop();
}
#ifdef _SYNOD__SET_POSIX_SOURCE
#undef _SYNOD__SET_POSIX_SOURCE
#undef _POSIX_SOURCE
#endif