/* * 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