This archive contains answers to questions sent to Unidata support through mid-2025. Note that the archive is no longer being updated. We provide the archive for reference; many of the answers presented here remain technically correct, even if somewhat outdated. For the most up-to-date information on the use of NSF Unidata software and data services, please consult the Software Documentation first.
Paul Hamer wrote: > Anne, > > I've just downloaded and unpacked ldm-5.0.9.tar.Z and pqact.c is missing > from the distribution. > > Thought you might like to know. > > Paul. > Yikes! You're right. I just discovered that as I was trying to install and build our own IRIX version. Attached is pqact.c for you. We'll fix the distribution. Thanks! And our apologies for the inconvenience. Anne -- *************************************************** Anne Wilson UCAR Unidata Program address@hidden P.O. Box 3000 (303) 497-8677 Boulder, CO 80307 ---------------------------------------------------- Unidata WWW server http://www.unidata.ucar.edu/ ****************************************************
/* * Copyright 1993, University Corporation for Atmospheric Research * See ../COPYRIGHT file for copying and redistribution conditions. */ /* $Id: pqact.c,v 1.37 1999/04/02 23:16:19 davis Exp $ */ /* * ldm server mainline program module */ #include <ldmconfig.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <rpc/rpc.h> #include <signal.h> #include <errno.h> #include <sys/types.h> #include <regex.h> #ifndef NO_WAITPID #include <sys/wait.h> #endif #include "paths.h" /* built by configure from paths.h.in */ #include "ldm.h" #include "atofeedt.h" #include "pq.h" #include "palt.h" #include "ldmprint.h" #include "filel.h" /* pipe_timeo */ #include "ulog.h" #ifdef NO_ATEXIT #include "atexit.h" #endif static const char *pqfname = DEFAULT_QUEUE; static pqueue *pq = NULL; static volatile int done = 0; static volatile int hupped = 0; static char *conffilename = 0; #ifndef DEFAULT_INTERVAL #define DEFAULT_INTERVAL 15 #endif #ifndef DEFAULT_FEEDTYPE #define DEFAULT_FEEDTYPE ANY #endif #ifndef DEFAULT_PATTERN #define DEFAULT_PATTERN ".*" #endif /* * Timeout used for PIPE actions, * referenced in filel.c */ #ifndef DEFAULT_PIPE_TIMEO #define DEFAULT_PIPE_TIMEO 60 #endif /* !DEFAULT_PIPE_TIMEO */ int pipe_timeo = DEFAULT_PIPE_TIMEO; /* * called at exit */ static void cleanup(void) { unotice("Exiting"); if(done) { /* * We are not in the interrupt context, so these can * be performed safely. */ fl_close_all(); if(pq) (void) pq_close(pq); while ( reap(-1, WNOHANG) > 0 ) /* EMPTY */; } (void) closeulog(); } /* * called upon receipt of signals */ static void signal_handler(int sig) { #ifdef SVR3SIGNALS /* * Some systems reset handler to SIG_DFL upon entry to handler. * In that case, we reregister our handler. */ (void) signal(sig, signal_handler); #endif switch(sig) { case SIGHUP : udebug("SIGHUP"); hupped = !0; return; case SIGINT : unotice("Interrupt"); exit(0); case SIGTERM : udebug("SIGTERM"); done = !0; return; case SIGUSR1 : udebug("SIGUSR1"); /* TODO? stats */ return; case SIGUSR2 : udebug("SIGUSR2"); rollulogpri(); return; case SIGALRM : udebug("SIGALRM"); return; case SIGCHLD : udebug("SIGCHLD"); return; } udebug("signal_handler: unhandled signal: %d", sig); } /* * register the signal_handler */ static void set_sigactions(void) { struct sigaction sigact; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; /* Ignore these */ sigact.sa_handler = SIG_IGN; (void) sigaction(SIGPIPE, &sigact, NULL); /* Handle these */ #ifdef SA_RESTART /* SVR4, 4.3+ BSD */ /* usually, restart system calls */ sigact.sa_flags |= SA_RESTART; #endif sigact.sa_handler = signal_handler; (void) sigaction(SIGHUP, &sigact, NULL); (void) sigaction(SIGTERM, &sigact, NULL); (void) sigaction(SIGUSR1, &sigact, NULL); (void) sigaction(SIGUSR2, &sigact, NULL); (void) sigaction(SIGALRM, &sigact, NULL); (void) sigaction(SIGCHLD, &sigact, NULL); /* Don't restart after interrupt */ sigact.sa_flags = 0; #ifdef SA_INTERRUPT /* SunOS 4.x */ sigact.sa_flags |= SA_INTERRUPT; #endif (void) sigaction(SIGINT, &sigact, NULL); } static void usage( char *av0 /* id string */ ) { (void)fprintf(stderr, "Usage: %s [options] [confilename]\t\nOptions:\n", av0); (void)fprintf(stderr, "\t-v Verbose, log each match (SIGUSR2 cycles)\n"); (void)fprintf(stderr, "\t-x Debug mode (SIGUSR2 cycles)\n"); (void)fprintf(stderr, "\t-l logfile Send log info to file (default uses syslogd)\n"); (void)fprintf(stderr, "\t-d datadir cd to \"datadir\" before interpreting filenames in\n"); (void)fprintf(stderr, "\t conffile (default %s)\n", DEFAULT_DATADIR); (void)fprintf(stderr, "\t-q queue default \"%s\"\n", DEFAULT_QUEUE); (void)fprintf(stderr, "\t-p pattern Interested in products matching \"pattern\" (default \"%s\")\n", DEFAULT_PATTERN); (void)fprintf(stderr, "\t-f feedtype Interested in products from feed \"feedtype\" (default %s)\n", s_feedtypet(DEFAULT_FEEDTYPE)); (void)fprintf(stderr, "\t-i interval loop, polling each \"interval\" seconds (default %d)\n", DEFAULT_INTERVAL); (void)fprintf(stderr, "\t-t timeo set write timeo for PIPE subprocs to \"timeo\" secs (default %d)\n", DEFAULT_PIPE_TIMEO); (void)fprintf(stderr, "\t-o offset the oldest product we will consider is \"offset\" secs before now (default: most recent in queue)\n"); (void)fprintf(stderr, "\t(default conffilename is %s)\n", DEFAULT_CONFFILENAME); exit(1); } int main(int ac, char *av[]) { int status = 0; char *logfname = 0; int logfd = -1; /* data directory, conffile paths may be relative */ char *datadir = DEFAULT_DATADIR; int interval = DEFAULT_INTERVAL; prod_spec spec; prod_class clss; int toffset = TOFFSET_NONE; conffilename = DEFAULT_CONFFILENAME; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = DEFAULT_PATTERN; if(set_timestamp(&clss.from) != ENOERR) /* corrected by toffset below */ { int errnum = errno; fprintf(stderr, "Couldn't set timestamp: %s", strerror(errnum)); exit(1); } clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; /* * Check the environment for some options. * May be overridden by command line switches below. */ { const char *ldmpqfname = getenv("LDMPQFNAME"); if(ldmpqfname != NULL) pqfname = ldmpqfname; } /* * deal with the command line, set options */ { extern int optind; extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_NOTICE)); int fterr; opterr = 1; while ((ch = getopt(ac, av, "vxl:d:f:q:o:p:i:t:")) != EOF) switch (ch) { case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'd': datadir = optarg; break; case 'f': fterr = strfeedtypet(optarg, &spec.feedtype); if(fterr != FEEDTYPE_OK) { fprintf(stderr, "Bad feedtype \"%s\", %s\n", optarg, strfeederr(fterr)); usage(av[0]); } break; case 'q': pqfname = optarg; break; case 'o': toffset = atoi(optarg); if(toffset == 0 && *optarg != '0') { fprintf(stderr, "%s: invalid offset %s\n", av[0], optarg); usage(av[0]); } break; case 'i': interval = atoi(optarg); if(interval == 0 && *optarg != '0') { fprintf(stderr, "%s: invalid interval %s\n", av[0], optarg); usage(av[0]); } break; case 't': pipe_timeo = atoi(optarg); if(pipe_timeo == 0 && *optarg != 0) { fprintf(stderr, "%s: invalid pipe_timeo %s", av[0], optarg); usage(av[0]); } break; case 'p': spec.pattern = optarg; break; case '?': usage(av[0]); break; } if(ac - optind == 1) conffilename = av[optind]; (void) setulogmask(logmask); status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB); if(status != 0) { fprintf(stderr, "Can't compile regular expression \"%s\"\n", spec.pattern); usage(av[0]); } } /* * initialize logger * (Close fd 2 to remap stderr to the logfile, when * appropriate. I know, this is anal.) */ if(logfname != NULL && !(logfname[0] == '-' && logfname[1] == 0)) (void)close(2); logfd = openulog(ubasename(av[0]), (LOG_CONS|LOG_PID), LOG_LDM, logfname); unotice("Starting Up"); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); unotice("Exiting"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Read in (compile) the configuration file. We do this first so * its syntax may be checked without opening a product queue. */ if(readPatFile(conffilename) < 0) exit(1); /* * Open the product queue */ (void) fclose(stdin); /* more anality :-) */ status = pq_open(pqfname, PQ_READONLY, &pq); if(status) { uerror("pq_open failed: %s: %s\n", pqfname, strerror(status)); exit(1); } (void) fclose(stdout); /* more anality :-), get one more descriptor */ if(toffset == TOFFSET_NONE) { /* * Be permissive with the time filter, * jump now to the end of the queue. */ clss.from = TS_ZERO; (void) pq_last(pq, &clss, NULL); } else { /* * Filter and queue position set by * toffset. */ clss.from.tv_sec -= toffset; pq_cset(pq, &clss.from); } if(ulogIsVerbose()) { char buf[1984]; uinfo("%s", s_prod_class(buf, sizeof(buf), &clss)); } /* * Change directories if datadir was specified */ if(datadir != NULL && *datadir != 0) { /* change to data directory */ if (chdir(datadir) == -1) { serror("cannot chdir to %s", datadir); exit(4); } } /* * Do special pre main loop actions in pattern/action file * N.B. Deprecate. */ dummyprod("_BEGIN_"); /* * Main loop */ while(!done) { if(hupped) { unotice("ReReading configuration file %s", conffilename); (void) readPatFile(conffilename); hupped = 0; } status = pq_sequence(pq, TV_GT, &clss, processProduct, 0); switch(status) { case 0: /* no error */ break; case PQUEUE_END: udebug("End of Queue"); if(interval == 0) { /* one trip */ done = !0; continue; } break; case EAGAIN: case EACCES: udebug("Hit a lock"); break; #if defined(EDEADLOCK) && EDEADLOCK != EDEADLK case EDEADLOCK: #endif case EDEADLK: uerror("%s", strerror(status)); break; default: uerror("pq_sequence failed: %s (errno = %d)", strerror(status), status); exit(1); break; } if(status) { pq_suspend(interval); /* close the least recently used idle descriptor */ close_lru(FL_NOTRANSIENT); } /* Attempt (non-blocking) to sync everyone */ fl_sync(-1, FALSE); /* * Wait on any children which may have died */ while ( reap(-1, WNOHANG) > 0 ) /* EMPTY */; } exit(0); /*NOTREACHED*/ }