Commit d1c6a037 by Bruce Korb

properly handle child processes

From-SVN: r26644
parent 039d4bce
...@@ -147,9 +147,11 @@ pid_t process_chain_head = (pid_t) -1; ...@@ -147,9 +147,11 @@ pid_t process_chain_head = (pid_t) -1;
const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]"; const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
regex_t incl_quote_re; regex_t incl_quote_re;
char *load_file (const char *pzFile); char *load_file (const char *);
void process (char *data, const char *file); void process (char *, const char *);
void run_compiles (void); void run_compiles ();
void wait_for_pid( pid_t, int );
void initialize ();
#include "fixincl.x" #include "fixincl.x"
...@@ -164,8 +166,6 @@ main (argc, argv) ...@@ -164,8 +166,6 @@ main (argc, argv)
{ {
static const char gnu_lib_mark[] = static const char gnu_lib_mark[] =
"This file is part of the GNU C Library"; "This file is part of the GNU C Library";
static const char var_not_found[] =
"fixincl ERROR: %s environment variable not defined\n";
#ifndef NO_BOGOSITY_LIMITS #ifndef NO_BOGOSITY_LIMITS
# define BOGUS_LIMIT MINIMUM_MAXIMUM_LINES # define BOGUS_LIMIT MINIMUM_MAXIMUM_LINES
...@@ -212,6 +212,113 @@ main (argc, argv) ...@@ -212,6 +212,113 @@ main (argc, argv)
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
initialize ();
#ifndef NO_BOGOSITY_LIMITS
/* Some systems only allow so many calls to fork(2).
This is inadequate for this program. Consequently,
we must let a grandfather process spawn children
that then spawn all the processes that do the real work.
*/
for (;;)
{
file_name_ct = 0;
{
char *pz_buf = file_name_buf;
/* Only the parent process can read from stdin without confusing
the world. (How does the child tell the parent to skip
forward? Pipes and files behave differently.) */
while ( (file_name_ct < BOGUS_LIMIT)
&& (pz_buf < (file_name_buf + NAME_TABLE_SIZE - MAXPATHLEN)))
{
if (fgets (pz_buf, MAXPATHLEN, stdin) == (char *) NULL)
break;
while (isspace (*pz_buf))
pz_buf++;
if ((*pz_buf == '\0') || (*pz_buf == '#'))
continue;
apz_names[file_name_ct++] = pz_buf;
pz_buf += strlen (pz_buf);
while (isspace (pz_buf[-1]))
pz_buf--;
*pz_buf++ = '\0';
}
}
/* IF we did not get any files this time thru
THEN we must be done. */
if (file_name_ct == 0)
return EXIT_SUCCESS;
{
pid_t child = fork ();
if (child == NULLPROCESS)
break;
if (child == NOPROCESS)
{
fprintf (stderr, "Error %d (%s) forking in main\n",
errno, strerror (errno));
exit (EXIT_FAILURE);
}
wait_for_pid( child, file_name_ct );
}
}
#else
#error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
#endif
/*
Here we are the child of the grandparent process. The parent
of all the little fixup processes. We ignore the deaths of
our children. */
signal (SIGCLD, SIG_IGN);
#ifdef DEBUG
fprintf (stderr, "Child start -- processing %d files\n",
file_name_ct);
#endif
/* For every file specified in stdandard in
(except as throttled for bogus reasons)...
*/
for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++)
{
char *pz_data;
char *pz_file_name = apz_names[loop_ct];
if (access (pz_file_name, R_OK) != 0)
{
int erno = errno;
fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
pz_file_name, getcwd ((char *) NULL, MAXPATHLEN),
erno, strerror (erno));
}
else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL))
{
if (strstr (pz_data, gnu_lib_mark) == (char *) NULL)
process (pz_data, pz_file_name);
free ((void *) pz_data);
}
}
return EXIT_SUCCESS;
}
/* * * * * * * * * * * * */
void
initialize()
{
static const char var_not_found[] =
"fixincl ERROR: %s environment variable not defined\n";
{ {
static const char var[] = "TARGET_MACHINE"; static const char var[] = "TARGET_MACHINE";
pz_machine = getenv (var); pz_machine = getenv (var);
...@@ -264,110 +371,74 @@ main (argc, argv) ...@@ -264,110 +371,74 @@ main (argc, argv)
signal (SIGALRM, SIG_IGN); signal (SIGALRM, SIG_IGN);
signal (SIGTERM, SIG_IGN); signal (SIGTERM, SIG_IGN);
#ifndef NO_BOGOSITY_LIMITS /*
/* Some systems only allow so many calls to fork(2). Make sure that if we opened a server process, we close it now.
This is inadequate for this program. Consequently, This is the grandparent process. We don't need the server anymore
we must let a grandfather process spawn children and our children should make their own. */
that then spawn all the processes that do the real work.
*/
for (;;)
{
char *pz_buf;
pid_t child;
/* Only the parent process can read from stdin without confusing
the world. (How does the child tell the parent to skip
forward? Pipes and files behave differently.) */
file_name_ct = 0;
pz_buf = file_name_buf;
while ( (file_name_ct < BOGUS_LIMIT)
&& (pz_buf < (file_name_buf + NAME_TABLE_SIZE - MAXPATHLEN)))
{
if (fgets (pz_buf, MAXPATHLEN, stdin) == (char *) NULL)
break;
while (isspace (*pz_buf))
pz_buf++;
if ((*pz_buf == '\0') || (*pz_buf == '#'))
continue;
apz_names[file_name_ct++] = pz_buf;
pz_buf += strlen (pz_buf);
while (isspace (pz_buf[-1]))
pz_buf--;
*pz_buf++ = '\0';
}
/* IF we did not get any files this time thru
THEN we must be done. */
if (file_name_ct == 0)
return EXIT_SUCCESS;
child = fork ();
if (child == NULLPROCESS)
break;
if (child == NOPROCESS) close_server ();
{ (void)wait ( (int*)NULL );
fprintf (stderr, "Error %d (%s) forking in main\n", }
errno, strerror (errno));
exit (EXIT_FAILURE);
}
#ifndef DEBUG
{
int status;
(void)wait (&status);
}
#else
fprintf (stderr, "Waiting for %d to complete %d files\n",
child, file_name_ct);
{ /* * * * * * * * * * * * *
int status;
pid_t dead_kid = wait (&status); wait_for_pid - Keep calling `wait(2)' until it returns
the process id we are looking for. Not every system has
`waitpid(2)'. We also ensure that the children exit with success. */
if (dead_kid != child) void
fprintf (stderr, "fixincl woke up from a strange child %d (not %d)\n", wait_for_pid( pid_t child, int file_name_ct )
dead_kid, child); {
else #ifdef DEBUG
fprintf (stderr, "child finished %d files %s\n", file_name_ct, fprintf (stderr, "Waiting for %d to complete %d files\n",
status ? strerror (status & 0xFF) : "ok"); child, file_name_ct);
}
#endif
}
#else
#error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
#endif #endif
signal (SIGCLD, SIG_IGN); for (;;) {
int status;
pid_t dead_kid = wait (&status);
if (dead_kid == child)
{
if (! WIFEXITED( status ))
{
fprintf (stderr, "child process %d is hung on signal %d\n",
child, WSTOPSIG( status ));
exit (EXIT_FAILURE);
}
if (WEXITSTATUS( status ) != 0)
{
fprintf (stderr, "child process %d exited with status %d\n",
child, WEXITSTATUS( status ));
exit (EXIT_FAILURE);
}
#ifdef DEBUG #ifdef DEBUG
fprintf (stderr, "Child start -- processing %d files\n", fprintf (stderr, "child finished %d files %s\n", file_name_ct,
file_name_ct); status ? strerror (status & 0xFF) : "ok");
#endif #endif
break; /* normal child completion */
}
/* For every file specified in stdandard in /*
(except as throttled for bogus reasons)... IF there is an error, THEN see if it is retryable.
*/ If it is not retryable, then break out of this loop. */
for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++) if (dead_kid == NOPROCESS)
{ {
char *pz_data; switch (errno) {
char *pz_file_name = apz_names[loop_ct]; case EINTR:
case EAGAIN:
break;
if (access (pz_file_name, R_OK) != 0) default:
{ fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
int erno = errno; errno, strerror( errno ), child );
fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n", /* FALLTHROUGH */
pz_file_name, getcwd ((char *) NULL, MAXPATHLEN),
erno, strerror (erno));
}
else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL))
{
if (strstr (pz_data, gnu_lib_mark) == (char *) NULL)
process (pz_data, pz_file_name);
free ((void *) pz_data);
}
}
return EXIT_SUCCESS; case ECHILD: /* no children to wait for?? */
return;
}
}
} done_waiting:;
} }
...@@ -476,6 +547,12 @@ run_compiles () ...@@ -476,6 +547,12 @@ run_compiles ()
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
/* Make sure re_compile_pattern does not stumble across invalid
data */
memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
/* The patterns we search for are all egrep patterns. /* The patterns we search for are all egrep patterns.
In the shell version of this program, we invoke egrep In the shell version of this program, we invoke egrep
with the supplied pattern. Here, we will run with the supplied pattern. Here, we will run
......
...@@ -178,14 +178,17 @@ load_data (fp) ...@@ -178,14 +178,17 @@ load_data (fp)
* Make certain the server process is dead, close the * Make certain the server process is dead, close the
* pipes to it and from it, finally NULL out the file pointers * pipes to it and from it, finally NULL out the file pointers
*/ */
static void void
close_server () close_server ()
{ {
kill ((pid_t) server_id, SIGKILL); if (server_id != NULLPROCESS)
server_id = NULLPROCESS; {
fclose (server_pair.pf_read); kill ((pid_t) server_id, SIGKILL);
fclose (server_pair.pf_write); server_id = NULLPROCESS;
server_pair.pf_read = server_pair.pf_write = (FILE *) NULL; fclose (server_pair.pf_read);
fclose (server_pair.pf_write);
server_pair.pf_read = server_pair.pf_write = (FILE *) NULL;
}
} }
/* /*
......
...@@ -90,5 +90,5 @@ pid_t proc2_open _P_ (( t_fd_pair * p_pair, t_pchar * pp_args)); ...@@ -90,5 +90,5 @@ pid_t proc2_open _P_ (( t_fd_pair * p_pair, t_pchar * pp_args));
int chain_open _P_ (( int in_fd, int chain_open _P_ (( int in_fd,
t_pchar * pp_args, t_pchar * pp_args,
pid_t * p_child)); pid_t * p_child));
void close_server _P_ (( void ));
#endif /* FIXINC_SERVER_H */ #endif /* FIXINC_SERVER_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment