/* * lut_lookup -- find an entry */ void * lut_lookup(struct lut *root, const char *lhs) { int diff; if (root == NULL || lhs == NULL) return (NULL); else if ((diff = strcmp(root->lut_lhs, lhs)) == 0) return (root->lut_rhs); else if (diff > 0) return (lut_lookup(root->lut_left, lhs)); else return (lut_lookup(root->lut_right, lhs)); }
static int build_lookup(struct timecode_def *def) { unsigned int n; bits_t current, last; if (def->lookup) return 0; fprintf(stderr, "Building LUT for %d bit %dHz timecode (%s)\n", def->bits, def->resolution, def->desc); if (lut_init(&def->lut, def->length) == -1) return -1; current = def->seed; for (n = 0; n < def->length; n++) { /* timecode must not wrap */ dassert(lut_lookup(&def->lut, current) == (unsigned)-1); lut_push(&def->lut, current); last = current; current = fwd(current, def); dassert(rev(current, def) == last); } def->lookup = true; return 0; }
struct ipath * ipath_for_usednames(struct node *np) { struct ipath *ret, *ipp; int i = 0; struct node *np2; for (np2 = np; np2 != NULL; np2 = np2->u.name.next) i++; ret = MALLOC(sizeof (*ret) * (i + 1)); for (i = 0, np2 = np; np2 != NULL; np2 = np2->u.name.next) { ret[i].s = np2->u.name.s; ret[i++].i = 0; } ret[i].s = NULL; if ((ipp = lut_lookup(Ipaths, (void *)ret, (lut_cmp)ipath_cmp)) != NULL) { FREE(ret); return (ipp); } Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp); stats_counter_bump(Nipath); stats_counter_add(Nbytes, (i + 1) * sizeof (struct ipath)); return (ret); }
struct ipath * ipath_dummy(struct node *np, struct ipath *ipp) { struct ipath *ret; ret = ipp; while (ipp[1].s != NULL) ipp++; if (strcmp(ipp[0].s, np->u.name.last->u.name.s) == 0) return (ret); ret = MALLOC(sizeof (*ret) * 2); ret[0].s = np->u.name.last->u.name.s; ret[0].i = 0; ret[1].s = NULL; if ((ipp = lut_lookup(Ipaths, (void *)ret, (lut_cmp)ipath_cmp)) != NULL) { FREE(ret); return (ipp); } Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp); stats_counter_bump(Nipath); stats_counter_add(Nbytes, 2 * sizeof (struct ipath)); return (ret); }
void printer(const char *lhs, void *rhs, void *arg) { struct lut *root = (struct lut *)arg; printf("<%s> <%s> (<%s>)\n", lhs, (char *)rhs, (char *)lut_lookup(arg, lhs)); }
/* * conf_opts -- return the parsed opts for an entry */ struct opts * conf_opts(const char *lhs) { struct confinfo *cp = lut_lookup(Conflut, lhs); if (cp != NULL) return (cp->cf_opts); return (opts_parse(NULL, NULL, OPTF_CONF)); }
/* * conf_lookup -- lookup an entry in the config file */ void * conf_lookup(const char *lhs) { struct confinfo *cp = lut_lookup(Conflut, lhs); if (cp != NULL) err_fileline(Confname, cp->cf_lineno); return (cp); }
/* * ipath -- find instanced path in cache, or add it if necessary */ const struct ipath * ipath(struct node *np) { struct ipath *ret; int count; struct node *namep; int i; if ((ret = lut_lookup(Ipaths, (void *)np, (lut_cmp)ipath_epnamecmp)) != NULL) return (ret); /* already in cache */ /* * not in cache, make new cache entry. * start by counting the length of the name. */ count = 0; namep = np; while (namep != NULL) { ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t)); count++; namep = namep->u.name.next; } ASSERT(count > 0); /* allocate array for name and last NULL entry */ ret = MALLOC(sizeof (*ret) * (count + 1)); ret[count].s = NULL; /* fill in ipath entry */ namep = np; i = 0; while (namep != NULL) { ASSERT(i < count); ret[i].s = namep->u.name.s; if (namep->u.name.child != NULL && namep->u.name.child->t == T_NUM) ret[i].i = (int)namep->u.name.child->u.ull; else config_getcompname(namep->u.name.cp, NULL, &ret[i].i); i++; namep = namep->u.name.next; } /* add it to the cache */ Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp); stats_counter_bump(Nipath); stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath)); return (ret); }
/* * conf_set -- set options for an entry in the config file */ void conf_set(const char *entry, char *o, const char *optarg) { struct confinfo *cp = lut_lookup(Conflut, entry); if (Conffd == -1) return; if (cp != NULL) { if (cp->cf_opts == NULL) cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF); cp->cf_flags &= ~CONFF_DELETED; } else { fillconflist(0, STRDUP(entry), NULL, opts_parse(NULL, OPTF_CONF), NULL, 0); if ((cp = lut_lookup(Conflut, entry)) == NULL) err(0, "conf_set internal error"); } (void) opts_set(cp->cf_opts, o, optarg); Confchanged = B_TRUE; }
/* * conf_set -- set options for an entry in the config file */ void conf_set(const char *entry, char *o, const char *optarg) { struct confinfo *cp = lut_lookup(Conflut, entry); if (Conffd == -1) return; if (cp != NULL) { cp->cf_flags &= ~CONFF_DELETED; } else { fillconflist(0, STRDUP(entry), opts_parse(NULL, NULL, OPTF_CONF), NULL, 0); if ((cp = lut_lookup(Conflut, entry)) == NULL) err(0, "conf_set internal error"); } (void) opts_set(cp->cf_opts, o, optarg); if (strcmp(o, "P") == 0) Changed |= CHG_TIMES; else Changed = CHG_BOTH; }
/* * conf_opts -- return the parsed opts for an entry */ struct opts * conf_opts(const char *lhs) { struct confinfo *cp = lut_lookup(Conflut, lhs); if (cp != NULL) { if (cp->cf_opts) return (cp->cf_opts); /* already parsed */ err_fileline(Confname, cp->cf_lineno); cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF); return (cp->cf_opts); } return (opts_parse(NULL, OPTF_CONF)); }
/* * conf_replace -- replace an entry in the config file */ void conf_replace(const char *lhs, struct opts *newopts) { struct confinfo *cp = lut_lookup(Conflut, lhs); if (Conffd == -1) return; if (cp != NULL) { cp->cf_opts = newopts; cp->cf_args = NULL; if (newopts == NULL) cp->cf_flags |= CONFF_DELETED; } else fillconflist(0, lhs, NULL, newopts, NULL, 0); Confchanged = B_TRUE; }
/* * scan the memory image of a file * returns: 0: error, 1: ok, 3: -P option found */ static int conf_scan(const char *fname, char *buf, int buflen, int timescan, struct opts *cliopts) { int ret = 1; int lineno = 0; char *line; char *eline; char *ebuf; char *entry, *comment; ebuf = &buf[buflen]; if (buf[buflen - 1] != '\n') err(EF_WARN|EF_FILE, "file %s doesn't end with newline, " "last line ignored.", fname); for (line = buf; line < ebuf; line = eline) { char *ap; struct opts *opts = NULL; struct confinfo *cp; lineno++; err_fileline(fname, lineno); eline = line; comment = NULL; for (; eline < ebuf; eline++) { /* check for continued lines */ if (comment == NULL && *eline == '\\' && eline + 1 < ebuf && *(eline + 1) == '\n') { *eline = ' '; *(eline + 1) = ' '; lineno++; err_fileline(fname, lineno); continue; } /* check for comments */ if (comment == NULL && *eline == '#') { *eline = '\0'; comment = (eline + 1); continue; } /* check for end of line */ if (*eline == '\n') break; } if (comment >= ebuf) comment = NULL; if (eline >= ebuf) { /* discard trailing unterminated line */ continue; } *eline++ = '\0'; /* * now we have the entry, if any, at "line" * and the comment, if any, at "comment" */ /* entry is first token */ entry = nexttok(&line); if (entry == NULL) { /* it's just a comment line */ if (!timescan) fillconflist(lineno, entry, NULL, comment, 0); continue; } if (strcmp(entry, "logadm-version") == 0) { /* * we somehow opened some future format * conffile that we likely don't understand. * if the given version is "1" then go on, * otherwise someone is mixing versions * and we can't help them other than to * print an error and exit. */ if ((entry = nexttok(&line)) != NULL && strcmp(entry, "1") != 0) err(0, "%s version not supported " "by this version of logadm.", fname); continue; } /* form an argv array */ ArgsI = 0; while (ap = nexttok(&line)) fillargs(ap); Args[ArgsI] = NULL; LOCAL_ERR_BEGIN { if (SETJMP) { err(EF_FILE, "cannot process invalid entry %s", entry); ret = 0; LOCAL_ERR_BREAK; } if (timescan) { /* append to config options */ cp = lut_lookup(Conflut, entry); if (cp == NULL) { /* orphaned entry */ if (opts_count(cliopts, "v")) err(EF_FILE, "stale timestamp " "for %s", entry); LOCAL_ERR_BREAK; } opts = cp->cf_opts; } opts = opts_parse(opts, Args, OPTF_CONF); if (!timescan) { fillconflist(lineno, entry, opts, comment, 0); } LOCAL_ERR_END } if (ret == 1 && opts && opts_optarg(opts, "P") != NULL) ret = 3; } err_fileline(NULL, 0); return (ret); }
/* * kw_expand -- expand src into dst with given n value for $n (or $N) * * n == -1 means expand src into a reglob * if gz is true, include ".gz" extension * * returns true if template contains $n or $N (implying rotation of files) */ boolean_t kw_expand(struct fn *src, struct fn *dst, int n, boolean_t gz) { int c; char buf[MAXDIGITS]; boolean_t hasn = B_FALSE; struct fn *kw = fn_new(NULL); char *ptr; struct tm *gmt_tm = localtime(&Now); while ((c = fn_getc(src)) != '\0') switch (c) { case '.': case '(': case ')': case '^': case '+': case '{': case '}': /* when building an re, escape with a backslash */ if (n < 0) fn_putc(dst, '\\'); fn_putc(dst, c); break; case '?': /* when building an re, change '?' to a single dot */ if (n < 0) fn_putc(dst, '.'); break; case '*': /* when building an re, change '*' to ".*" */ if (n < 0) fn_putc(dst, '.'); fn_putc(dst, '*'); break; case '$': /* '$' marks the start of a keyword */ switch (c = fn_getc(src)) { case '$': /* double '$' stands for a single '$' */ if (n < 0) fn_putc(dst, '\\'); fn_putc(dst, '$'); break; case '#': /* * $# expands to nothing, but forces an end * of keyword, allow juxtaposition of a * keyword with lower-case characters */ break; case 'n': case 'N': if (c == 'N' || !islower(fn_peekc(src))) { /* * we've found $n or $N, if we're * building an re, build one that * matches a number, otherwise * expand the keyword to the n * passed in to this function */ hasn = B_TRUE; if (n < 0) fn_puts(dst, "([0-9]+)$0"); else { (void) snprintf(buf, MAXDIGITS, "%d", (c == 'n') ? n : n + 1); fn_puts(dst, buf); } break; } /*FALLTHROUGH*/ default: /* gather up the keyword name */ fn_renew(kw, NULL); fn_putc(kw, c); while (islower(fn_peekc(src))) fn_putc(kw, fn_getc(src)); /* lookup keyword */ if ((ptr = (char *)lut_lookup(Keywords, fn_s(kw))) == NULL) { /* nope, copy it unexpanded */ if (n < 0) fn_putc(dst, '\\'); fn_putc(dst, '$'); fn_putfn(dst, kw); } else fn_puts(dst, ptr); } break; case '%': /* * % sequence for strftime(), if we're building * an re, we take our best guess at the re for * this sequence, otherwise we pass it to strftime() */ if (n < 0) { /* * the regex for a percent sequence is * usually just ".*" unless it is one * of the common cases we know about * that are numeric. in those cases, we * tighten up the regex to just match digits. * * while it is gross that we embed knowledge * of strftime() sequences here, they are * specified in a standard so aren't * expected to change often, and it *really* * cuts down on the possibility that we'll * expire a file that isn't an old log file. */ if ((c = fn_getc(src)) == 'E' || c == 'O') { c = fn_getc(src); fn_puts(dst, ".*"); } else switch (c) { case 'd': case 'g': case 'G': case 'H': case 'I': case 'j': case 'm': case 'M': case 'S': case 'u': case 'U': case 'V': case 'w': case 'W': case 'y': case 'Y': /* pure numeric cases */ fn_puts(dst, "[0-9]+"); break; case 'e': case 'k': case 'l': /* possible space then num */ fn_puts(dst, " *[0-9]+"); break; case 'D': /* %m/%d/%y */ /* adds slashes! */ fn_puts(dst, "[0-9]+/[0-9]+/[0-9]+"); break; case 'R': /* %H:%M */ fn_puts(dst, "[0-9]+:[0-9]+"); break; case 'T': /* %H:%M:%S */ fn_puts(dst, "[0-9]+:[0-9]+:[0-9]+"); break; default: fn_puts(dst, ".*"); } } else { char tbuf[4]; /* copy % sequence to tbuf */ tbuf[0] = '%'; tbuf[1] = fn_getc(src); if (tbuf[1] == 'E' || tbuf[1] == 'O') { /* "extended" sequence */ tbuf[2] = fn_getc(src); tbuf[3] = '\0'; } else tbuf[2] = '\0'; if (strftime(buf, MAXDIGITS, tbuf, gmt_tm) == 0) /* just copy %x */ fn_puts(dst, tbuf); else fn_puts(dst, buf); } break; default: /* nothing special, just copy it */ fn_putc(dst, c); } if (gz) { if (n < 0) fn_puts(dst, "(\\.gz){0,1}"); else fn_puts(dst, ".gz"); } fn_free(kw); return (hasn); }
const unsigned long long * lex_s2ullp_lut_lookup(struct lut *root, const char *s) { return ((unsigned long long *)lut_lookup(root, (void *)s, NULL)); }
static int lex_s2i_lut_lookup(struct lut *root, const char *s) { return ((intptr_t)lut_lookup(root, (void *)s, NULL)); }