diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2021-03-27 19:16:06 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2021-03-27 19:16:06 +0000 |
commit | fcfa49ef6735be96386bda87bab2d0976475f585 (patch) | |
tree | fccbaafc41fb0f98682d4d48f7ff584bdbb81904 /other/pamexec.c | |
parent | a7fca291a0c78333da13e855bdb73aa819ba8649 (diff) | |
download | netpbm-mirror-fcfa49ef6735be96386bda87bab2d0976475f585.tar.gz netpbm-mirror-fcfa49ef6735be96386bda87bab2d0976475f585.tar.xz netpbm-mirror-fcfa49ef6735be96386bda87bab2d0976475f585.zip |
Promote Development to Advanced, Release 10.94.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@4076 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'other/pamexec.c')
-rw-r--r-- | other/pamexec.c | 77 |
1 files changed, 60 insertions, 17 deletions
diff --git a/other/pamexec.c b/other/pamexec.c index c3a1ee78..cbde81ac 100644 --- a/other/pamexec.c +++ b/other/pamexec.c @@ -15,8 +15,11 @@ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ +#include <stdbool.h> #include <string.h> #include <stdio.h> +#include <signal.h> +#include <setjmp.h> #include <errno.h> #include "pm_c_util.h" @@ -25,7 +28,27 @@ #include "mallocvar.h" #include "pam.h" -struct cmdlineInfo { + +/* About SIGPIPE: + + Unix has a strange function where by default, if you write into a pipe when + the reading side of the pipe has been closed, it generates a signal (of + class SIGPIPE), but if you tell the OS to ignore signals of class SIGPIPE, + then instead of generating that signal, the system call to write to the + pipe just fails. + + Pamexec writes to a pipe when it feeds an image to the user's program's + Standard Input. Should the user's program close its end of the pipe (such + as by exiting) before reading the whole image, that would, if we did + nothing to deal with it, cause Pamexec to receive a SIGPIPE signal, which + would make the OS terminate Pamexec. + + We don't want that, so we tell the OS to ignore SIGPIPE signals, so that + instead our attempt to write to the pipe just fails and we fail with a + meaningful error message. +*/ + +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -40,7 +63,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, const char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the pointers we place into *cmdlineP are sometimes to storage in the argv array. @@ -59,13 +82,13 @@ parseCommandLine(int argc, const char ** argv, OPTENT3(0, "check", OPT_FLAG, NULL, &cmdlineP->check, 0); opt.opt_table = option_def; - opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = false; /* We have no parms that are negative numbers */ pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - if (argc-1 < 1) + if (argc-1 < 1) pm_error("You must specify at least one argument: the shell command " "to execute"); else { @@ -92,7 +115,7 @@ pipeOneImage(FILE * const infileP, struct pam inpam; struct pam outpam; enum pm_check_code checkRetval; - + unsigned int row; tuple * tuplerow; @@ -107,9 +130,25 @@ pipeOneImage(FILE * const infileP, tuplerow = pnm_allocpamrow(&inpam); - for (row = 0; row < inpam.height; ++row) { - pnm_readpamrow(&inpam, tuplerow); - pnm_writepamrow(&outpam, tuplerow); + { + jmp_buf jmpbuf; + int rc; + rc = setjmp(jmpbuf); + if (rc == 0) { + pm_setjmpbuf(&jmpbuf); + + for (row = 0; row < inpam.height; ++row) { + pnm_readpamrow(&inpam, tuplerow); + pnm_writepamrow(&outpam, tuplerow); + } + } else { + pm_setjmpbuf(NULL); + pm_error("Failed to read image and pipe it to program's " + "Standard Input. If previous messages indicate " + "a broken pipe error, that means the program closed " + "its Standard Error (possibly by exiting) before " + "it had read the entire image>"); + } } pnm_freepamrow(tuplerow); @@ -133,7 +172,7 @@ doOneImage(FILE * const ifP, ofP = popen(command, "w"); if (ofP == NULL) - pm_asprintf(errorP, + pm_asprintf(errorP, "Failed to start shell to run command '%s'. " "errno = %d (%s)", command, errno, strerror(errno)); @@ -141,7 +180,7 @@ doOneImage(FILE * const ifP, int rc; pipeOneImage(ifP, ofP); - + rc = pclose(ofP); if (check && rc != 0) @@ -157,7 +196,7 @@ doOneImage(FILE * const ifP, int main(int argc, const char *argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; /* Input file pointer */ int eof; /* No more images in input */ @@ -169,12 +208,17 @@ main(int argc, const char *argv[]) { pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - + + /* Make write to closed pipe fail rather than generate a signal. + See comments at top of program. + */ + signal(SIGPIPE, SIG_IGN); + ifP = pm_openr(cmdline.inputFileName); - for (eof = FALSE, imageSeq = 0; !eof; ++imageSeq) { + for (eof = false, imageSeq = 0; !eof; ++imageSeq) { const char * error; - + doOneImage(ifP, cmdline.command, cmdline.check, &error); if (error) { @@ -185,9 +229,8 @@ main(int argc, const char *argv[]) { pnm_nextimage(ifP, &eof); } pm_close(ifP); - + return 0; } - |