/* * Prints to the standard output stream all values in the registry whose path * name starts with a given prefix. * * Arguments: * path Pointer to a registry pathname to be printed. Shall * not be NULL. * quiet Whether or not to be quiet about a pathname not * existing. * Returns: * 0 Success * NO_SUCH_ENTRY No such value or node. "log_flush()" called iff "quiet * == 0". * SYSTEM_ERROR Failure. "log_flush()" called. */ static Status printPath( const char* path, const int quiet) { Status status = 0; /* success */ RegStatus regStatus; char* value; log_debug("%s printing path \"%s\"", quiet ? "Quietly" : "Non-quietly", path); /* * The path name is first assumed to reference an existing value; * otherwise, the value wouldn't be printed. */ if (0 == (regStatus = reg_getString(path, &value))) { if (NULL != value) { (void)printf("%s\n", value); free(value); } /* "value" allocated */ } /* got value-string */ else { if (ENOENT != regStatus) { log_flush_error(); status = SYSTEM_ERROR; } else { /* * The path must reference a node. */ RegNode* node; log_clear(); if (0 != (regStatus = reg_getNode(path, &node, 0))) { if (ENOENT == regStatus) { if (!quiet) { log_error("No such value or node: \"%s\"", path); } status = NO_SUCH_ENTRY; } else { log_flush_error(); status = SYSTEM_ERROR; } } /* didn't get node */ else { _pathPrefix = path; if (0 != reg_visitNodes(node, printNodeValues)) { log_flush_error(); status = SYSTEM_ERROR; } /* error visiting nodes */ } /* got node */ } /* no such value */ } /* didn't get value-string */ return status; }
static void usage(const char* progname) { log_add( "Usages:\n" " Create Registry: %s [-v|-x] [-d dir] -c\n" " Reset Registry: %s [-v|-x] [-d dir] -R\n" " Print Parameters: %s [-v|-x] [-d dir] [-q] [path ...]\n" " Remove Parameter(s): %s [-v|-x] [-d dir] [-q] -r path ...\n" " Set Parameter: %s [-v|-x] [-d dir] (-b bool|-h sig|-s string|-t time|-u uint) " "valpath\n" "Where:\n" " -b bool Boolean registry value: TRUE, FALSE\n" " -d dir Path name of registry directory. Default=\"%s\"\n" " -h sig Data-product signature as 32 hexadecimal characters\n" " -q Be quiet about missing values or nodes\n" " -s string String registry value\n" " -t time Time registry value as YYYYMMDDThhmmss[.uuuuuu]\n" " -u uint Unsigned integer registry value\n" " -v Log INFO messages\n" " -x Log DEBUG messages\n" " path Absolute pathname of registry node or value\n" " valpath Absolute pathname of value\n", progname, progname, progname, progname, progname, getRegistryDirPath()); log_flush_error(); }
/** * There is data available on the feed. Read it into the buffer * then deal with what we got. * * @param ifd [in] File-descriptor of the input data-feed * @retval 0 Success * @retval ENOMEM Out of memory * @retval ENODATA End of input data-feed */ int feedTheXbuf(const int ifd) { int status; size_t nn = 0; /* space available in buffer */ ptrdiff_t remaining = (ptrdiff_t)theBuf->bufsiz - (theBuf->get - theBuf->base); if (remaining <= CHUNKSIZE) { if (theBuf->bufsiz >= maxProductSize) { log_warning_q( "Data-product would exceed %lu bytes. Resetting input buffer.", maxProductSize); justify_xbuf(theBuf, 0); } log_info_q("Expanding input buffer size to %lu\n", (unsigned long)(2 * theBuf->bufsiz)); theBuf = expand_xbuf(theBuf, theBuf->bufsiz); if (theBuf == NULL) { status = errno == 0 ? ENOMEM : errno; log_add_syserr("expand_xbuf"); log_flush_error(); return status; } } status = (*read_feed)(ifd, (char *)theBuf->put, CHUNKSIZE, &nn); if(status != ENOERR) { log_add_errno(status, "read_feed"); log_flush_error(); return status; } /* else */ if(nn == 0) return ENODATA; /* end of file */ /* else */ /* usual case */ /* assert(nn > 0); */ theBuf->cnt += nn; theBuf->put += nn; return ENOERR; }
static void test_add_get(void) { FmtpProdIndex fileA = 1; FmtpProdIndex fileB; int status; status = piq_add(rq, fileA); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL(piq_count(rq), 1); status = piq_removeNoWait(rq, &fileB); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL_FATAL(fileB, fileA); CU_ASSERT_EQUAL(piq_count(rq), 0); }
/* * Removes the values referenced by an absolute registry pathname. * * Arguments: * path Pointer to a an absolute registry pathname. Shall not * be NULL. If the pathname refers to a node, then the * node and all its subnodes are recursively removed. * quiet Whether or not to be quiet about a pathname not * existing. * Returns: * 0 Success. * NO_SUCH_ENTRY No such entry in the registry. "log_flush()" called iff * "quiet == 0". * SYSTEM_ERROR System error. "log_flush()" called. */ static Status deletePath( const char* const path, const int quiet) { log_debug("%s deleting path \"%s\"", quiet ? "Quietly" : "Non-quietly", path); switch (reg_deleteValue(path)) { case 0: return 0; case ENOENT: { RegNode* node; switch (reg_getNode(path, &node, 0)) { case 0: reg_deleteNode(node); if (reg_flushNode(node)) { log_flush_error(); return SYSTEM_ERROR; } return 0; case ENOENT: if (!quiet) { log_error("No such value or node: \"%s\"", path); } return NO_SUCH_ENTRY; default: log_flush_error(); return SYSTEM_ERROR; } } /* FALLTHROUGH */ /* no break */ default: log_flush_error(); return SYSTEM_ERROR; } }
static void test_sa_parseWithDefaults(void) { ServiceAddr* sa; int status; const char* hostId = "uni14.unidata.ucar.edu"; const short port = 388; status = sa_parseWithDefaults(&sa, hostId, NULL, 388); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_STRING_EQUAL(sa_getInetId(sa), hostId); CU_ASSERT_EQUAL(sa_getPort(sa), port); sa_free(sa); }
static void sa_parse_test( const char* const inetId, const unsigned short port) { ServiceAddr* sa; char* buf = ldm_format(80, strchr(inetId, ':') ? "[%s]:%d" : "%s:%d", inetId, port); int status; CU_ASSERT_PTR_NOT_NULL_FATAL(buf); status = sa_parse(&sa, buf); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_STRING_EQUAL(sa_getInetId(sa), inetId); CU_ASSERT_EQUAL(sa_getPort(sa), port); sa_free(sa); }
/** * Sets an LDM product-identifier from a GRIB message. * * Not Atomic, * Idempotent, * Thread-safe * * @param[out] ident Product-identifier buffer. * @param[in] identSize Size of product-identifier buffer in bytes. * @param[in] decoded Decoded GRIB message. * @param[in] wmoHead WMO header associated with the GRIB message. * @retval 0 Success. \c *ident is set. * @retval 1 GRIB message has no data. * @retval 3 System error. */ static int setIdent( char* const ident, const size_t identSize, DecodedGrib2Msg* const decoded, const char* const wmoHead) { const size_t numFields = g2d_getNumFields(decoded); int status; if (0 == numFields) { log_add("GRIB message has no fields"); status = 1; } else { StringBuf* const prods = strBuf_new(127); /* initially empty */ if (NULL == prods) { log_add_syserr("Couldn't allocate string-buffer for products"); log_flush_error(); status = 3; } else { Gribmsg gribMsg; Geminfo gemInfo; int modelId; status = appendParameterNames(prods, decoded, &gribMsg, &gemInfo); if (0 == status) { status = getModelId(decoded, &modelId); if (0 == status) composeIdent(ident, identSize, decoded, &gribMsg, &gemInfo, prods, wmoHead, modelId); } strBuf_free(prods); } /* "prods" allocated */ } /* numFields > 0 */ return status; }
/** * Initializes this module. * * @param readfunct [in] The function that reads the data * @param maxProdSize [in] The size, in bytes, of the largest expected * data-product * @retval 0 Success * @retval ENOMEM Out of memory */ int initTheXbuf( int (*readfunct)(int ifd, char *buf, size_t nbytes, size_t *ngotp), const unsigned long maxProdSize) { read_feed = readfunct; maxProductSize = maxProdSize > INIT_CIRCBUFSIZE ? maxProdSize : INIT_CIRCBUFSIZE; if(theBuf == NULL) { theBuf = new_xbuf(INIT_CIRCBUFSIZE); if(theBuf == NULL) { const int status = errno == 0 ? ENOMEM : errno; log_add_syserr("new_xbuf"); log_flush_error(); return status; } } return ENOERR; }
static void usage( const char* const progname /* id string */ ) { log_add( "Usage: %s [options] filename ...\n" " Options:\n" " -v Verbose, tell me about each product\n" " -l dest Log to `dest`. One of: \"\" (system logging daemon), \"-\"\n" " (standard error), or file `dest`. Default is \"%s\"\n" " -q queue Use <queue> as product-queue. Default:\n" " \"%s\"\n" " -s seqno Set initial product sequence number to <seqno>.\n" " Default: 0\n" " -f feedtype Assert your feed type as <feedtype>. Default: \"EXP\"\n" " -p productID Assert product-ID as <productID>. Default is the \n" " filename. With multiple files, product-ID becomes\n" " <productID>.<seqno>\n" " -i Compute product signature (MD5 checksum) from product ID\n", progname, log_get_default_destination(), getDefaultQueuePath()); log_flush_error(); exit(1); }
static void test_order(void) { FmtpProdIndex fileA = 1; FmtpProdIndex fileB = 2; FmtpProdIndex fileC = 3; FmtpProdIndex fileD; int status; status = piq_add(rq, fileA); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL(piq_count(rq), 1); status = piq_add(rq, fileB); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL(piq_count(rq), 2); status = piq_add(rq, fileC); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL(piq_count(rq), 3); status = piq_removeNoWait(rq, &fileD); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL_FATAL(fileD, fileA); CU_ASSERT_EQUAL(piq_count(rq), 2); status = piq_removeNoWait(rq, &fileD); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL_FATAL(fileD, fileB); CU_ASSERT_EQUAL(piq_count(rq), 1); status = piq_removeNoWait(rq, &fileD); log_flush_error(); CU_ASSERT_EQUAL_FATAL(status, 0); CU_ASSERT_EQUAL_FATAL(fileD, fileC); CU_ASSERT_EQUAL(piq_count(rq), 0); }
/* * Returns: * 0 Success * 1 Incorrect usage (i.e., command-line syntax error). * 2 No such parameter or node. Error message written. * 3 System error. Error message written. */ int main( int argc, char* argv[]) { int status; const char* const progname = basename(argv[0]); (void)log_init(progname); if ((status = sb_new(&_valuePath, 80))) { log_error("Couldn't initialize utility"); status = SYSTEM_ERROR; } else { enum { UNKNOWN, CREATE, PRINT, PUT_BOOL, PUT_STRING, PUT_UINT, PUT_SIGNATURE, PUT_TIME, RESET, REMOVE } action = UNKNOWN; const char* string; signaturet signature; timestampt timestamp; unsigned long uint; int boolean; int ch; int quiet = 0; opterr = 0; /* supress getopt(3) error messages */ while (0 == status && (ch = getopt(argc, argv, ":b:cd:h:qRrs:t:u:vx")) != -1) { switch (ch) { case 'b': { if (strcasecmp(optarg, "TRUE") == 0) { boolean = 1; } else if (strcasecmp(optarg, "FALSE") == 0) { boolean = 0; } else { log_add("Not a boolean value: \"%s\"", optarg); status = COMMAND_SYNTAX; } if (status == 0) { if (CREATE == action) { log_error("Create option ignored"); } action = PUT_BOOL; } break; } case 'c': { if (UNKNOWN != action) { log_add("Can't mix create action with other actions"); status = COMMAND_SYNTAX; } else { action = CREATE; } break; } case 'd': { if ((status = reg_setDirectory(optarg))) status = SYSTEM_ERROR; break; } case 'h': { status = sigParse(optarg, &signature); if (0 > status || 0 != optarg[status]) { log_add("Not a signature: \"%s\"", optarg); status = COMMAND_SYNTAX; } else { if (CREATE == action) { log_info("Create action ignored"); } action = PUT_SIGNATURE; status = 0; } break; } case 'q': { quiet = 1; break; } case 'R': { if (UNKNOWN != action) { log_add("Can't mix reset action with other actions"); status = COMMAND_SYNTAX; } else { action = RESET; } break; } case 'r': { if (UNKNOWN != action) { log_add("Can't mix remove action with other actions"); status = COMMAND_SYNTAX; } else { action = REMOVE; } break; } case 's': { if (CREATE == action) { log_info("Create action ignored"); } string = optarg; action = PUT_STRING; break; } case 't': { status = tsParse(optarg, ×tamp); if (0 > status || 0 != optarg[status]) { log_add("Not a timestamp: \"%s\"", optarg); status = COMMAND_SYNTAX; } else { if (CREATE == action) { log_info("Create action ignored"); } action = PUT_TIME; status = 0; } break; } case 'u': { char* end; errno = 0; uint = strtoul(optarg, &end, 0); if (0 != *end || (0 == uint && 0 != errno)) { log_add("Not an unsigned integer: \"%s\"", optarg); status = COMMAND_SYNTAX; } else { if (CREATE == action) { log_info("Create option ignored"); } action = PUT_UINT; } break; } 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 ':': { log_add("Option \"-%c\" requires an operand", optopt); status = COMMAND_SYNTAX; break; } default: log_add("Unknown option: \"%c\"", optopt); status = COMMAND_SYNTAX; /* no break */ } } /* options loop */ if (status) { log_flush_error(); if (COMMAND_SYNTAX == status) usage(progname); } else { const int argCount = argc - optind; if (UNKNOWN == action) action = PRINT; switch (action) { case CREATE: { if (0 < argCount) { log_error("Too many arguments"); usage(progname); status = COMMAND_SYNTAX; } else { status = createRegistry(); } break; } case RESET: { if (0 < argCount) { log_error("Too many arguments"); usage(progname); status = COMMAND_SYNTAX; } else { status = resetRegistry(); } break; } case REMOVE: { if (0 == argCount) { log_error( "Removal action requires absolute pathname(s)"); usage(progname); status = COMMAND_SYNTAX; } else { log_debug("Removing registry"); status = actUponPathList(argv + optind, deletePath, quiet); } break; } case PRINT: { log_debug("Printing registry"); status = (0 == argCount) ? printPath("/", quiet) : actUponPathList(argv + optind, printPath, quiet); break; } default: { /* * Must be some kind of "put". */ if (0 == argCount) { log_error("Put action requires value pathname"); usage(progname); status = COMMAND_SYNTAX; } else { switch (action) { case PUT_BOOL: status = reg_putBool(argv[optind], boolean); break; case PUT_UINT: status = reg_putUint(argv[optind], uint); break; case PUT_STRING: status = reg_putString(argv[optind], string); break; case PUT_TIME: status = reg_putTime(argv[optind], ×tamp); break; case PUT_SIGNATURE: status = reg_putSignature(argv[optind], signature); break; default: abort(); } if (status) { log_flush_error(); status = SYSTEM_ERROR; } } } /* put switch */ /* no break */ } /* "action" switch */ } /* decoded options */ sb_free(_valuePath); } /* "_valuePath" allocated */ return status; }
/** * Generates an LDM product-identifier from a GRIB edition 2 message. * * Atomic, * Idempotent, * Not thread-safe * * @param[in] data Pointer to the GRIB message. * @param[in] sz Length of the GRIB message in bytes. * @param[in] wmohead Pointer to the associated WMO header string. * @param[out] ident Pointer to a buffer to receive the LDM * product-identifier. * @param[in] identSize Size of the \c ident buffer in bytes. * @retval 0 Success. \c ident is set and NUL-terminated. * @retval 1 Invalid GRIB message. * @retval 2 GRIB message isn't edition 2. * @retval 3 System error. */ int grib2name ( char* const data, const size_t sz, const char* const wmohead, char* const ident, const size_t identSize) { #if USE_GRIB2_DECODER int status; DecodedGrib2Msg* decoded; if (status = g2d_new(&decoded, (unsigned char*)data, sz)) { log_add("Couldn't decode GRIB message"); status = G2D_INVALID == status ? 1 : G2D_NOT_2 ? 2 : 3; } else { if (status = setIdent(ident, identSize, decoded, wmohead)) { log_add("Couldn't set LDM product-identifier"); status = 1; } g2d_free(decoded); } /* "decoded" allocated */ return status; #else static StringBuf* paramNames; /* Buffer for parameter name(s) */ int iField; /* GRIB-2 field index */ int status; /* Function return code */ g2int listsec0[3]; /* GRIB-2 section 0 parameters */ g2int listsec1[13]; /* GRIB-2 section 1 parameters */ g2int numlocal; /* Number of GRIB section 2-s */ int model_id; /* ID of model */ int grid_id; /* ID of grid */ char fdats[80]; /* No idea */ char levelstmp[80]; /* Level? */ Gribmsg g2Msg; /* GRIB-2 message structure */ if (paramNames) { strBuf_clear(paramNames); } else { paramNames = strBuf_new(127); if (NULL == paramNames) { log_add("Couldn't allocate buffer for parameter name(s)"); return 3; } } g2Msg.cgrib2 = (unsigned char*)data; g2Msg.mlength = sz; g2Msg.gfld = NULL; g2Msg.field_tot = 0; if ((status = g2_info(g2Msg.cgrib2, g2Msg.mlength, listsec0, listsec1, &(g2Msg.field_tot), &numlocal)) != 0) return (2 == status) ? 2 : 1; if (g2Msg.field_tot <= 0) { log_add("GRIB-2 message has no data fields"); return 1; } for (iField = 0; iField < g2Msg.field_tot; iField++) { static char g2tables[5][LLMXLN]; /* GRIB tables */ static char* tbllist[5] = {g2tables[0], g2tables[1], g2tables[2], g2tables[3], g2tables[4]}; /* Addresses of GRIB tables */ Geminfo gemInfo; /* GEMPAK structure */ int const lastField = iField == g2Msg.field_tot - 1; status = g2_getfld(g2Msg.cgrib2, g2Msg.mlength, iField+1, 0, 0, &g2Msg.gfld); if (status) { log_add("Invalid GRIB-2 message: g2_getfld() status=%d", status); return (2 == status) ? 2 : 1; } /* "g2Msg.gfld" is allocated */ /* Initialize strings in Geminfo structure */ (void)memset(gemInfo.cproj, 0, sizeof(gemInfo.cproj)); (void)memset(gemInfo.parm, 0, sizeof(gemInfo.parm)); (void)memset(gemInfo.gdattm1, 0, sizeof(gemInfo.gdattm1)); (void)memset(gemInfo.gdattm2, 0, sizeof(gemInfo.gdattm2)); /* * In the original code, the last field determined the model ID. */ if (lastField) model_id = g2Msg.gfld->ipdtmpl[4]; /* * This assignment to "grid_id" isn't under the above "lastField" * conditional because "decode_g2gnum()" might have side-effects upon * which "gb2_2gem()" depends. */ grid_id = (g2Msg.gfld->griddef == 0) ? decode_g2gnum(g2Msg.gfld) : g2Msg.gfld->griddef; gb2_2gem(&g2Msg, &gemInfo, tbllist, &status); if (status) { log_add("Couldn't decode GRIB2 message. WMO header=\"%s\"", wmohead); log_flush_error(); if (lastField) { (void)strcpy(fdats, "FHRS"); /* safe */ (void)strcpy(levelstmp, "LVL"); /* safe */ } } else { char g2name[13]; /**< Name of product/parameter */ int ilen; /**< Length of resulting string */ (void)strcpy(g2name, gemInfo.parm); /* both 13 bytes */ cst_rmbl(g2name, g2name, &ilen, &status); if (iField) strBuf_appendString(paramNames, ";"); strBuf_appendString(paramNames, g2name); cst_rxbl(gemInfo.unit, gemInfo.unit, &ilen, &status); if (ilen == 0) (void)strcpy(gemInfo.unit, "-"); /* safe */ cst_rmbl(gemInfo.gdattm1, gemInfo.gdattm1, &ilen, &status); cst_rmbl(gemInfo.gdattm2, gemInfo.gdattm2, &ilen, &status); /* * In the original code, the last field determined the following * parameters. */ if (lastField) { static char strBuf[5]; /* Holds 4-char string */ static char* strptr = strBuf; /* For "cst_itoc()" */ if (ilen > 0) (void)snprintf(fdats, sizeof(fdats), "%s-%s", gemInfo.gdattm1, gemInfo.gdattm2); else (void)snprintf(fdats, sizeof(fdats), "%s", gemInfo.gdattm1); for (ilen = 1; ilen > 0; cst_rmst(fdats, "/", &ilen, fdats, &status)); cst_itoc(&gemInfo.vcord, 1, &strptr, &status); if (gemInfo.level[1] == -1) (void)snprintf(levelstmp, sizeof(levelstmp), "%d %s %s", gemInfo.level[0], gemInfo.unit, strptr); else (void)snprintf(levelstmp, sizeof(levelstmp), "%d-%d %s %s", gemInfo.level[0], gemInfo.level[1], gemInfo.unit, strptr); } } g2_free(g2Msg.gfld); g2Msg.gfld = NULL; } /* * See if the WMO header can be used for grid 0 products */ if ((grid_id == 0) && (strlen(wmohead) > 11) && (wmohead[7] == 'K') && (wmohead[8] == 'W')) { int wmoGridId = wmo_to_gridid(&wmohead[0], &wmohead[2]); if (wmoGridId > 0) grid_id = wmoGridId; } (void)snprintf(ident, identSize, "grib2/%s/%s/#%03d/%s/%s/%s", s_pds_center((int)listsec1[0], (int)listsec1[1]), s_pds_model((int)listsec1[0], model_id), grid_id, fdats, strBuf_toString(paramNames), levelstmp); return 0; #endif }
/* * 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 *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); }