diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2009-09-27 21:44:29 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2009-09-27 21:44:29 +0000 |
commit | 43939e66b1d4eeb2f3799c124f3598756755005a (patch) | |
tree | 15733092de55d52421a6ea02f5a43d5f8ff24393 /urt/rle_open_f.c | |
parent | 49f4336c9bba33650573ba780b70bc501b38643e (diff) | |
download | netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.gz netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.xz netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.zip |
Rebase Stable series to current Advanced: 10.47.04
git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@995 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'urt/rle_open_f.c')
-rw-r--r-- | urt/rle_open_f.c | 422 |
1 files changed, 230 insertions, 192 deletions
diff --git a/urt/rle_open_f.c b/urt/rle_open_f.c index d2575c11..07dbea01 100644 --- a/urt/rle_open_f.c +++ b/urt/rle_open_f.c @@ -1,10 +1,10 @@ /* * rle_open_f.c - Open a file with defaults. * - * Author : Jerry Winters - * EECS Dept. - * University of Michigan - * Date: 11/14/89 + * Author : Jerry Winters + * EECS Dept. + * University of Michigan + * Date: 11/14/89 * Copyright (c) 1990, University of Michigan */ @@ -15,19 +15,24 @@ #include <unistd.h> #include <fcntl.h> +#include "pm_c_util.h" +#include "nstring.h" +#include "rle.h" + + + +#define MAX_CHILDREN 100 + /* Maximum number of children we track; any more than this remain + zombies. + */ + + #ifndef NO_OPEN_PIPES -/* Need to have a SIGCLD signal catcher. */ +/* Need to have a SIGCHLD signal catcher. */ #include <signal.h> #include <sys/wait.h> #include <errno.h> -#include "rle.h" - -/* Count outstanding children. Assume no more than 100 possible. */ -#define MAX_CHILDREN 100 -static int catching_children = 0; -static int pids[MAX_CHILDREN]; - static FILE * @@ -43,55 +48,55 @@ my_popen(const char * const cmd, /* Check args. */ if ( *mode != 'r' && *mode != 'w' ) { - errno = EINVAL; - return NULL; + errno = EINVAL; + return NULL; } if ( pipe(pipefd) < 0 ) - return NULL; + return NULL; /* Flush known files. */ fflush(stdout); fflush(stderr); if ( (thepid = fork()) < 0 ) { - close(pipefd[0]); - close(pipefd[1]); - return NULL; + close(pipefd[0]); + close(pipefd[1]); + return NULL; } else if (thepid == 0) { - /* In child. */ - /* Rearrange file descriptors. */ - if ( *mode == 'r' ) - { - /* Parent reads from pipe, so reset stdout. */ - close(1); - dup2(pipefd[1],1); - } else { - /* Parent writing to pipe. */ - close(0); - dup2(pipefd[0],0); - } - /* Close anything above fd 2. (64 is an arbitrary magic number). */ - for ( i = 3; i < 64; i++ ) - close(i); - - /* Finally, invoke the program. */ - if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 ) - exit(127); - /* NOTREACHED */ - } + /* In child. */ + /* Rearrange file descriptors. */ + if ( *mode == 'r' ) + { + /* Parent reads from pipe, so reset stdout. */ + close(1); + dup2(pipefd[1],1); + } else { + /* Parent writing to pipe. */ + close(0); + dup2(pipefd[0],0); + } + /* Close anything above fd 2. (64 is an arbitrary magic number). */ + for ( i = 3; i < 64; i++ ) + close(i); + + /* Finally, invoke the program. */ + if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 ) + exit(127); + /* NOTREACHED */ + } /* Close file descriptors, and gen up a FILE ptr */ if ( *mode == 'r' ) { - /* Parent reads from pipe. */ - close(pipefd[1]); - retfile = fdopen( pipefd[0], mode ); + /* Parent reads from pipe. */ + close(pipefd[1]); + retfile = fdopen( pipefd[0], mode ); } else { - /* Parent writing to pipe. */ - close(pipefd[0]); - retfile = fdopen( pipefd[1], mode ); + /* Parent writing to pipe. */ + close(pipefd[0]); + retfile = fdopen( pipefd[1], mode ); } /* Return the PID. */ @@ -99,8 +104,128 @@ my_popen(const char * const cmd, return retfile; } + + + +static void +reapChildren(int * const catchingChildrenP, + pid_t * const pids) { + + /* Check for dead children. */ + + if (*catchingChildrenP > 0) { + unsigned int i; + + /* Check all children to see if any are dead, reap them if so. */ + for (i = 0; i < *catchingChildrenP; ++i) { + /* The assumption here is that if it's dead, the kill + * will fail, but, because we haven't waited for + * it yet, it's a zombie. + */ + if (kill(pids[i], 0) < 0) { + int opid = pids[i], pid = 0; + /* Wait for processes & delete them from the list, + * until we get the one we know is dead. + * When removing one earlier in the list than + * the one we found, decrement our loop index. + */ + while (pid != opid) { + unsigned int j; + pid = wait(NULL); + for (j = 0; + j < *catchingChildrenP && pids[j] != pid; + ++j) + ; + if (pid < 0) + break; + if (j < *catchingChildrenP) { + if (i >= j) + --i; + for (++j; j < *catchingChildrenP; ++j) + pids[j-1] = pids[j]; + --*catchingChildrenP; + } + } + } + } + } +} #endif /* !NO_OPEN_PIPES */ + + +static void +dealWithSubprocess(const char * const file_name, + const char * const mode, + int * const catchingChildrenP, + pid_t * const pids, + FILE ** const fpP, + bool * const noSubprocessP, + const char ** const errorP) { + +#ifdef NO_OPEN_PIPES + *noSubprocessP = TRUE; +#else + const char *cp; + + reapChildren(catchingChildrenP, pids); + + /* Real file, not stdin or stdout. If name ends in ".Z", + * pipe from/to un/compress (depending on r/w mode). + * + * If it starts with "|", popen that command. + */ + + cp = file_name + strlen(file_name) - 2; + /* Pipe case. */ + if (file_name[0] == '|') { + pid_t thepid; /* PID from my_popen */ + + *noSubprocessP = FALSE; + + *fpP = my_popen(file_name + 1, mode, &thepid); + if (*fpP == NULL) + *errorP = "%s: can't invoke <<%s>> for %s: "; + else { + /* One more child to catch, eventually. */ + if (*catchingChildrenP < MAX_CHILDREN) + pids[(*catchingChildrenP)++] = thepid; + } + } else if (cp > file_name && *cp == '.' && *(cp + 1) == 'Z' ) { + /* Compress case. */ + pid_t thepid; /* PID from my_popen. */ + const char * command; + + *noSubprocessP = FALSE; + + if (*mode == 'w') + asprintfN(&command, "compress > %s", file_name); + else if (*mode == 'a') + asprintfN(&command, "compress >> %s", file_name); + else + asprintfN(&command, "compress -d < %s", file_name); + + *fpP = my_popen(command, mode, &thepid); + + if (*fpP == NULL) + *errorP = "%s: can't invoke 'compress' program, " + "trying to open %s for %s"; + else { + /* One more child to catch, eventually. */ + if (*catchingChildrenP < MAX_CHILDREN) + pids[(*catchingChildrenP)++] = thepid; + } + strfree(command); + } else { + *noSubprocessP = TRUE; + *errorP = NULL; + } +#endif +} + + + + /* * Purpose : Open a file for input or ouput as controlled by the mode * parameter. If no file name is specified (ie. file_name is null) then @@ -113,10 +238,10 @@ my_popen(const char * const cmd, * * parameters * input: - * prog_name: name of the calling program. - * file_name : name of the file to open - * mode : either "r" for read or input file or "w" for write or - * output file + * prog_name: name of the calling program. + * file_name : name of the file to open + * mode : either "r" for read or input file or "w" for write or + * output file * * output: * a file pointer @@ -127,150 +252,63 @@ rle_open_f_noexit(const char * const prog_name, const char * const file_name, const char * const mode ) { - FILE *fp; - void perror(); - CONST_DECL char *err_str; - const char *cp; - char *combuf; + FILE * retval; + FILE * fp; + const char * err_str; + int catching_children; + pid_t pids[MAX_CHILDREN]; - if ( *mode == 'w' || *mode == 'a' ) + catching_children = 0; + + if (*mode == 'w' || *mode == 'a') fp = stdout; /* Set the default value */ else fp = stdin; - if ( file_name != NULL && strcmp( file_name, "-" ) != 0 ) - { -#ifndef NO_OPEN_PIPES - /* Check for dead children. */ - if ( catching_children > 0 ) - { - int i, j; - - /* Check all children to see if any are dead, reap them if so. */ - for ( i = 0; i < catching_children; i++ ) - { - /* The assumption here is that if it's dead, the kill - * will fail, but, because we haven't waited for - * it yet, it's a zombie. - */ - if (kill(pids[i], 0) < 0) { - int opid = pids[i], pid = 0; - /* Wait for processes & delete them from the list, - * until we get the one we know is dead. - * When removing one earlier in the list than - * the one we found, decrement our loop index. - */ - while (pid != opid) { - pid = wait( NULL ); - for ( j = 0; - j < catching_children && pids[j] != pid; - j++ ) - ; - if ( pid < 0 ) - break; - if ( j < catching_children ) { - if ( i >= j ) - i--; - for ( j++; j < catching_children; j++ ) - pids[j-1] = pids[j]; - catching_children--; - } - } - } - } - } - - /* Real file, not stdin or stdout. If name ends in ".Z", - * pipe from/to un/compress (depending on r/w mode). - * - * If it starts with "|", popen that command. - */ - - cp = file_name + strlen( (char*) file_name ) - 2; - /* Pipe case. */ - if ( *file_name == '|' ) - { - int thepid; /* PID from my_popen */ - if ( (fp = my_popen( file_name + 1, mode, &thepid )) == NULL ) - { - err_str = "%s: can't invoke <<%s>> for %s: "; - goto err; - } - /* One more child to catch, eventually. */ - if (catching_children < MAX_CHILDREN) { - pids[catching_children++] = thepid; - } - } - - /* Compress case. */ - else if ( cp > file_name && *cp == '.' && *(cp + 1) == 'Z' ) - { - int thepid; /* PID from my_popen. */ - combuf = (char *)malloc( 20 + strlen( file_name ) ); - if ( combuf == NULL ) - { - err_str = "%s: out of memory opening (compressed) %s for %s"; - goto err; - } - - if ( *mode == 'w' ) - sprintf( combuf, "compress > %s", file_name ); - else if ( *mode == 'a' ) - sprintf( combuf, "compress >> %s", file_name ); - else - sprintf( combuf, "compress -d < %s", file_name ); - - fp = my_popen( combuf, mode, &thepid ); - free( combuf ); - - if ( fp == NULL ) - { - err_str = - "%s: can't invoke 'compress' program, " - "trying to open %s for %s"; - goto err; - } - /* One more child to catch, eventually. */ - if (catching_children < MAX_CHILDREN) { - pids[catching_children++] = thepid; - } - } - else -#endif /* !NO_OPEN_PIPES */ - { - /* Ordinary, boring file case. */ - /* In the original code, the code to add the "b" was - conditionally included only if the macro STDIO_NEEDS_BINARY was - defined. But for Netpbm, there is no need make a distinction; - we always add the "b". -BJH 2000.07.20. - */ - char mode_string[32]; /* Should be enough. */ - - /* Concatenate a 'b' onto the mode. */ - mode_string[0] = mode[0]; - mode_string[1] = 'b'; - strcpy( mode_string + 2, mode + 1 ); + if (file_name != NULL && !streq(file_name, "-")) { + bool noSubprocess; + dealWithSubprocess(file_name, mode, &catching_children, pids, + &fp, &noSubprocess, &err_str); + + if (!err_str) { + if (noSubprocess) { + /* Ordinary, boring file case. */ + /* In the original code, the code to add the "b" was + conditionally included only if the macro + STDIO_NEEDS_BINARY was defined. But for Netpbm, + there is no need make a distinction; we always add + the "b". -BJH 2000.07.20. + */ + char mode_string[32]; /* Should be enough. */ + + /* Concatenate a 'b' onto the mode. */ + mode_string[0] = mode[0]; + mode_string[1] = 'b'; + strcpy( mode_string + 2, mode + 1 ); - if ( (fp = fopen(file_name, mode_string)) == NULL ) - { - err_str = "%s: can't open %s for %s: "; - goto err; + fp = fopen(file_name, mode_string); + if (fp == NULL ) + err_str = "%s: can't open %s for %s: "; } } - } - - return fp; + } else + err_str = NULL; + + if (err_str) { + fprintf(stderr, err_str, + prog_name, file_name, + (*mode == 'w') ? "output" : + (*mode == 'a') ? "append" : + "input" ); + fprintf(stderr, "errno = %d (%s)\n", errno, strerror(errno)); + retval = NULL; + } else + retval = fp; + + return retval; +} -err: - fprintf( stderr, err_str, - prog_name, file_name, - (*mode == 'w') ? "output" : - (*mode == 'a') ? "append" : - "input" ); - perror( "" ); - return NULL; -} FILE * rle_open_f(const char * prog_name, const char * file_name, const char * mode) @@ -278,7 +316,7 @@ rle_open_f(const char * prog_name, const char * file_name, const char * mode) FILE *fp; if ( (fp = rle_open_f_noexit( prog_name, file_name, mode )) == NULL ) - exit( -1 ); + exit( -1 ); return fp; } @@ -290,21 +328,21 @@ rle_open_f(const char * prog_name, const char * file_name, const char * mode) * Close a file opened by rle_open_f. If the file is stdin or stdout, * it will not be closed. * Inputs: - * fd: File to close. + * fd: File to close. * Outputs: - * None. + * None. * Assumptions: - * fd is open. + * fd is open. * Algorithm: - * If fd is NULL, just return. - * If fd is stdin or stdout, don't close it. Otherwise, call fclose. + * If fd is NULL, just return. + * If fd is stdin or stdout, don't close it. Otherwise, call fclose. */ void rle_close_f( fd ) -FILE *fd; + FILE *fd; { if ( fd == NULL || fd == stdin || fd == stdout ) - return; + return; else - fclose( fd ); + fclose( fd ); } |