/******************************************************************************* Process: prosper.c PROcess SPawnER Author: Alex Measday Purpose: PROSPER is a program used to spawn a program when needed. PROSPER was written for use under operating systems which don't support UNIX-style FORK()s. PROSPER simply spawns a specified program and waits for the program to signal a semaphore. When the subprocess signals the semaphore, PROSPER spawns another copy of the program and waits for it to signal the semaphore. And so on and so on: PROSPER / | \ Sub#1 Sub#2 ... When PROSPER spawns a program, it inserts a "-@ semaphore" option in the subprocess's argument list. is the integer ID of the semaphore that the subprocess should signal when it's time for PROSPER to spawn another copy of the program. PROSPER was specifically written to run TPOCC server processes under VMS. Some TPOCC programs such as TSTOL and Reports execute as network servers. When a network connection request is received, the server process forks a subprocess to handle the new connection. Under UNIX, the new connection's socket can be passed from the server process to the child process. Not so under VMS! With PROSPER, the server process must act as both the server and the child process. Initially, the server opens a listening port socket and waits for a connection request. When a request is received, the server process closes its listening port socket, signals the PROSPER semaphore, and goes off to service the new connection. PROSPER, upon being signalled, starts up a new server process, which creates a listening port socket, waits for a connection request, etc., etc. NOTE: Under VMS, the server process can't simply spawn a subprocess to become the new server. Doing so would result in a single-branching tree of server processes; if one subprocess went away, all subprocesses following it (below it in the tree) would go away, too! Invocation: % prosper [-debug] [-vperror] where: "-debug" enables PROSPER debug output. PROSPER's "-debug" option must be specified before the program name argument (see below). "-vperror" enables the output of VPERROR() messages (generated by TPOCC library functions in the event of an error). PROSPER's "-vperror" option must be specified before the program name argument (see below). "" is the name of the program which will be repeatedly spawned. Under VMS, this must be the pathname of the program (including the directory, etc.) or a foreign command which, when translated, gives the pathname of the program. "" are the command line arguments the program is expecting. *******************************************************************************/ /*PDL----------------------------PDL--------------------------PDL** Establish the termination and interrupt handlers. CALL OPT_GET() to process the command line arguments. CALL SIGNAL_FLAG() to create a semaphore and initialize its value. Construct the argument list for the program to be spawned. Insert the "-@ " option in the argument list. DO CALL WAIT_ON_FLAG() to wait for the latest subprocess to signal the semaphore. CALL VFORK(3) to spawn a new copy of PROSPER. IF executing in the new PROSPER subprocess THEN CALL EXECVE(2) to overlay the new PROSPER subprocess with the program that was supposed to be spawned in the first place. ENDIF ENDDO **PDL----------------------------PDL--------------------------PDL*/ #include /* System error definitions. */ #include /* Signal definitions. */ #include /* Standard I/O definitions. */ #include /* Standard C Library definitions. */ #include /* C Library string functions. */ #ifdef sun extern int on_exit () ; /* Eventually, SunOS' ON_EXIT should go away. */ # define atexit(f) on_exit(f, (char *) NULL) #else extern int atexit () ; /* ATEXIT(2) is the ANSI C standard. */ #endif #include "libutilgen.h" /* LIBUTILGEN definitions. */ #ifdef vms # include "libutilvms.h" /* LIBUTILVMS definitions. */ #endif #include "opt_util.h" /* Option scanning definitions. */ /* Non-local variables. */ static int debug = 0 ; /******************************************************************************* Private Functions *******************************************************************************/ static void exit_handler ( # if __STDC__ || defined(vaxc) void # endif ) ; static void interrupt_handler ( # if __STDC__ || defined(vaxc) int sig # endif ) ; /******************************************************************************* PROSPER's Main Program. *******************************************************************************/ int main ( # if __STDC__ || defined(vaxc) int argc, char *argv[], char *envp[]) # else argc, argv, envp) int argc ; char *argv[] ; char *envp[] ; # endif { /* Local variables. */ char **arg_list, *argument, buffer[16], *command_line, *s ; int errflg, i, length, num_args, optind, option, semaphore, status ; /* Set up a termination handler and an interrupt handler. */ if (atexit (exit_handler)) perror ("[PROSPER] Error declaring the exit handler") ; signal (SIGINT, interrupt_handler) ; /******************************************************************************* Scan the command line options. Note that PROSPER-specific options must be specified BEFORE the program name (a non-option argument). *******************************************************************************/ opt_init (argc, argv, 0, "{debug}{vperror}", NULL) ; errflg = 0 ; while (option = opt_get (NULL, &argument)) { switch (option) { case 1: /* "-debug" */ debug = 1 ; vperror_print = 1 ; break ; case 2: /* "-vperror" */ vperror_print = 1 ; break ; case NONOPT: /* "" */ optind = opt_index (NULL) ; break ; case OPTERR: errflg++ ; break ; default : break ; } if (option == NONOPT) break; } if (errflg || (optind>= argc)) { /* Error or missing program name? */ fprintf (stderr, "Usage: prosper [-debug] [-vperror] []\n") ; exit (EINVAL) ; } /* Create the semaphore used by the spawned programs to signal PROSPER that another program should be spawned. Also, to initiate the spawning of the very first process, signal the flag. */ semaphore = -1 ; if (signal_flag (&semaphore)) { vperror ("[PROSPER] Error creating/signalling semaphore.\nsignal_flag: ") ; exit (errno) ; } /* Construct the list of command line arguments that will be passed to the program that will be spawned. This list is essentially a duplicate of PROSPER's argument list, except a "-@ " argument is inserted. */ num_args = argc - optind + 2 ; arg_list = (char **) calloc (num_args + 1, sizeof (char *)) ; if (arg_list == NULL) { vperror ("[PROSPER] Error allocating list for %d arguments.\ncalloc: ", num_args) ; exit (errno) ; } arg_list[0] = argv[optind++] ; /* Program name. */ #ifdef vms s = getenv (arg_list[0]) ; if (s != NULL) /* Translate foreign command definitions. */ arg_list[0] = s + strspn (s, " $") ; #endif arg_list[1] = "-@" ; /* Semaphore ID option. */ sprintf (buffer, "%d", semaphore) ; arg_list[2] = str_dupl (buffer, -1) ; i = 3 ; while (optind < argc) /* Remaining program arguments. */ arg_list[i++] = argv[optind++] ; arg_list[i] = NULL ; /* For debugging purposes, concatenate the arguments into a single command string. Arguments with embedded spaces are enclosed in double quotes. */ length = strlen (arg_list[0]) ; for (i = 1 ; i < num_args ; i++) { length = length + 1 + strlen (arg_list[i]) ; if (strchr (arg_list[i], ' ') != NULL) length = length + 2 ; } command_line = str_dupl (NULL, length) ; strcpy (command_line, arg_list[0]) ; for (i = 1 ; i < num_args ; i++) { strcat (command_line, " ") ; if (strchr (arg_list[i], ' ') != NULL) strcat (command_line, "\"") ; strcat (command_line, arg_list[i]) ; if (strchr (arg_list[i], ' ') != NULL) strcat (command_line, "\"") ; } /******************************************************************************* Until PROSPER is terminated, spawn the program, wait for it to signal that another program can be spawned, and then do so. *******************************************************************************/ for ( ; ; ) { /* Ever and ever. */ /* Wait for the semaphore to be signalled, indicating that the program should be spawned again. */ if (wait_on_flag (&semaphore, -1)) { vperror ("[PROSPER] Error waiting on semaphore %d.\nwait_on_flag: ", semaphore) ; exit (errno) ; } /* Spawn the program. */ if (debug) printf ("[PROSPER] Spawning: %s\n", command_line) ; #ifdef vms status = vfork () ; #else status = fork () ; #endif if (status> 0) { /* Am I the main process? */ continue ; } else if (status == 0) { /* Am I the "forked" process? */ if (execve (arg_list[0], arg_list, envp)) { vperror ("[PROSPER] Error forking program: %s\nexecve: ", command_line) ; exit (errno) ; } } else { /* Error. */ vperror ("[PROSPER] Error forking program: %s\nfork: ", command_line) ; exit (errno) ; } } } /******************************************************************************* Procedure: exit_handler () Purpose: The exit handler is automatically invoked when a process terminates. *******************************************************************************/ static void exit_handler ( # if __STDC__ || defined(vaxc) void) # elif defined(sun) status, arg) int status ; char *arg ; # else ) # endif { ; } /******************************************************************************* Procedure: interrupt_handler () Purpose: Invoked by the system in response to a SIGINT signal: interrupt_handler (sig) where is the signal causing invocation of the handler. *******************************************************************************/ static void interrupt_handler ( # if __STDC__ || defined(vaxc) int sig) # else sig) int sig ; # endif { exit (-1) ; }

AltStyle によって変換されたページ (->オリジナル) /