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; }