|
Packit |
78deda |
/*
|
|
Packit |
78deda |
* rle_open_f.c - Open a file with defaults.
|
|
Packit |
78deda |
*
|
|
Packit |
78deda |
* Author : Jerry Winters
|
|
Packit |
78deda |
* EECS Dept.
|
|
Packit |
78deda |
* University of Michigan
|
|
Packit |
78deda |
* Date: 11/14/89
|
|
Packit |
78deda |
* Copyright (c) 1990, University of Michigan
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#define _XOPEN_SOURCE /* Make sure fdopen() is in stdio.h */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <string.h>
|
|
Packit |
78deda |
#include <stdio.h>
|
|
Packit |
78deda |
#include <unistd.h>
|
|
Packit |
78deda |
#include <fcntl.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "netpbm/pm_c_util.h"
|
|
Packit |
78deda |
#include "netpbm/nstring.h"
|
|
Packit |
78deda |
#include "rle_config.h"
|
|
Packit |
78deda |
#include "rle.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#define MAX_CHILDREN 100
|
|
Packit |
78deda |
/* Maximum number of children we track; any more than this remain
|
|
Packit |
78deda |
zombies.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#ifndef NO_OPEN_PIPES
|
|
Packit |
78deda |
/* Need to have a SIGCHLD signal catcher. */
|
|
Packit |
78deda |
#include <signal.h>
|
|
Packit |
78deda |
#include <sys/wait.h>
|
|
Packit |
78deda |
#include <errno.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static FILE *
|
|
Packit |
78deda |
my_popen(const char * const cmd,
|
|
Packit |
78deda |
const char * const mode,
|
|
Packit |
78deda |
int * const pid) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
FILE *retfile;
|
|
Packit |
78deda |
int thepid = 0;
|
|
Packit |
78deda |
int pipefd[2];
|
|
Packit |
78deda |
int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Check args. */
|
|
Packit |
78deda |
if ( *mode != 'r' && *mode != 'w' )
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
errno = EINVAL;
|
|
Packit |
78deda |
return NULL;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (pm_pipe(pipefd) < 0 )
|
|
Packit |
78deda |
return NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Flush known files. */
|
|
Packit |
78deda |
fflush(stdout);
|
|
Packit |
78deda |
fflush(stderr);
|
|
Packit |
78deda |
if ( (thepid = fork()) < 0 )
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
close(pipefd[0]);
|
|
Packit |
78deda |
close(pipefd[1]);
|
|
Packit |
78deda |
return NULL;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
else if (thepid == 0) {
|
|
Packit |
78deda |
/* In child. */
|
|
Packit |
78deda |
/* Rearrange file descriptors. */
|
|
Packit |
78deda |
if ( *mode == 'r' )
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
/* Parent reads from pipe, so reset stdout. */
|
|
Packit |
78deda |
close(1);
|
|
Packit |
78deda |
dup2(pipefd[1],1);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
/* Parent writing to pipe. */
|
|
Packit |
78deda |
close(0);
|
|
Packit |
78deda |
dup2(pipefd[0],0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
/* Close anything above fd 2. (64 is an arbitrary magic number). */
|
|
Packit |
78deda |
for ( i = 3; i < 64; i++ )
|
|
Packit |
78deda |
close(i);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Finally, invoke the program. */
|
|
Packit |
78deda |
if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 )
|
|
Packit |
78deda |
exit(127);
|
|
Packit |
78deda |
/* NOTREACHED */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Close file descriptors, and gen up a FILE ptr */
|
|
Packit |
78deda |
if ( *mode == 'r' )
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
/* Parent reads from pipe. */
|
|
Packit |
78deda |
close(pipefd[1]);
|
|
Packit |
78deda |
retfile = fdopen( pipefd[0], mode );
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
/* Parent writing to pipe. */
|
|
Packit |
78deda |
close(pipefd[0]);
|
|
Packit |
78deda |
retfile = fdopen( pipefd[1], mode );
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Return the PID. */
|
|
Packit |
78deda |
*pid = thepid;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return retfile;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
reapChildren(int * const catchingChildrenP,
|
|
Packit |
78deda |
pid_t * const pids) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Check for dead children. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (*catchingChildrenP > 0) {
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Check all children to see if any are dead, reap them if so. */
|
|
Packit |
78deda |
for (i = 0; i < *catchingChildrenP; ++i) {
|
|
Packit |
78deda |
/* The assumption here is that if it's dead, the kill
|
|
Packit |
78deda |
* will fail, but, because we haven't waited for
|
|
Packit |
78deda |
* it yet, it's a zombie.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
if (kill(pids[i], 0) < 0) {
|
|
Packit |
78deda |
int opid = pids[i], pid = 0;
|
|
Packit |
78deda |
/* Wait for processes & delete them from the list,
|
|
Packit |
78deda |
* until we get the one we know is dead.
|
|
Packit |
78deda |
* When removing one earlier in the list than
|
|
Packit |
78deda |
* the one we found, decrement our loop index.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
while (pid != opid) {
|
|
Packit |
78deda |
unsigned int j;
|
|
Packit |
78deda |
pid = wait(NULL);
|
|
Packit |
78deda |
for (j = 0;
|
|
Packit |
78deda |
j < *catchingChildrenP && pids[j] != pid;
|
|
Packit |
78deda |
++j)
|
|
Packit |
78deda |
;
|
|
Packit |
78deda |
if (pid < 0)
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
if (j < *catchingChildrenP) {
|
|
Packit |
78deda |
if (i >= j)
|
|
Packit |
78deda |
--i;
|
|
Packit |
78deda |
for (++j; j < *catchingChildrenP; ++j)
|
|
Packit |
78deda |
pids[j-1] = pids[j];
|
|
Packit |
78deda |
--*catchingChildrenP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
#endif /* !NO_OPEN_PIPES */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
dealWithSubprocess(const char * const file_name,
|
|
Packit |
78deda |
const char * const mode,
|
|
Packit |
78deda |
int * const catchingChildrenP,
|
|
Packit |
78deda |
pid_t * const pids,
|
|
Packit |
78deda |
FILE ** const fpP,
|
|
Packit |
78deda |
bool * const noSubprocessP,
|
|
Packit |
78deda |
const char ** const errorP) {
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
#ifdef NO_OPEN_PIPES
|
|
Packit |
78deda |
*noSubprocessP = TRUE;
|
|
Packit Service |
2370ca |
#else
|
|
Packit Service |
2370ca |
const char *cp;
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
reapChildren(catchingChildrenP, pids);
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
/* Real file, not stdin or stdout. If name ends in ".Z",
|
|
Packit Service |
2370ca |
* pipe from/to un/compress (depending on r/w mode).
|
|
Packit Service |
2370ca |
*
|
|
Packit Service |
2370ca |
* If it starts with "|", popen that command.
|
|
Packit Service |
2370ca |
*/
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
cp = file_name + strlen(file_name) - 2;
|
|
Packit Service |
2370ca |
/* Pipe case. */
|
|
Packit Service |
2370ca |
if (file_name[0] == '|') {
|
|
Packit Service |
2370ca |
pid_t thepid; /* PID from my_popen */
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
*noSubprocessP = FALSE;
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
*fpP = my_popen(file_name + 1, mode, &thepid);
|
|
Packit Service |
2370ca |
if (*fpP == NULL)
|
|
Packit Service |
2370ca |
*errorP = "%s: can't invoke <<%s>> for %s: ";
|
|
Packit Service |
2370ca |
else {
|
|
Packit Service |
2370ca |
/* One more child to catch, eventually. */
|
|
Packit Service |
2370ca |
if (*catchingChildrenP < MAX_CHILDREN)
|
|
Packit Service |
2370ca |
pids[(*catchingChildrenP)++] = thepid;
|
|
Packit Service |
2370ca |
}
|
|
Packit Service |
2370ca |
} else if (cp > file_name && *cp == '.' && *(cp + 1) == 'Z' ) {
|
|
Packit Service |
2370ca |
/* Compress case. */
|
|
Packit Service |
2370ca |
pid_t thepid; /* PID from my_popen. */
|
|
Packit Service |
2370ca |
const char * command;
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
*noSubprocessP = FALSE;
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
if (*mode == 'w')
|
|
Packit Service |
2370ca |
pm_asprintf(&command, "compress > %s", file_name);
|
|
Packit Service |
2370ca |
else if (*mode == 'a')
|
|
Packit Service |
2370ca |
pm_asprintf(&command, "compress >> %s", file_name);
|
|
Packit Service |
2370ca |
else
|
|
Packit Service |
2370ca |
pm_asprintf(&command, "compress -d < %s", file_name);
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
*fpP = my_popen(command, mode, &thepid);
|
|
Packit Service |
2370ca |
|
|
Packit Service |
2370ca |
if (*fpP == NULL)
|
|
Packit Service |
2370ca |
*errorP = "%s: can't invoke 'compress' program, "
|
|
Packit Service |
2370ca |
"trying to open %s for %s";
|
|
Packit Service |
2370ca |
else {
|
|
Packit Service |
2370ca |
/* One more child to catch, eventually. */
|
|
Packit Service |
2370ca |
if (*catchingChildrenP < MAX_CHILDREN)
|
|
Packit Service |
2370ca |
pids[(*catchingChildrenP)++] = thepid;
|
|
Packit Service |
2370ca |
}
|
|
Packit Service |
2370ca |
pm_strfree(command);
|
|
Packit Service |
2370ca |
} else {
|
|
Packit Service |
2370ca |
*noSubprocessP = TRUE;
|
|
Packit Service |
2370ca |
*errorP = NULL;
|
|
Packit Service |
2370ca |
}
|
|
Packit Service |
2370ca |
#endif
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/*
|
|
Packit |
78deda |
* Purpose : Open a file for input or ouput as controlled by the mode
|
|
Packit |
78deda |
* parameter. If no file name is specified (ie. file_name is null) then
|
|
Packit |
78deda |
* a pointer to stdin or stdout will be returned. The calling routine may
|
|
Packit |
78deda |
* call this routine with a file name of "-". For this case rle_open_f
|
|
Packit |
78deda |
* will return a pointer to stdin or stdout depending on the mode.
|
|
Packit |
78deda |
* If the user specifies a non-null file name and an I/O error occurs
|
|
Packit |
78deda |
* when trying to open the file, rle_open_f will terminate execution with
|
|
Packit |
78deda |
* an appropriate error message.
|
|
Packit |
78deda |
*
|
|
Packit |
78deda |
* parameters
|
|
Packit |
78deda |
* input:
|
|
Packit |
78deda |
* prog_name: name of the calling program.
|
|
Packit |
78deda |
* file_name : name of the file to open
|
|
Packit |
78deda |
* mode : either "r" for read or input file or "w" for write or
|
|
Packit |
78deda |
* output file
|
|
Packit |
78deda |
*
|
|
Packit |
78deda |
* output:
|
|
Packit |
78deda |
* a file pointer
|
|
Packit |
78deda |
*
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
FILE *
|
|
Packit |
78deda |
rle_open_f_noexit(const char * const prog_name,
|
|
Packit |
78deda |
const char * const file_name,
|
|
Packit |
78deda |
const char * const mode ) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
FILE * retval;
|
|
Packit |
78deda |
FILE * fp;
|
|
Packit |
78deda |
const char * err_str;
|
|
Packit |
78deda |
int catching_children;
|
|
Packit |
78deda |
pid_t pids[MAX_CHILDREN];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
catching_children = 0;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (*mode == 'w' || *mode == 'a')
|
|
Packit |
78deda |
fp = stdout; /* Set the default value */
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
fp = stdin;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (file_name != NULL && !streq(file_name, "-")) {
|
|
Packit |
78deda |
bool noSubprocess;
|
|
Packit |
78deda |
dealWithSubprocess(file_name, mode, &catching_children, pids,
|
|
Packit |
78deda |
&fp, &noSubprocess, &err_str);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!err_str) {
|
|
Packit |
78deda |
if (noSubprocess) {
|
|
Packit |
78deda |
/* Ordinary, boring file case. */
|
|
Packit |
78deda |
/* In the original code, the code to add the "b" was
|
|
Packit |
78deda |
conditionally included only if the macro
|
|
Packit |
78deda |
STDIO_NEEDS_BINARY was defined. But for Netpbm,
|
|
Packit |
78deda |
there is no need make a distinction; we always add
|
|
Packit |
78deda |
the "b". -BJH 2000.07.20.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
char mode_string[32]; /* Should be enough. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Concatenate a 'b' onto the mode. */
|
|
Packit |
78deda |
mode_string[0] = mode[0];
|
|
Packit |
78deda |
mode_string[1] = 'b';
|
|
Packit |
78deda |
strcpy( mode_string + 2, mode + 1 );
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fp = fopen(file_name, mode_string);
|
|
Packit |
78deda |
if (fp == NULL )
|
|
Packit |
78deda |
err_str = "%s: can't open %s for %s: ";
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
err_str = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (err_str) {
|
|
Packit |
78deda |
fprintf(stderr, err_str,
|
|
Packit |
78deda |
prog_name, file_name,
|
|
Packit |
78deda |
(*mode == 'w') ? "output" :
|
|
Packit |
78deda |
(*mode == 'a') ? "append" :
|
|
Packit |
78deda |
"input" );
|
|
Packit |
78deda |
fprintf(stderr, "errno = %d (%s)\n", errno, strerror(errno));
|
|
Packit |
78deda |
retval = NULL;
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
retval = fp;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
FILE *
|
|
Packit |
78deda |
rle_open_f(const char * prog_name, const char * file_name, const char * mode)
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
FILE *fp;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if ( (fp = rle_open_f_noexit( prog_name, file_name, mode )) == NULL )
|
|
Packit |
78deda |
exit( -1 );
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return fp;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/*****************************************************************
|
|
Packit |
78deda |
* TAG( rle_close_f )
|
|
Packit |
78deda |
*
|
|
Packit |
78deda |
* Close a file opened by rle_open_f. If the file is stdin or stdout,
|
|
Packit |
78deda |
* it will not be closed.
|
|
Packit |
78deda |
* Inputs:
|
|
Packit |
78deda |
* fd: File to close.
|
|
Packit |
78deda |
* Outputs:
|
|
Packit |
78deda |
* None.
|
|
Packit |
78deda |
* Assumptions:
|
|
Packit |
78deda |
* fd is open.
|
|
Packit |
78deda |
* Algorithm:
|
|
Packit |
78deda |
* If fd is NULL, just return.
|
|
Packit |
78deda |
* If fd is stdin or stdout, don't close it. Otherwise, call fclose.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
rle_close_f( fd )
|
|
Packit |
78deda |
FILE *fd;
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
if ( fd == NULL || fd == stdin || fd == stdout )
|
|
Packit |
78deda |
return;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
fclose( fd );
|
|
Packit |
78deda |
}
|