int main( int ac, char* av[]) { const char* pqfname = getQueuePath(); int sock = -1; int status; int doSomething = 1; in_addr_t locIpAddr = (in_addr_t) htonl(INADDR_ANY ); unsigned ldmPort = LDM_PORT; ensureDumpable(); /* * 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_WARNING) | LOG_MASK(LOG_NOTICE); opterr = 1; while ((ch = getopt(ac, av, "I:vxl:nq:o:P:M:m:t:")) != EOF) { switch (ch) { case 'I': { in_addr_t ipAddr = inet_addr(optarg); if ((in_addr_t) -1 == ipAddr) { (void) fprintf(stderr, "Interface specification \"%s\" " "isn't an IP address\n", optarg); exit(1); } locIpAddr = ipAddr; break; } case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'q': pqfname = optarg; setQueuePath(optarg); break; case 'o': toffset = atoi(optarg); if (toffset == 0 && *optarg != '0') { (void) fprintf(stderr, "%s: invalid offset %s\n", av[0], optarg); usage(av[0]); } break; case 'P': { char* suffix = ""; long port; errno = 0; port = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= port || 0xffff < port) { (void) fprintf(stderr, "%s: invalid port %s\n", av[0], optarg); usage(av[0]); } ldmPort = (unsigned) port; break; } case 'M': { int max = atoi(optarg); if (max < 0) { (void) fprintf(stderr, "%s: invalid maximum number of clients %s\n", av[0], optarg); usage(av[0]); } maxClients = max; break; } case 'm': max_latency = atoi(optarg); if (max_latency <= 0) { (void) fprintf(stderr, "%s: invalid max_latency %s\n", av[0], optarg); usage(av[0]); } break; case 'n': doSomething = 0; break; case 't': rpctimeo = (unsigned) atoi(optarg); if (rpctimeo == 0 || rpctimeo > 32767) { (void) fprintf(stderr, "%s: invalid timeout %s", av[0], optarg); usage(av[0]); } break; case '?': usage(av[0]); break; } /* "switch" statement */ } /* argument loop */ if (ac - optind == 1) setLdmdConfigPath(av[optind]); (void) setulogmask(logmask); if (toffset != TOFFSET_NONE && toffset > max_latency) { (void) fprintf(stderr, "%s: invalid toffset (%d) > max_latency (%d)\n", av[0], toffset, max_latency); usage(av[0]); } } /* command-line argument decoding */ #ifndef DONTFORK /* * daemon behavior * * Background the process unless we are logging to stderr, in which * case we assume interactive. */ if (logfname == NULL || *logfname != '-') { /* detach */ pid_t pid; pid = ldmfork(); if (pid == -1) { log_add("Couldn't fork LDM daemon"); log_log(LOG_ERR); exit(2); } if (pid > 0) { /* parent */ (void) printf("%ld\n", (long) pid); exit(0); } /* detach the child from parents process group ?? */ (void) setsid(); } #endif /* * Initialize logger. * (Close fd 2 to remap stderr to the logfile, when * appropriate. I know, this is anal.) */ if (logfname == NULL ) (void) fclose(stderr); else if (!(logfname[0] == '-' && logfname[1] == 0)) (void) close(2); (void) openulog(ubasename(av[0]), (LOG_CONS | LOG_PID), LOG_LDM, logfname); unotice("Starting Up (version: %s; built: %s %s)", PACKAGE_VERSION, __DATE__, __TIME__); /* * register exit handler */ if (atexit(cleanup) != 0) { serror("atexit"); unotice("Exiting"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Close the standard input and standard output streams because they won't * be used (more anality :-) */ (void) fclose(stdout); (void) fclose(stdin); if (!doSomething) { /* * Vet the configuration file. */ udebug("main(): Vetting configuration-file"); if (read_conf(getLdmdConfigPath(), doSomething, ldmPort) != 0) { log_log(LOG_ERR); exit(1); } } else { /* * Create a service portal. This should be done before anything is * created because this is the function that relinquishes superuser * privileges. */ udebug("main(): Creating service portal"); if (create_ldm_tcp_svc(&sock, locIpAddr, ldmPort) != ENOERR) { /* error reports are emitted from create_ldm_tcp_svc() */ exit(1); } udebug("tcp sock: %d", sock); /* * Verify that the product-queue can be open for writing. */ udebug("main(): Opening product-queue"); if (status = pq_open(pqfname, PQ_DEFAULT, &pq)) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent", pqfname); } else { uerror("pq_open failed: %s: %s", pqfname, strerror(status)); } exit(1); } (void) pq_close(pq); pq = NULL; /* * Create the sharable database of upstream LDM metadata. */ udebug("main(): Creating shared upstream LDM database"); if (status = uldb_delete(NULL)) { if (ULDB_EXIST == status) { log_clear(); } else { LOG_ADD0( "Couldn't delete existing shared upstream LDM database"); log_log(LOG_ERR); exit(1); } } if (uldb_create(NULL, maxClients * 1024)) { LOG_ADD0("Couldn't create shared upstream LDM database"); log_log(LOG_ERR); exit(1); } /* * Read the configuration file (downstream LDM-s are started). */ udebug("main(): Reading configuration-file"); if (read_conf(getLdmdConfigPath(), doSomething, ldmPort) != 0) { log_log(LOG_ERR); exit(1); } /* * Serve */ udebug("main(): Serving socket"); sock_svc(sock); } /* "doSomething" is true */ return (0); }
int main(int ac, char *av[]) { const char* pqfname = getQueuePath(); const char *opqfname = getSurfQueuePath(); const char *progname = ubasename(av[0]); char *logfname; prod_class_t clss; prod_spec spec; int status = 0; unsigned interval = DEFAULT_INTERVAL; int logoptions = (LOG_CONS|LOG_PID); double age = DEFAULT_AGE; /* these are containers for the pqact args */ char *argv[16]; int argc = 0; int toffset = TOFFSET_NONE; logfname = ""; 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; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = DEFAULT_PATTERN; memset(argv, 0, sizeof(argv)); argv[0] = "pqact"; argc++; { extern int optind; extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); int fterr; const char *conffilename = getPqsurfConfigPath(); const char *datadir = getPqsurfDataDirPath(); usePil = 1; opterr = 1; while ((ch = getopt(ac, av, "vxl:d:f:p:q:Q:o:i:a:t:")) != EOF) switch (ch) { case 'v': argv[argc++] = "-v"; logmask |= LOG_MASK(LOG_INFO); break; case 'x': argv[argc++] = "-x"; logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': argv[argc++] = "-l"; argv[argc++] = optarg; logfname = optarg; break; case 'd': datadir = optarg; break; case 'f': fterr = strfeedtypet(optarg, &spec.feedtype); if(fterr != FEEDTYPE_OK) { fprintf(stderr, "%s: %s: \"%s\"\n", av[0], strfeederr(fterr), optarg); usage(progname); } argv[argc++] = "-f"; argv[argc++] = optarg; break; case 'p': spec.pattern = optarg; /* compiled below */ break; case 'q': pqfname = optarg; break; case 'Q': opqfname = 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]); } argv[argc++] = "-o"; argv[argc++] = optarg; break; case 'i': interval = atoi(optarg); if(interval == 0 && *optarg != '0') { fprintf(stderr, "%s: invalid interval \"%s\"\n", av[0], optarg); usage(av[0]); } /* N.B. -i just used for input queue. */ break; case 'a': age = atof(optarg); if(age < 0.) { (void) fprintf(stderr, "age (%s) must be non negative\n", optarg); usage(av[0]); } break; case 't': /* pipe_timeo */ argv[argc++] = "-t"; argv[argc++] = optarg; break; case '?': usage(progname); break; } (void) setulogmask(logmask); if (re_isPathological(spec.pattern)) { fprintf(stderr, "Adjusting pathological regular-expression: " "\"%s\"\n", spec.pattern); re_vetSpec(spec.pattern); } status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB); if(status != 0) { fprintf(stderr, "Bad regular expression \"%s\"\n", spec.pattern); usage(av[0]); } if(ac - optind == 1) conffilename = av[optind]; argv[argc++] = "-d"; argv[argc++] = (char*)datadir; argv[argc++] = "-q"; argv[argc++] = (char*)opqfname; argv[argc++] = (char*)conffilename; age *= 3600.; } if(toffset != TOFFSET_NONE) { clss.from.tv_sec -= toffset; } else { clss.from.tv_sec -= (age - interval); } /* * Set up error logging. * N.B. log ident is the remote */ (void) openulog(progname, logoptions, LOG_LDM, logfname); unotice("Starting Up (%d)", getpgrp()); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Open the output product queue */ status = pq_open(opqfname, PQ_DEFAULT, &opq); if(status) { if (PQ_CORRUPT == status) { uerror("The output product-queue \"%s\" is inconsistent\n", opqfname); } else { uerror("pq_open failed: %s: %s\n", opqfname, strerror(status)); } exit(1); } act_pid = run_child(argc, argv); if(act_pid == (pid_t)-1) exit(1); /* * Open the input product queue */ status = pq_open(pqfname, PQ_READONLY, &pq); if(status) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent\n", pqfname); } else { uerror("pq_open failed: %s: %s\n", pqfname, strerror(status)); } exit(1); } if(toffset == TOFFSET_NONE) { /* Jump to the end of the queue */ timestampt sav; sav = clss.from; clss.from = TS_ZERO; (void) pq_last(pq, &clss, NULL); clss.from = sav; } else { pq_cset(pq, &clss.from); } if(ulogIsVerbose()) { char buf[1984]; uinfo("%s", s_prod_class(buf, sizeof(buf), &clss)); } while(exitIfDone(0)) { if(stats_req) { dump_stats(); stats_req = 0; } status = pq_sequence(pq, TV_GT, &clss, split_prod, NULL); switch(status) { case 0: /* no error */ continue; /* N.B., other cases sleep */ case PQUEUE_END: udebug("surf: End of Queue"); break; case EAGAIN: case EACCES: udebug("Hit a lock"); break; default: uerror("pq_sequence failed: %s (errno = %d)", strerror(status), status); exit(1); break; } if(interval == 0) { break; } (void) expire(opq, interval, age); pq_suspend(interval); (void) reap_act(WNOHANG); } /* * TODO: how can we determine that pqact has finished * the work in opq? */ sleep(5); exit(0); }
int main( int ac, char *av[] ) { const char* const pqfname = getQueuePath(); const char* const progname = ubasename(av[0]); int useProductID = FALSE; int signatureFromId = FALSE; char *productID = NULL; int multipleFiles = FALSE; char identifier[KEYSIZE]; int status; int seq_start = 0; enum ExitCode { exit_success = 0, /* all files inserted successfully */ exit_system = 1, /* operating-system failure */ exit_pq_open = 2, /* couldn't open product-queue */ exit_infile = 3, /* couldn't process input file */ exit_dup = 4, /* input-file already in product-queue */ exit_md5 = 6 /* couldn't initialize MD5 processing */ } exitCode = exit_success; #if !USE_MMAP pqeIndex = PQE_NONE; #endif { extern int optind; extern int opterr; extern char *optarg; int ch; (void) openulog(progname, LOG_NOTIME, LOG_LDM, "-"); (void) setulogmask(LOG_UPTO(LOG_NOTICE)); opterr = 0; /* Suppress getopt(3) error messages */ while ((ch = getopt(ac, av, ":ivxl:q:f:s:p:")) != EOF) switch (ch) { case 'i': signatureFromId = 1; break; case 'v': (void) setulogmask(getulogmask() | LOG_MASK(LOG_INFO)); break; case 'x': (void) setulogmask(getulogmask() | LOG_MASK(LOG_DEBUG)); break; case 'l': openulog(progname, ulog_get_options(), LOG_LDM, optarg); break; case 'q': setQueuePath(optarg); break; case 's': seq_start = atoi(optarg); break; case 'f': feedtype = atofeedtypet(optarg); if(feedtype == NONE) { fprintf(stderr, "Unknown feedtype \"%s\"\n", optarg); usage(progname); } break; case 'p': useProductID = TRUE; productID = optarg; break; case ':': { LOG_ADD1("Option \"-%c\" requires an operand", optopt); usage(progname); } /* no break */ default: LOG_ADD1("Unknown option: \"%c\"", optopt); usage(progname); /* no break */ } ac -= optind; av += optind ; if(ac < 1) usage(progname); } /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(exit_system); } /* * set up signal handlers */ set_sigactions(); /* * who am i, anyway */ (void) strncpy(myname, ghostname(), sizeof(myname)); myname[sizeof(myname)-1] = 0; /* * open the product queue */ if(status = pq_open(pqfname, PQ_DEFAULT, &pq)) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent\n", pqfname); } else { uerror("pq_open: \"%s\" failed: %s", pqfname, status > 0 ? strerror(status) : "Internal error"); } exit(exit_pq_open); } { char *filename; int fd; struct stat statb; product prod; MD5_CTX *md5ctxp = NULL; /* * Allocate an MD5 context */ md5ctxp = new_MD5_CTX(); if(md5ctxp == NULL) { serror("new_md5_CTX failed"); exit(exit_md5); } /* These members are constant over the loop. */ prod.info.origin = myname; prod.info.feedtype = feedtype; if (ac > 1) { multipleFiles = TRUE; } for(prod.info.seqno = seq_start ; ac > 0 ; av++, ac--, prod.info.seqno++) { filename = *av; fd = open(filename, O_RDONLY, 0); if(fd == -1) { serror("open: %s", filename); exitCode = exit_infile; continue; } if( fstat(fd, &statb) == -1) { serror("fstat: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } /* Determine what to use for product identifier */ if (useProductID) { if (multipleFiles) { sprintf(identifier,"%s.%d", productID, prod.info.seqno); prod.info.ident = identifier; } else prod.info.ident = productID; } else prod.info.ident = filename; prod.info.sz = statb.st_size; prod.data = NULL; /* These members, and seqno, vary over the loop. */ status = set_timestamp(&prod.info.arrival); if(status != ENOERR) { serror("set_timestamp: %s, filename"); exitCode = exit_infile; continue; } #if USE_MMAP prod.data = mmap(0, prod.info.sz, PROT_READ, MAP_PRIVATE, fd, 0); if(prod.data == NULL) { serror("mmap: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } status = signatureFromId ? mm_md5(md5ctxp, prod.info.ident, strlen(prod.info.ident), prod.info.signature) : mm_md5(md5ctxp, prod.data, prod.info.sz, prod.info.signature); (void)exitIfDone(1); if (status != 0) { serror("mm_md5: %s", filename); (void) munmap(prod.data, prod.info.sz); (void) close(fd); exitCode = exit_infile; continue; } /* These members, and seqno, vary over the loop. */ status = set_timestamp(&prod.info.arrival); if(status != ENOERR) { serror("set_timestamp: %s, filename"); exitCode = exit_infile; continue; } /* * Do the deed */ status = pq_insert(pq, &prod); switch (status) { case ENOERR: /* no error */ if(ulogIsVerbose()) uinfo("%s", s_prod_info(NULL, 0, &prod.info, ulogIsDebug())) ; break; case PQUEUE_DUP: uerror("Product already in queue: %s", s_prod_info(NULL, 0, &prod.info, 1)); exitCode = exit_dup; break; case PQUEUE_BIG: uerror("Product too big for queue: %s", s_prod_info(NULL, 0, &prod.info, 1)); exitCode = exit_infile; break; case ENOMEM: uerror("queue full?"); exitCode = exit_system; break; case EINTR: #if defined(EDEADLOCK) && EDEADLOCK != EDEADLK case EDEADLOCK: /*FALLTHROUGH*/ #endif case EDEADLK: /* TODO: retry ? */ /*FALLTHROUGH*/ default: uerror("pq_insert: %s", status > 0 ? strerror(status) : "Internal error"); break; } (void) munmap(prod.data, prod.info.sz); #else // USE_MMAP above; !USE_MMAP below status = signatureFromId ? mm_md5(md5ctxp, prod.info.ident, strlen(prod.info.ident), prod.info.signature) : fd_md5(md5ctxp, fd, statb.st_size, prod.info.signature); (void)exitIfDone(1); if (status != 0) { serror("xx_md5: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } if(lseek(fd, 0, SEEK_SET) == (off_t)-1) { serror("rewind: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } pqeIndex = PQE_NONE; status = pqe_new(pq, &prod.info, &prod.data, &pqeIndex); if(status != ENOERR) { serror("pqe_new: %s", filename); exitCode = exit_infile; } else { ssize_t nread = read(fd, prod.data, prod.info.sz); (void)exitIfDone(1); if (nread != prod.info.sz) { serror("read %s %u", filename, prod.info.sz); status = EIO; } else { status = pqe_insert(pq, pqeIndex); pqeIndex = PQE_NONE; switch (status) { case ENOERR: /* no error */ if(ulogIsVerbose()) uinfo("%s", s_prod_info(NULL, 0, &prod.info, ulogIsDebug())) ; break; case PQUEUE_DUP: uerror("Product already in queue: %s", s_prod_info(NULL, 0, &prod.info, 1)); exitCode = exit_dup; break; case ENOMEM: uerror("queue full?"); break; case EINTR: #if defined(EDEADLOCK) && EDEADLOCK != EDEADLK case EDEADLOCK: /*FALLTHROUGH*/ #endif case EDEADLK: /* TODO: retry ? */ /*FALLTHROUGH*/ default: uerror("pq_insert: %s", status > 0 ? strerror(status) : "Internal error"); } } /* data read into `pqeIndex` region */ if (status != ENOERR) { (void)pqe_discard(pq, pqeIndex); pqeIndex = PQE_NONE; } } /* `pqeIndex` region allocated */ #endif (void) close(fd); } /* input-file loop */ free_MD5_CTX(md5ctxp); } /* code block */ exit(exitCode); }
int main(int ac, char *av[]) { unsigned timeo = DEFAULT_TIMEO; unsigned interval = DEFAULT_TIMEO; unsigned TotalTimeo = DEFAULT_TOTALTIMEO; prod_spec spec; int status; prod_class_t* clssp; /* * initialize logger */ if (log_init(av[0])) { log_syserr("Couldn't initialize logging module"); exit(1); } if(set_timestamp(&clss.from) != 0) { fprintf(stderr, "Couldn't set timestamp\n"); exit(1); } clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = DEFAULT_PATTERN; { /* Begin getopt block */ extern int optind; extern int opterr; extern char *optarg; int ch; int fterr; opterr = 1; while ((ch = getopt(ac, av, "vxl:f:o:t:h:P:p:T:")) != EOF) switch (ch) { case 'v': if (!log_is_enabled_info) log_set_level(LOG_LEVEL_INFO); break; case 'x': log_set_level(LOG_LEVEL_DEBUG); break; case 'l': if (log_set_destination(optarg)) { log_syserr("Couldn't set logging destination to \"%s\"", optarg); usage(av[0]); } break; case 'h': remote = optarg; break; case 'P': { log_warning("Port specification is ignored"); break; } case 'p': spec.pattern = optarg; /* compiled below */ 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 'o': clss.from.tv_sec -= atoi(optarg); break; case 'T': TotalTimeo = atoi(optarg); if(TotalTimeo == 0) { fprintf(stderr, "%s: invalid TotalTimeo %s", av[0], optarg); usage(av[0]); } break; case 't': timeo = (unsigned)atoi(optarg); if(timeo == 0 || timeo > 32767) { fprintf(stderr, "%s: invalid timeout %s", av[0], optarg); usage(av[0]); } break; case '?': usage(av[0]); break; } if(ac - optind > 0) usage(av[0]); if (re_isPathological(spec.pattern)) { fprintf(stderr, "Adjusting pathological regular-expression: " "\"%s\"\n", spec.pattern); re_vetSpec(spec.pattern); } status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB); if(status != 0) { fprintf(stderr, "Bad regular expression \"%s\"\n", spec.pattern); usage(av[0]); } if(TotalTimeo < timeo) { fprintf(stderr, "TotalTimeo %u < timeo %u\n", TotalTimeo, timeo); usage(av[0]); } } /* End getopt block */ log_notice_q("Starting Up: %s: %s", remote, s_prod_class(NULL, 0, &clss)); /* * register exit handler */ if(atexit(cleanup) != 0) { log_syserr("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Try forever. */ while (exitIfDone(0)) { clssp = &clss; status = forn5(NOTIFYME, remote, &clssp, timeo, TotalTimeo, notifymeprog_5); (void)exitIfDone(0); switch(status) { /* problems with remote, retry */ case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: case ECONNREFUSED: sleep(interval); break; case 0: /* assert(done); */ break; default: /* some wierd error */ done = 1; exit(1); } } exit(0); /*NOTREACHED*/ }
int main(int ac, char *av[]) { int status = 0; char* logfname = 0; /// Data directory, conffile paths may be relative const char* datadir; int interval = DEFAULT_INTERVAL; prod_spec spec; prod_class_t clss; int toffset = TOFFSET_NONE; int loggingToStdErr = 0; unsigned queue_size = 5000; const char* progname = basename(av[0]); unsigned logopts = LOG_CONS|LOG_PID; /* * Setup default logging before anything else. */ (void)log_init(progname); const char* pqfname = getQueuePath(); spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = DEFAULT_PATTERN; if(set_timestamp(&clss.from)) /* corrected by toffset below */ { int errnum = errno; log_error("Couldn't set timestamp: %s", strerror(errnum)); exit(EXIT_FAILURE); /*NOTREACHED*/ } clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; /* * deal with the command line, set options */ { extern int optind; extern int opterr; extern char *optarg; int ch; int fterr; opterr = 1; while ((ch = getopt(ac, av, "vxel:d:f:q:o:p:i:t:")) != EOF) { switch (ch) { case 'v': if (!log_is_enabled_info) (void)log_set_level(LOG_LEVEL_INFO); break; case 'x': (void)log_set_level(LOG_LEVEL_DEBUG); break; case 'e': key = ftok("/etc/rc.d/rc.local",'R'); semkey = ftok("/etc/rc.d/rc.local",'e'); shmid = shmget(key, sizeof(edex_message) * queue_size, 0666 | IPC_CREAT); semid = semget(semkey, 2, 0666 | IPC_CREAT); break; case 'l': logfname = optarg; (void)log_set_destination(logfname); break; case 'd': setPqactDataDirPath(optarg); break; case 'f': fterr = strfeedtypet(optarg, &spec.feedtype); if(fterr != FEEDTYPE_OK) { log_error("Bad feedtype \"%s\", %s\n", optarg, strfeederr(fterr)); usage(progname); } break; case 'q': pqfname = optarg; break; case 'o': toffset = atoi(optarg); if(toffset == 0 && *optarg != '0') { log_error("invalid offset %s\n", optarg); usage(progname); } break; case 'i': interval = atoi(optarg); if(interval == 0 && *optarg != '0') { log_error("invalid interval %s\n", optarg); usage(progname); } break; case 't': pipe_timeo = atoi(optarg); if(pipe_timeo == 0 && *optarg != 0) { log_error("invalid pipe_timeo %s", optarg); usage(progname); } break; case 'p': spec.pattern = optarg; break; default: usage(progname); break; } } conffilename = getPqactConfigPath(); datadir = getPqactDataDirPath(); { int numOperands = ac - optind; if (1 < numOperands) { log_error("Too many operands"); usage(progname); } else if (1 == numOperands) { conffilename = av[optind]; } } } setQueuePath(pqfname); log_notice("Starting Up"); if ('/' != conffilename[0]) { /* * The pathname of the configuration-file is relative. Convert it * to absolute so that it can be (re)read even if the current * working directory changes. */ #ifdef PATH_MAX char buf[PATH_MAX]; /* includes NUL */ #else char buf[_POSIX_PATH_MAX]; /* includes NUL */ #endif if (getcwd(buf, sizeof(buf)) == NULL) { log_syserr("Couldn't get current working directory"); exit(EXIT_FAILURE); } (void)strncat(buf, "/", sizeof(buf)-strlen(buf)-1); (void)strncat(buf, conffilename, sizeof(buf)-strlen(buf)-1); conffilename = strdup(buf); if (conffilename == NULL) { log_syserr("Couldn't duplicate string \"%s\"", buf); exit(EXIT_FAILURE); } } /* * Initialize the previous-state module for this process. */ if (stateInit(conffilename) < 0) { log_error("Couldn't initialize previous-state module"); exit(EXIT_FAILURE); /*NOTREACHED*/ } /* * Configure the standard I/O streams for execution of child processes. */ if (configure_stdio_file_descriptors()) { log_error("Couldn't configure standard I/O streams for execution " "of child processes"); exit(EXIT_FAILURE); } /* * Inform the "filel" module about the number of available file * descriptors. File descriptors are reserved for stdin, stdout, * stderr, the product-queue, the configuration-file, and (possibly) * logging. */ if (0 != set_avail_fd_count(openMax() - 6)) { log_error("Couldn't set number of available file-descriptors"); log_notice("Exiting"); exit(EXIT_FAILURE); /*NOTREACHED*/ } /* * Inform the "filel" module of the shared memory segment */ if (shmid != -1 && semid != -1) { set_shared_space(shmid, semid, queue_size); } /* * Compile the pattern. */ if (re_isPathological(spec.pattern)) { log_error("Adjusting pathological regular-expression: \"%s\"", spec.pattern); re_vetSpec(spec.pattern); } status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB); if(status != 0) { log_error("Can't compile regular expression \"%s\"", spec.pattern); log_notice("Exiting"); exit(EXIT_FAILURE); /*NOTREACHED*/ } /* * register exit handler */ if(atexit(cleanup) != 0) { log_syserr("atexit"); log_notice("Exiting"); exit(EXIT_FAILURE); /*NOTREACHED*/ } /* * 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 ((status = readPatFile(conffilename)) < 0) { exit(EXIT_FAILURE); /*NOTREACHED*/ } else if (status == 0) { log_notice("Configuration-file \"%s\" has no entries. " "You should probably not start this program instead.", conffilename); } /* * Open the product queue */ status = pq_open(pqfname, PQ_READONLY, &pq); if(status) { if (PQ_CORRUPT == status) { log_error("The product-queue \"%s\" is inconsistent\n", pqfname); } else { log_error("pq_open failed: %s: %s\n", pqfname, strerror(status)); } exit(EXIT_FAILURE); /*NOTREACHED*/ } if(toffset != TOFFSET_NONE) { /* * Filter and queue position set by "toffset". */ clss.from.tv_sec -= toffset; pq_cset(pq, &clss.from); } else { bool startAtTailEnd = true; timestampt insertTime; clss.from = TS_ZERO; /* * Try getting the insertion-time of the last, * successfully-processed data-product from the previous session. */ status = stateRead(&insertTime); if (status) { log_warning("Couldn't get insertion-time of last-processed " "data-product from previous session"); } else { timestampt now; (void)set_timestamp(&now); if (tvCmp(now, insertTime, <)) { log_warning("Time of last-processed data-product from previous " "session is in the future"); } else { char buf[80]; (void)strftime(buf, sizeof(buf), "%Y-%m-%d %T", gmtime(&insertTime.tv_sec)); log_notice("Starting from insertion-time %s.%06lu UTC", buf, (unsigned long)insertTime.tv_usec); pq_cset(pq, &insertTime); startAtTailEnd = false; } } if (startAtTailEnd) { log_notice("Starting at tail-end of product-queue"); (void)pq_last(pq, &clss, NULL); } }
/* * Returns: * 0 Success. Write-count of product-queue is zero. * 1 System failure. See error-message. * 2 Product-queue doesn't support a writer-counter. Not possible * if "-F" option used. * 3 Write-count of product-queue is greater than zero. Not possible * if "-F" option used. * 4 The product-queue is internally inconsistent. */ int main(int ac, char *av[]) { const char *progname = ubasename(av[0]); char *logfname; int status = 0; int logoptions = (LOG_CONS|LOG_PID) ; unsigned write_count; int force = 0; logfname = ""; if(isatty(fileno(stderr))) { /* set interactive defaults */ logfname = "-" ; logoptions = 0 ; } { extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); opterr = 1; pqfname = getQueuePath(); while ((ch = getopt(ac, av, "Fvxl:q:")) != EOF) switch (ch) { case 'F': force = 1; break; case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'q': pqfname = optarg; break; case '?': usage(progname); break; } (void) setulogmask(logmask); } /* * Set up error logging. */ (void) openulog(progname, logoptions, LOG_LDM, logfname); unotice("Starting Up (%d)", getpgrp()); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); return 1; } /* * set up signal handlers */ set_sigactions(); if (force) { /* * Add writer-counter capability to the file, if necessary, and set * the writer-counter to zero. */ status = pq_clear_write_count(pqfname); if (status) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent", pqfname); return 4; } else { uerror("pq_clear_write_count() failure: %s: %s", pqfname, strerror(status)); return 1; } } write_count = 0; } else { /* * Get the writer-counter of the product-queue. */ status = pq_get_write_count(pqfname, &write_count); if (status) { if (ENOSYS == status) { uerror("Product-queue \"%s\" doesn't have a writer-counter", pqfname); return 2; } else if (PQ_CORRUPT == status) { uerror("Product-queue \"%s\" is inconsistent", pqfname); return 4; } else { uerror("pq_get_write_count() failure: %s: %s", pqfname, strerror(status)); return 1; } } } uinfo("The writer-counter of the product-queue is %u", write_count); return write_count == 0 ? 0 : 3; }
/** * Reads a NOAAPORT data stream, creates LDM data-products from the stream, and * inserts the data-products into an LDM product-queue. The NOAAPORT data * stream can take the form of multicast UDP packets from (for example) a * Novra S300 DVB-S2 receiver or the standard input stream. * * Usage: * noaaportIngester [-l <em>log</em>] [-n|-v|-x] [-q <em>queue</em>] [-u <em>n</em>] [-m <em>mcastAddr</em>] [-I <em>iface</em>] [-b <em>npages</em>]\n * * Where: * <dl> * <dt>-b <em>npages</em></dt> * <dd>Allocate \e npages pages of memory for the internal buffer.</dd> * * <dt>-I <em>iface</em></dt> * <dd>Listen for multicast packets on interface \e iface.</dd> * * <dt>-l <em>log</em></dt> * <dd>Log to file \e log. The default is to use the system logging daemon * if the current process is a daemon; otherwise, the standard error * stream is used.</dd> * * <dt>-m <em>mcastAddr</em></dt> * <dd>Use the multicast address \e mcastAddr. The default is to * read from the standard input stream.</dd> * * <dt>-n</dt> * <dd>Log messages of level NOTE and higher priority. Each data-product * will generate a log message.</dd> * * <dt>-q <em>queue</em></dt> * <dd>Use \e queue as the pathname of the LDM product-queue. The default * is to use the default LDM pathname of the product-queue.</dd> * * <dt>-u <em>n</em></dt> * <dd>If logging is to the system logging daemon, then use facility * <b>local</b><em>n</em>. The default is to use the LDM facility.</dd> * * <dt>-v</dt> * <dd>Log messages of level INFO and higher priority.</dd> * * <dt>-x</dt> * <dd>Log messages of level DEBUG and higher priority.</dd> * </dl> * * If neither -n, -v, nor -x is specified, then logging will be restricted to * levels ERROR and WARN only. * * @retval 0 if successful. * @retval 1 if an error occurred. At least one error-message will be logged. */ int main( const int argc, /**< [in] Number of arguments */ char* const argv[]) /**< [in] Arguments */ { int status = 0; /* default success */ extern int optind; extern int opterr; int ch; const char* const progName = ubasename(argv[0]); const char* interface = NULL; int logmask = LOG_UPTO(LOG_WARNING); const unsigned logOptions = LOG_CONS | LOG_PID; const char* mcastSpec = NULL; const char* prodQueuePath = NULL; size_t npages = DEFAULT_NPAGES; Fifo* fifo; int ttyFd = open("/dev/tty", O_RDONLY); int processPriority = 0; const char* logPath = (-1 == ttyFd) ? NULL /* log to system logging daemon */ : "-"; /* log to standard error stream */ (void)close(ttyFd); (void)setulogmask(logmask); status = initLogging(progName, logOptions, logFacility, logPath); opterr = 0; /* no error messages from getopt(3) */ while (0 == status && (ch = getopt(argc, argv, "b:I:l:m:np:q:u:vx")) != -1) { switch (ch) { extern char* optarg; extern int optopt; case 'b': { unsigned long n; if (sscanf(optarg, "%lu", &n) != 1) { NPL_SERROR1("Couldn't decode FIFO size in pages: \"%s\"", optarg); status = 1; } else { npages = n; } } case 'I': interface = optarg; break; case 'l': logPath = optarg; status = initLogging(progName, logOptions, logFacility, logPath); break; case 'm': mcastSpec = optarg; break; case 'n': logmask |= LOG_MASK(LOG_NOTICE); (void)setulogmask(logmask); break; case 'p': { char* cp; errno = 0; processPriority = (int)strtol(optarg, &cp, 0); if (0 != errno) { NPL_SERROR1("Couldn't decode priority \"%s\"", optarg); nplLog(LOG_ERR); } else { if (processPriority < -20) processPriority = -20; else if (processPriority > 20) processPriority = 20; } break; } case 'q': prodQueuePath = optarg; break; case 'u': { int i = atoi(optarg); if (0 > i || 7 < i) { NPL_START1("Invalid logging facility number: %d", i); status = 1; } else { static int logFacilities[] = {LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7}; logFacility = logFacilities[i]; status = initLogging(progName, logOptions, logFacility, logPath); } break; } case 'v': logmask |= LOG_MASK(LOG_INFO); (void)setulogmask(logmask); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); (void)setulogmask(logmask); break; default: optopt = ch; /*FALLTHROUGH*/ case '?': { nplError("Unknown option: \"%c\"", optopt); status = 1; } } /* option character switch */ } /* getopt() loop */ if (0 == status) { if (optind < argc) { nplError("Extraneous command-line argument: \"%s\"", argv[optind]); status = 1; } } if (0 != status) { nplError("Error decoding command-line"); usage(progName); } else { nplNotice("Starting Up %s", PACKAGE_VERSION); nplNotice("%s", COPYRIGHT_NOTICE); if ((status = fifoNew(npages, &fifo)) != 0) { NPL_ADD0("Couldn't create FIFO"); nplLog(LOG_ERR); } else { LdmProductQueue* prodQueue; if ((status = lpqGet(prodQueuePath, &prodQueue)) != 0) { NPL_ADD0("Couldn't open LDM product-queue"); nplLog(LOG_ERR); } else { if (NULL == mcastSpec) { if (0 == (status = spawnProductMaker(NULL, fifo, prodQueue, &productMaker, &productMakerThread))) { status = spawnFileReader(NULL, NULL, fifo, &reader, &readerThread); } } /* reading file */ else { pthread_attr_t attr; if (0 != (status = pthread_attr_init(&attr))) { NPL_ERRNUM0(status, "Couldn't initialize thread attribute"); } else { #ifndef _POSIX_THREAD_PRIORITY_SCHEDULING nplWarn("Can't adjust thread priorities due to lack of " "necessary support from environment"); #else /* * In order to not miss any data, the reader thread * should preempt the product-maker thread as soon as * data is available and run as long as data is * available. */ const int SCHED_POLICY = SCHED_FIFO; struct sched_param param; param.sched_priority = sched_get_priority_max(SCHED_POLICY) - 1; (void)pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); (void)pthread_attr_setschedpolicy(&attr, SCHED_POLICY); (void)pthread_attr_setschedparam(&attr, ¶m); (void)pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); #endif if (0 == (status = spawnProductMaker(&attr, fifo, prodQueue, &productMaker, &productMakerThread))) { #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING param.sched_priority++; (void)pthread_attr_setschedparam(&attr, ¶m); #endif status = spawnMulticastReader(&attr, mcastSpec, interface, fifo, &reader, &readerThread); } /* product-maker spawned */ } /* "attr" initialized */ } /* reading multicast packets */ if (0 != status) { nplLog(LOG_ERR); status = 1; } else { pthread_t statThread; (void)gettimeofday(&startTime, NULL); reportTime = startTime; (void)pthread_create(&statThread, NULL, reportStatsWhenSignaled, NULL); set_sigactions(); (void)pthread_join(readerThread, NULL); status = readerStatus(reader); (void)pthread_cancel(statThread); (void)pthread_join(statThread, NULL); (void)fifoCloseWhenEmpty(fifo); (void)pthread_join(productMakerThread, NULL); if (0 != status) status = pmStatus(productMaker); reportStats(); readerFree(reader); } /* "reader" spawned */ (void)lpqClose(prodQueue); } /* "prodQueue" open */ } /* "fifo" created */ } /* command line decoded */ return status; }
int main(int ac, char *av[]) { int logfd; int width; int ready; unsigned long idle; fd_set readfds; fd_set exceptfds; struct timeval timeo; const char* const progname = basename(av[0]); unsigned long maxProductSize = DEFAULT_MAX_PRODUCT_SIZE; /* * Setup default logging before anything else. */ (void)log_init(progname); feedtype = whatami(av[0]); { extern int optind; extern int opterr; extern char *optarg; int ch; opterr = 0; /* stops getopt() from printing to stderr */ usePil = 1; useNex = 1; while ((ch = getopt(ac, av, ":vxcni5Nl:b:p:P:T:q:r:f:s:")) != EOF) switch (ch) { case 'v': if (!log_is_enabled_info) (void)log_set_level(LOG_LEVEL_INFO); break; case 'x': (void)log_set_level(LOG_LEVEL_DEBUG); break; case 'c': chkflag = CHK_CHECK; break; case 'n': chkflag = CHK_DONT; break; case 'i': usePil = 0; break; case 'N': useNex = 0; break; case '5': skipLeadingCtlString = 0; break; case 'l': { (void)log_set_destination(optarg); break; } case 'b': baud = optarg; break; case 'p': parity = optarg; break; #if NET case 'P': *((int *)&server_port) = atoi(optarg); /* cast away const */ if(server_port <= 0 || server_port > 65536) { log_error("Invalid server port: \"%s\"", optarg); usage(progname); } break; case 'T': reset_secs = atoi(optarg); if(reset_secs < 0) { log_add("Invalid timeout: \"%s\"", optarg); usage(progname); } break; #endif /* NET */ case 's': { unsigned long size; int nbytes; if (sscanf(optarg, "%lu %n", &size, &nbytes) != 1 || optarg[nbytes] != 0 || 1 > size) { log_error("Invalid maximum data-product size: \"%s\"", optarg); usage(progname); } maxProductSize = size; break; } case 'q': setQueuePath(optarg); break; case 'r': rawfname = optarg; break; case 'f': { feedtypet type; type = atofeedtypet(optarg); if(type != NONE) { feedtype = type; if(!parity && !baud) setFeedDefaults(type); } } break; case '?': { log_add("Unknown option: \"%c\"", optopt); usage(progname); break; } case ':': /*FALLTHROUGH*/ default: log_add("Missing argument for option: \"%c\"", optopt); usage(progname); break; } /* last arg, feedfname, is required */ if(ac - optind != 1) { log_add("Wrong number of operands: %d", ac - optind); usage(progname); } (void)strncat(feedfname, av[optind], sizeof(feedfname)-6); } pqpath = getQueuePath(); log_notice("Starting Up"); log_debug(PACKAGE_VERSION); /* * register exit handler */ if(atexit(cleanup) != 0) { log_syserr("atexit"); return 1; } /* * set up signal handlers */ set_sigactions(); /* * open the product queue, unless we were invoked as "feedtest" */ if(strcmp(progname, "feedtest") != 0) { if((ready = pq_open(pqpath, PQ_DEFAULT, &pq))) { if (PQ_CORRUPT == ready) { log_error("The product-queue \"%s\" is inconsistent\n", pqpath); } else { log_error("pq_open: \"%s\" failed: %s", pqpath, strerror(ready)); } return 1; } } /* * who am i, anyway */ (void) strncpy(myname, ghostname(), sizeof(myname)); myname[sizeof(myname)-1] = 0; /* * open the feed */ if(!(*feedfname == '-' && feedfname[1] == 0) && logfd != 0) (void) close(0); if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR) return 1; if(usePil == 1) { if ((feedtype & DDS)||(feedtype & PPS)||(feedtype & IDS)|| (feedtype & HRS)) { usePil = 1; log_info("Creating AFOS-like pil tags\0"); } else { usePil = 0; } } if (feedtype & HDS) { if(chkflag == CHK_CHECK || (isatty(ifd) && chkflag != CHK_DONT)) setTheScanner(scan_wmo_binary_crc); else setTheScanner(scan_wmo_binary); } else if (feedtype == ( DDPLUS | IDS ) ) { /* this is the combined NOAAPORT fos-alike. We know these have the 4 byte start and end sequences. Using the binary scanner ensures that we don't stop on an arbitray embedded CTRL-C */ log_notice("Note: Using the wmo_binary scanner for SDI ingest\0"); setTheScanner (scan_wmo_binary); } else if (feedtype & (NMC2 | NMC3)) { setTheScanner(scan_wmo_binary); } else if (feedtype == AFOS) { prod_stats = afos_stats; setTheScanner(scan_afos); } else if (feedtype == FAA604) { prod_stats = faa604_stats; if(chkflag == CHK_CHECK || (isatty(ifd) && chkflag != CHK_DONT && parity != NULL && *parity != 'n') ) { setTheScanner(scan_faa604_parity); } else { setTheScanner(scan_faa604); } } else { if(chkflag == CHK_CHECK || (isatty(ifd) && chkflag != CHK_DONT && parity != NULL && *parity != 'n') ) { setTheScanner(scan_wmo_parity); } else { setTheScanner(scan_wmo); } } /* * Allocate an MD5 context */ md5ctxp = new_MD5_CTX(); if(md5ctxp == NULL) { log_syserr("new_md5_CTX failed"); return 1; } /* * Main Loop */ idle = 0; while(exitIfDone(0)) { #if NET if (INPUT_IS_SOCKET) { if (port_error) { /* * lost connection => close */ if (ifd >= 0) { if(feed_close) (*feed_close)(ifd); ifd = -1; } port_error = 0; sleep (2); /* allow things to settle down */ continue; } } #endif if(stats_req) { log_notice("Statistics Request"); if(pq != NULL) { off_t highwater = 0; size_t maxregions = 0; (void) pq_highwater(pq, &highwater, &maxregions); log_notice(" Queue usage (bytes):%8ld", (long)highwater); log_notice(" (nregions):%8ld", (long)maxregions); } log_notice(" Idle: %8lu seconds", idle); #if NET if (INPUT_IS_SOCKET) { log_notice(" Timeout: %8d", reset_secs); } #endif log_notice("%21s: %s", "Status", (ifd < 0) ? "Not connected or input not open." : "Connected."); (*prod_stats)(); (*feed_stats)(); stats_req = 0; } #if NET if (INPUT_IS_SOCKET) { if (ifd < 0) { /* Attempt reconnect */ static int retries = 0; if (retries > MAX_RETRIES) { log_error ("maximum retry attempts %d, aborting", MAX_RETRIES); done = !0; continue; } /* Try to reopen on tcp read errors */ log_notice("Trying to re-open connection on port %d", server_port); ++retries; if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR) { log_notice ("sleeping %d seconds before retry %d", retries * RETRY_DELAY, retries+1); sleep (retries * RETRY_DELAY); continue; } retries = 0; } } #endif /* NET */ timeo.tv_sec = 3; timeo.tv_usec = 0; FD_ZERO(&readfds); FD_ZERO(&exceptfds); FD_SET(ifd, &readfds); FD_SET(ifd, &exceptfds); width = ifd + 1; ready = select(width, &readfds, 0, &exceptfds, &timeo); if(ready < 0 ) { /* handle EINTR as a special case */ if(errno == EINTR) { errno = 0; continue; } log_syserr("select"); return 1; } /* else */ #if 0 if (FD_ISSET(ifd, &exceptfds)) { log_error("Exception on input fd %d, select returned %d", ifd, ready); } #endif if(ready > 0) { /* do some work */ if(FD_ISSET(ifd, &readfds) || FD_ISSET(ifd, &exceptfds)) { idle = 0; if(feedTheXbuf(ifd) != ENOERR) { #if NET if (INPUT_IS_SOCKET) { port_error = !0; continue; } /* else */ #endif /* NET */ done = !0; } FD_CLR(ifd, &readfds); FD_CLR(ifd, &exceptfds); } else { log_error("select returned %d but ifd not set", ready); idle += timeo.tv_sec; } } else /* ready == 0 */ { idle += timeo.tv_sec; #if NET if (INPUT_IS_SOCKET) { /* VOODOO * This is necessary to stimulate * 'Connection reset by peer' * when the Portmaster goes down and comes * back up. */ static char zed[1] = {0}; if(write(ifd, zed, sizeof(zed)) < 0) { port_error = !0; continue; } } #endif } #if NET if (INPUT_IS_SOCKET) { if ((reset_secs > 0) && (idle >= reset_secs)) { log_notice("Idle for %ld seconds, reconnecting", idle); /* force reconnect */ port_error = !0; idle = 0; continue; } } #endif /* NET */ (void) scanTheXbuf(); } return 0; }
/** * Reads NOAAPORT data from a shared-memory FIFO or a file, creates LDM * data-products, and inserts the data-products into an LDM product-queue. * * Usage: * * readnoaaport [-nvx] [-q <em>queue</em>] [-u <em>n</em>] [-m mcastAddr] [path]\n * * Where: * <dl> * <dt>-l <em>log</em></dt> * <dd>Log to \e log. if \e log is "-", then logging occurs to the * standard error stream; otherwise, \e log is the pathname of a file to * which logging will occur. If not specified, then log messages will go * to the system logging daemon. </dd> * * <dt>-m <em>mcastAddr</em></dt> * <dd>Use the shared-memory FIFO associated with the UDP * multicast address \e mcastAddr.</dd> * * <dt>-n</dt> * <dd>Log messages of level NOTICE and higher priority.</dd> * * <dt>-q <em>queue</em></dt> * <dd>Use \e queue as the pathname of the LDM product-queue. The default * is to use the default LDM pathname of the product-queue.</dd> * * <dt>-u <em>n</em></dt> * <dd>If logging is to the system logging daemon, then use facility * <b>local</b><em>n</em>. The default is to use the LDM facility. * * <dt>-v</dt> * <dd>Log messages of level INFO and higher priority. Each data-product * will generate a log message.</dd> * * <dt>-x</dt> * <dd>Log messages of level DEBUG and higher priority.</dd> * * <dt><em>path</em></dt> * <dd>Pathname of the file from which to read data. The default is to use * a shared-memory FIFO.</dd> * </dl> * * @retval 0 if successful. * @retval 1 if an error occurred. At least one error-message is logged. */ int main( const int argc, char* const argv[]) { #ifdef HAVE_GET_QUEUE_PATH const char* pqfname = getQueuePath(); #else const char* pqfname = DEFAULT_QUEUE; #endif int fd; char* prodmmap; char* memheap = NULL; size_t heapsize; size_t heapcount; unsigned char b1; int cnt, dataoff, datalen, deflen; int nscan; long IOFF; int NWSTG, GOES, PNGINIT = 0, PROD_COMPRESSED; long last_sbn_seqno = (-1); char PROD_NAME[1024]; int status; prodstore prod; sbn_struct* sbn; pdh_struct* pdh; psh_struct* psh; ccb_struct* ccb; pdb_struct* pdb; datastore* pfrag; extern int optind; extern int opterr; extern char* optarg; int ch; int logmask = LOG_MASK(LOG_ERR); const char* logfname = NULL; /* use system logging daemon */ unsigned logOptions = LOG_CONS | LOG_PID; unsigned logFacility = LOG_LDM; /* use default LDM facility */ const char* const progName = ubasename(argv[0]); MD5_CTX* md5ctxp = NULL; /*unsigned char *compr; long comprLen = 10000 * sizeof (int);*/ int pid_channel = -1; /*compr = (unsigned char *) calloc (comprLen, 1);*/ /* Initialize the logger. */ (void)setulogmask(logmask); (void)openulog(progName, logOptions, logFacility, logfname); opterr = 1; while ((ch = getopt(argc, argv, "nvxl:q:u:m:")) != EOF) { switch (ch) { case 'v': logmask |= LOG_MASK(LOG_INFO); (void)setulogmask(logmask); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); (void)setulogmask(logmask); break; case 'n': logmask |= LOG_MASK(LOG_NOTICE); (void)setulogmask(logmask); break; case 'l': if (optarg[0] == '-' && optarg[1] != 0) { nplError("logfile \"%s\" ??\n", optarg); usage(argv[0]); } /* else */ logfname = optarg; (void)openulog(progName, logOptions, logFacility, logfname); break; case 'q': pqfname = optarg; break; case 'u': { int i = atoi(optarg); if (0 <= i && 7 >= i) { static int logFacilities[] = {LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7}; logFacility = logFacilities[i]; (void)openulog(progName, logOptions, logFacility, logfname); } break; } case 'm': sscanf(optarg, "%*d.%*d.%*d.%d", &pid_channel); if ((pid_channel < 1) || (pid_channel > MAX_DVBS_PID)) { pid_channel = -1; } else { shm = shmfifo_new(); cnt = 0; while (((status = shmfifo_shm_from_key(shm, s_port[pid_channel - 1])) == -3) && (cnt < 30)) { nplInfo("Trying to get shared-memory FIFO"); cnt++; sleep(1); } if (0 != status) { nplError("Couldn't get shared-memory FIFO. " "Check associated dvbs_multicast(1) process."); shmfifo_free(shm); shm = NULL; } else { nplInfo("Got shared-memory FIFO"); } } break; case '?': usage(argv[0]); break; } } if (argc - optind < 0) usage(argv[0]); nplNotice("Starting Up %s", PACKAGE_VERSION); fd = ((argc - optind) == 0) ? fileno(stdin) : open(argv[optind], O_RDONLY, 0); if ((!shm) && (fd == -1)) { nplError("could not open input file"); exit(0); } /* * Set up signal handlers */ set_sigactions(); /* * Register atexit routine */ if (atexit(cleanup) != 0) { nplSerror("atexit"); exit(-1); } sbn = (sbn_struct*)malloc(sizeof(sbn_struct)); pdh = (pdh_struct*)malloc(sizeof(pdh_struct)); psh = (psh_struct*)malloc(sizeof(psh_struct)); ccb = (ccb_struct*)malloc(sizeof(ccb_struct)); pdb = (pdb_struct*)malloc(sizeof(pdb_struct)); prodmmap = (char*)malloc(10000); if (prodmmap == NULL) { nplError("could not allocate read buffer"); exit(-1); } md5ctxp = new_MD5_CTX(); prod.head = NULL; prod.tail = NULL; if (lpqGet(pqfname, &ldmProdQueue) != 0) { NPL_ADD1("Couldn't open LDM product-queue \"%s\"", pqfname); exit(1); } while (DONE == 0) { /* See if any stats need to be logged */ if (logstats) { logstats = 0; dump_stats(); } /* Look for first byte == 255 and a valid SBN checksum */ if ((status = bufread(fd, prodmmap, 1)) != 0) { if (-3 == status) break; abort(); } if ((b1 = (unsigned char)prodmmap[0]) != 255) { if (ulogIsVerbose()) nplInfo("trying to resync %u", b1); if (ulogIsDebug()) nplDebug("bufread loop"); continue; } if (bufread(fd, prodmmap + 1, 15) != 0) { if (ulogIsDebug()) nplDebug("couldn't read 16 bytes for sbn"); continue; } while ((status = readsbn(prodmmap, sbn)) != 0) { if (ulogIsDebug()) nplDebug("Not SBN start"); IOFF = 1; while ((IOFF < 16) && ((b1 = (unsigned char) prodmmap[IOFF]) != 255)) IOFF++; if (IOFF > 15) { break; } else { for (ch = IOFF; ch < 16; ch++) prodmmap[ch - IOFF] = prodmmap[ch]; if (bufread(fd, prodmmap + 16 - IOFF, IOFF) != 0) { if (ulogIsDebug()) nplDebug("Couldn't read bytes for SBN, resync"); break; } } } if (status != 0) { if (ulogIsDebug()) nplDebug("SBN status continue"); continue; } IOFF = 0; if (bufread(fd, prodmmap + 16, 16) != 0) { if (ulogIsDebug()) nplDebug("error reading Product Definition Header"); continue; } if (ulogIsDebug()) nplDebug("***********************************************"); if (last_sbn_seqno != -1) { if (sbn->seqno != last_sbn_seqno + 1) { nplNotice("Gap in SBN sequence number %ld to %ld [skipped %ld]", last_sbn_seqno, sbn->seqno, sbn->seqno - last_sbn_seqno - 1); if ( sbn->seqno > last_sbn_seqno ) nmissed = nmissed + (unsigned long)(sbn->seqno - last_sbn_seqno - 1); } } last_sbn_seqno = sbn->seqno; if (ulogIsVerbose()) nplInfo("SBN seqnumber %ld", sbn->seqno); if (ulogIsVerbose()) nplInfo("SBN datastream %d command %d", sbn->datastream, sbn->command); if (ulogIsDebug()) nplDebug("SBN version %d length offset %d", sbn->version, sbn->len); if (((sbn->command != 3) && (sbn->command != 5)) || (sbn->version != 1)) { nplError("Unknown sbn command/version %d PUNT", sbn->command); continue; } switch (sbn->datastream) { case 7: /* test */ case 6: /* was reserved...now nwstg2 */ case 5: NWSTG = 1; GOES = 0; break; case 1: case 2: case 4: NWSTG = 0; GOES = 1; break; default: nplError("Unknown NOAAport channel %d PUNT", sbn->datastream); continue; } /* End of SBN version low 4 bits */ if (readpdh(prodmmap + IOFF + sbn->len, pdh) == -1) { nplError("problem with pdh, PUNT"); continue; } if (pdh->len > 16) { bufread(fd, prodmmap + sbn->len + 16, pdh->len - 16); } if (ulogIsDebug()) nplDebug("Product definition header version %d pdhlen %d", pdh->version, pdh->len); if (pdh->version != 1) { nplError("Error: PDH transfer type %u, PUNT", pdh->transtype); continue; } else if (ulogIsDebug()) { nplDebug("PDH transfer type %u", pdh->transtype); } if ((pdh->transtype & 8) > 0) nplError("Product transfer flag error %u", pdh->transtype); if ((pdh->transtype & 32) > 0) nplError("Product transfer flag error %u", pdh->transtype); if ((pdh->transtype & 16) > 0) { PROD_COMPRESSED = 1; if (ulogIsDebug()) nplDebug("Product transfer flag compressed %u", pdh->transtype); } else { PROD_COMPRESSED = 0; } if (ulogIsDebug()) nplDebug("header length %ld [pshlen = %d]", pdh->len + pdh->pshlen, pdh->pshlen); if (ulogIsDebug()) nplDebug("blocks per record %ld records per block %ld\n", pdh->blocks_per_record, pdh->records_per_block); if (ulogIsDebug()) nplDebug("product seqnumber %ld block number %ld data block size " "%ld", pdh->seqno, pdh->dbno, pdh->dbsize); /* Stop here if no psh */ if ((pdh->pshlen == 0) && (pdh->transtype == 0)) { IOFF = IOFF + sbn->len + pdh->len; continue; } if (pdh->pshlen != 0) { if (bufread(fd, prodmmap + sbn->len + pdh->len, pdh->pshlen) != 0) { nplError("problem reading psh"); continue; } else { if (ulogIsDebug()) nplDebug("read psh %d", pdh->pshlen); } /* Timing block */ if (sbn->command == 5) { if (ulogIsDebug()) nplDebug("Timing block recieved %ld %ld\0", psh->olen, pdh->len); /* * Don't step on our psh of a product struct of prod in * progress. */ continue; } if (readpsh(prodmmap + IOFF + sbn->len + pdh->len, psh) == -1) { nplError("problem with readpsh"); continue; } if (psh->olen != pdh->pshlen) { nplError("ERROR in calculation of psh len %ld %ld", psh->olen, pdh->len); continue; } if (ulogIsDebug()) nplDebug("len %ld", psh->olen); if (ulogIsDebug()) nplDebug("product header flag %d, version %d", psh->hflag, psh->version); if (ulogIsDebug()) nplDebug("prodspecific data length %ld", psh->psdl); if (ulogIsDebug()) nplDebug("bytes per record %ld", psh->bytes_per_record); if (ulogIsDebug()) nplDebug("Fragments = %ld category %d ptype %d code %d", psh->frags, psh->pcat, psh->ptype, psh->pcode); if (psh->frags < 0) nplError("check psh->frags %d", psh->frags); if (psh->origrunid != 0) nplError("original runid %d", psh->origrunid); if (ulogIsDebug()) nplDebug("next header offset %ld", psh->nhoff); if (ulogIsDebug()) nplDebug("original seq number %ld", psh->seqno); if (ulogIsDebug()) nplDebug("receive time %ld", psh->rectime); if (ulogIsDebug()) nplDebug("transmit time %ld", psh->transtime); if (ulogIsDebug()) nplDebug("run ID %ld", psh->runid); if (ulogIsDebug()) nplDebug("original run id %ld", psh->origrunid); if (prod.head != NULL) { nplError("OOPS, start of new product [%ld ] with unfinished " "product %ld", pdh->seqno, prod.seqno); ds_free(); prod.head = NULL; prod.tail = NULL; if (PNGINIT != 0) { pngout_end(); PNGINIT = 0; } nplError("Product definition header version %d pdhlen %d", pdh->version, pdh->len); nplError("PDH transfer type %u", pdh->transtype); if ((pdh->transtype & 8) > 0) nplError("Product transfer flag error %u", pdh->transtype); if ((pdh->transtype & 32) > 0) nplError("Product transfer flag error %u", pdh->transtype); nplError("header length %ld [pshlen = %d]", pdh->len + pdh->pshlen, pdh->pshlen); nplError("blocks per record %ld records per block %ld", pdh->blocks_per_record, pdh->records_per_block); nplError("product seqnumber %ld block number %ld data block " "size %ld", pdh->seqno, pdh->dbno, pdh->dbsize); nplError("product header flag %d", psh->hflag); nplError("prodspecific data length %ld", psh->psdl); nplError("bytes per record %ld", psh->bytes_per_record); nplError("Fragments = %ld category %d", psh->frags, psh->pcat); if (psh->frags < 0) nplError("check psh->frags %d", psh->frags); if (psh->origrunid != 0) nplError("original runid %d", psh->origrunid); nplError("next header offset %ld", psh->nhoff); nplError("original seq number %ld", psh->seqno); nplError("receive time %ld", psh->rectime); nplError("transmit time %ld", psh->transtime); nplError("run ID %ld", psh->runid); nplError("original run id %ld", psh->origrunid); } prod.seqno = pdh->seqno; prod.nfrag = psh->frags; ds_init(prod.nfrag); /* NWSTG CCB = dataoff, WMO = dataoff + 24 */ if (bufread(fd, prodmmap + sbn->len + pdh->len + pdh->pshlen, pdh->dbsize) != 0) { nplError("problem reading datablock"); continue; } if (sbn->datastream == 4) { if (psh->pcat != 3) { GOES = 0; NWSTG = 1; } } heapcount = 0; MD5Init(md5ctxp); if (GOES == 1) { if (readpdb(prodmmap + IOFF + sbn->len + pdh->len + pdh->pshlen, psh, pdb, PROD_COMPRESSED, pdh->dbsize) == -1) { nplError("Error reading pdb, punt"); continue; } memcpy(PROD_NAME, psh->pname, sizeof(PROD_NAME)); if (ulogIsDebug()) nplDebug("Read GOES %d %d %d [%d] %d", sbn->len, pdh->len, pdh->pshlen, sbn->len + pdh->len + pdh->pshlen, pdb->len); /* Data starts at first block after pdb */ ccb->len = 0; heapsize = prodalloc(psh->frags, 5152, &memheap); } if (NWSTG == 1) { memset(psh->pname, 0, sizeof(psh->pname)); if (readccb(prodmmap + IOFF + sbn->len + pdh->len + pdh->pshlen, ccb, psh, pdh->dbsize) == -1) nplError("Error reading ccb, using default name"); if (ulogIsDebug()) nplDebug("look at ccb start %d %d", ccb->b1, ccb->len); /* cnt = 0; memset(psh->pname,0,sizeof(psh->pname)); while ((b1 = (unsigned char)prodmmap[ IOFF + sbn->len + pdh->len + pdh->pshlen + ccb->len + cnt]) >= 32) { psh->pname[cnt] = prodmmap[ IOFF + sbn->len + pdh->len + pdh->pshlen + ccb->len + cnt]; cnt++; } if(cnt > 0) */ if (ulogIsVerbose()) nplInfo("%s", psh->pname); memcpy(PROD_NAME, psh->pname, sizeof(PROD_NAME)); heapsize = prodalloc(psh->frags, 4000 + 15, &memheap); /* * We will only compute md5 checksum on the data, 11 FOS * characters at start */ /* * sprintf(memheap,"\001\015\015\012%04d\015\015\012", * ((int)pdh->seqno)%10000); */ sprintf(memheap, "\001\015\015\012%03d\040\015\015\012", ((int) pdh->seqno) % 1000); heapcount += 11; if (psh->metaoff > 0) psh->metaoff = psh->metaoff + 11; } } else { /* If a continuation record...don't let psh->pcat get missed */ if ((sbn->datastream == 4) && (psh->pcat != 3)) { GOES = 0; NWSTG = 1; } ccb->len = 0; if (ulogIsDebug()) nplDebug("continuation record"); if ((pdh->transtype & 4) > 0) { psh->frags = 0; } if (bufread(fd, prodmmap + sbn->len + pdh->len + pdh->pshlen, pdh->dbsize) != 0) { nplError("problem reading datablock (cont)"); continue; } if (prod.head == NULL) { if (ulogIsVerbose()) nplInfo("found data block before header, " "skipping sequence %d frag #%d", pdh->seqno, pdh->dbno); continue; } } /* Get the data */ dataoff = IOFF + sbn->len + pdh->len + pdh->pshlen + ccb->len; datalen = pdh->dbsize - ccb->len; if (ulogIsDebug()) nplDebug("look at datalen %d", datalen); pfrag = ds_alloc(); pfrag->seqno = pdh->seqno; pfrag->fragnum = pdh->dbno; pfrag->recsiz = datalen; pfrag->offset = heapcount; pfrag->next = NULL; /*memcpy(memheap+heapcount,prodmmap+dataoff,datalen); MD5Update(md5ctxp, (unsigned char *)(memheap+heapcount), datalen); test_deflate(compr,comprLen,(unsigned char *)(memheap+heapcount), datalen);*/ if (GOES == 1) { if (pfrag->fragnum > 0) { if ((pfrag->fragnum != prod.tail->fragnum + 1) || (pfrag->seqno != prod.seqno)) { nplError("Missing GOES fragment in sequence, " "last %d/%d this %d/%d\0", prod.tail->fragnum, prod.seqno, pfrag->fragnum, pfrag->seqno); ds_free(); prod.head = NULL; prod.tail = NULL; continue; } if ((PNGINIT != 1) && (!PROD_COMPRESSED)) { nplError("failed pnginit %d %d %s", sbn->datastream, psh->pcat, PROD_NAME); continue; } if (pdh->records_per_block < 1) { nplError("records_per_block %d blocks_per_record %d " "nx %d ny %d", pdh->records_per_block, pdh->blocks_per_record, pdb->nx, pdb->ny); nplError("source %d sector %d channel %d", pdb->source, pdb->sector, pdb->channel); nplError("nrec %d recsize %d date %02d%02d%02d %02d%02d " "%02d.%02d", pdb->nrec, pdb->recsize, pdb->year, pdb->month, pdb->day, pdb->hour, pdb->minute, pdb->second, pdb->sechunds); nplError("pshname %s", psh->pname); } if (!PROD_COMPRESSED) { for (nscan = 0; (nscan * pdb->nx) < pdh->dbsize; nscan++) { if (ulogIsDebug()) nplDebug("png write nscan %d", nscan); if (nscan >= pdh->records_per_block) { nplError("nscan exceeding records per block %d [%d " "%d %d]", pdh->records_per_block, nscan, pdb->nx, pdh->dbsize); } else { pngwrite(prodmmap + dataoff + (nscan * pdb->nx)); } } } else { memcpy(memheap + heapcount, prodmmap + dataoff, datalen); MD5Update(md5ctxp, (unsigned char *) (memheap + heapcount), datalen); heapcount += datalen; } } else { if (!PROD_COMPRESSED) { png_set_memheap(memheap, md5ctxp); png_header(prodmmap + dataoff, datalen); /* * Add 1 to number of scanlines, image ends with * f0f0f0f0... */ pngout_init(pdb->nx, pdb->ny + 1); PNGINIT = 1; } else { memcpy(memheap + heapcount, prodmmap + dataoff, datalen); MD5Update(md5ctxp, (unsigned char*)(memheap + heapcount), datalen); heapcount += datalen; } nplNotice("records_per_block %d blocks_per_record %d nx %d ny %d", pdh->records_per_block, pdh->blocks_per_record, pdb->nx, pdb->ny); nplNotice("source %d sector %d channel %d", pdb->source, pdb->sector, pdb->channel); nplNotice("nrec %d recsize %d date %02d%02d%02d %02d%02d " "%02d.%02d", pdb->nrec, pdb->recsize, pdb->year, pdb->month, pdb->day, pdb->hour, pdb->minute, pdb->second, pdb->sechunds); nplNotice("pshname %s", psh->pname); } deflen = 0; } else { /* * test_deflate(memheap+heapcount,heapsize-heapcount,(unsigned char * *)(prodmmap+dataoff),datalen,&deflen); */ /* If the product already has a FOS trailer, don't add * another....this will match what pqing(SDI) sees */ if ((prod.nfrag != 0) && (prod.tail != NULL)) { if ((pfrag->fragnum != prod.tail->fragnum + 1) || (pfrag->seqno != prod.seqno)) { nplError("Missing fragment in sequence, last %d/%d this " "%d/%d\0", prod.tail->fragnum, prod.seqno, pfrag->fragnum, pfrag->seqno); ds_free(); prod.head = NULL; prod.tail = NULL; continue; } } if ((prod.nfrag == 0) || (prod.nfrag == (pfrag->fragnum + 1))) { char testme[4]; while (datalen > 4) { memcpy(testme, prodmmap + (dataoff + datalen - 4), 4); if (memcmp(testme, FOS_TRAILER, 4) == 0) { datalen -= 4; if (ulogIsDebug()) nplDebug("removing FOS trailer from %s", PROD_NAME); } else { break; } } } if (heapcount + datalen > heapsize) { /* * this above wasn't big enough heapsize = * prodalloc(psh->frags,4000+15,&memheap); */ nplError("Error in heapsize %d product size %d [%d %d], Punt!\0", heapsize, (heapcount + datalen), heapcount, datalen); continue; } memcpy(memheap + heapcount, prodmmap + dataoff, datalen); deflen = datalen; MD5Update(md5ctxp, (unsigned char *) (memheap + heapcount), deflen); } pfrag->recsiz = deflen; /*heapcount += datalen;*/ heapcount += deflen; if (prod.head == NULL) { prod.head = pfrag; prod.tail = pfrag; } else { prod.tail->next = pfrag; prod.tail = pfrag; } if ((prod.nfrag == 0) || (prod.nfrag == (pfrag->fragnum + 1))) { if (GOES == 1) { if (PNGINIT == 1) { pngout_end(); heapcount = png_get_prodlen(); } else { if (ulogIsDebug()) nplDebug("GOES product already compressed %d", heapcount); } } if (ulogIsVerbose()) nplInfo("we should have a complete product %ld %ld/%ld %ld /heap " "%ld", prod.seqno, pfrag->seqno, prod.nfrag, pfrag->fragnum, (long) heapcount); if ((NWSTG == 1) && (heapcount > 4)) { cnt = 4; /* number of bytes to add for TRAILER */ /* * Do a DDPLUS vs HDS check for NWSTG channel only */ if (sbn->datastream == 5) { /* nwstg channel */ switch (psh->pcat) { case 1: case 7: /* Do a quick check for non-ascii text products */ if (!prod_isascii(PROD_NAME, memheap, heapcount)) psh->pcat += 100; /* call these HDS */ /* else { ** call these DDPLUS ** if (memheap[heapcount-1] == FOS_TRAILER[3]) ** ETX check ** cnt = 0; ** no need to add extra ETX pqing doesn't see it ** } */ break; } } if (cnt > 0) { memcpy(memheap + heapcount, FOS_TRAILER + 4 - cnt, cnt); MD5Update(md5ctxp, (unsigned char*)(memheap + heapcount), cnt); heapcount += cnt; } } process_prod(prod, PROD_NAME, memheap, heapcount, md5ctxp, ldmProdQueue, psh, sbn); ds_free(); prod.head = NULL; prod.tail = NULL; PNGINIT = 0; } else { if (ulogIsDebug()) nplDebug("processing record %ld [%ld %ld]", prod.seqno, prod.nfrag, pfrag->fragnum); if ((pdh->transtype & 4) > 0) { nplError("Hmmm....should call completed product %ld [%ld %ld]", prod.seqno, prod.nfrag, pfrag->fragnum); } } IOFF += (sbn->len + pdh->len + pdh->pshlen + pdh->dbsize); if (ulogIsDebug()) nplDebug("look IOFF %ld datalen %ld (deflate %ld)", IOFF, datalen, deflen); } if (fd != -1) (void)close(fd); exit(0); }
int main(int ac, char *av[]) { const char* const pqfname = getQueuePath(); const char* const progname = ubasename(av[0]); char *logfname = NULL; /* log to syslogd(8) */ int logoptions = LOG_CONS | LOG_PID; int logmask = LOG_UPTO(LOG_NOTICE); prod_class_t clss; prod_spec spec; int status = 0; int interval = DEFAULT_INTERVAL; int toffset = TOFFSET_NONE; extern const char *remote; char* hostname = ghostname(); /* * Setup default logging before anything else. */ (void) openulog(progname, logoptions, LOG_LDM, logfname); (void) setulogmask(logmask); remote = "localhost"; 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; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = ".*"; /* * Sigh, in order to read back from existing stats files, * we call mktime(3). Since the stats are in UTC, * and mktime uses "local" time, the local time for * this program must be UTC. */ if(setenv("TZ", "UTC0",1)) { int errnum = errno; uerror("setenv: Couldn't set TZ: %s", strerror(errnum)); exit(1); } { int ch; opterr = 0; /* stops getopt() from printing to stderr */ while ((ch = getopt(ac, av, ":vxl:p:f:q:o:i:H:h:P:")) != EOF) { switch (ch) { case 'v': logmask |= LOG_MASK(LOG_INFO); (void) setulogmask(logmask); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); (void) setulogmask(logmask); break; case 'l': logfname = optarg; if (strcmp(logfname, "") == 0) logfname = NULL; logoptions = (logfname == NULL) ? (LOG_CONS|LOG_PID) : LOG_NOTIME; openulog(progname, logoptions, LOG_LDM, logfname); break; case 'H': hostname = optarg; break; case 'h': remote = optarg; break; case 'p': spec.pattern = optarg; if (re_isPathological(spec.pattern)) { unotice("Adjusting pathological regular-expression \"%s\"", spec.pattern); re_vetSpec(spec.pattern); } break; case 'f': { int fterr = strfeedtypet(optarg, &spec.feedtype) ; if (fterr != FEEDTYPE_OK) { uerror("Bad feedtype \"%s\", %s", optarg, strfeederr(fterr)) ; usage(progname); } break; } case 'q': setQueuePath(optarg); break; case 'o': toffset = atoi(optarg); if(toffset == 0 && *optarg != '0') { uerror("Invalid offset %s", optarg); usage(progname); } break; case 'P': { char* suffix = ""; long port; errno = 0; port = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= port || 0xffff < port) { uerror("Invalid port %s", optarg); usage(progname); } remotePort = (unsigned)port; break; } case 'i': interval = atoi(optarg); if (interval == 0 && *optarg != '0') { uerror("Invalid interval %s", optarg); usage(progname); } break; case '?': uerror("Invalid option \"%c\"", optopt); usage(progname); break; case ':': uerror("No argument for option \"%c\"", optopt); usage(progname); break; } } /* getopt() loop */ if (optind != ac) { uerror("Invalid operand: \"%s\"", av[optind]); usage(progname); } } /* command-line decoding block */ if (regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB)) { uerror("Bad regular expression \"%s\"\n", spec.pattern); usage(progname); } unotice("Starting Up (%d)", getpgrp()); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Open the product queue */ status = pq_open(pqfname, PQ_READONLY, &pq); if(status) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent\n", pqfname); } else { uerror("pq_open failed: %s: %s\n", pqfname, strerror(status)); } exit(1); } 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); } while(exitIfDone(0)) { if(stats_req) { dump_statsbins(); stats_req = 0; } status = pq_sequence(pq, TV_GT, &clss, addtostats, 0); switch(status) { case 0: /* no error */ continue; /* N.B., other cases sleep */ case PQUEUE_END: udebug("End of Queue"); break; case EAGAIN: case EACCES: udebug("Hit a lock"); break; default: uerror("pq_sequence failed: %s (errno = %d)", strerror(status), status); exit(1); break; } syncbinstats(hostname); if(interval == 0) { done = 1; break; } pq_suspend(interval); } return 0; }
int main( int ac, char *av[] ) { char *progname = av[0]; char *logfname; int useProductID = FALSE; int signatureFromId = FALSE; char *productID = NULL; int multipleFiles = FALSE; char identifier[KEYSIZE]; int status; int seq_start = 0; enum ExitCode { exit_success = 0, exit_system = 1, /* operating-system failure */ exit_pq_open = 2, /* couldn't open product-queue */ exit_infile = 3, /* couldn't process input file */ exit_md5 = 6 /* couldn't initialize MD5 processing */ } exitCode = exit_success; logfname = "-"; /* * Check the environment for some options. * May be overridden by command line switches below. */ { const char *ldmpqfname = getenv("LDMPQFNAME"); if(ldmpqfname != NULL) pqfname = ldmpqfname; } { extern int optind; extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); opterr = 1; while ((ch = getopt(ac, av, "ivxl:q:f:s:p:")) != EOF) switch (ch) { case 'i': signatureFromId = 1; break; case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'q': pqfname = optarg; break; case 's': seq_start = atoi(optarg); break; case 'f': feedtype = atofeedtypet(optarg); if(feedtype == NONE) { fprintf(stderr, "Unknown feedtype \"%s\"\n", optarg); usage(progname); } break; case 'p': useProductID = TRUE; productID = optarg; break; case '?': usage(progname); break; } ac -= optind; av += optind ; if(ac < 1) usage(progname); (void) setulogmask(logmask); } /* * Set up error logging */ (void) openulog(ubasename(progname), LOG_NOTIME, LOG_LDM, logfname); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(exit_system); } /* * set up signal handlers */ set_sigactions(); /* * who am i, anyway */ (void) strcpy(myname, ghostname()); /* * open the product queue */ if(status = pq_open(pqfname, PQ_DEFAULT, &pq)) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent\n", pqfname); } else { uerror("pq_open: \"%s\" failed: %s", pqfname, status > 0 ? strerror(status) : "Internal error"); } exit(exit_pq_open); } { char *filename; int fd; struct stat statb; product prod; MD5_CTX *md5ctxp = NULL; /* * Allocate an MD5 context */ md5ctxp = new_MD5_CTX(); if(md5ctxp == NULL) { serror("new_md5_CTX failed"); exit(exit_md5); } /* These members are constant over the loop. */ prod.info.origin = myname; prod.info.feedtype = feedtype; if (ac > 1) { multipleFiles = TRUE; } for(prod.info.seqno = seq_start ; ac > 0 ; av++, ac--, prod.info.seqno++) { filename = *av; fd = open(filename, O_RDONLY, 0); if(fd == -1) { serror("open: %s", filename); exitCode = exit_infile; continue; } if( fstat(fd, &statb) == -1) { serror("fstat: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } /* Determine what to use for product identifier */ if (useProductID) { if (multipleFiles) { sprintf(identifier,"%s.%d", productID, prod.info.seqno); prod.info.ident = identifier; } else prod.info.ident = productID; } else prod.info.ident = filename; prod.info.sz = statb.st_size; prod.data = NULL; #ifndef NO_MMAP prod.data = mmap(0, prod.info.sz, PROT_READ, MAP_PRIVATE, fd, 0); if(prod.data == NULL) { serror("mmap: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } status = signatureFromId ? mm_md5(md5ctxp, prod.info.ident, strlen(prod.info.ident), prod.info.signature) : mm_md5(md5ctxp, prod.data, prod.info.sz, prod.info.signature); (void)exitIfDone(1); if (status != 0) { serror("mm_md5: %s", filename); (void) munmap(prod.data, prod.info.sz); (void) close(fd); exitCode = exit_infile; continue; } /* These members, and seqno, vary over the loop. */ status = set_timestamp(&prod.info.arrival); if(status != ENOERR) { serror("set_timestamp: %s, filename"); exitCode = exit_infile; continue; } /* * Do the deed */ status = pq_insert(pq, &prod); switch (status) { case ENOERR: /* no error */ if(ulogIsVerbose()) uinfo("%s", s_prod_info(NULL, 0, &prod.info, ulogIsDebug())) ; break; case PQUEUE_DUP: uerror("Product already in queue: %s", s_prod_info(NULL, 0, &prod.info, 1)); break; case ENOMEM: uerror("queue full?"); break; case EINTR: #if defined(EDEADLOCK) && EDEADLOCK != EDEADLK case EDEADLOCK: /*FALLTHROUGH*/ #endif case EDEADLK: /* TODO: retry ? */ /*FALLTHROUGH*/ default: uerror("pq_insert: %s", status > 0 ? strerror(status) : "Internal error"); break; } (void) munmap(prod.data, prod.info.sz); #else /*!NO_MMAP*/ status = signatureFromId ? mm_md5(md5ctxp, prod.info.ident, strlen(prod.info.ident), prod.info.signature) : fd_md5(md5ctxp, fd, statb.st_size, prod.info.signature); (void)exitIfDone(1); if (status != 0) { serror("fd_md5: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } if(lseek(fd, 0, SEEK_SET) == (off_t)-1) { serror("rewind: %s", filename); (void) close(fd); exitCode = exit_infile; continue; } index = PQE_NONE; status = pqe_new(pq, &prod.info, &prod.data, &index); if(status != ENOERR) { serror("pqe_new: %s", filename); exitCode = exit_infile; } else { ssize_t nread = read(fd, prod.data, prod.info.sz); (void)exitIfDone(1); if (nread != prod.info.sz) { serror("read %s %u", filename, prod.info.sz); status = EIO; } else { status = pqe_insert(pq, index); index = PQE_NONE; switch (status) { case ENOERR: /* no error */ if(ulogIsVerbose()) uinfo("%s", s_prod_info(NULL, 0, &prod.info, ulogIsDebug())) ; break; case PQUEUE_DUP: uerror("Product already in queue: %s", s_prod_info(NULL, 0, &prod.info, 1)); break; case ENOMEM: uerror("queue full?"); break; case EINTR: #if defined(EDEADLOCK) && EDEADLOCK != EDEADLK case EDEADLOCK: /*FALLTHROUGH*/ #endif case EDEADLK: /* TODO: retry ? */ /*FALLTHROUGH*/ default: uerror("pq_insert: %s", status > 0 ? strerror(status) : "Internal error"); } } /* data read into "index" region */ if (status != ENOERR) { (void)pqe_discard(pq, index); index = PQE_NONE; } } /* "index" region allocated */ #endif /*!NO_MMAP*/ (void) close(fd); } /* input-file loop */ free_MD5_CTX(md5ctxp); } /* code block */ exit(exitCode); }
int main (int ac, char *av[]) { char *progname = av[0]; int status; int seq_start = 0; stat_info *sinfo, *shead = NULL, *slast = NULL; int statusoff=0; /* * Set up error logging */ if (log_init(progname)) { log_syserr("Couldn't initialize logging module"); exit(1); } const char* pqfname = getQueuePath(); /* * Check the environment for some options. * May be overridden by command line switches below. */ { const char *ldmpqfname = getenv ("LDMPQFNAME"); if (ldmpqfname != NULL) pqfname = ldmpqfname; } { extern int optind; extern int opterr; extern char *optarg; int ch; opterr = 1; while ((ch = getopt (ac, av, "vxl:q:f:s:S")) != EOF) switch (ch) { case 'v': if (!log_is_enabled_info) (void)log_set_level(LOG_LEVEL_INFO); break; case 'x': (void)log_set_level(LOG_LEVEL_DEBUG); break; case 'l': if (log_set_destination(optarg)) { log_syserr("Couldn't set logging destination to \"%s\"", optarg); exit(1); } break; case 'q': pqfname = optarg; break; case 's': seq_start = atoi (optarg); break; case 'f': feedtype = atofeedtypet (optarg); if (feedtype == NONE) { fprintf (stderr, "Unknown feedtype \"%s\"\n", optarg); usage (progname); } break; case 'S': statusoff=1; break; case '?': usage (progname); break; } setQueuePath(pqfname); ac -= optind; av += optind; if (ac < 1) usage (progname); } /* * register exit handler */ if (atexit (cleanup) != 0) { log_syserr ("atexit"); exit (1); } /* * set up signal handlers */ set_sigactions (); /* * who am i, anyway */ (void) strcpy (myname, ghostname ()); /* * open the product queue */ if ((status = pq_open (pqfname, PQ_DEFAULT, &pq))) { if (status > 0) { log_add_syserr("\"%s\" failed", pqfname); log_flush_error(); } else { log_error_q("\"%s\" failed: %s", pqfname, "Internal error"); } exit (2); } { char *filename; int fd; struct stat statb; product prod; unsigned char *prodmmap; MD5_CTX *md5ctxp = NULL; int gversion; /* * Allocate an MD5 context */ md5ctxp = new_MD5_CTX (); if (md5ctxp == NULL) { log_syserr ("new_md5_CTX failed"); exit (6); } /* These members are constant over the loop. */ prod.info.origin = myname; prod.info.feedtype = feedtype; prod.info.seqno = seq_start; /* * Open the file to be inserted and process */ while (ac > 0) { long insert_sum = 0; long sinfo_cnt = 0; long stat_size = 0; filename = *av; av++; ac--; log_notice_q ("open and memorymap %s\0", filename); fd = open (filename, O_RDONLY, 0); if (fd == -1) { log_syserr ("open: %s", filename); continue; } if (fstat (fd, &statb) == -1) { log_syserr ("fstat: %s", filename); (void) close (fd); continue; } if ((prodmmap = (unsigned char *) mmap (0, statb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { log_syserr ("allocation failed"); } else { int GRIBDONE = 0; off_t griboff = 0; size_t griblen = 0; log_notice_q ("%ld bytes memory mapped\0", (long) statb.st_size); while (!GRIBDONE) { log_debug("griboff %d\0", (int) griboff); /* get offset of next grib product */ status = get_grib_info (prodmmap, statb.st_size, &griboff, &griblen, &gversion); switch (status) { case 0: prod.data = prodmmap + griboff; prod.info.sz = griblen; /* * revised MD5 calculation...using filename * to allow duplicate products in different files. */ MD5Init (md5ctxp); MD5Update (md5ctxp, (void *)filename, strlen(filename)); /*MD5Update (md5ctxp, (void *)prod.data, prod.info.sz);*/ if ( prod.info.sz > 10000 ) MD5Update (md5ctxp, (void *)prod.data, 10000); else MD5Update (md5ctxp, (void *)prod.data, prod.info.sz); MD5Final (prod.info.signature, md5ctxp); /*if (mm_md5 (md5ctxp, prod.data, prod.info.sz, prod.info.signature) != 0) { log_error_q ("could not compute MD5\0"); } else { */ prod.info.ident = (char *) malloc (KEYSIZE + 1); get_gribname (gversion, prod.data, prod.info.sz, filename, prod.info.seqno, prod.info.ident); /* * Do the deed */ status = set_timestamp (&prod.info.arrival); if (status != ENOERR) { log_add_syserr("could not set timestamp"); log_flush_error(); } /* * Insert the product */ status = pq_insert (pq, &prod); log_info_q ("%d %s\0", status, prod.info.ident); if ( status == ENOERR ) insert_sum += prod.info.sz; if (! statusoff ) { /* * Log this status */ sinfo_cnt++; sinfo = (stat_info *)malloc(sizeof(stat_info)); sinfo->insertstatus = status; sinfo->prodname = (char *)malloc(strlen(prod.info.ident)+1); strcpy(sinfo->prodname, prod.info.ident); sinfo->seqno = prod.info.seqno; sinfo->prodsz = prod.info.sz; sinfo->next = NULL; stat_size += strlen(sinfo->prodname); if(shead == NULL) { shead = sinfo; slast = sinfo; } else { slast->next = sinfo; slast = sinfo; } } /*}*/ griboff += griblen; prod.info.seqno++; break; case -1: GRIBDONE = 1; break; case -2: log_error_q ("truncated grib file at: %d", prod.info.seqno); GRIBDONE = 1; break; case -7: log_error_q ("End sequence 7777 not found where expected: %d", prod.info.seqno); griboff += griblen; log_error_q("resume looking at %d\0",griboff); break; default: log_error_q ("unknown error %d\0", status); griboff += griblen; if (griboff >= statb.st_size) GRIBDONE = 1; break; } if (griboff >= statb.st_size) GRIBDONE = 1; } log_notice_q ("munmap\0"); (void) munmap ((void *)prodmmap, statb.st_size); if ( stat_size != 0 ) /* * Add a status message to product queue */ { char *statusmess; log_notice_q("stats_size %ld %ld\0",stat_size,sinfo_cnt); statusmess = calloc((30 * sinfo_cnt) + stat_size + strlen(filename) + 128, sizeof(char)); if(statusmess == NULL) { log_syserr("could not malloc status message %ld\0", stat_size); } else { char tmpprod[512]; sinfo = shead; slast = NULL; status = set_timestamp(&prod.info.arrival); /* ctime ends with \n\0" */ sprintf(statusmess,"%s complete (%ld bytes) at %sInserted %ld of %ld\n", filename,(long)statb.st_size, ctime(&prod.info.arrival.tv_sec), insert_sum,(long)statb.st_size); while(sinfo != NULL) { sprintf(tmpprod,"%3d %5d %8d %s\n",sinfo->insertstatus, sinfo->seqno,sinfo->prodsz,sinfo->prodname); strcat(statusmess,tmpprod); slast = sinfo; sinfo = sinfo->next; free(slast->prodname); free(slast); } shead = NULL; sprintf(tmpprod,".status.%s %06d",filename, prod.info.seqno); prod.info.ident = tmpprod; prod.data = statusmess; prod.info.sz = strlen(statusmess); status = mm_md5(md5ctxp, prod.data, prod.info.sz, prod.info.signature); status = set_timestamp(&prod.info.arrival); status = pq_insert(pq, &prod); if(log_is_enabled_info) log_info_q("%s", s_prod_info(NULL, 0, &prod.info, log_is_enabled_debug)) ; free(statusmess); prod.info.seqno++; } } } (void) close (fd); } } exit(0); }
int main(int ac, char *av[]) { char myname[HOSTNAMESIZE]; char *progname = av[0]; char *logfname; unsigned version; prod_class_t clss; prod_spec spec; int seq_start = 0; int status; ErrorObj* error; unsigned remotePort = LDM_PORT; logfname = "-"; remote = "localhost"; (void)set_timestamp(&clss.from); clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = ".*"; { extern int optind; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); while ((ch = getopt(ac, av, "vxl:h:f:P:s:")) != 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 'h': remote = optarg; break; case 'f': spec.feedtype = atofeedtypet(optarg); if(spec.feedtype == NONE) { fprintf(stderr, "Unknown feedtype \"%s\"\n", optarg); usage(progname); } break; case 'P': { char* suffix = ""; long port; errno = 0; port = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= port || 0xffff < port) { (void)fprintf(stderr, "%s: invalid port %s\n", av[0], optarg); usage(av[0]); } remotePort = (unsigned)port; break; } case 's': seq_start = atoi(optarg); break; case '?': usage(progname); break; } ac -= optind; av += optind; if(ac < 1) usage(progname); (void) setulogmask(logmask); } /* * Set up error logging */ (void) openulog(ubasename(progname), LOG_NOTIME, LOG_LDM, logfname); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); (void) strcpy(myname, ghostname()); /* * Contact the server. */ error = ldm_clnttcp_create_vers(remote, remotePort, SIX, &clnt, NULL, NULL); (void)exitIfDone(1); if (!error) { version = SIX; hiya = my_hiya_6; send_product = send_product_6; nullproc = nullproc_6; } else if (LDM_CLNT_BAD_VERSION == err_code(error)) { err_free(error); error = ldm_clnttcp_create_vers(remote, remotePort, FIVE, &clnt, NULL, NULL); (void)exitIfDone(1); if (!error) { version = FIVE; hiya = my_hiya_5; send_product = send_product_5; nullproc = NULL; } } if (error) { err_log(error, ERR_FAILURE); err_free(error); status = 1; } else { udebug("version %u", version); status = ldmsend(clnt, &clss, myname, seq_start, ac, av); } return status != 0; }
int master_server(int port, void *data) { int lsock[MAXLISTENSOCK]; struct addrinfo *ai_head; struct xnbd_info *xnbd = (struct xnbd_info *) data; ai_head = net_getaddrinfo(NULL, port, PF_UNSPEC); if (!ai_head) return 0; nlistened = net_listen_all_addrinfo(ai_head, lsock); if (nlistened <= 0) err("no socket to listen to"); freeaddrinfo(ai_head); for (nfds_t i = 0; i < nlistened; i++) { eventfds[i].fd = lsock[i]; eventfds[i].events = POLLRDNORM; } for (nfds_t i = nlistened; i < MAXLISTENSOCK; i++) eventfds[i].fd = -1; set_sigactions(); sigset_t sigs_blocked; sigset_t orig_sigmask; /* * The master process does not want to get SIGCHLD anytime; when SIGCHLD received, some * system calls may fail with errno == EINTR. Only this ppoll() can be intrrupted. */ sigemptyset(&sigs_blocked); /* do now allow SIG_CHLD except ppoll() */ sigaddset(&sigs_blocked, SIGCHLD); sigaddset(&sigs_blocked, SIGINT); sigaddset(&sigs_blocked, SIGTERM); sigaddset(&sigs_blocked, SIGHUP); pthread_sigmask(SIG_BLOCK, &sigs_blocked, &orig_sigmask); GList *socklist = NULL; int restarting = 0; for (;;) { int nready; /* * N.B. If compiled with fake ppoll() support, the master * process may deadlock when a child process exited. * * For Debian's 2.6.18 kernels, ppoll() is equivalent to calling * sigprocmask(), poll(), and then sigprocmask(); it is not an * atomic system call. * * In this code, while the master process is running outside * this ppoll(), a delivered signal goes to pending state * until the process accepts the signal. The handler of the * signal is called just after the process unblocks the signal. * * In this ppoll(), the first sigprocmask() unblocks the * signal. Before the poll(), the signal handler is called. * poll() does not detect the signal, and does not return until * the next event comes. * * This means that ppoll() does not return -1 with errno == * EINTR, for the signal that deliverred while the process was * running outside ppoll(). * * For Debian's 2.6.26 kernels, it's ok. */ /* * In glibc-2.7, sysdeps/unix/sysv/linux/kernel-features.h says * pselect/ppoll were introduced just after 2.6.16-rc1. Due * to the way the kernel versions are advertised we can only * rely on 2.6.17 to have the code. On x86_64 and SH this * appeared first in 2.6.19-rc1, on ia64 in 2.6.22-rc1 and on * alpha just after 2.6.22-rc1. **/ if (need_exit) { dbg("need exit"); break; } if (got_sigchld) { dbg("got sigchld"); got_sigchld = 0; /* SIGCHLD */ for (;;) { int status; pid_t pid = waitpid(-1, &status, WNOHANG); /* no more exiting child process */ if (pid < 0) break; /* pid == 0: no more exiting child process. there still * remains one or more running process(es). */ if (pid == 0) break; struct xnbd_session *ses = find_session_with_pid(xnbd, pid); if (!ses) err("unknown session pid %d", pid); xnbd->sessions = g_list_remove(xnbd->sessions, ses); free_session(xnbd, ses); info("session (pid %d) exited", pid); if (WIFEXITED(status)) info(" with exit status=%d", WEXITSTATUS(status)); if (WIFSIGNALED(status)) info(" killed by signal=%d(%s)", WTERMSIG(status), sys_siglist[WTERMSIG(status)]); } } if (restarting && g_list_length(xnbd->sessions) == 0) { /* All sessions are stopped. Now start new sessions with existing sockets. */ info("All sessions are stopped. Now restart."); /* * invoke_new_session() manipulates xnbd->sessions, * adding an entry to it. The fixed list is used here * instead of xnbd->sessions. **/ for (GList *list = g_list_first(socklist); list != NULL; list = g_list_next(list)) { int csockfd = (int) ((long) list->data); /* See below */ invoke_new_session(xnbd, csockfd); } /* must be reinitialized with NULL */ g_list_free(socklist); socklist = NULL; info("restarting has done"); restarting = 0; } if (got_sighup) { info("got SIGHUP, restart %d process(es)", g_list_length(xnbd->sessions)); got_sighup = 0; /* notify all sessions of termination */ for (GList *list = g_list_first(xnbd->sessions); list != NULL; list = g_list_next(list)) { struct xnbd_session *s = (struct xnbd_session *) list->data; dbg("%p\n", s); /* * If a new connection is accepted during * restarting, send SIGHUP to the master server * again. **/ if (s->notifying) continue; s->notifying = 1; /* preserve connected sockets */ int csockfd = dup(s->clientfd); if (csockfd < 0) err("dup %d, %m", csockfd); /* it's ok because sizeof(void *) >= sizeof(int); 32bit =, 64bit > */ socklist = g_list_append(socklist, (void *) ((long) csockfd)); info("notify %d of termination", s->pid); ssize_t ret = write(s->event_notifier_fd, "0", 1); if (ret < 0) warn("notifiy failed"); } restarting = 1; } /* SIGCHLD must be blocked here, so that only this ppoll() detects that */ //raise(SIGCHLD); info("start polling"); nready = ppoll(eventfds, nlistened, NULL, &orig_sigmask); //printf("poll ready %d\n", nready); if (nready == -1) { /* signal catched */ if (errno == EINTR) { info("polling signal catched"); continue; } else err("poll, %s", strerror(errno)); } for (nfds_t i = 0; i < nlistened; i++) { int sockfd = eventfds[i].fd; if (sockfd < 0) continue; if (eventfds[i].revents & (POLLHUP | POLLNVAL)) err("unknown events, %x", eventfds[i].revents); if (eventfds[i].revents & (POLLRDNORM | POLLERR)) { /* if POLLERR, the next read() returns -1 */ /* POLLERR never occurs because we wait new connections */ int csockfd = net_accept(sockfd); if (csockfd < 0) { warn("accept() failed"); continue; } int ret; if (xnbd->readonly) ret = nbd_negotiate_with_client_readonly(csockfd, xnbd->disksize); else ret = nbd_negotiate_with_client(csockfd, xnbd->disksize); if (ret < 0) { warn("negotiation with the client failed"); continue; } info("csockfd %d", csockfd); invoke_new_session(xnbd, csockfd); } /* short cut */ nready -= 1; if (nready == 0) break; } } /* notify child processes */ shutdown_all_sessions(xnbd); return 0; }
int main( int ac, char* av[]) { const char* pqfname = getQueuePath(); int status; int doSomething = 1; in_addr_t ldmIpAddr = (in_addr_t) htonl(INADDR_ANY ); unsigned ldmPort = LDM_PORT; ensureDumpable(); /* * 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_WARNING) | LOG_MASK(LOG_NOTICE); opterr = 1; while ((ch = getopt(ac, av, "I:vxl:nq:o:P:M:m:t:")) != EOF) { switch (ch) { case 'I': { in_addr_t ipAddr = inet_addr(optarg); if ((in_addr_t) -1 == ipAddr) { (void) fprintf(stderr, "Interface specification \"%s\" " "isn't an IP address\n", optarg); exit(1); } ldmIpAddr = ipAddr; break; } case 'v': logmask |= LOG_MASK(LOG_INFO); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); break; case 'l': logfname = optarg; break; case 'q': pqfname = optarg; setQueuePath(optarg); break; case 'o': toffset = atoi(optarg); if (toffset == 0 && *optarg != '0') { (void) fprintf(stderr, "%s: invalid offset %s\n", av[0], optarg); usage(av[0]); } break; case 'P': { unsigned port; int nbytes; if (sscanf(optarg, "%5u %n", &port, &nbytes) != 1 || 0 != optarg[nbytes] || port > 0xffff) { (void)fprintf(stderr, "%s: invalid port number: %s\n", av[0], optarg); usage(av[0]); } ldmPort = port; break; } case 'M': { int max = atoi(optarg); if (max < 0) { (void) fprintf(stderr, "%s: invalid maximum number of clients %s\n", av[0], optarg); usage(av[0]); } maxClients = max; break; } case 'm': max_latency = atoi(optarg); if (max_latency <= 0) { (void) fprintf(stderr, "%s: invalid max_latency %s\n", av[0], optarg); usage(av[0]); } break; case 'n': doSomething = 0; break; case 't': rpctimeo = (unsigned) atoi(optarg); if (rpctimeo == 0 || rpctimeo > 32767) { (void) fprintf(stderr, "%s: invalid timeout %s", av[0], optarg); usage(av[0]); } break; case '?': usage(av[0]); break; } /* "switch" statement */ } /* argument loop */ if (ac - optind == 1) setLdmdConfigPath(av[optind]); (void) setulogmask(logmask); if (toffset != TOFFSET_NONE && toffset > max_latency) { (void) fprintf(stderr, "%s: invalid toffset (%d) > max_latency (%d)\n", av[0], toffset, max_latency); usage(av[0]); } } /* command-line argument decoding */ if (logfname != NULL && *logfname == '-') { /* * Logging to standard error stream. Assume interactive. * * Make this process a process group leader so that all child processes * (e.g., upstream LDM, downstream LDM, pqact(1)s) will be signaled by * `cleanup()`. */ (void)setpgid(0, 0); // can't fail } #ifndef DONTFORK else { /* * Logging to system logging daemon or file. Make this process a daemon. */ pid_t pid; pid = ldmfork(); if (pid == -1) { log_add("Couldn't fork LDM daemon"); log_log(LOG_ERR); exit(2); } if (pid > 0) { /* parent */ (void) printf("%ld\n", (long) pid); exit(0); } /* detach the child from parents process group ?? */ (void) setsid(); // also makes this process a process group leader } #endif /* * Initialize logger. * (Close fd 2 to remap stderr to the logfile, when * appropriate. I know, this is anal.) */ if (logfname == NULL ) (void) fclose(stderr); else if (!(logfname[0] == '-' && logfname[1] == 0)) (void) close(2); (void) openulog(ubasename(av[0]), (LOG_CONS | LOG_PID), LOG_LDM, logfname); unotice("Starting Up (version: %s; built: %s %s)", PACKAGE_VERSION, __DATE__, __TIME__); /* * register exit handler */ if (atexit(cleanup) != 0) { serror("atexit"); unotice("Exiting"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Close the standard input and standard output streams because they won't * be used (more anality :-) */ (void) fclose(stdout); (void) fclose(stdin); /* * Vet the configuration file. */ udebug("main(): Vetting configuration-file"); if (read_conf(getLdmdConfigPath(), 0, ldmIpAddr, ldmPort) != 0) { log_log(LOG_ERR); exit(1); } if (doSomething) { int sock = -1; if (lcf_isServerNeeded()) { /* * Create a service portal. This should be done before anything is * created because this is the function that relinquishes superuser * privileges. */ udebug("main(): Creating service portal"); if (create_ldm_tcp_svc(&sock, ldmIpAddr, ldmPort) != ENOERR) { /* error reports are emitted from create_ldm_tcp_svc() */ exit(1); } udebug("tcp sock: %d", sock); } /* * Verify that the product-queue can be open for writing. */ udebug("main(): Opening product-queue"); if ((status = pq_open(pqfname, PQ_DEFAULT, &pq))) { if (PQ_CORRUPT == status) { uerror("The product-queue \"%s\" is inconsistent", pqfname); } else { uerror("pq_open failed: %s: %s", pqfname, strerror(status)); } exit(1); } (void) pq_close(pq); pq = NULL; /* * Create the sharable database of upstream LDM metadata. */ udebug("main(): Creating shared upstream LDM database"); if ((status = uldb_delete(NULL))) { if (ULDB_EXIST == status) { log_clear(); } else { LOG_ADD0( "Couldn't delete existing shared upstream LDM database"); log_log(LOG_ERR); exit(1); } } if (uldb_create(NULL, maxClients * 1024)) { LOG_ADD0("Couldn't create shared upstream LDM database"); log_log(LOG_ERR); exit(1); } /* * Initialize the multicast sender map. */ #if WANT_MULTICAST if (msm_init()) { LOG_ADD0("Couldn't initialize multicast LDM sender map"); log_log(LOG_ERR); exit(1); } #endif /* * Re-read (and execute) the configuration file (downstream LDM-s are * started). */ lcf_free(); // Start with a clean slate to prevent duplicates udebug("main(): Reading configuration-file"); if (read_conf(getLdmdConfigPath(), 1, ldmIpAddr, ldmPort) != 0) { log_log(LOG_ERR); exit(1); } if (lcf_isServerNeeded()) { /* * Serve */ udebug("main(): Serving socket"); sock_svc(sock); } else { /* * Wait until all child processes have terminated. */ while (reap(-1, 0) > 0) /* empty */; } } // configuration-file will be executed return (0); }
/* * Returns: * 0 Success * SYSTEM_ERROR O/S failure. "log_add()" called. * LP_TIMEDOUT The RPC call timed-out. "log_add()" called. * LP_RPC_ERROR RPC error. "log_add()" called. * LP_LDM_ERROR LDM error. "log_add()" called. */ int main( int ac, char* av[]) { char myname[_POSIX_HOST_NAME_MAX]; char* progname = av[0]; prod_class_t clss; prod_spec spec; int seq_start = 0; int status; ErrorObj* error; unsigned remotePort = LDM_PORT; /* * Set up error logging */ (void)log_init(progname); remote = "localhost"; (void)set_timestamp(&clss.from); clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = ".*"; { extern int optind; extern char *optarg; int ch; while ((ch = getopt(ac, av, "vxl:h:f:P:s:")) != EOF) switch (ch) { case 'v': if (!log_is_enabled_info) (void)log_set_level(LOG_LEVEL_INFO); break; case 'x': (void)log_set_level(LOG_LEVEL_DEBUG); break; case 'l': (void)log_set_destination(optarg); break; case 'h': remote = optarg; break; case 'f': spec.feedtype = atofeedtypet(optarg); if(spec.feedtype == NONE) { fprintf(stderr, "Unknown feedtype \"%s\"\n", optarg); usage(progname); } break; case 'P': { char* suffix = ""; long port; errno = 0; port = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= port || 0xffff < port) { (void)fprintf(stderr, "%s: invalid port %s\n", av[0], optarg); usage(av[0]); } remotePort = (unsigned)port; break; } case 's': seq_start = atoi(optarg); break; case '?': usage(progname); break; } ac -= optind; av += optind; if(ac < 1) usage(progname); } /* * Register the exit handler */ if(atexit(cleanup) != 0) { log_syserr_q("atexit"); exit(SYSTEM_ERROR); } /* * Set up signal handlers */ set_sigactions(); (void) strncpy(myname, ghostname(), sizeof(myname)); myname[sizeof(myname)-1] = 0; (void)exitIfDone(INTERRUPTED); /* * Connect to the LDM. */ status = lp_new(remote, &ldmProxy); if (0 != status) { log_flush_error(); status = (LP_SYSTEM == status) ? SYSTEM_ERROR : CONNECTION_ABORTED; } else { log_debug("version %u", lp_version(ldmProxy)); status = ldmsend(ldmProxy, &clss, myname, seq_start, ac, av); if (0 != status) log_flush_error(); lp_free(ldmProxy); ldmProxy = NULL; } /* "ldmProxy" allocated */ return status; }
int main(int ac, char *av[]) { char *logfname = 0; unsigned timeo = DEFAULT_TIMEO; unsigned interval = DEFAULT_TIMEO; unsigned TotalTimeo = DEFAULT_TOTALTIMEO; prod_spec spec; int status; prod_class_t *clssp; unsigned remotePort = LDM_PORT; if(set_timestamp(&clss.from) != 0) { fprintf(stderr, "Couldn't set timestamp\n"); exit(1); } clss.to = TS_ENDT; clss.psa.psa_len = 1; clss.psa.psa_val = &spec; spec.feedtype = DEFAULT_FEEDTYPE; spec.pattern = DEFAULT_PATTERN; { /* Begin getopt block */ extern int optind; extern int opterr; extern char *optarg; int ch; int logmask = (LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING) | LOG_MASK(LOG_NOTICE)); int fterr; opterr = 1; while ((ch = getopt(ac, av, "vxl:f:o:t:h:P:p: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 'h': remote = optarg; break; case 'P': { char* suffix = ""; long port; errno = 0; port = strtol(optarg, &suffix, 0); if (0 != errno || 0 != *suffix || 0 >= port || 0xffff < port) { (void)fprintf(stderr, "%s: invalid port %s\n", av[0], optarg); usage(av[0]); } remotePort = (unsigned)port; break; } case 'p': spec.pattern = optarg; /* compiled below */ 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 'o': clss.from.tv_sec -= atoi(optarg); break; case 'T': TotalTimeo = atoi(optarg); if(TotalTimeo == 0) { fprintf(stderr, "%s: invalid TotalTimeo %s", av[0], optarg); usage(av[0]); } break; case 't': timeo = (unsigned)atoi(optarg); if(timeo == 0 || timeo > 32767) { fprintf(stderr, "%s: invalid timeout %s", av[0], optarg); usage(av[0]); } break; case '?': usage(av[0]); break; } if(ac - optind > 0) usage(av[0]); if (re_isPathological(spec.pattern)) { fprintf(stderr, "Adjusting pathological regular-expression: " "\"%s\"\n", spec.pattern); re_vetSpec(spec.pattern); } status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB); if(status != 0) { fprintf(stderr, "Bad regular expression \"%s\"\n", spec.pattern); usage(av[0]); } (void) setulogmask(logmask); if(TotalTimeo < timeo) { fprintf(stderr, "TotalTimeo %u < timeo %u\n", TotalTimeo, timeo); usage(av[0]); } } /* End getopt block */ /* * initialize logger */ (void) openulog(ubasename(av[0]), (LOG_CONS|LOG_PID), LOG_LDM, logfname); unotice("Starting Up: %s: %s", remote, s_prod_class(NULL, 0, &clss)); /* * register exit handler */ if(atexit(cleanup) != 0) { serror("atexit"); exit(1); } /* * set up signal handlers */ set_sigactions(); /* * Try forever. */ while (exitIfDone(0)) { clssp = &clss; status = forn5(NOTIFYME, remote, &clssp, timeo, TotalTimeo, notifymeprog_5); (void)exitIfDone(0); switch(status) { /* problems with remote, retry */ case ECONNABORTED: case ECONNRESET: case ETIMEDOUT: case ECONNREFUSED: sleep(interval); break; case 0: /* assert(done); */ break; default: /* some wierd error */ done = 1; exit(1); } } exit(0); /*NOTREACHED*/ }
/** * Reads a NOAAPORT data stream, creates LDM data-products from the stream, and * inserts the data-products into an LDM product-queue. The NOAAPORT data * stream can take the form of multicast UDP packets from (for example) a * Novra S300 DVB-S2 receiver or the standard input stream. * * Usage: * noaaportIngester [-l <em>log</em>] [-n|-v|-x] [-q <em>queue</em>] [-u <em>n</em>] [-m <em>mcastAddr</em>] [-I <em>iface</em>] [-b <em>npages</em>]\n * * Where: * <dl> * <dt>-b <em>npages</em></dt> * <dd>Allocate \e npages pages of memory for the internal buffer.</dd> * * <dt>-I <em>iface</em></dt> * <dd>Listen for multicast packets on interface \e iface.</dd> * * <dt>-l <em>log</em></dt> * <dd>Log to file \e log. The default is to use the system logging daemon * if the current process is a daemon; otherwise, the standard error * stream is used.</dd> * * <dt>-m <em>mcastAddr</em></dt> * <dd>Use the multicast address \e mcastAddr. The default is to * read from the standard input stream.</dd> * * <dt>-n</dt> * <dd>Log messages of level NOTE and higher priority. Each data-product * will generate a log message.</dd> * * <dt>-q <em>queue</em></dt> * <dd>Use \e queue as the pathname of the LDM product-queue. The default * is to use the default LDM pathname of the product-queue.</dd> * * <dt>-u <em>n</em></dt> * <dd>If logging is to the system logging daemon, then use facility * <b>local</b><em>n</em>. The default is to use the LDM facility.</dd> * * <dt>-v</dt> * <dd>Log messages of level INFO and higher priority.</dd> * * <dt>-x</dt> * <dd>Log messages of level DEBUG and higher priority.</dd> * </dl> * * If neither -n, -v, nor -x is specified, then logging will be restricted to * levels ERROR and WARN only. * * @retval 0 if successful. * @retval 1 if an error occurred. At least one error-message will be logged. */ int main( const int argc, /**< [in] Number of arguments */ char* const argv[]) /**< [in] Arguments */ { int status = 0; /* default success */ extern int optind; extern int opterr; int ch; const char* const progName = ubasename(argv[0]); const char* interface = NULL; int logmask = LOG_UPTO(LOG_WARNING); const unsigned logOptions = LOG_CONS | LOG_PID; const char* mcastSpec = NULL; const char* prodQueuePath = NULL; size_t npages = DEFAULT_NPAGES; Fifo* fifo; int ttyFd = open("/dev/tty", O_RDONLY); int processPriority = 0; int idx; const char* logPath = (-1 == ttyFd) ? NULL /* log to system logging daemon */ : "-"; /* log to standard error stream */ (void)close(ttyFd); (void)setulogmask(logmask); status = initLogging(progName, logOptions, logFacility, logPath); opterr = 0; /* no error messages from getopt(3) */ while (0 == status && (ch = getopt(argc, argv, "b:I:l:m:np:q:r:s:t:u:vx")) != -1) { switch (ch) { extern char* optarg; extern int optopt; case 'b': { unsigned long n; if (sscanf(optarg, "%lu", &n) != 1) { LOG_SERROR1("Couldn't decode FIFO size in pages: \"%s\"", optarg); status = 1; } else { npages = n; } break; } case 'I': interface = optarg; break; case 'l': logPath = optarg; status = initLogging(progName, logOptions, logFacility, logPath); break; case 'm': mcastSpec = optarg; break; case 'n': logmask |= LOG_MASK(LOG_NOTICE); (void)setulogmask(logmask); break; case 'p': { char* cp; errno = 0; processPriority = (int)strtol(optarg, &cp, 0); if (0 != errno) { LOG_SERROR1("Couldn't decode priority \"%s\"", optarg); log_log(LOG_ERR); } else { if (processPriority < -20) processPriority = -20; else if (processPriority > 20) processPriority = 20; } break; } case 'q': prodQueuePath = optarg; break; case 'r': #ifdef RETRANS_SUPPORT retrans_xmit_enable = atoi(optarg); if(retrans_xmit_enable == 1) retrans_xmit_enable = OPTION_ENABLE; else retrans_xmit_enable = OPTION_DISABLE; #endif break; case 's': { #ifdef RETRANS_SUPPORT strcpy(sbn_channel_name, optarg); if(!strcmp(optarg,NAME_SBN_TYP_GOES)) { sbn_type = SBN_TYP_GOES; break; } if(!strcmp(optarg,NAME_SBN_TYP_NOAAPORT_OPT)) { sbn_type = SBN_TYP_NOAAPORT_OPT; break; } if(!strcmp(optarg,"NWSTG")) { sbn_type = SBN_TYP_NMC; break; } if(!strcmp(optarg,NAME_SBN_TYP_NMC)) { sbn_type = SBN_TYP_NMC; break; } if(!strcmp(optarg,NAME_SBN_TYP_NMC2)) { sbn_type = SBN_TYP_NMC2; break; } if(!strcmp(optarg,NAME_SBN_TYP_NMC3)) { sbn_type = SBN_TYP_NMC3; break; } if(!strcmp(optarg,NAME_SBN_TYP_NWWS)) { sbn_type = SBN_TYP_NWWS; break; } if(!strcmp(optarg,NAME_SBN_TYP_ADD)) { sbn_type = SBN_TYP_ADD; break; } if(!strcmp(optarg,NAME_SBN_TYP_ENC)) { sbn_type = SBN_TYP_ENC; break; } if(!strcmp(optarg,NAME_SBN_TYP_EXP)) { sbn_type = SBN_TYP_EXP; break; } if(!strcmp(optarg,NAME_SBN_TYP_GRW)) { sbn_type = SBN_TYP_GRW; break; } if(!strcmp(optarg,NAME_SBN_TYP_GRE)) { sbn_type = SBN_TYP_GRE; break; } printf("Operator input: UNKNOWN type must be\n"); printf(" %s, %s, %s, %s, %s, %s, %s, %s, %s, %s or %s \n", NAME_SBN_TYP_NMC, NAME_SBN_TYP_GOES, NAME_SBN_TYP_NOAAPORT_OPT, NAME_SBN_TYP_NMC2, NAME_SBN_TYP_NMC3, NAME_SBN_TYP_NWWS, NAME_SBN_TYP_ADD, NAME_SBN_TYP_ENC, NAME_SBN_TYP_EXP, NAME_SBN_TYP_GRW, NAME_SBN_TYP_GRE); #endif break; } case 't': #ifdef RETRANS_SUPPORT strcpy(transfer_type, optarg); if(!strcmp(transfer_type,"MHS") || !strcmp(transfer_type,"mhs")){ /** Using MHS for communication with NCF **/ }else{ uerror("No other mechanism other than MHS is currently supported\n"); status = 1; } #endif break; case 'u': { int i = atoi(optarg); if (0 > i || 7 < i) { LOG_START1("Invalid logging facility number: %d", i); status = 1; } else { static int logFacilities[] = {LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7}; logFacility = logFacilities[i]; status = initLogging(progName, logOptions, logFacility, logPath); } break; } case 'v': logmask |= LOG_MASK(LOG_INFO); (void)setulogmask(logmask); break; case 'x': logmask |= LOG_MASK(LOG_DEBUG); (void)setulogmask(logmask); break; default: optopt = ch; /*FALLTHROUGH*/ /* no break */ case '?': { uerror("Unknown option: \"%c\"", optopt); status = 1; break; } } /* option character switch */ } /* getopt() loop */ if (0 == status) { if (optind < argc) { uerror("Extraneous command-line argument: \"%s\"", argv[optind]); status = 1; } } if (0 != status) { uerror("Error decoding command-line"); usage(progName); } else { unotice("Starting Up %s", PACKAGE_VERSION); unotice("%s", COPYRIGHT_NOTICE); if ((status = fifoNew(npages, &fifo)) != 0) { LOG_ADD0("Couldn't create FIFO"); log_log(LOG_ERR); } else { LdmProductQueue* prodQueue; if ((status = lpqGet(prodQueuePath, &prodQueue)) != 0) { LOG_ADD0("Couldn't open LDM product-queue"); log_log(LOG_ERR); } else { if (NULL == mcastSpec) { if (0 == (status = spawnProductMaker(NULL, fifo, prodQueue, &productMaker, &productMakerThread))) { status = spawnFileReader(NULL, NULL, fifo, &reader, &readerThread); } } /* reading file */ else { pthread_attr_t attr; if (0 != (status = pthread_attr_init(&attr))) { LOG_ERRNUM0(status, "Couldn't initialize thread attribute"); } else { #ifndef _POSIX_THREAD_PRIORITY_SCHEDULING uwarn("Can't adjust thread priorities due to lack of " "necessary support from environment"); #else /* * In order to not miss any data, the reader thread * should preempt the product-maker thread as soon as * data is available and run as long as data is * available. */ const int SCHED_POLICY = SCHED_FIFO; struct sched_param param; param.sched_priority = sched_get_priority_max(SCHED_POLICY) - 1; (void)pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); (void)pthread_attr_setschedpolicy(&attr, SCHED_POLICY); (void)pthread_attr_setschedparam(&attr, ¶m); (void)pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); #endif #ifdef RETRANS_SUPPORT if (retrans_xmit_enable == OPTION_ENABLE){ /* Copy mcastAddress needed to obtain the cpio entries */ strcpy(mcastAddr, mcastSpec); } #endif if (0 == (status = spawnProductMaker(&attr, fifo, prodQueue, &productMaker, &productMakerThread))) { #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING param.sched_priority++; (void)pthread_attr_setschedparam(&attr, ¶m); #endif status = spawnMulticastReader(&attr, mcastSpec, interface, fifo, &reader, &readerThread); } /* product-maker spawned */ } /* "attr" initialized */ } /* reading multicast packets */ if (0 != status) { log_log(LOG_ERR); status = 1; } else { pthread_t statThread; (void)gettimeofday(&startTime, NULL); reportTime = startTime; (void)pthread_create(&statThread, NULL, reportStatsWhenSignaled, NULL); set_sigactions(); (void)pthread_join(readerThread, NULL); status = readerStatus(reader); (void)pthread_cancel(statThread); (void)pthread_join(statThread, NULL); (void)fifoCloseWhenEmpty(fifo); (void)pthread_join(productMakerThread, NULL); if (0 != status) status = pmStatus(productMaker); reportStats(); readerFree(reader); #ifdef RETRANS_SUPPORT /** Release buffer allocated for retransmission **/ if(retrans_xmit_enable == OPTION_ENABLE){ freeRetransMem(); } #endif } /* "reader" spawned */ (void)lpqClose(prodQueue); } /* "prodQueue" open */ } /* "fifo" created */ } /* command line decoded */ return status; }