system () mal anders



  • Hi

    system ("emerge world");
    

    wie könnte man mit einer anderen funktion system () ersetzen?

    vielen dank im voraus

    PS" Ich bin dabei mir ein programm zu coden wo man diese systemprogramme ausführt"



  • %windir%\\system\\blah.exe

    aber warum willst du system ersetzen?? warum das rad neu erfinden??



  • Moin!
    Gute Idee system() nicht zu verwenden. So richtig trivial ist es aber nicht etwas anderes zu verwenden. Im Grunde läuft es auf ein fork()-> exec() hinaus. Jedoch hast du damit ersteinmal nichts gewonnen. Entscheident ist die Kontrolle des ausgeführten Programmes. Das würde z.B. so gehen das du zunächst im Vater zwei Pipes erzeugst und im Sohn mit dup2() stdin und stdout des Sohnes in die Pipes umlenkst. Dann kannst du mit select() im Vater davon lesen wenn das Programm etwas nach stdin/stdout schreibt. Gleichzeitig erhälst du mit select() eine timeout Überwachung deines gestarteten Programmes. Feinheiten wie setsid() im Sohn führen dazu, das der Vater bei erreichen eines Timeouts alle Prozesse die der Sohn kreiert hat killen kann. Im Vater musst du dann noch eine sig-catch() Funktion erzeugen die das SIGCHLD abfängt und mit waitpid() den Returnwert fängt. Klasse sind call-back Funktionen in der select() schleife die z.B. jeweils eine Zeile die nach stdout/stderr geschrieben wurde an eine Funktion übergeben werden. Diese Funktion kann dann die Zeile untersuchen und ggf. zum frühzeitigen Abbruch des Programmes führen.

    Letztlich sind's bei mir ca. 577 Zeilen code. Aber es lohnt sich, da man dann endlich etwas gesichert ausführen kann.

    Gruß
    Karsten



  • das hört sich gut an
    kannst mir auch den code zeigen?
    danke schön



  • Hier der Source. Sei so nett und beachte OpenSource..

    /** @defgroup xlib
    /==============================================================================
    /
    / File: xexec.c
    /
    / Description:
    / ...
    / execute a external programm with given parameters. stdout/stderr will be
    / fetched and a appropiate call-back function is called to give the possibility
    / to scan the output. Also a timeout is included. All returnvalues will be
    / stored in a structure which is returned after execution.
    / ...
    /
    / Author:
    / K. Kankowski
    /
    / Version:
    / 0.0.1  initial     Sa 15.05.2004 - 10:33:50       Karsten
    /=============================================================================*/
    
    #include <xlib.h>
    
    extern char **environ;
    static int prog_returned = 0;
    
    static int stop_prog(execInfo_t info);
    static void prog_exit(int signr);
    
    /**
    /==============================================================================
    / @ingroup xlib
    /
    / FunctionName xexec
    /----------------------------------------------------------------------
    / Will be called by:
    / - divers
    /
    / Description
    / execute a given programm and return a filled xexecInfo_t
    / structure with appropiate data of the execution.
    / All needet data must befilled in the xexecInfo_t structure
    /
    / \param xeceInfo_t
    / \return xexecInfo_t Ptr otherwise NULL
    /=============================================================================/
    */
    execInfo_t
    xexec(int ac, char **av, char **env, execInfo_t exInfo)  {
    
       int sout[2] = { -1, -1 };        // pipe for stdout
       int eout[2] = { -1, -1 };        // pipe for stderr
       int sin[2] = { -1, -1 };         // pipe for stdin
       pid_t prog_pid;                  // process id of external programm
       msg_t msg_dat[3];             // msg structures for better handling
       sigfkt old_sigchild_handler = NULL;
    
       if(exInfo == NULL)   {
    
          xlog("xexec need a prefilled exInfo structur!");
          return(exInfo);
       }
    
       // make it more secure
       av[ac]=NULL;
       exInfo->retval = 0;
       if(env == NULL)
          env = environ;
    
       // check if we cann access the given programm
       if( access(av[0], F_OK )) {
    
          exInfo->retval = -1;
          exInfo->error = XEXEC_NOPROG;
          exInfo->ex_errno = errno;
          return (exInfo);
       }
    
       if( access(av[0], R_OK|X_OK )) {
    
          exInfo->retval = -1;
          exInfo->error = XEXEC_NOPERM;
          exInfo->ex_errno = errno;
          return (exInfo);
       }
    
       if(pipe(sout)<0) {
    
          exInfo->retval = -1;
          exInfo->error = XEXEC_NOPIPE;
          exInfo->ex_errno = errno;
    
       } else if(pipe(eout)<0) {
    
          exInfo->retval = -1;
          exInfo->error = XEXEC_NOPIPE;
          exInfo->ex_errno = errno;
    
       } else if(pipe(sin)<0) {
    
          exInfo->retval = -1;
          exInfo->error = XEXEC_NOPIPE;
          exInfo->ex_errno = errno;
       }
    
       prog_returned = 0;
       // install own signal handler for SIGCHLD and save the old one
       old_sigchild_handler = signal(SIGCHLD,prog_exit);
    
       if( exInfo->error == 0 ) {
    
          if(( prog_pid = fork()) == 0 ) {
    
             /*
             * This is the slave
             */
    
             // close the read side of pipes
             close(sout[0]);
             close(eout[0]);
             // close the write side of pipe
             close(sin[1]);
    
             if( dup2(sout[1], 1) < 0 ) {
    
                xlog("dup2() sout failed (%s)",strerror(errno));
                exit(1);
    
             } else if( dup2(eout[1], 2) < 0 ) {
    
                xlog("dup2() eout failed (%s)",strerror(errno));
                exit(1);
    
             } else if( dup2(sin[0], 0) < 0 ) {
    
                xlog("dup2() sin failed (%s)",strerror(errno));
                exit(1);
             }
    
             // make the slave the process leader for recursiv kill!
             setsid();
    
             if( execve(av[1],av+1,env) < 0 ) {
    
                char msg[PATH_MAX + 256];
                int len = 0;
    
                sprintf(msg,"Exec of %s failed",av[1]);
                len = strlen(msg);
                write(2, msg, len);
                exit(1);
             }
    
          } else if(prog_pid < 0 )   {
    
             exInfo->retval = -1;
             exInfo->error = XEXEC_NOFORK;
             exInfo->ex_errno = errno;
             xlog("fork() failed (%s)",strerror(errno));
    
          } else {
    
             /*
             * Master
             */
    
             pid_t parent = getppid();
             int end = 0, in_end = 0, out_end = 0, std_end = 0;
             int i = 0;
             int highfd = 0;
             int status = 0;
             int eintr_cnt = 0;
             fd_set rfds;
             fd_set wfds;
             struct timeval tv;
             time_t exitTime = time(NULL) + exInfo->timeout;
    
             // close the write side of pipes
             close(sout[1]); sout[1]=-1;
             close(eout[1]); eout[1]=-1;
    
             // close the read side of pipe
             close(sin[0]); sin[0]=-1;
    
             memset(msg_dat,0,sizeof(msg_dat));
    
             // fill the msg_t struct for stdout/stderr
             msg_dat[0].msg_fd = sout[0];
             msg_dat[1].msg_fd = eout[0];
             msg_dat[0].msg_callback = exInfo->stdout_callback;
             msg_dat[1].msg_callback = exInfo->stderr_callback;
    
             // fill the msg_t struct for stdin
             msg_dat[2].msg_fd = sin[1];
             msg_dat[2].msg_buffer = exInfo->stdin_buffer;
             msg_dat[2].msg_len = exInfo->stdin_len;
    
             exInfo->start = time(NULL);
             exInfo->exec_pid = prog_pid;
    
             highfd = sout[0];
    
             if(highfd < eout[0])
                highfd = eout[0];
    
             if(highfd < sin[1])
                highfd = sin[1];
    
             for( end = 0; end == 0; )  {
    
                tv.tv_sec = 1;
                tv.tv_usec = 0;
    
                FD_ZERO(&rfds);
                FD_ZERO(&wfds);
                FD_SET(sout[0],&rfds);
                FD_SET(eout[0],&rfds);
    
                if(in_end == 1 && std_end == 1)  {
    
                   highfd = sout[0];
                   if(highfd < eout[0])
                      highfd = eout[0];
                   close(sin[1]);
    
                } else {
    
                   FD_SET(sin[1],&wfds);
                }
    
                status = select(highfd + 1, &rfds, &wfds , NULL, &tv);
    
                // If an error ocurrs, or select was interrupt by a signal.
                if(status < 0) {
    
                   if( errno == EINTR && eintr_cnt++ < 10 )
                      continue;
    
                   end=1;
                   exInfo->retval = -1;
                   exInfo->error = XEXEC_SELECT;
                   break;
    
                }
    
                // If my parent is no longer alive (paranoia)
                if( kill( parent, 0 ) < 0 ) {
    
                   exInfo->retval = -1;
                   exInfo->error = XEXEC_NOPAR;
    
                   xlog("Parent process died. Will interrupt the "
                      "programm now.");
    
                   stop_prog(exInfo);
                   end=1;
                   break;
                }
    
                // If the given timeout is reached
                if(exInfo->timeout && (( exitTime - time(NULL)) < 0 )) {
    
                   exInfo->timeoutReached = 1;
                   exInfo->retval = -1;
                   exInfo->error = XEXEC_TIMEOUT;
    
                   xlog("Timeout reached, try to kill (%d)\n",prog_pid);
    
                   stop_prog(exInfo);
                   end = 1;
                   break;
                }
    
                // if stdin pipe write able
                if(FD_ISSET(msg_dat[2].msg_fd, &wfds)) {
    
                   // should we use our own stdin channel?
                   if(exInfo->use_stdin == 1) {
    
                      fcntl(sin[1], F_SETFL, O_NONBLOCK);
    
                      // read from stdin
                      while(!feof(stdin))  {
    
                         int tx = 0;
                         char ch[2];
    
                         if((tx = fread(ch, 1, 1, stdin)) < 0)  {
    
                            xlog("read from stdin failed (%s)",strerror(errno));
                            end = 1;
                            break;
                         }
    
                         if(tx == 0) {
    
                            std_end = 1;
                            break;
                         }
    
                         // write to stdin pipe
                         if((tx = write(sin[1], ch, 1)) < 0) {
    
                            if(errno != EAGAIN)  {
    
                               xlog("error on write to stdin (%s)\n",
                                  strerror(errno));
                               end = 1;
    
                            } else {
    
                               break;
                            }
                         }
                      }
    
                      fcntl(sin[1], F_SETFL, ~O_NONBLOCK);
    
                   } else {
    
                      std_end = 1;
                   }
    
                   // if we have data to write to stdin
                   if(msg_dat[2].msg_buffer != NULL)   {
    
                      int tx = 0;
    
                      fcntl(msg_dat[2].msg_fd, F_SETFL, O_NONBLOCK);
    
                      while(msg_dat[2].msg_wrote < msg_dat[2].msg_len)   {
    
                         tx = write(sin[1],
                               msg_dat[2].msg_buffer + msg_dat[2].msg_wrote,
                               msg_dat[2].msg_len - msg_dat[2].msg_wrote);
    
                         if(tx > 0)  {
    
                            exInfo->bytesToStdin =
                            msg_dat[2].msg_wrote += tx;
    
                         } else {
    
                            if(errno != EAGAIN)  {
    
                               xlog("error on write to stdin (%s)\n",
                                  strerror(errno));
                               end = 1;
    
                            } else {
    
                               break;
                            }
                         }
                      }
    
                      fcntl(msg_dat[2].msg_fd, F_SETFL, ~O_NONBLOCK);
    
                      if(msg_dat[2].msg_wrote == exInfo->stdin_len)   {
    
                         in_end = 1;
                      }
    
                   } else {
    
                      // set in_end to 1 while there are no data to write
                      in_end = 1;
                   }
                }
    
                // read data from stderr/out and call callback
                for(i = 0, end = 0; i < 2 ; i++) {
    
                   if(FD_ISSET(msg_dat[i].msg_fd,&rfds)) {
    
                      char ch[2];
                      char r = 0;
    
                      fcntl(msg_dat[i].msg_fd,F_SETFL,O_NONBLOCK);
    
                      while(!end && (r = read(msg_dat[i].msg_fd,ch,1))>0) {
    
                         if(msg_dat[i].msg_len >=
                            msg_dat[i].msg_buffer_size - 1) {
    
                            msg_dat[i].msg_buffer_size += 8192;
                            msg_dat[i].msg_buffer = (char *)XREALLOC(
                               msg_dat[i].msg_buffer,
                               msg_dat[i].msg_buffer_size);
                         }
    
                         if( ch[0] == '\n' && exInfo->call_block == 0 ) {
    
                            // insert '\n' in buffer
                            *(msg_dat[i].msg_buffer +
                               msg_dat[i].msg_len) = ch[0];
                            msg_dat[i].msg_len++;
    
                            // terminate buffer
                            *(msg_dat[i].msg_buffer+msg_dat[i].msg_len)=0;
                            msg_dat[i].msg_len++;
    
                            if(msg_dat[i].msg_callback) {
    
                               status = msg_dat[i].msg_callback(
                                  prog_pid,
                                  msg_dat[i].msg_buffer);
    
                               if(status == TERMINATE_PROG) {
    
                                  exInfo->retval = -1;
                                  exInfo->error = XEXEC_TERM;
    
                                  stop_prog(exInfo);
                                  end = 1;
                                  break;
                               }
                            }
    
                            msg_dat[i].msg_len=0;
    
                         } else {
    
                            if(i==0) exInfo->bytesOnStdout++;
                            if(i==1) exInfo->bytesOnStderr++;
    
                            *(msg_dat[i].msg_buffer +
                               msg_dat[i].msg_len) = ch[0];
    
                            msg_dat[i].msg_len++;
                         }
                      }
    
                      if( r == 0 ) // EOF
                         msg_dat[i].msg_end = 1;
    
                      fcntl(msg_dat[i].msg_fd,F_SETFL,~O_NONBLOCK);
                   }
    
                   // set end if stdout/stderr detect EOF
                   if(msg_dat[0].msg_end == 1 && msg_dat[1].msg_end == 1)   {
    
                      /*
                      * If call_line == 1 we call the callback function
                      * with whole msg_buffer instead after every line
                      */
                      if(exInfo->call_block ) {
    
                        for(i = 0; i < 2 ; i++)  {
    
                           if(msg_dat[i].msg_callback && msg_dat[i].msg_len) {
    
                              status = msg_dat[i].msg_callback(
                                 prog_pid,
                                 msg_dat[i].msg_buffer);
    
                              if(status == TERMINATE_PROG) {
    
                                 exInfo->retval = -1;
                                 exInfo->error = XEXEC_TERM;
    
                                 stop_prog(exInfo);
                                 end = 1;
                                 break;
                               }
                            }
                         }
                      }
    
                      out_end = 1;
                      break;
                   }
                }
    
                if(in_end == 1 && out_end == 1 && std_end == 1)
                   end = 1;
             }
          }
       }
    
       // clean up now!
       stop_prog(exInfo);
       // reinstall orig SIGCHLD handler
       signal(SIGCHLD,old_sigchild_handler);
    
       XFREE(msg_dat[0].msg_buffer);
       XFREE(msg_dat[1].msg_buffer);
    
       if(sout[0]!=-1) close(sout[0]);
       if(sout[1]!=-1) close(sout[1]);
       if(eout[0]!=-1) close(eout[0]);
       if(eout[1]!=-1) close(eout[1]);
    
       return (exInfo);
    }
    
    static int
    stop_prog(execInfo_t info) {
    
    #define MAXRETRYS 5
    
       int retrys = 0;
       int signr = SIGTERM;
       int loop = 0;
       pid_t retpid = 0;
    
       if(prog_returned) {
    
          /*
          * Programm was returned, so fetch the retval via waitpid
          */
          retpid = waitpid(info->exec_pid, &info->retState, WNOHANG);
    
          info->retState = WEXITSTATUS(info->retState);
    
          if( retpid > 0 ) {
    
             if(WIFSIGNALED(info->retState))
                xlog("Process don't caught signal!");
          }
    
       } else {
    
          /*
          * try kill the programm and fetch the retval via waitpid
          */
    
          do {
    
             kill( -info->exec_pid, SIGTERM );
    
             for(loop=0,retrys=0,retpid = 0; loop<2 && retpid == 0;
                loop++,retrys=0,signr=SIGKILL) {
    
                kill( -info->exec_pid, signr );
                sleep(1);
             }
    
             retpid = waitpid(info->exec_pid, &info->retState, WNOHANG);
    
             info->retState = WEXITSTATUS(info->retState);
    
             if( retpid > 0 ) {
    
                if(WIFSIGNALED(info->retState))
                   xlog("Process don't caught signal!");
    
                break;
             }
    
             sleep(1);
    
          } while( !prog_returned && retpid == 0 && ( ++retrys < MAXRETRYS));
       }
    
       info->duration = time(NULL) - info->start;
    
       return (info->retState);
    }
    
    static void
    prog_exit(int signr) {
    
       if(signr == SIGCHLD)
          prog_returned = 1;
    }
    

Anmelden zum Antworten