int mysystem(AppInfo* appinfo, JobInfo* jobinfo, char* envp[]) /* purpose: emulate the system() libc call, but save utilization data. * paramtr: appinfo (IO): shared record of information * isPrinted (IO): reset isPrinted in child process! * input (IN): connect to stdin or share * output (IN): connect to stdout or share * error (IN): connect to stderr or share * jobinfo (IO): updated record of job-specific information * argv (IN): assembled commandline * child (OUT): pid of child process * status (OUT): also returned as function result * saverr (OUT): will be set to value of errno * start (OUT): will be set to startup time * final (OUT): will be set to finish time after reap * use (OUT): rusage record from application call * input (IN): connect to stdin or share * output (IN): connect to stdout or share * error (IN): connect to stderr or share * envp (IN): vector with the parent's environment * returns: -1: failure in mysystem processing, check errno * 126: connecting child to its new stdout failed * 127: execve() call failed * else: status of child */ { struct sigaction ignore, saveintr, savequit; /* sanity checks first */ if ( ! jobinfo->isValid ) { errno = ENOEXEC; /* no executable */ return -1; } memset( &ignore, 0, sizeof(ignore) ); ignore.sa_handler = SIG_IGN; sigemptyset( &ignore.sa_mask ); ignore.sa_flags = 0; if ( sigaction( SIGINT, &ignore, &saveintr ) < 0 ) return -1; if ( sigaction( SIGQUIT, &ignore, &savequit ) < 0 ) return -1; /* start wall-clock */ now( &(jobinfo->start) ); if ( (jobinfo->child=fork()) < 0 ) { /* no more process table space */ jobinfo->status = -1; } else if ( jobinfo->child == 0 ) { /* child */ appinfo->isPrinted=1; /* connect jobs stdio */ if ( forcefd( &appinfo->input, STDIN_FILENO ) ) _exit(126); if ( forcefd( &appinfo->output, STDOUT_FILENO ) ) _exit(126); if ( forcefd( &appinfo->error, STDERR_FILENO ) ) _exit(126); /* undo signal handlers */ sigaction( SIGINT, &saveintr, NULL ); sigaction( SIGQUIT, &savequit, NULL ); /* If we are tracing, then hand over control to the proc module */ if (appinfo->enableTracing) { if ( procChild() ) _exit(126); } execve( jobinfo->argv[0], (char* const*) jobinfo->argv, envp ); perror("execve"); _exit(127); /* executed in child process */ } else { /* parent */ if (appinfo->enableTracing) { procParentTrace(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children)); } else { procParentWait(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children)); } /* sanity check */ if ( kill( jobinfo->child, 0 ) == 0 ) { debugmsg( "ERROR: job %d is still running!\n", jobinfo->child ); if ( ! errno ) errno = EINPROGRESS; } } /* save any errors before anybody overwrites this */ jobinfo->saverr = errno; /* stop wall-clock */ now( &(jobinfo->finish) ); /* ignore errors on these, too. */ sigaction( SIGINT, &saveintr, NULL ); sigaction( SIGQUIT, &savequit, NULL ); /* finalize */ return jobinfo->status; }
int mysystem(AppInfo* appinfo, JobInfo* jobinfo, char* envp[]) { /* purpose: emulate the system() libc call, but save utilization data. * paramtr: appinfo (IO): shared record of information * isPrinted (IO): reset isPrinted in child process! * input (IN): connect to stdin or share * output (IN): connect to stdout or share * error (IN): connect to stderr or share * jobinfo (IO): updated record of job-specific information * argv (IN): assembled commandline * child (OUT): pid of child process * status (OUT): also returned as function result * saverr (OUT): will be set to value of errno * start (OUT): will be set to startup time * final (OUT): will be set to finish time after reap * use (OUT): rusage record from application call * input (IN): connect to stdin or share * output (IN): connect to stdout or share * error (IN): connect to stderr or share * envp (IN): vector with the parent's environment * returns: -1: failure in mysystem processing, check errno * 126: connecting child to its new stdout failed * 127: execve() call failed * else: status of child */ /* sanity checks first */ if (!jobinfo->isValid) { errno = ENOEXEC; /* no executable */ return -1; } /* Ignore SIGINT and SIGQUIT */ struct sigaction ignore, saveintr, savequit; memset(&ignore, 0, sizeof(ignore)); ignore.sa_handler = SIG_IGN; sigemptyset(&ignore.sa_mask); ignore.sa_flags = 0; if (sigaction(SIGINT, &ignore, &saveintr) < 0) { return -1; } if (sigaction(SIGQUIT, &ignore, &savequit) < 0) { return -1; } /* Prefix for trace files generated by this job */ char trace_file_prefix[128]; snprintf(trace_file_prefix, 128, "gs.trace.%d", getpid()); /* Temp dir where trace files are stored for this job */ const char *tempdir = getTempDir(); if (tempdir == NULL) { tempdir = "/tmp"; } /* start wall-clock */ now(&(jobinfo->start)); if ((jobinfo->child=fork()) < 0) { /* no more process table space */ jobinfo->status = -1; } else if (jobinfo->child == 0) { /* child */ appinfo->isPrinted=1; // If we are using library tracing, try to set the necessary // environment variables if (appinfo->enableLibTrace) { envp = tryGetNewEnvironment(envp, tempdir, trace_file_prefix); } /* connect jobs stdio */ if (forcefd(&appinfo->input, STDIN_FILENO)) _exit(126); if (forcefd(&appinfo->output, STDOUT_FILENO)) _exit(126); if (forcefd(&appinfo->error, STDERR_FILENO)) _exit(126); /* undo signal handlers */ sigaction(SIGINT, &saveintr, NULL); sigaction(SIGQUIT, &savequit, NULL); /* If we are tracing, then hand over control to the proc module */ if (appinfo->enableTracing) { if (procChild()) _exit(126); } execve(jobinfo->argv[0], (char* const*) jobinfo->argv, envp); perror("execve"); _exit(127); /* executed in child process */ } else { /* Track the current child process */ appinfo->currentChild = jobinfo->child; /* parent */ if (appinfo->enableTracing) { /* TODO If this returns an error, then we need to untrace all the children and try the wait instead */ procParentTrace(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children), appinfo->enableSysTrace); } else { procParentWait(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children)); } /* sanity check */ if (kill(jobinfo->child, 0) == 0) { printerr("ERROR: job %d is still running!\n", jobinfo->child); if (!errno) errno = EINPROGRESS; } /* Child is no longer running */ appinfo->currentChild = 0; } /* save any errors before anybody overwrites this */ jobinfo->saverr = errno; /* stop wall-clock */ now(&(jobinfo->finish)); /* ignore errors on these, too. */ sigaction(SIGINT, &saveintr, NULL); sigaction(SIGQUIT, &savequit, NULL); /* Look for trace files from libinterpose and add trace data to jobinfo */ if (appinfo->enableLibTrace) { jobinfo->children = processTraceFiles(tempdir, trace_file_prefix); } /* finalize */ return jobinfo->status; }