From 40c8c828972af044b7628b2c167093f78353fcdd Mon Sep 17 00:00:00 2001 From: John Denker Date: Tue, 17 Jul 2012 13:05:15 -0700 Subject: fix commented-out bug; clarify variable-name --- tools/hi-q.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 7215b0c..237dbd5 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -424,7 +424,7 @@ int main(int argc, char** argv) { cerr << endl; } - pid_t special_kid = kidpid[nkids-1]; + pid_t special_pid = kidpid[nkids-1]; int alive(nkids-1); // not counting the special kid int best_blame(0); // best reason, even if not a great reason pid_t argbest_blame(-1); // kid# associated with best blame @@ -432,7 +432,7 @@ int main(int argc, char** argv) { for (;;) { if (alive == 0) break; pid_t somekid = waitpid(-1, &kidstatus, WUNTRACED); - if (somekid == special_kid){ + if (somekid == special_pid){ // do not decrement the "alive" counter // since that only applies to non-special kids if (WIFEXITED(kidstatus)) { @@ -510,13 +510,8 @@ int main(int argc, char** argv) { // now that the envelope information has been transfered, // wait for the last kid in the usual way { - -#ifdef moretesting -fprintf(stderr, "About to wait for kid #%d (%d)\n", - special_kid, kidpid[special_kid]); -#endif for(;;) { - waitpid(special_kid, &kidstatus, WUNTRACED); + waitpid(special_pid, &kidstatus, WUNTRACED); if (WIFEXITED(kidstatus)) { int sts = WEXITSTATUS(kidstatus); cerr << "hi-q ends with status: " << sts << endl; -- cgit v1.2.3 From b02174df1578e5d869001446815f461fb48589aa Mon Sep 17 00:00:00 2001 From: John Denker Date: Wed, 18 Jul 2012 04:58:36 -0700 Subject: minor upgrade to log/progress msg --- tools/hi-q.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 237dbd5..81e717a 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -514,11 +514,16 @@ int main(int argc, char** argv) { waitpid(special_pid, &kidstatus, WUNTRACED); if (WIFEXITED(kidstatus)) { int sts = WEXITSTATUS(kidstatus); - cerr << "hi-q ends with status: " << sts << endl; + cerr << "hi-q says: qq program " << kidpid[nkids-1] + << " i.e. '" << filter[nkids-1][0] << "'" + << " returned status " << sts + << endl; return sts; } else if (WIFSIGNALED(kidstatus)) { - cerr << "hi-q: special kid was killed by signal " - << WTERMSIG(kidstatus) << endl; + cerr << "hi-q says: qq program " << kidpid[nkids-1] + << " i.e. '" << filter[nkids-1][0] << "'" + << " was killed by signal " << WTERMSIG(kidstatus) + << endl; return ex_syserr; } else { /* paused, not dead */ -- cgit v1.2.3 From 8fe5ccdb4ee79b4d287b82e80004e1acc9ee4b94 Mon Sep 17 00:00:00 2001 From: John Denker Date: Thu, 19 Jul 2012 14:10:35 -0700 Subject: teach hi-q to have a "mode" word at the front of each line --- tools/hi-q.c | 82 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 32 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 81e717a..6140206 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -134,6 +134,39 @@ int xclose(int arg){ extern char** environ; +typedef enum {gray, black, qq, fail} moder; + +class jobber{ +public: + moder mode; + vector cmd; + + jobber(const moder _mode, const vector _cmd) + : mode(_mode), cmd(_cmd) + {} + + jobber(const string _mode, const vector _cmd) + : mode(fail), cmd(_cmd){ + setmode(_mode); + } + + jobber() + : mode(fail), cmd(0) + {} + + void setmode(const string _mode) { + if (0) {} + else if (_mode == "gray") mode = gray; + else if (_mode == "grey") mode = gray; // variant spelling + else if (_mode == "black") mode = black; + else if (_mode == "qq") mode = qq; + else { + cerr << "jobber: bad mode: " << _mode << endl; + mode = fail; + } + } +}; + int main(int argc, char** argv) { int verbose(0); int kidstatus; @@ -141,27 +174,8 @@ int main(int argc, char** argv) { int rslt; int loose_end = 0; -#ifdef SpareStuff - char* slurp2_args[] = {"/home/jsd/hack/slurp2", 0}; - char* echo_args[] = {"/bin/echo", "hi there", 0}; - char* wc_args[] = {"/usr/bin/wc", 0}; - char* cat_args[] = {"/bin/cat", 0}; - char* spama_args[] = {"/usr/local/bin/spamassassin", "-e", 0}; - char* spamc_args[] = {"/usr/local/bin/spamc", "-Z", "7", 0}; - char* qq_args[] = {"/var/qmail/bin/qmail-queue", 0}; - - - - const char** joblist[] = { - cat_args, - slurp2_args, - 0 // required: zero terminates the list - }; - -#endif - typedef vector VS; - vector filter; + vector filter; string conf_var = "HI_Q_CONF"; char* auth = getenv("QMAIL_AUTHORIZED"); if (auth && *auth) conf_var = "HI_Q_AUCONF"; @@ -199,15 +213,19 @@ int main(int argc, char** argv) { string line; if (!getline(conf, line).good()) break; istringstream parse(line); - vector job; + jobber job; while (parse.good()){ string token; parse >> token; if (parse.fail()) break; if (token[0] == '#') break; - job.push_back(token); + job.cmd.push_back(token); + } + if (job.cmd.size()) { + job.setmode(job.cmd.front()); + job.cmd.erase(job.cmd.begin()); } - if (job.size()) filter.push_back(job); + if (job.cmd.size()) filter.push_back(job); } unsigned int nkids = filter.size(); @@ -218,8 +236,8 @@ int main(int argc, char** argv) { if (0 && verbose) for (unsigned int ii = 0; ii < nkids; ii++) { cerr << "hi-q filter[" << ii << "] :; "; - for (VS::const_iterator token = filter[ii].begin(); - token != filter[ii].end(); token++){ + for (VS::const_iterator token = filter[ii].cmd.begin(); + token != filter[ii].cmd.end(); token++){ cerr << *token << " "; } cerr << endl; @@ -351,10 +369,10 @@ int main(int argc, char** argv) { // (except last kid reads fd1 as well as fd0). //// probe_fd(); - int ntok = filter[ii].size(); + int ntok = filter[ii].cmd.size(); const char* prog[1+ntok]; for (int jj = 0; jj < ntok; jj++){ - prog[jj] = filter[ii][jj].c_str(); + prog[jj] = filter[ii].cmd[jj].c_str(); } prog[ntok] = 0; close(resync[rEnd]); @@ -417,8 +435,8 @@ int main(int argc, char** argv) { cerr << "hi-q filter[" << ii << "] " << kidpid[ii] << " :; "; - for (VS::const_iterator token = filter[ii].begin(); - token != filter[ii].end(); token++){ + for (VS::const_iterator token = filter[ii].cmd.begin(); + token != filter[ii].cmd.end(); token++){ cerr << *token << " "; } cerr << endl; @@ -477,7 +495,7 @@ int main(int argc, char** argv) { if (sts == 1) { cerr << "hi-q says: kid[" << kidno << "]" << " pid " << argbest_blame - << " i.e. '" << filter[kidno][0] << "'" + << " i.e. '" << filter[kidno].cmd[0] << "'" << " reports spam." << endl; panic(ex_spam); } @@ -515,13 +533,13 @@ int main(int argc, char** argv) { if (WIFEXITED(kidstatus)) { int sts = WEXITSTATUS(kidstatus); cerr << "hi-q says: qq program " << kidpid[nkids-1] - << " i.e. '" << filter[nkids-1][0] << "'" + << " i.e. '" << filter[nkids-1].cmd[0] << "'" << " returned status " << sts << endl; return sts; } else if (WIFSIGNALED(kidstatus)) { cerr << "hi-q says: qq program " << kidpid[nkids-1] - << " i.e. '" << filter[nkids-1][0] << "'" + << " i.e. '" << filter[nkids-1].cmd[0] << "'" << " was killed by signal " << WTERMSIG(kidstatus) << endl; return ex_syserr; -- cgit v1.2.3 From a356f2e89ba2bc25207f2d9605a1d6bcca15d6d7 Mon Sep 17 00:00:00 2001 From: John Denker Date: Thu, 19 Jul 2012 14:56:22 -0700 Subject: log some interesting variables --- tools/hi-q.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 6140206..2ddc448 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -120,11 +120,16 @@ void usage() { // we have data coming in on fd 0. // and envelope / control information coming in on fd 1. +string progname; +pid_t mypid; + void dump(const string var){ char* str = getenv(var.c_str()); - if (str) cerr << "hi-q: " << var - << " is set to '" << str << "'" << endl; - else cerr << "hi-q: " << var << " is not set." << endl; + cerr << progname + << "[" << mypid << "] " + << var; + if (str) cerr << " is set to '" << str << "'" << endl; + else cerr << " is not set." << endl; } int xclose(int arg){ @@ -149,7 +154,7 @@ public: : mode(fail), cmd(_cmd){ setmode(_mode); } - + jobber() : mode(fail), cmd(0) {} @@ -168,6 +173,10 @@ public: }; int main(int argc, char** argv) { + progname = *argv; + mypid = getpid(); + dump("TCPREMOTEIP"); + dump("TCPREMOTEHOST"); int verbose(0); int kidstatus; @@ -534,7 +543,7 @@ int main(int argc, char** argv) { int sts = WEXITSTATUS(kidstatus); cerr << "hi-q says: qq program " << kidpid[nkids-1] << " i.e. '" << filter[nkids-1].cmd[0] << "'" - << " returned status " << sts + << " returned status " << sts << endl; return sts; } else if (WIFSIGNALED(kidstatus)) { -- cgit v1.2.3 From 84688a05a4430daf8dedf80bce35286aff4f4b1c Mon Sep 17 00:00:00 2001 From: John Denker Date: Thu, 19 Jul 2012 17:24:43 -0700 Subject: bare beginnings of a greylisting system --- tools/hi-q.c | 111 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 51 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 2ddc448..21724a1 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -11,7 +11,7 @@ #include #include /* for exit(), getenv() */ -#include +#include /* for perror */ #include #include /* for fork(), wait() */ #include @@ -29,6 +29,7 @@ using namespace std; // error exit codes, mostly as stated in qmail.c const int ex_good = 0; const int ex_spam = 21; +const int ex_grey = 70; const int ex_syserr = 71; const int ex_comerr = 74; @@ -139,7 +140,7 @@ int xclose(int arg){ extern char** environ; -typedef enum {gray, black, qq, fail} moder; +typedef enum {grey, black, qq, fail} moder; class jobber{ public: @@ -161,8 +162,8 @@ public: void setmode(const string _mode) { if (0) {} - else if (_mode == "gray") mode = gray; - else if (_mode == "grey") mode = gray; // variant spelling + else if (_mode == "gray") mode = grey; + else if (_mode == "grey") mode = grey; // variant spelling else if (_mode == "black") mode = black; else if (_mode == "qq") mode = qq; else { @@ -175,8 +176,8 @@ public: int main(int argc, char** argv) { progname = *argv; mypid = getpid(); - dump("TCPREMOTEIP"); - dump("TCPREMOTEHOST"); +// dump("TCPREMOTEIP"); +// dump("TCPREMOTEHOST"); int verbose(0); int kidstatus; @@ -270,41 +271,44 @@ int main(int argc, char** argv) { // to close it and dup() something useful onto it. map iiofpid; - for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */ - int datapipe[2]; - int kid_end; + for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */ //xx fprintf(stderr, "Top of loop %d loose: %d\n", ii, loose_end); - if (loose_end) { - close(0); - dup2(loose_end, 0); - close(loose_end); - } + int kid_end; + if (filter[ii].mode != grey){ + int datapipe[2]; -// Create a pipe, which will be used to connect -// this child's fd1 to the next child's fd0 ... -// except for the last kid, which reads both fd0 and fd1, -// while writing nothing. + if (loose_end) { + close(0); + dup2(loose_end, 0); + close(loose_end); + } - rslt = pipe(datapipe); - if (rslt < 0) { - fprintf(stderr, "hi-q: could not create datapipe: "); - perror(0); - panic(ex_syserr); - } + // Create a pipe, which will be used to connect + // this child's fd1 to the next child's fd0 ... + // except for the last kid, which reads both fd0 and fd1, + // while writing nothing. -//xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]); + rslt = pipe(datapipe); + if (rslt < 0) { + fprintf(stderr, "hi-q: could not create datapipe: "); + perror(0); + panic(ex_syserr); + } -// For N-1 kids, the loose end feeds forward. -// It will be written by this kid and read by the next kid. -// For the last kid, the loose end connects to hi-q. -// It will be written by hi-q and read by the last kid. + //xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]); - int lastkid = (ii == nkids-1); -#define flip(a,b) (lastkid ? b : a) - loose_end = datapipe[flip(rEnd, wEnd)]; - kid_end = datapipe[flip(wEnd, rEnd)]; + // For N-1 kids, the loose end feeds forward. + // It will be written by this kid and read by the next kid. + // For the last kid, the loose end connects to hi-q. + // It will be written by hi-q and read by the last kid. + + int lastkid = (ii == nkids-1); + #define flip(a,b) (lastkid ? b : a) + loose_end = datapipe[flip(rEnd, wEnd)]; + kid_end = datapipe[flip(wEnd, rEnd)]; + } kidpid[ii] = fork(); if (kidpid[ii] == -1) { @@ -358,24 +362,23 @@ int main(int argc, char** argv) { } } -// Now that we are through creating pipes, we don't -// need to continue blocking fd1: - close(1); - - close(loose_end); // the reading end is none of this kid's business - // except last kid: writing end + if (filter[ii].mode != grey){ + close(loose_end); // the reading end is none of this kid's business + // except last kid: writing end + + // Note this does an implicit close on the previously-open fd1: + rslt = dup2(kid_end, 1); // the writing end is stdout for this kid + // except last kid: nonstandard input + if (rslt < 0) { + fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end); + perror(0); + exit(ex_syserr); + } - rslt = dup2(kid_end, 1); // the writing end is stdout for this kid - // except last kid: nonstandard input - if (rslt < 0) { - fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end); - perror(0); - exit(ex_syserr); + close(kid_end); // use fd1 instead now + // OK, at this point this kid is set up to read fd0 and write fd1 + // (except last kid reads fd1 as well as fd0). } - - close(kid_end); // use fd1 instead now - // OK, at this point this kid is set up to read fd0 and write fd1 - // (except last kid reads fd1 as well as fd0). //// probe_fd(); int ntok = filter[ii].cmd.size(); @@ -499,14 +502,20 @@ int main(int argc, char** argv) { if (best_blame) { string short_name(""); int kidno(iiofpid[argbest_blame]); + string exword = "spam"; + int excode = ex_spam; + if (filter[kidno].mode == grey) { + exword = "greylisting"; + excode = ex_grey; + } if (WIFEXITED(best_blame)) { int sts = WEXITSTATUS(best_blame); if (sts == 1) { cerr << "hi-q says: kid[" << kidno << "]" << " pid " << argbest_blame << " i.e. '" << filter[kidno].cmd[0] << "'" - << " reports spam." << endl; - panic(ex_spam); + << " reports " << exword << endl; + panic(excode); } if (sts != 0) { cerr << "hi-q says: kid " << argbest_blame -- cgit v1.2.3 From e9b59f501b23b53eb6f230e0dfc4d50bb6995d45 Mon Sep 17 00:00:00 2001 From: John Denker Date: Fri, 20 Jul 2012 11:05:02 -0700 Subject: add some exit-code processing; require TCPREMOTEHOST --- tools/hi-q.c | 67 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 16 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 21724a1..f195508 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -27,11 +27,42 @@ using namespace std; #include // error exit codes, mostly as stated in qmail.c -const int ex_good = 0; -const int ex_spam = 21; -const int ex_grey = 70; -const int ex_syserr = 71; -const int ex_comerr = 74; +#define bar \ +foo(good, 0) ;\ +foo(spam, 21) ;\ +foo(permerr, 31) ;\ +foo(greylisting, 70) ;\ +foo(syserr, 71) ;\ +foo(comerr, 74) ; + +#define foo(name, num) const int ex_ ## name = num +bar +#undef foo + +map codemap; + + +#define bar_sa \ +foo_sa(GOOD, 0, "ham") ;\ +foo_sa(SPAM, 1, "spam") ;\ +foo_sa(USAGE, 64, "command line usage error") ;\ +foo_sa(DATAERR, 65, "data format error") ;\ +foo_sa(NOINPUT, 66, "cannot open input") ;\ +foo_sa(NOUSER, 67, "addressee unknown") ;\ +foo_sa(NOHOST, 68, "host name unknown") ;\ +foo_sa(UNAVAILABLE, 69, "service unavailable") ;\ +foo_sa(SOFTWARE, 70, "internal software error") ;\ +foo_sa(OSERR, 71, "system error (e.g., can't fork)") ;\ +foo_sa(OSFILE, 72, "critical OS file missing") ;\ +foo_sa(CANTCREAT, 73, "can't create (user) output file") ;\ +foo_sa(IOERR, 74, "input/output error") ;\ +foo_sa(TEMPFAIL, 75, "temp failure; user is invited to retry") ;\ +foo_sa(PROTOCOL, 76, "remote error in protocol") ;\ +foo_sa(NOPERM, 77, "permission denied") ;\ +foo_sa(CONFIG, 78, "configuration error") ;\ +foo_sa(TOOBIG, 98, "message was too big to process (see --max-size)" + + #define bufsize 16384 @@ -176,8 +207,11 @@ public: int main(int argc, char** argv) { progname = *argv; mypid = getpid(); -// dump("TCPREMOTEIP"); -// dump("TCPREMOTEHOST"); + +#define foo(name, num) codemap[num] = #name ; +bar +#undef foo + int verbose(0); int kidstatus; @@ -502,15 +536,15 @@ int main(int argc, char** argv) { if (best_blame) { string short_name(""); int kidno(iiofpid[argbest_blame]); - string exword = "spam"; - int excode = ex_spam; - if (filter[kidno].mode == grey) { - exword = "greylisting"; - excode = ex_grey; - } if (WIFEXITED(best_blame)) { + string exword = "spam"; // default, for non-modern status codes + int excode = ex_spam; // default, for non-modern status codes int sts = WEXITSTATUS(best_blame); - if (sts == 1) { + if (filter[kidno].mode == grey) { + exword = codemap[sts]; + excode = sts; + } + if (exword.length()) { cerr << "hi-q says: kid[" << kidno << "]" << " pid " << argbest_blame << " i.e. '" << filter[kidno].cmd[0] << "'" @@ -523,8 +557,9 @@ int main(int argc, char** argv) { << endl; panic(ex_syserr); } else { - // should never get here unless exit status was nonzero - cerr << "hi-q: should never happen" << endl; + // should never get here + // should be no accounting for blame if there was no blame + cerr << "hi-q: should never happen: no child to blame" << endl; panic(ex_syserr); } } else if (WIFSIGNALED(best_blame)) { -- cgit v1.2.3 From 60fd39ff24975486da7d02cdf07abae31c525529 Mon Sep 17 00:00:00 2001 From: John Denker Date: Fri, 20 Jul 2012 12:15:59 -0700 Subject: much smarter about exit status conventions --- tools/hi-q.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index f195508..369935e 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -68,6 +68,7 @@ foo_sa(TOOBIG, 98, "message was too big to process (see --max-size)" void panic(const int sts) { // FIXME: stop other children + cerr << "hi-q: panic called with " << sts << endl; exit(sts); } @@ -171,7 +172,15 @@ int xclose(int arg){ extern char** environ; -typedef enum {grey, black, qq, fail} moder; +// meanings: +// sa is a filter, using not-very-expressive exit codes: 0=ham 1=spam. +// stub is not a filter; no stdin or stdout; just looks at environment. +// series is a filter. +// qq is not a filter, just an absorber. +// +// Note that series and stub use the same exit codes as qq. +// +typedef enum {series, stub, sa, qq, fail} moder; class jobber{ public: @@ -193,9 +202,9 @@ public: void setmode(const string _mode) { if (0) {} - else if (_mode == "gray") mode = grey; - else if (_mode == "grey") mode = grey; // variant spelling - else if (_mode == "black") mode = black; + else if (_mode == "sa") mode = sa; + else if (_mode == "stub") mode = stub; + else if (_mode == "series") mode = series; else if (_mode == "qq") mode = qq; else { cerr << "jobber: bad mode: " << _mode << endl; @@ -310,7 +319,7 @@ bar //xx fprintf(stderr, "Top of loop %d loose: %d\n", ii, loose_end); int kid_end; - if (filter[ii].mode != grey){ + if (filter[ii].mode != stub){ int datapipe[2]; if (loose_end) { @@ -396,7 +405,7 @@ bar } } - if (filter[ii].mode != grey){ + if (filter[ii].mode != stub){ close(loose_end); // the reading end is none of this kid's business // except last kid: writing end @@ -540,7 +549,7 @@ bar string exword = "spam"; // default, for non-modern status codes int excode = ex_spam; // default, for non-modern status codes int sts = WEXITSTATUS(best_blame); - if (filter[kidno].mode == grey) { + if (filter[kidno].mode != sa) { exword = codemap[sts]; excode = sts; } -- cgit v1.2.3 From eb342191804df42d294e1579a880c58dd213d66d Mon Sep 17 00:00:00 2001 From: John Denker Date: Fri, 20 Jul 2012 16:15:13 -0700 Subject: fix up error parsing and error logging --- tools/hi-q.c | 263 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 173 insertions(+), 90 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 369935e..f6b57e1 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -5,7 +5,7 @@ // Hint: For testing, see also hi-test.conf which invokes ./hi-test: // ./hi-q hi-test.conf -// TODO: Panic stop should signal all children. +// TODO: Exeunt stop should signal all children. // TODO: Possibly: Wait for all kids in parallel? // That's because they might finish out of order. @@ -66,9 +66,128 @@ foo_sa(TOOBIG, 98, "message was too big to process (see --max-size)" #define bufsize 16384 -void panic(const int sts) { +// meanings: +// sa is a filter, using not-very-expressive exit codes: 0=ham 1=spam. +// stub is not a filter; no stdin or stdout; just looks at environment. +// series is a filter. +// qq is not a filter, just an absorber. +// +// Note that series and stub use the same exit codes as qq. +// +typedef enum {series, stub, sa, qq, postspam, fail} moder; + +class jobber{ +public: + moder mode; + vector cmd; + + jobber(const moder _mode, const vector _cmd) + : mode(_mode), cmd(_cmd) + {} + + jobber(const string _mode, const vector _cmd) + : mode(fail), cmd(_cmd){ + setmode(_mode); + } + + jobber() + : mode(fail), cmd(0) + {} + + void setmode(const string _mode) { + if (0) {} + else if (_mode == "sa") mode = sa; + else if (_mode == "stub") mode = stub; + else if (_mode == "series") mode = series; + else if (_mode == "qq") mode = qq; + else if (_mode == "postspam") mode = postspam; + else { + cerr << "jobber: bad mode: " << _mode << endl; + mode = fail; + } + } +}; + +// klugey global variable: +vector post; + +// We are fussy about the argument types because we want +// this to compile cleanly under g++ as well as gcc, +// and each is strict about different things, such that +// one or the other will complain unless everything is +// done just right. + +// This is the way execve really behaves: +// the characters are held constant +// and the (char*) pointers are held constant: +int Execve(char const * fn, + char const * const * argv, + char const * const * env) { +// coerce the arg types to match the unwise declaration in unistd.h : + return execve(fn, (char*const*) argv, (char*const*) env); +} + +int fork_and_wait(const jobber job){ + pid_t kidpid = fork(); + if (kidpid == -1) { + cerr << "hi-q: fork failed : "; + perror(0); + exit(ex_syserr); + } + int ntok = job.cmd.size(); + const char* prog[1+ntok]; + for (int jj = 0; jj < ntok; jj++){ + prog[jj] = job.cmd[jj].c_str(); + } + prog[ntok] = 0; + + if (!kidpid){ + /*** child code ***/ + int rslt; + rslt = Execve(prog[0], prog, environ); + fprintf(stderr, "hi-q: failed to exec '%s': ", prog[0]); + perror(0); + exit(ex_syserr); + } else { + /*** parent code ***/ + int kidstatus; + pid_t somekid; + somekid = waitpid(kidpid, &kidstatus, WUNTRACED); + if (WIFEXITED(kidstatus)) { + int sts = WEXITSTATUS(kidstatus); + if (sts != ex_good && sts != ex_spam) { + cerr << "hi-q: job " << prog[0] + << " unexpectedly returns status: " << sts + << endl; + exit(sts); + } + return 0; + } else if (WIFSIGNALED(kidstatus)) { + int sig = WTERMSIG(kidstatus); + if (sig == SIGUSR1) {/* normal, no logging required */} + else cerr << "hi-q: job " << prog[0] + << " killed by signal " << sig << endl; + return(ex_syserr); + } else { + /* paused, not dead */ + } + } + return 0; +} + +int fork_and_wait(vector post){ + for(vector::const_iterator foo = post.begin(); + foo != post.end(); foo++) { + int rslt = fork_and_wait(*foo); + if (rslt) return rslt; + } + return 0; +} + +void exeunt(const int sts) { // FIXME: stop other children - cerr << "hi-q: panic called with " << sts << endl; + //xxxx cerr << "hi-q: exeunt called with " << sts << endl; + if (sts == ex_spam) fork_and_wait(post); exit(sts); } @@ -83,7 +202,7 @@ void slurp(const int inch, const int ouch){ if (got < 0) { fprintf(stderr, "hi-q: input error: "); perror(0); - panic(ex_comerr); + exeunt(ex_comerr); } todo = got; @@ -92,7 +211,7 @@ void slurp(const int inch, const int ouch){ if (sent < 0 && errno != EINTR) { fprintf(stderr, "hi-q: output error on fd%d : ", ouch); perror(0); - panic(ex_comerr); + exeunt(ex_comerr); } todo -= sent; } @@ -126,22 +245,6 @@ void blurb(const int ii, const pid_t* kidpid) { } -// We are fussy about the argument types because we want -// this to compile cleanly under g++ as well as gcc, -// and each is strict about different things, such that -// one or the other will complain unless everything is -// done just right. - -// This is the way execve really behaves: -// the characters are held constant -// and the (char*) pointers are held constant: -int Execve(char const * fn, - char const * const * argv, - char const * const * env) { -// coerce the arg types to match the unwise declaration in unistd.h : - return execve(fn, (char*const*) argv, (char*const*) env); -} - void usage() { cerr << "Usage:\n" " hi-q filter.conf\n" @@ -172,47 +275,6 @@ int xclose(int arg){ extern char** environ; -// meanings: -// sa is a filter, using not-very-expressive exit codes: 0=ham 1=spam. -// stub is not a filter; no stdin or stdout; just looks at environment. -// series is a filter. -// qq is not a filter, just an absorber. -// -// Note that series and stub use the same exit codes as qq. -// -typedef enum {series, stub, sa, qq, fail} moder; - -class jobber{ -public: - moder mode; - vector cmd; - - jobber(const moder _mode, const vector _cmd) - : mode(_mode), cmd(_cmd) - {} - - jobber(const string _mode, const vector _cmd) - : mode(fail), cmd(_cmd){ - setmode(_mode); - } - - jobber() - : mode(fail), cmd(0) - {} - - void setmode(const string _mode) { - if (0) {} - else if (_mode == "sa") mode = sa; - else if (_mode == "stub") mode = stub; - else if (_mode == "series") mode = series; - else if (_mode == "qq") mode = qq; - else { - cerr << "jobber: bad mode: " << _mode << endl; - mode = fail; - } - } -}; - int main(int argc, char** argv) { progname = *argv; mypid = getpid(); @@ -278,7 +340,14 @@ bar job.setmode(job.cmd.front()); job.cmd.erase(job.cmd.begin()); } - if (job.cmd.size()) filter.push_back(job); + // here with a properly built job descriptor + if (job.cmd.size()) { + if (job.mode == postspam) { + post.push_back(job); + } else { + filter.push_back(job); + } + } } unsigned int nkids = filter.size(); @@ -337,7 +406,7 @@ bar if (rslt < 0) { fprintf(stderr, "hi-q: could not create datapipe: "); perror(0); - panic(ex_syserr); + exeunt(ex_syserr); } //xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]); @@ -451,7 +520,7 @@ bar if (kidpid[ii] < 0) { fprintf(stderr, "hi-q: failure to fork kid#%d: ", ii); perror(0); - panic(ex_syserr); + exeunt(ex_syserr); } close(kid_end); @@ -509,11 +578,20 @@ bar // do not decrement the "alive" counter // since that only applies to non-special kids if (WIFEXITED(kidstatus)) { - cerr << "hi-q: special kid exited early" << endl; - return(ex_syserr); - } else if (WIFSIGNALED(kidstatus) && WTERMSIG(kidstatus) != SIGUSR1) { - cerr << "hi-q: special kid exited early" << endl; + cerr << "hi-q: special kid exited early, status " + << WEXITSTATUS(kidstatus) + << " with " << alive << " kids still alive" + << endl; return(ex_syserr); + } else if (WIFSIGNALED(kidstatus)) { + int sig = WTERMSIG(kidstatus); + if (sig == SIGUSR1) {/* normal, no logging required */} + else { + cerr << "hi-q: special kid killed by signal " + << sig << endl; + // this is not normal + return(ex_syserr); + } } else { /* paused, not dead */ } @@ -542,42 +620,47 @@ bar /////////////////// // decode the best reason why the filter-chain terminated + //xx cerr << "cleanup: " << best_blame << endl; if (best_blame) { string short_name(""); int kidno(iiofpid[argbest_blame]); if (WIFEXITED(best_blame)) { - string exword = "spam"; // default, for non-modern status codes - int excode = ex_spam; // default, for non-modern status codes + string exword = "???"; // default, should never happen + int excode = ex_syserr; // default, should never happen int sts = WEXITSTATUS(best_blame); - if (filter[kidno].mode != sa) { - exword = codemap[sts]; - excode = sts; - } - if (exword.length()) { - cerr << "hi-q says: kid[" << kidno << "]" - << " pid " << argbest_blame - << " i.e. '" << filter[kidno].cmd[0] << "'" - << " reports " << exword << endl; - panic(excode); - } - if (sts != 0) { - cerr << "hi-q says: kid " << argbest_blame - << " exited with bad status: " << sts - << endl; - panic(ex_syserr); - } else { + if (sts == 0){ // should never get here // should be no accounting for blame if there was no blame cerr << "hi-q: should never happen: no child to blame" << endl; - panic(ex_syserr); + exeunt(ex_syserr); + } + + if (filter[kidno].mode != sa) { + exword = codemap[sts]; + excode = sts; + } else { // here to translate spamc results + if (sts == 1) { + excode = ex_spam; + exword = "spam"; + } else { + excode = ex_syserr; + stringstream foo; + foo << "bad status: " << sts; + exword = foo.str(); + } } + cerr << "hi-q concludes: kid[" << kidno << "]" + << " pid " << argbest_blame + << " i.e. '" << filter[kidno].cmd[0] << "'" + << " reports " << exword << endl; + exeunt(excode); } else if (WIFSIGNALED(best_blame)) { int sig = WTERMSIG(best_blame); cerr << "hi-q says: kid " << argbest_blame << " was killed by signal " << sig << endl; // if the *best* blame is a kill, that's not normal - panic(ex_syserr); + exeunt(ex_syserr); } } -- cgit v1.2.3 From 4e298a27d17d0d0a4181b302b4237363396eb0ed Mon Sep 17 00:00:00 2001 From: John Denker Date: Fri, 20 Jul 2012 17:02:38 -0700 Subject: more regularization of reporting --- tools/hi-q.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index f6b57e1..26e67a7 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -258,12 +258,11 @@ void usage() { string progname; pid_t mypid; +string progid; void dump(const string var){ char* str = getenv(var.c_str()); - cerr << progname - << "[" << mypid << "] " - << var; + cerr << progid << var; if (str) cerr << " is set to '" << str << "'" << endl; else cerr << " is not set." << endl; } @@ -276,8 +275,16 @@ int xclose(int arg){ extern char** environ; int main(int argc, char** argv) { - progname = *argv; - mypid = getpid(); + { + progname = *argv; + mypid = getpid(); + string shortname = progname; + size_t where = shortname.rfind("/"); + if (where != string::npos) shortname = shortname.substr(1+where); + stringstream binder; + binder << shortname << "[" << mypid << "]"; + progid = binder.str(); + } #define foo(name, num) codemap[num] = #name ; bar @@ -649,14 +656,18 @@ bar exword = foo.str(); } } - cerr << "hi-q concludes: kid[" << kidno << "]" - << " pid " << argbest_blame - << " i.e. '" << filter[kidno].cmd[0] << "'" + cerr << progid + << " concludes: kid[" << kidno << "]" + << " i.e. " << filter[kidno].cmd[0] + << "[" << argbest_blame << "]" << " reports " << exword << endl; exeunt(excode); } else if (WIFSIGNALED(best_blame)) { int sig = WTERMSIG(best_blame); - cerr << "hi-q says: kid " << argbest_blame + cerr << progid + << " concludes: kid[" << kidno << "]" + << " i.e. " << filter[kidno].cmd[0] + << "[" << argbest_blame << "]" << " was killed by signal " << sig << endl; // if the *best* blame is a kill, that's not normal @@ -677,14 +688,18 @@ bar waitpid(special_pid, &kidstatus, WUNTRACED); if (WIFEXITED(kidstatus)) { int sts = WEXITSTATUS(kidstatus); - cerr << "hi-q says: qq program " << kidpid[nkids-1] - << " i.e. '" << filter[nkids-1].cmd[0] << "'" + cerr << progid + << " says: qq program" + << " i.e. " << filter[nkids-1].cmd[0] + << "[" << kidpid[nkids-1] << "]" << " returned status " << sts << endl; return sts; } else if (WIFSIGNALED(kidstatus)) { - cerr << "hi-q says: qq program " << kidpid[nkids-1] - << " i.e. '" << filter[nkids-1].cmd[0] << "'" + cerr << progid + << " says: qq program" + << " i.e. " << filter[nkids-1].cmd[0] + << "[" << kidpid[nkids-1] << "]" << " was killed by signal " << WTERMSIG(kidstatus) << endl; return ex_syserr; -- cgit v1.2.3 From 60ebe6c00a2868e6bb69ef30cf04e5568276808b Mon Sep 17 00:00:00 2001 From: John Denker Date: Fri, 20 Jul 2012 22:18:31 -0700 Subject: implement penaltybox return-code (exit status) also make sure DNS checking doesn't interfere with more basic duties such as keeping the greylist database updated --- tools/hi-q.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 26e67a7..6aaf302 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -30,6 +30,7 @@ using namespace std; #define bar \ foo(good, 0) ;\ foo(spam, 21) ;\ +foo(penaltybox, 22) ;\ foo(permerr, 31) ;\ foo(greylisting, 70) ;\ foo(syserr, 71) ;\ @@ -188,6 +189,7 @@ void exeunt(const int sts) { // FIXME: stop other children //xxxx cerr << "hi-q: exeunt called with " << sts << endl; if (sts == ex_spam) fork_and_wait(post); + if (sts == ex_penaltybox) exit(ex_spam); exit(sts); } @@ -274,15 +276,18 @@ int xclose(int arg){ extern char** environ; +string basename(const string path){ + size_t where = path.rfind("/"); + if (where != string::npos) return path.substr(1+where); + return path; +} + int main(int argc, char** argv) { { progname = *argv; mypid = getpid(); - string shortname = progname; - size_t where = shortname.rfind("/"); - if (where != string::npos) shortname = shortname.substr(1+where); stringstream binder; - binder << shortname << "[" << mypid << "]"; + binder << basename(progname) << "[" << mypid << "]"; progid = binder.str(); } @@ -658,7 +663,7 @@ bar } cerr << progid << " concludes: kid[" << kidno << "]" - << " i.e. " << filter[kidno].cmd[0] + << " i.e. " << basename(filter[kidno].cmd[0]) << "[" << argbest_blame << "]" << " reports " << exword << endl; exeunt(excode); @@ -666,7 +671,7 @@ bar int sig = WTERMSIG(best_blame); cerr << progid << " concludes: kid[" << kidno << "]" - << " i.e. " << filter[kidno].cmd[0] + << " i.e. " << basename(filter[kidno].cmd[0]) << "[" << argbest_blame << "]" << " was killed by signal " << sig << endl; @@ -690,7 +695,7 @@ bar int sts = WEXITSTATUS(kidstatus); cerr << progid << " says: qq program" - << " i.e. " << filter[nkids-1].cmd[0] + << " i.e. " << basename(filter[nkids-1].cmd[0]) << "[" << kidpid[nkids-1] << "]" << " returned status " << sts << endl; @@ -698,7 +703,7 @@ bar } else if (WIFSIGNALED(kidstatus)) { cerr << progid << " says: qq program" - << " i.e. " << filter[nkids-1].cmd[0] + << " i.e. " << basename(filter[nkids-1].cmd[0]) << "[" << kidpid[nkids-1] << "]" << " was killed by signal " << WTERMSIG(kidstatus) << endl; -- cgit v1.2.3 From 8ce08aca2410c795dfc46f37dc27402ff6de5dd1 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sat, 21 Jul 2012 15:53:08 -0700 Subject: ignore penalty features for the moment --- tools/hi-q.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 6aaf302..8766b08 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -158,7 +158,7 @@ int fork_and_wait(const jobber job){ int sts = WEXITSTATUS(kidstatus); if (sts != ex_good && sts != ex_spam) { cerr << "hi-q: job " << prog[0] - << " unexpectedly returns status: " << sts + << " unexpectedly returns status: " << sts << endl; exit(sts); } @@ -179,7 +179,7 @@ int fork_and_wait(const jobber job){ int fork_and_wait(vector post){ for(vector::const_iterator foo = post.begin(); foo != post.end(); foo++) { - int rslt = fork_and_wait(*foo); + int rslt = fork_and_wait(*foo); if (rslt) return rslt; } return 0; @@ -590,7 +590,7 @@ bar // do not decrement the "alive" counter // since that only applies to non-special kids if (WIFEXITED(kidstatus)) { - cerr << "hi-q: special kid exited early, status " + cerr << "hi-q: special kid exited early, status " << WEXITSTATUS(kidstatus) << " with " << alive << " kids still alive" << endl; @@ -599,10 +599,10 @@ bar int sig = WTERMSIG(kidstatus); if (sig == SIGUSR1) {/* normal, no logging required */} else { - cerr << "hi-q: special kid killed by signal " + cerr << "hi-q: special kid killed by signal " << sig << endl; // this is not normal - return(ex_syserr); + return(ex_syserr); } } else { /* paused, not dead */ @@ -612,7 +612,13 @@ bar // here if somekid is not the special kid if (WIFEXITED(kidstatus)) { alive--; - if (WEXITSTATUS(kidstatus)) { + int sts = WEXITSTATUS(kidstatus); +#ifndef PENALIZE_SPAMMERS + // ignore penalties for the moment + // to see whether there are any false positives + if (sts == ex_penaltybox) sts = ex_good; +#endif + if (sts) { argbest_blame = somekid; best_blame = kidstatus; break; @@ -694,7 +700,7 @@ bar if (WIFEXITED(kidstatus)) { int sts = WEXITSTATUS(kidstatus); cerr << progid - << " says: qq program" + << " says: qq program" << " i.e. " << basename(filter[nkids-1].cmd[0]) << "[" << kidpid[nkids-1] << "]" << " returned status " << sts @@ -702,7 +708,7 @@ bar return sts; } else if (WIFSIGNALED(kidstatus)) { cerr << progid - << " says: qq program" + << " says: qq program" << " i.e. " << basename(filter[nkids-1].cmd[0]) << "[" << kidpid[nkids-1] << "]" << " was killed by signal " << WTERMSIG(kidstatus) -- cgit v1.2.3 From 4e5612a4e83eee652b8bc79cfdcbd24e515879b8 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 22 Jul 2012 20:27:21 -0700 Subject: progress toward cleaning up logic of various modes and how the use their pipes --- tools/hi-q.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 8766b08..39c68e3 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -425,13 +425,31 @@ bar // For N-1 kids, the loose end feeds forward. // It will be written by this kid and read by the next kid. - // For the last kid, the loose end connects to hi-q. - // It will be written by hi-q and read by the last kid. - - int lastkid = (ii == nkids-1); - #define flip(a,b) (lastkid ? b : a) - loose_end = datapipe[flip(rEnd, wEnd)]; - kid_end = datapipe[flip(wEnd, rEnd)]; + // For the special kid, the loose end will be its nonstandard input. + // It will be written by us (hi-q) and read by the last kid. + + switch (filter[ii].mode) { + case series: + case sa: + loose_end = datapipe[rEnd]; + kid_end = datapipe[wEnd]; + break; + case qq: + loose_end = datapipe[wEnd]; // reverse of normal "series" case + kid_end = datapipe[rEnd]; // reverse of normal "series" case + break; + case postspam: + case stub: // didn't need a connection at all + cerr << "ignoring fd " << datapipe[wEnd] + << " and " << datapipe[rEnd] + << endl; + xclose(datapipe[wEnd]); + xclose(datapipe[rEnd]); + break; + case fail: + cerr << "should never happen: invalid filter" << endl; + exeunt(ex_syserr); + } } kidpid[ii] = fork(); -- cgit v1.2.3 From f8b0737d4ac6eb7152628a2c5fb8f30ae7fe2a24 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 22 Jul 2012 21:19:50 -0700 Subject: change from if-statements to switch-statements, to make sure all cases get handled --- tools/hi-q.c | 158 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 67 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 39c68e3..114570f 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -299,7 +299,7 @@ bar int kidstatus; int rslt; - int loose_end = 0; + int loose_end = 0; // our original stdin typedef vector VS; vector filter; @@ -368,7 +368,7 @@ bar // This makes it safe to assume that nkids-1 is non-negative. if (nkids == 0) exit(0); // nothing to do - if (0 && verbose) for (unsigned int ii = 0; ii < nkids; ii++) { + if (verbose) for (unsigned int ii = 0; ii < nkids; ii++) { cerr << "hi-q filter[" << ii << "] :; "; for (VS::const_iterator token = filter[ii].cmd.begin(); token != filter[ii].cmd.end(); token++){ @@ -397,59 +397,66 @@ bar map iiofpid; for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */ -//xx fprintf(stderr, "Top of loop %d loose: %d\n", ii, loose_end); - + //xx cerr << "top of loop ... loose end " << loose_end << " for " << ii << endl; + if (loose_end > 20) exit(99); int kid_end; - if (filter[ii].mode != stub){ - int datapipe[2]; - - if (loose_end) { - close(0); - dup2(loose_end, 0); - close(loose_end); - } - - // Create a pipe, which will be used to connect - // this child's fd1 to the next child's fd0 ... - // except for the last kid, which reads both fd0 and fd1, - // while writing nothing. - rslt = pipe(datapipe); - if (rslt < 0) { - fprintf(stderr, "hi-q: could not create datapipe: "); - perror(0); - exeunt(ex_syserr); - } - - //xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]); + int datapipe[2]; + + switch (filter[ii].mode) { + case series: + case qq: + case sa: +// connect *old* loose end to this kid's stdin + //xx cerr << "moving old loose end " << loose_end << " to 0 for " << ii << endl; + if (loose_end) { + close(0); + dup2(loose_end, 0); + close(loose_end); + } + +// Create a pipe, which will be used to connect +// this child's fd1 to the next child's fd0 ... +// except for the last kid, which reads both fd0 and fd1, +// while writing nothing. + rslt = pipe(datapipe); + if (rslt < 0) { + fprintf(stderr, "hi-q: could not create datapipe: "); + perror(0); + exeunt(ex_syserr); + } + break; + case postspam: + case stub: + // do not need to create a pipe + break; + case fail: + cerr << "should never happen: invalid filter" << endl; + exeunt(ex_syserr); + } - // For N-1 kids, the loose end feeds forward. - // It will be written by this kid and read by the next kid. - // For the special kid, the loose end will be its nonstandard input. - // It will be written by us (hi-q) and read by the last kid. +// For N-1 kids, the loose end feeds forward. +// It will be written by this kid and read by the next kid. +// For the special kid, the loose end will be its nonstandard input. +// It will be written by us (hi-q) and read by the last kid. - switch (filter[ii].mode) { - case series: - case sa: - loose_end = datapipe[rEnd]; - kid_end = datapipe[wEnd]; - break; - case qq: - loose_end = datapipe[wEnd]; // reverse of normal "series" case - kid_end = datapipe[rEnd]; // reverse of normal "series" case - break; - case postspam: - case stub: // didn't need a connection at all - cerr << "ignoring fd " << datapipe[wEnd] - << " and " << datapipe[rEnd] - << endl; - xclose(datapipe[wEnd]); - xclose(datapipe[rEnd]); - break; - case fail: - cerr << "should never happen: invalid filter" << endl; - exeunt(ex_syserr); - } + switch (filter[ii].mode) { + case series: + case sa: + loose_end = datapipe[rEnd]; + kid_end = datapipe[wEnd]; + break; + case qq: + loose_end = datapipe[wEnd]; // reverse of normal "series" case + kid_end = datapipe[rEnd]; // reverse of normal "series" case + break; + case postspam: + case stub: + // no pipe even got created. + break; + case fail: + cerr << "should never happen:: invalid filter" << endl; + exeunt(ex_syserr); } kidpid[ii] = fork(); @@ -460,6 +467,7 @@ bar } iiofpid[kidpid[ii]] = ii; if (!kidpid[ii]) { /*** child code ***/ + if (verbose) cerr << "top of kid ... loose end " << loose_end << " for " << ii << endl; pid_t kidgroup(0); // process group for all kids is // equal to pid of kid#0 @@ -488,6 +496,7 @@ bar #endif close(resync[wEnd]); // send resync + //xx cerr << "after sending resync " << ii << endl; // ... now we must wait for everybody else, because ... // ... if we do the exec(), the new process group becomes invalid ... @@ -504,23 +513,38 @@ bar } } - if (filter[ii].mode != stub){ - close(loose_end); // the reading end is none of this kid's business - // except last kid: writing end - - // Note this does an implicit close on the previously-open fd1: - rslt = dup2(kid_end, 1); // the writing end is stdout for this kid - // except last kid: nonstandard input - if (rslt < 0) { - fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end); - perror(0); - exit(ex_syserr); - } - - close(kid_end); // use fd1 instead now - // OK, at this point this kid is set up to read fd0 and write fd1 - // (except last kid reads fd1 as well as fd0). + if (0) cerr << "before closing loose end " << loose_end + << " and kid end " << kid_end + << " for " << ii << endl; + switch (filter[ii].mode){ + case sa: + case qq: + case series: + close(loose_end); // the reading end is none of this kid's business + // except last kid: writing end + + // Note this does an implicit close on the previously-open fd1: + rslt = dup2(kid_end, 1); // the writing end is stdout for this kid + // except last kid: nonstandard input + if (rslt < 0) { + fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end); + perror(0); + exit(ex_syserr); + } + close(kid_end); // use fd1 instead now + // OK, at this point this kid is set up to read fd0 and write fd1 + // (except last kid reads fd1 as well as fd0). + break; + case stub: + case postspam: + // nothing to do + break; + case fail: + cerr << "should never happen: invalid filter" << endl; + exeunt(ex_syserr); + break; } + //// probe_fd(); int ntok = filter[ii].cmd.size(); -- cgit v1.2.3 From 1c7804ee064dadadb06e786efcf4992e2a3b2028 Mon Sep 17 00:00:00 2001 From: John Denker Date: Mon, 23 Jul 2012 12:42:23 -0700 Subject: much more logical about keeping track of pipes and how they are used --- tools/hi-q.c | 195 +++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 122 insertions(+), 73 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 114570f..5ee7688 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -64,6 +64,7 @@ foo_sa(CONFIG, 78, "configuration error") ;\ foo_sa(TOOBIG, 98, "message was too big to process (see --max-size)" +typedef enum {MSG, ENV} channeler; #define bufsize 16384 @@ -198,6 +199,7 @@ void slurp(const int inch, const int ouch){ ssize_t todo; for (;;) { ssize_t got = read(inch, buf, bufsize); + //xx cerr << "slurp: read returns " << got << endl; if (got == 0) { // EoF break; } @@ -210,6 +212,7 @@ void slurp(const int inch, const int ouch){ todo = got; while (todo) { ssize_t sent = write(ouch, buf, todo); + //xx cerr << "slurp: write returns " << sent << endl; if (sent < 0 && errno != EINTR) { fprintf(stderr, "hi-q: output error on fd%d : ", ouch); perror(0); @@ -282,6 +285,22 @@ string basename(const string path){ return path; } +void attach(const int pipe_end, const int fd, const int kidno){ + cerr << "attaching current pipe_end " << pipe_end + << " to " << fd + << " for " << kidno << endl; + if (pipe_end != fd) { + int rslt = dup2(pipe_end, fd); + if (rslt < 0) { + fprintf(stderr, "hi-q: dup2(%d,%d) failed for kid %d : ", pipe_end, fd, kidno); + perror(0); + exit(ex_syserr); + } + close(pipe_end); + } + +} + int main(int argc, char** argv) { { progname = *argv; @@ -299,7 +318,6 @@ bar int kidstatus; int rslt; - int loose_end = 0; // our original stdin typedef vector VS; vector filter; @@ -395,11 +413,28 @@ bar // to close it and dup() something useful onto it. map iiofpid; - + map next_read; + next_read[MSG] = 0; // our original stdin + next_read[ENV] = -1; // no kid is (yet) empowered to read envelope info + int slurp_read(1); // our original non-standard input + int slurp_write = -1; // effectively next_write[ENV]; + map current_read; + map cur_write; // current kid writes here + cur_write[MSG] = -1; + cur_write[ENV] = -1; + +// important loop to start all kids for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */ - //xx cerr << "top of loop ... loose end " << loose_end << " for " << ii << endl; - if (loose_end > 20) exit(99); - int kid_end; + current_read = next_read; + + cerr << "top of loop: " + << " cr.MSG: " << current_read[MSG] + << " cr.ENV: " << current_read[ENV] + << " w.MSG: " << cur_write[MSG] + << " w.ENV: " << cur_write[ENV] + << " for " << ii << endl; + if (current_read[MSG] > 20) exit(99); + if (current_read[ENV] > 20) exit(99); int datapipe[2]; @@ -407,17 +442,15 @@ bar case series: case qq: case sa: -// connect *old* loose end to this kid's stdin - //xx cerr << "moving old loose end " << loose_end << " to 0 for " << ii << endl; - if (loose_end) { - close(0); - dup2(loose_end, 0); - close(loose_end); - } -// Create a pipe, which will be used to connect -// this child's fd1 to the next child's fd0 ... -// except for the last kid, which reads both fd0 and fd1, +// Create a new pipe. +// Pipe must be created here (in the parent). +// The intended bindings must be figured out shortly below. +// Some of the bindings must be hooked up later (in the child), +// while others are used by the parent (e.g. envelope slurp). +// This pipe will be used (by the children) to connect +// this child's output to the next child's input ... +// except for the special kid, which reads both fd0 and fd1, // while writing nothing. rslt = pipe(datapipe); if (rslt < 0) { @@ -425,6 +458,10 @@ bar perror(0); exeunt(ex_syserr); } + if (1) cerr << "new pipe" + << " reading: " << datapipe[rEnd] + << " writing: " << datapipe[wEnd] + << endl; break; case postspam: case stub: @@ -435,20 +472,23 @@ bar exeunt(ex_syserr); } -// For N-1 kids, the loose end feeds forward. -// It will be written by this kid and read by the next kid. -// For the special kid, the loose end will be its nonstandard input. -// It will be written by us (hi-q) and read by the last kid. - +// figure out the intended bindings: switch (filter[ii].mode) { - case series: case sa: - loose_end = datapipe[rEnd]; - kid_end = datapipe[wEnd]; + case series: + cur_write[MSG] = datapipe[wEnd]; + next_read[MSG] = datapipe[rEnd]; break; case qq: - loose_end = datapipe[wEnd]; // reverse of normal "series" case - kid_end = datapipe[rEnd]; // reverse of normal "series" case + if (slurp_write >= 0){ + cerr << "???? multiple qq jobs?" << endl; + } + slurp_write= datapipe[wEnd]; + current_read[ENV] = datapipe[rEnd]; + next_read[ENV] = -1; + next_read[MSG] = -1; + cur_write[ENV] = -1; + cur_write[MSG] = -1; break; case postspam: case stub: @@ -467,7 +507,7 @@ bar } iiofpid[kidpid[ii]] = ii; if (!kidpid[ii]) { /*** child code ***/ - if (verbose) cerr << "top of kid ... loose end " << loose_end << " for " << ii << endl; + if (verbose) cerr << "top of kid ... loose end " << current_read[MSG] << " for " << ii << endl; pid_t kidgroup(0); // process group for all kids is // equal to pid of kid#0 @@ -513,31 +553,19 @@ bar } } - if (0) cerr << "before closing loose end " << loose_end - << " and kid end " << kid_end - << " for " << ii << endl; switch (filter[ii].mode){ - case sa: case qq: + attach(current_read[MSG], 0, ii); + attach(current_read[ENV], 1, ii); + break; + case sa: case series: - close(loose_end); // the reading end is none of this kid's business - // except last kid: writing end - - // Note this does an implicit close on the previously-open fd1: - rslt = dup2(kid_end, 1); // the writing end is stdout for this kid - // except last kid: nonstandard input - if (rslt < 0) { - fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end); - perror(0); - exit(ex_syserr); - } - close(kid_end); // use fd1 instead now - // OK, at this point this kid is set up to read fd0 and write fd1 - // (except last kid reads fd1 as well as fd0). + attach(current_read[MSG], 0, ii); + attach(cur_write[MSG], 1, ii); break; case stub: case postspam: - // nothing to do + // nothing to hook up; no pipe was even created. break; case fail: cerr << "should never happen: invalid filter" << endl; @@ -545,6 +573,12 @@ bar break; } +// in all modes: +// close envelope channel in kid space +// (leaving it open in parent space) + close(current_read[ENV]); + close(slurp_write); + //// probe_fd(); int ntok = filter[ii].cmd.size(); @@ -576,7 +610,10 @@ bar perror(0); exeunt(ex_syserr); } - close(kid_end); + +// these tricks are for kid: + close(cur_write[MSG]); + close(cur_write[ENV]); // Let kid #0 run a little ways: if (ii==0) { @@ -598,6 +635,7 @@ bar } /* end loop starting all kids */ // here with the whole pipeline of kids launched +// parent program continues close(resync[wEnd]); // important, so that block gets released close(resync[rEnd]); // less important, just housecleaning @@ -730,35 +768,46 @@ bar // Here if all filters agree this is not spam. // Now it is safe to transfer the envelope information: - slurp(1, loose_end); - close(1); - close(loose_end); + + if (0) cerr << "about to slurp: " + << " cr.MSG: " << current_read[MSG] + << " cr.ENV: " << current_read[ENV] + << " w.MSG: " << cur_write[MSG] + << " w.ENV: " << cur_write[ENV] + << " slurp_read: " << slurp_read + << " slurp_write: " << slurp_write + << endl; + + slurp(slurp_read, slurp_write); + close(slurp_write); + close(slurp_read); // now that the envelope information has been transfered, // wait for the last kid in the usual way - { - for(;;) { - waitpid(special_pid, &kidstatus, WUNTRACED); - if (WIFEXITED(kidstatus)) { - int sts = WEXITSTATUS(kidstatus); - cerr << progid - << " says: qq program" - << " i.e. " << basename(filter[nkids-1].cmd[0]) - << "[" << kidpid[nkids-1] << "]" - << " returned status " << sts - << endl; - return sts; - } else if (WIFSIGNALED(kidstatus)) { - cerr << progid - << " says: qq program" - << " i.e. " << basename(filter[nkids-1].cmd[0]) - << "[" << kidpid[nkids-1] << "]" - << " was killed by signal " << WTERMSIG(kidstatus) - << endl; - return ex_syserr; - } else { - /* paused, not dead */ - } + + for(;;) { + waitpid(special_pid, &kidstatus, WUNTRACED); + if (WIFEXITED(kidstatus)) { + int sts = WEXITSTATUS(kidstatus); + cerr << progid + << " says: qq program" + << " i.e. " << basename(filter[nkids-1].cmd[0]) + << "[" << kidpid[nkids-1] << "]" + << " returned status " << sts + << endl; + return sts; + } else if (WIFSIGNALED(kidstatus)) { + cerr << progid + << " says: qq program" + << " i.e. " << basename(filter[nkids-1].cmd[0]) + << "[" << kidpid[nkids-1] << "]" + << " was killed by signal " << WTERMSIG(kidstatus) + << endl; + return ex_syserr; + } else { + /* paused, not dead */ } - } + } /* loop until all kids accounted for */ + // should never get here; + // exit from within loop is the only way out } -- cgit v1.2.3 From 97dd4547d93c1de38a4d69f768cc8c6b99a5d69e Mon Sep 17 00:00:00 2001 From: John Denker Date: Mon, 23 Jul 2012 14:31:05 -0700 Subject: finally () get smart about not leaving stray FDs lying around; also get smart about blocking fd0 and fd1 for later use. --- tools/hi-q.c | 119 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 27 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 5ee7688..3d654c5 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -22,10 +22,15 @@ using namespace std; #include #include #include +#include #include #include #include +#include /* for fstat */ +#include /* .. */ +#include /* .. */ + // error exit codes, mostly as stated in qmail.c #define bar \ foo(good, 0) ;\ @@ -63,6 +68,13 @@ foo_sa(NOPERM, 77, "permission denied") ;\ foo_sa(CONFIG, 78, "configuration error") ;\ foo_sa(TOOBIG, 98, "message was too big to process (see --max-size)" +string progname; +pid_t mypid; +string progid; + +extern char** environ; +const int rEnd(0); // end of a pipe for reading +const int wEnd(1); // end of a pipe for writing typedef enum {MSG, ENV} channeler; @@ -204,7 +216,9 @@ void slurp(const int inch, const int ouch){ break; } if (got < 0) { - fprintf(stderr, "hi-q: input error: "); + cerr << progid + << " slurp: input error on fd " << inch + << " : "; perror(0); exeunt(ex_comerr); } @@ -214,7 +228,9 @@ void slurp(const int inch, const int ouch){ ssize_t sent = write(ouch, buf, todo); //xx cerr << "slurp: write returns " << sent << endl; if (sent < 0 && errno != EINTR) { - fprintf(stderr, "hi-q: output error on fd%d : ", ouch); + cerr << progid + << " slurp: output rror on fd " << ouch + << " : "; perror(0); exeunt(ex_comerr); } @@ -261,10 +277,6 @@ void usage() { // we have data coming in on fd 0. // and envelope / control information coming in on fd 1. -string progname; -pid_t mypid; -string progid; - void dump(const string var){ char* str = getenv(var.c_str()); cerr << progid << var; @@ -277,7 +289,39 @@ int xclose(int arg){ return close(arg); } -extern char** environ; +typedef list LI; +void block_fd(const LI todo){ + int blocker(-1); + int inplace(0); + + for (LI::const_iterator ptr = todo.begin(); + ptr != todo.end(); ptr++) { + int fd = *ptr; + struct stat statbuf; + int rslt = fstat(fd, &statbuf); + if (rslt) { + if (0) { + cerr << "definitely needed to block_fd unit " << fd << " : "; + perror(0); + } + if (blocker < 0) { + int blockex[2]; + pipe(blockex); + close(blockex[rEnd]); + blocker = blockex[wEnd]; + } + if (blocker != fd){ + dup2(blocker, fd); + close(blocker); + } else { + inplace++; + } + } else { + if (0) cerr << "unit " << fd << " already blocked" << endl; + } + } + if (!inplace) close(blocker); +} string basename(const string path){ size_t where = path.rfind("/"); @@ -286,7 +330,7 @@ string basename(const string path){ } void attach(const int pipe_end, const int fd, const int kidno){ - cerr << "attaching current pipe_end " << pipe_end + cerr << "attaching current pipe_end " << pipe_end << " to " << fd << " for " << kidno << endl; if (pipe_end != fd) { @@ -298,7 +342,7 @@ void attach(const int pipe_end, const int fd, const int kidno){ } close(pipe_end); } - + } int main(int argc, char** argv) { @@ -397,8 +441,6 @@ bar vector kidpid(nkids); // indexed by kid number - const int rEnd(0); // end of a pipe for reading - const int wEnd(1); // end of a pipe for writing int sync[2]; int resync[2]; if (pipe(sync) != 0) cerr << "sync pipe failed" << endl; @@ -419,19 +461,30 @@ bar int slurp_read(1); // our original non-standard input int slurp_write = -1; // effectively next_write[ENV]; map current_read; - map cur_write; // current kid writes here - cur_write[MSG] = -1; - cur_write[ENV] = -1; + map current_write; // current kid writes here + current_write[MSG] = -1; + current_write[ENV] = -1; + list blockme; + blockme.push_back(0); + blockme.push_back(1); // important loop to start all kids for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */ + string kidid; + { + stringstream foo; + foo << ii + << " mode " << filter[ii].mode + << " " << filter[ii].cmd[0]; + kidid = foo.str(); + } current_read = next_read; cerr << "top of loop: " - << " cr.MSG: " << current_read[MSG] + << " cr.MSG: " << current_read[MSG] << " cr.ENV: " << current_read[ENV] - << " w.MSG: " << cur_write[MSG] - << " w.ENV: " << cur_write[ENV] + << " w.MSG: " << current_write[MSG] + << " w.ENV: " << current_write[ENV] << " for " << ii << endl; if (current_read[MSG] > 20) exit(99); if (current_read[ENV] > 20) exit(99); @@ -452,6 +505,7 @@ bar // this child's output to the next child's input ... // except for the special kid, which reads both fd0 and fd1, // while writing nothing. + block_fd(blockme); rslt = pipe(datapipe); if (rslt < 0) { fprintf(stderr, "hi-q: could not create datapipe: "); @@ -473,10 +527,13 @@ bar } // figure out the intended bindings: + int pardang1(-1), pardang2(-1); // used by current kid, + // but dangling, from parent's point of view switch (filter[ii].mode) { case sa: case series: - cur_write[MSG] = datapipe[wEnd]; + pardang1 = current_write[MSG] = datapipe[wEnd]; + pardang2 = current_read[MSG]; next_read[MSG] = datapipe[rEnd]; break; case qq: @@ -484,11 +541,11 @@ bar cerr << "???? multiple qq jobs?" << endl; } slurp_write= datapipe[wEnd]; - current_read[ENV] = datapipe[rEnd]; + pardang1 = current_read[ENV] = datapipe[rEnd]; next_read[ENV] = -1; next_read[MSG] = -1; - cur_write[ENV] = -1; - cur_write[MSG] = -1; + current_write[ENV] = -1; + current_write[MSG] = -1; break; case postspam: case stub: @@ -561,7 +618,7 @@ bar case sa: case series: attach(current_read[MSG], 0, ii); - attach(cur_write[MSG], 1, ii); + attach(current_write[MSG], 1, ii); break; case stub: case postspam: @@ -612,8 +669,16 @@ bar } // these tricks are for kid: - close(cur_write[MSG]); - close(cur_write[ENV]); + close(current_write[MSG]); + close(current_write[ENV]); + close(current_read[ENV]); + if (0) cerr << "closing " << pardang1 + << " for parent of " << kidid << endl; + + close(pardang1); + if (0) cerr << "closing " << pardang2 + << " for parent of " << kidid << endl; + close(pardang2); // Let kid #0 run a little ways: if (ii==0) { @@ -770,10 +835,10 @@ bar // Now it is safe to transfer the envelope information: if (0) cerr << "about to slurp: " - << " cr.MSG: " << current_read[MSG] + << " cr.MSG: " << current_read[MSG] << " cr.ENV: " << current_read[ENV] - << " w.MSG: " << cur_write[MSG] - << " w.ENV: " << cur_write[ENV] + << " w.MSG: " << current_write[MSG] + << " w.ENV: " << current_write[ENV] << " slurp_read: " << slurp_read << " slurp_write: " << slurp_write << endl; -- cgit v1.2.3 From 41552786cd6dee05e8cdc20c2daaf5127ec8cb9f Mon Sep 17 00:00:00 2001 From: John Denker Date: Mon, 23 Jul 2012 14:43:34 -0700 Subject: minor polishing --- tools/hi-q.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 3d654c5..d267d2c 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -301,7 +301,7 @@ void block_fd(const LI todo){ int rslt = fstat(fd, &statbuf); if (rslt) { if (0) { - cerr << "definitely needed to block_fd unit " << fd << " : "; + cerr << "**** definitely needed to block_fd unit " << fd << " : "; perror(0); } if (blocker < 0) { @@ -330,7 +330,7 @@ string basename(const string path){ } void attach(const int pipe_end, const int fd, const int kidno){ - cerr << "attaching current pipe_end " << pipe_end + if (0) cerr << "attaching current pipe_end " << pipe_end << " to " << fd << " for " << kidno << endl; if (pipe_end != fd) { @@ -480,7 +480,7 @@ bar } current_read = next_read; - cerr << "top of loop: " + if (verbose) cerr << "top of loop: " << " cr.MSG: " << current_read[MSG] << " cr.ENV: " << current_read[ENV] << " w.MSG: " << current_write[MSG] @@ -512,7 +512,7 @@ bar perror(0); exeunt(ex_syserr); } - if (1) cerr << "new pipe" + if (0) cerr << "new pipe" << " reading: " << datapipe[rEnd] << " writing: " << datapipe[wEnd] << endl; -- cgit v1.2.3 From 3993d2f92fc1d357ee668d42cbb44aa3744e6d2c Mon Sep 17 00:00:00 2001 From: John Denker Date: Mon, 23 Jul 2012 14:52:21 -0700 Subject: more minor polishing --- tools/hi-q.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index d267d2c..502de69 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -527,13 +527,13 @@ bar } // figure out the intended bindings: - int pardang1(-1), pardang2(-1); // used by current kid, - // but dangling, from parent's point of view + list pardang; switch (filter[ii].mode) { case sa: case series: - pardang1 = current_write[MSG] = datapipe[wEnd]; - pardang2 = current_read[MSG]; + current_write[MSG] = datapipe[wEnd]; + pardang.push_back(current_write[MSG]); + pardang.push_back(current_read[MSG]); next_read[MSG] = datapipe[rEnd]; break; case qq: @@ -541,7 +541,8 @@ bar cerr << "???? multiple qq jobs?" << endl; } slurp_write= datapipe[wEnd]; - pardang1 = current_read[ENV] = datapipe[rEnd]; + current_read[ENV] = datapipe[rEnd]; + pardang.push_back(current_read[ENV]); next_read[ENV] = -1; next_read[MSG] = -1; current_write[ENV] = -1; @@ -672,13 +673,13 @@ bar close(current_write[MSG]); close(current_write[ENV]); close(current_read[ENV]); - if (0) cerr << "closing " << pardang1 - << " for parent of " << kidid << endl; + for (LI::const_iterator ptr = pardang.begin(); + ptr != pardang.end(); ptr++) { + if (0) cerr << "closing " << *ptr + << " for parent of " << kidid << endl; - close(pardang1); - if (0) cerr << "closing " << pardang2 - << " for parent of " << kidid << endl; - close(pardang2); + close(*ptr); + } // Let kid #0 run a little ways: if (ii==0) { -- cgit v1.2.3 From 92280557b6bdde0b3e1d8fa93ba2fae494d5c355 Mon Sep 17 00:00:00 2001 From: John Denker Date: Sun, 29 Jul 2012 15:58:57 -0700 Subject: clean up error reporting --- tools/hi-q.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'tools/hi-q.c') diff --git a/tools/hi-q.c b/tools/hi-q.c index 502de69..59cad5d 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -144,7 +144,7 @@ int Execve(char const * fn, int fork_and_wait(const jobber job){ pid_t kidpid = fork(); if (kidpid == -1) { - cerr << "hi-q: fork failed : "; + cerr << progid << " fork failed : "; perror(0); exit(ex_syserr); } @@ -157,9 +157,9 @@ int fork_and_wait(const jobber job){ if (!kidpid){ /*** child code ***/ - int rslt; - rslt = Execve(prog[0], prog, environ); - fprintf(stderr, "hi-q: failed to exec '%s': ", prog[0]); + Execve(prog[0], prog, environ); + cerr << progid << " failed to exec '" + << prog[0] << "' : " << endl; perror(0); exit(ex_syserr); } else { @@ -167,6 +167,11 @@ int fork_and_wait(const jobber job){ int kidstatus; pid_t somekid; somekid = waitpid(kidpid, &kidstatus, WUNTRACED); + if (somekid < 0) { + cerr << progid << " ??? waitpid failed : "; + perror(0); + return(ex_syserr); + } if (WIFEXITED(kidstatus)) { int sts = WEXITSTATUS(kidstatus); if (sts != ex_good && sts != ex_spam) { @@ -179,7 +184,7 @@ int fork_and_wait(const jobber job){ } else if (WIFSIGNALED(kidstatus)) { int sig = WTERMSIG(kidstatus); if (sig == SIGUSR1) {/* normal, no logging required */} - else cerr << "hi-q: job " << prog[0] + else cerr << progid << " job " << prog[0] << " killed by signal " << sig << endl; return(ex_syserr); } else { @@ -199,8 +204,8 @@ int fork_and_wait(vector post){ } void exeunt(const int sts) { - // FIXME: stop other children - //xxxx cerr << "hi-q: exeunt called with " << sts << endl; + // FIXME: stop other children, maybe? + //xxxx cerr << progid << " exeunt called with " << sts << endl; if (sts == ex_spam) fork_and_wait(post); if (sts == ex_penaltybox) exit(ex_spam); exit(sts); @@ -336,7 +341,9 @@ void attach(const int pipe_end, const int fd, const int kidno){ if (pipe_end != fd) { int rslt = dup2(pipe_end, fd); if (rslt < 0) { - fprintf(stderr, "hi-q: dup2(%d,%d) failed for kid %d : ", pipe_end, fd, kidno); + cerr << progid << " dup2(" << pipe_end + << "," << fd << ")" + " failed for kid " << kidno << " : "; perror(0); exit(ex_syserr); } @@ -394,7 +401,7 @@ bar ifstream conf; conf.open(conf_name); if (! conf.good()) { - cerr << "hi-q: could not open filter.conf file '" + cerr << progid << " could not open filter.conf file '" << conf_name << "'" << endl; exit(1); } @@ -431,7 +438,7 @@ bar if (nkids == 0) exit(0); // nothing to do if (verbose) for (unsigned int ii = 0; ii < nkids; ii++) { - cerr << "hi-q filter[" << ii << "] :; "; + cerr << progid << " filter[" << ii << "] :; "; for (VS::const_iterator token = filter[ii].cmd.begin(); token != filter[ii].cmd.end(); token++){ cerr << *token << " "; @@ -508,7 +515,7 @@ bar block_fd(blockme); rslt = pipe(datapipe); if (rslt < 0) { - fprintf(stderr, "hi-q: could not create datapipe: "); + cerr << progid << " could not create datapipe : "; perror(0); exeunt(ex_syserr); } @@ -559,7 +566,7 @@ bar kidpid[ii] = fork(); if (kidpid[ii] == -1) { - cerr << "hi-q: fork failed : "; + cerr << progid << " fork failed : "; perror(0); exit(ex_syserr); } @@ -657,14 +664,15 @@ bar exit(1); } rslt = Execve(prog[0], prog, environ); - fprintf(stderr, "hi-q: failed to exec '%s': ", prog[0]); + cerr << progid << " failed to exec '" + << prog[0] << "' : "; perror(0); exit(ex_syserr); } /*** parent code ***/ if (kidpid[ii] < 0) { - fprintf(stderr, "hi-q: failure to fork kid#%d: ", ii); + cerr << " failure to fork kid#" << ii << " : "; perror(0); exeunt(ex_syserr); } @@ -714,7 +722,7 @@ bar // so we don't need it. if (verbose) for (unsigned int ii = 0; ii < nkids; ii++) { - cerr << "hi-q filter[" << ii << "] " + cerr << progid << " filter[" << ii << "] " << kidpid[ii] << " :; "; for (VS::const_iterator token = filter[ii].cmd.begin(); @@ -736,7 +744,7 @@ bar // do not decrement the "alive" counter // since that only applies to non-special kids if (WIFEXITED(kidstatus)) { - cerr << "hi-q: special kid exited early, status " + cerr << progid << " special kid exited early, status " << WEXITSTATUS(kidstatus) << " with " << alive << " kids still alive" << endl; @@ -745,7 +753,7 @@ bar int sig = WTERMSIG(kidstatus); if (sig == SIGUSR1) {/* normal, no logging required */} else { - cerr << "hi-q: special kid killed by signal " + cerr << progid << " special kid killed by signal " << sig << endl; // this is not normal return(ex_syserr); @@ -795,7 +803,7 @@ bar if (sts == 0){ // should never get here // should be no accounting for blame if there was no blame - cerr << "hi-q: should never happen: no child to blame" << endl; + cerr << progid << " should never happen: no child to blame" << endl; exeunt(ex_syserr); } -- cgit v1.2.3