home *** CD-ROM | disk | FTP | other *** search
- #include "stk.h"
- #include <fcntl.h>
- #include <errno.h>
- #include <sys/param.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <signal.h>
-
-
- #define MAX_PROC_NUM 256 /*enough eh?*/
- #define MAX_ARGS_NO 256
-
- #define NO_REDIRECTION 0
- #define REDIRECTION_BY_FILE 1
- #define REDIRECTION_BY_STREAM 2
-
-
- /******** SIGUSR1 handler *******/
- static void su1_handler(){
- /* printf("SIGUSR1 arrived\n"); */
- }
- /*********************************/
-
- /**** Registering processes ****/
- static SCM proc_arr[MAX_PROC_NUM];
-
-
- static init_proc_table(){
- int i;
- for(i = 0; i<MAX_PROC_NUM; i++)
- proc_arr[i] = ntruth;
- }
-
- static int find_process(SCM prc){
- int i;
- int ret = -1;
- for(i = 0; i<MAX_PROC_NUM; i++){
- if(prc==proc_arr[i]){
- ret = i;
- break;
- }
- }
- return ret;
- }
-
- static int reg_process(SCM prc){
- int i;
- /* find slot */
- i = find_process(ntruth);
- if(i<0){
- gc_for_newcell();
- i = find_process(ntruth);
- }
- if (i < 0){
- err("Too many processes", NIL);
- return -1;
- }
- proc_arr[i] = prc;
- return 0;
- }
-
- static
- int find_slot(){
- int i;
- /* find slot */
- i = find_process(ntruth);
- if(i<0){
- gc_for_newcell();
- i = find_process(ntruth);
- }
- if (i < 0){
- err("Too many processes", NIL);
- return -1;
- }
- return i;
- }
-
- static int remove_process(SCM prc){
- int i;
- /* find slot */
- i = find_process(prc);
- if(i<0){
- err("unregistered process", prc);
- return -1;
- }
- proc_arr[i] = ntruth;
- return 0;
- }
-
-
-
-
-
- /**** gc-helpers *****/
- static void free_process( SCM process );
- static void mark_process( SCM process );
-
-
-
- static int tc_process;
-
- static extended_scheme_type process_type = {
- "process", /* name */
- 0, /* is_procp */
- mark_process, /* gc_mark_fct */
- free_process, /* gc_sweep_fct */
- NULL, /* apply_fct */
- NULL /* display_fct */
- };
-
-
-
- struct process_info {
- int pid; /* pid */
- char *commandLine; /* Cmdline used to start process */
- char redirection[3]; /* Types of redirection */
- struct obj *stream[3];
- };
-
- #define PROCESS(x) ((struct process_info *)(x->storage_as.extension.data))
- #define PROCESSP(x) (TYPEP (x, tc_process))
- #define NPROCESSP(x) (NTYPEP (x, tc_process))
- #define PROCPID(x) PROCESS(x)->pid
-
-
- extern char **sys_errlist;
-
- static char *stdStreams[3] = {
- "standard input", "standard output", "standard error",
- };
-
- static char *strName[3] = {
- "stdin", "stdout", "stderr",
- };
-
- static PRIMITIVE
- fork_process( SCM command, SCM args, SCM redirection, int run_async );
-
- PRIMITIVE
- run_process( SCM command, SCM args, SCM redirection ) {
- return fork_process(command, args, redirection, 1);
- }
-
- PRIMITIVE
- run_sync( SCM command, SCM args, SCM redirection ) {
- return fork_process(command, args, redirection, 0);
- }
-
- static PRIMITIVE
- fork_process( SCM command, SCM args, SCM redirection, int run_async ) {
- SCM pinfo, arg, pnames, ptypes;
- char *argv[MAX_ARGS_NO], msg[256], *files[3];
- int argc, pid, i;
- long flag;
- int pipes[3][2];
- int redirectionType[3];
- struct process_info *info;
- void *old_chld_sig_action;
- int svMask, usermask; int ok;
- int svMask1, mypid;
- usermask = (sigmask(SIGUSR1));
-
- /* Checking arguments and creating UNIX-style */
- /* arguments list */
-
- if( NSTRINGP( command ) )
- err("run-process: bad program name", command);
- i = find_slot();
- if( i < 0)
- return ntruth;
-
- NEWCELL(pinfo, tc_process);
- proc_arr[i] = pinfo;
-
- info = (struct process_info *) malloc( sizeof( struct process_info ) );
- PROCESS(pinfo) = info;
- /*
- *
- * Initializing info structure
- *
- */
-
- info->commandLine = strdup(CHARS( command ) );
-
- for( i = 0; i < 3; i++ ) {
- info->redirection[i] = NO_REDIRECTION;
- info->stream[i] = NIL;
- }
-
- argv[0] = CHARS( command );
-
- for( argc = 1; argc < MAX_ARGS_NO && NNULLP( args ); ++argc ) {
- if( NCONSP( args ) )
- err("run-process: bad arguments list", args);
-
- arg = CAR( args );
- args = CDR( args );
-
- if( NSTRINGP( arg ) ) {
- /* In future, may be I implement conversion from */
- /* non-string argument to the string, but today */
- /* I don't want to do that :) */
-
- err("run-process: bad argument -- must be string", arg);
- }
-
- argv[argc] = CHARS( arg );
- }
-
- if( argc == MAX_ARGS_NO )
- err("run-process: too many arguments (limit is 256)", args);
-
- argv[argc] = NULL;
-
-
- /* Parsing redirection's list and creating communication */
-
- if( NNULLP( redirection ) ) {
-
- for( i = 0; i < 3; ++i ) {
- if( NCONSP( redirection ) )
- err("run-process: wrong redirection's list", redirection);
-
- if( STRINGP( CAR( redirection ) ) ) {
-
- info->redirection[i] = REDIRECTION_BY_FILE;
- info->stream[i] = string_copy( CAR( redirection ) );
-
- /* redirectionType[i] = REDIRECTION_BY_FILE;
- files[i] = CHARS( CAR( redirection ) ); */
-
- pipes[i][0] = open(CHARS( CAR( redirection ) ),
- i == 0 ? O_RDONLY : O_WRONLY);
- if( pipes[i][0] < 0 ) {
- sprintf(msg, "run-process: can't redirect %s to file %s",
- stdStreams[i], CHARS( CAR( redirection ) ));
-
- err( msg, NIL );
- }
-
- redirection = CDR( redirection );
- continue;
- }
-
- if( BOOLEANP( CAR( redirection ) ) ) {
-
- if( CAR( redirection ) == truth ) {
- if( pipe( pipes[i] ) < 0 ) {
-
- sprintf(msg, "run-process: can't create stream for %s\n",
- stdStreams[i]
-
- );
- perror("Process");
- err( msg, NIL );
- }
-
- /* redirectionType[i] = REDIRECTION_BY_STREAM; */
-
- info->redirection[i] = REDIRECTION_BY_STREAM;
- }
-
- redirection = CDR( redirection );
- continue;
- }
-
- err("run-process: bad redirection type", CAR( redirection ));
- }
- }
-
-
- /* set handler to catch SIGUSR1 */
- signal(SIGUSR1,su1_handler);
-
- /* block user1 signal till parent will be ready */
- svMask1 = sigblock(usermask);
- mypid = getpid();
-
- /* Now, forking and catching the errors */
- pid = fork();
-
- if( pid < 0 ) {
- char msg[256];
-
- sprintf(msg,
- "run-process: can't create child process because of (see stderr)"
- );
- perror("CHILD process");
- err( msg, NIL );
- }
-
- /* Processing child's behavior */
-
- if( pid == 0 ) {
- if(run_async){
- svMask = sigblock(usermask);
- signal(SIGUSR1,su1_handler);
- /* send notification to parent that I'm ready */
- ok = kill(mypid,SIGUSR1);
- if(ok < 0) perror( "Sending to parent");
- sigpause(0);
- sigsetmask(svMask);
- /*
- * fprintf(stderr, "Mask: %x\n", usermask);
- * fprintf(stderr, "Child continues...");
- * perror("Child:");
- */
-
- setsid();
- }
-
- for( i = 0; i < 3; ++i ) {
- switch( info->redirection[i] ) {
-
- case REDIRECTION_BY_FILE:
- dup2( pipes[i][0], i );
- close( pipes[i][0] );
- break;
-
- case REDIRECTION_BY_STREAM:
- dup2( pipes[i][ i == 0 ? 0 : 1], i );
- close( pipes[i][0] );
- close( pipes[i][1] );
- break;
-
- default:
- break;
- }
- }
-
- for( i = 3; i < NOFILE; ++i )
- close( i );
-
-
- /* And then, EXEC'ing... */
-
- execvp( argv[0], argv );
-
- /* Unfortunatelly, we can't exec this process -- but */
- /* we can't tell 'bout this fact to our daddy. :( */
-
- fprintf(stderr, "Can't exec!");
- exit( 1 );
- }
-
- /* Ok, guys, we are still in the parent process. Making redirection */
- /* and filling-up PROCESS structure */
- PROCPID( pinfo ) = pid;
- if(!run_async) waitpid(pid);
- else {
- for( i = 0; i < 3; ++i ) {
- switch( info->redirection[i] ) {
- case REDIRECTION_BY_FILE:
- close( pipes[i][0] );
- break;
-
- case REDIRECTION_BY_STREAM:
- close( pipes[i][ i == 0 ? 0 : 1 ] );
-
- flag = no_interrupt(1);
-
- NEWCELL( info->stream[i], i == 0 ? tc_oport : tc_iport );
-
- if( (info->stream[i]->storage_as.port.f =
- fdopen( pipes[i][ i == 0 ? 1 : 0],
- i == 0 ? "w" : "r" )) == NULL )
- err("process-input: can't FDOPEN stream", pinfo);
-
- sprintf(msg, "*%s-%d*", strName[i], pid);
-
- info->stream[i]->storage_as.port.name = must_malloc( strlen( msg ) + 1 );
- strcpy( info->stream[i]->storage_as.port.name, msg );
-
- no_interrupt( flag );
- break;
-
- default:
- break;
- }
- }
- /** all house keeping is done... notyfy child to go ***/
- #if 1
- sigpause(0); /* wait for child notification */
- sigsetmask(svMask1);
- /* notify child */
- ok = kill(pid,SIGUSR1);
- if(ok < 0) perror("Parent sigusr");
- /* else fprintf(stderr, "Parent sending SIGUSR1 to %d\n",pid); */
- #endif
- }
- PROCESS( pinfo ) = info;
- return pinfo;
- }
-
-
- /*** INTERFACE ****/
-
- PRIMITIVE
- processp( SCM process ) {
- return PROCESSP( process ) ? truth : ntruth;
- }
-
-
- PRIMITIVE
- process_alivep( SCM process ) {
-
- if( NPROCESSP( process ) )
- err("process-alive?: wrong argument type", process);
-
- return kill( PROCPID( process ), 0 ) == 0 ? truth : ntruth;
- }
-
- PRIMITIVE
- process_pid( SCM process ) {
-
- if( NPROCESSP( process ) )
- err("process-pid: wrong argument type", process);
-
- return makeinteger( PROCPID( process ) );
- }
-
- static char *rtFile = "*File*";
- static char *rtStream = "*Stream*";
- static char *rtNone = "*None*";
-
- static PRIMITIVE
- get_internal_redirection( SCM process, int i ) {
- SCM rType, rName;
- struct process_info *info;
-
- if( NPROCESSP( process ) )
- err("process-stream-type: wrong argument type", process);
-
- info = PROCESS( process );
-
- switch( info->redirection[i] ) {
-
- case REDIRECTION_BY_FILE:
- rType = makestrg( strlen( rtFile ), rtFile );
- rName = string_copy( info->stream[i] );
- break;
-
- case NO_REDIRECTION:
- rType = makestrg( strlen( rtNone ), rtNone );
- rName = NIL;
- break;
-
- default: /* REDIRECTION_BY_STREAM */
- rType = makestrg( strlen( rtStream ), rtStream );
- rName = makestrg( strlen( stdStreams[i] ), stdStreams[i] );
- break;
- }
-
- return cons( rType, rName );
- }
-
-
- /*** enumerate ***/
- PRIMITIVE
- process_list(){
- int i;
- SCM lst = NIL;
- for(i = 0; i<MAX_PROC_NUM; i++)
- if(proc_arr[i] != ntruth)
- lst = cons(proc_arr[i],lst);
- return lst;
- }
-
-
-
- PRIMITIVE
- process_input_info( SCM process ) {
-
- return get_internal_redirection( process, 0 );
- }
-
- PRIMITIVE
- process_output_info( SCM process ) {
-
- return get_internal_redirection( process, 1 );
- }
-
- PRIMITIVE
- process_error_info( SCM process ) {
-
- return get_internal_redirection( process, 2 );
- }
-
- PRIMITIVE
- process_command( SCM process ) {
- struct process_info *info;
-
- if( NPROCESSP( process ) )
- err("process-command: wrong argument type", process);
-
- info = PROCESS( process );
-
- return makestrg( strlen( info->commandLine ), info->commandLine );
- }
-
-
- /*
- * Creating and returning ports to opened streams
- */
-
- PRIMITIVE
- process_input( SCM process ) {
- struct process_info *info;
-
- if( NPROCESSP( process ) )
- err("process-input: wrong argument type", process);
-
- info = PROCESS( process );
-
- if( info->redirection[0] != REDIRECTION_BY_STREAM ) {
- return NIL;
- }
-
- return info->stream[0];
- }
-
- PRIMITIVE
- process_output( SCM process ) {
- struct process_info *info;
-
- if( NPROCESSP( process ) )
- err("process-input: wrong argument type", process);
-
- info = PROCESS( process );
-
- if( info->redirection[1] != REDIRECTION_BY_STREAM ) {
- return NIL;
- }
-
- return info->stream[1];
- }
-
- PRIMITIVE
- process_error( SCM process ) {
- struct process_info *info;
-
- if( NPROCESSP( process ) )
- err("process-input: wrong argument type", process);
-
- info = PROCESS( process );
-
- if( info->redirection[2] != REDIRECTION_BY_STREAM ) {
- return NIL;
- }
-
- return info->stream[2];
- }
-
-
- void
- mark_process( SCM process ){
- struct process_info *info;
- int i;
- info = PROCESS(process);
- for(i=0; i<3 ; i++)
- gc_mark(info->stream[i]);
- }
-
-
- void
- free_process( SCM process ) {
- int i;
- struct process_info *info;
- info = PROCESS( process );
- i = remove_process(process);
- if(i < 0)
- err("cannot unregister process", process);
- if( info->commandLine )
- free( info->commandLine );
-
- for( i = 0; i < 3; ++i ) {
- if( info->redirection[i] == REDIRECTION_BY_STREAM && info->stream[i] != NIL ) {
- freeport( info->stream[i] );
- }
- }
- free(info); /* A.T. ++ */
- }
-
-
- PRIMITIVE
- process_kill( SCM process ) {
- struct process_info *info;
- int i;
- if( NPROCESSP( process ) )
- err("process-kill: wrong argument", process);
-
- info = PROCESS( process );
- #if 1
- for( i = 0; i < 3; ++i ) {
- if( info->redirection[i] == REDIRECTION_BY_STREAM &&
- info->stream[i] != NIL ) {
- freeport( info->stream[i] );
- info->stream[i]=NIL;
- }
- }
- #endif
- kill( PROCPID( process ), 15 );
- return truth;
- }
-
-
- /******* run-time initialization ********/
- void init_process(void)
- {
- tc_process = add_new_type(&process_type);
- init_proc_table();
-
- add_new_primitive("run-process", tc_subr_3, run_process); /* + */
- add_new_primitive("run-sync", tc_subr_3, run_sync); /* + */
- add_new_primitive("process?", tc_subr_1, processp); /* + */
- add_new_primitive("process-alive?", tc_subr_1, process_alivep); /* + */
- add_new_primitive("process-input-info", tc_subr_1, process_input_info); /* + */
- add_new_primitive("process-output-info", tc_subr_1, process_output_info); /* + */
- add_new_primitive("process-error-info", tc_subr_1, process_error_info); /* + */
- add_new_primitive("process-command", tc_subr_1, process_command); /* + */
- add_new_primitive("process-pid", tc_subr_1, process_pid); /* + */
- add_new_primitive("process-input", tc_subr_1, process_input); /* + */
- add_new_primitive("process-output", tc_subr_1, process_output); /* + */
- add_new_primitive("process-error", tc_subr_1, process_error); /* + */
- add_new_primitive("process-kill", tc_subr_1,process_kill); /* + */
- add_new_primitive("process-list", tc_subr_0,process_list); /* + */
-
- }
-