/* * Internal version of lookup_dt() used by both lookup_dt() and * update_dt(); same semantics as lookup_dt() except that the `partial' * argument has been generalized into a `flags' field and the handle has * been turned into a FILE pointer. */ static int find_dt(FILE *fp, uint_t flags, uint_t query, int count, const dt_rec_t *targetp, dt_rec_list_t **recordsp, uint_t *nrecordsp) { int retval = DSVC_SUCCESS; char *buf = NULL, *fields[DTF_MAX_FIELDS]; uint_t nrecords; dt_rec_t *recordp; dt_rec_list_t *records, *new_records; unsigned int nfields; off_t recoff; if (fseek(fp, 0, SEEK_SET) == -1) return (DSVC_INTERNAL); records = NULL; for (nrecords = 0; count < 0 || nrecords < count; ) { free(buf); if (flags & FIND_POSITION) recoff = ftello(fp); buf = read_entry(fp); if (buf == NULL) { if (!feof(fp)) retval = DSVC_NO_MEMORY; break; } /* * Skip pure comment lines; for now this just skips the * header information at the top of the container. */ if (buf[0] == DTF_COMMENT_CHAR) continue; /* * Parse out the entry into the dt_rec_t */ nfields = field_split(buf, DTF_MAX_FIELDS, fields, " \t"); if (nfields < DTF_MAX_FIELDS) continue; /* * See if we've got a match. If so, allocate the new * record, fill it in, and continue. */ if (DSVC_QISEQ(query, DT_QTYPE) && targetp->dt_type != fields[DTF_TYPE][0]) continue; else if (DSVC_QISNEQ(query, DT_QTYPE) && targetp->dt_type == fields[DTF_TYPE][0]) continue; if (DSVC_QISEQ(query, DT_QKEY) && strcmp(targetp->dt_key, fields[DTF_KEY]) != 0) continue; else if (DSVC_QISNEQ(query, DT_QKEY) && strcmp(targetp->dt_key, fields[DTF_KEY]) == 0) continue; /* * Caller just wants a count of the number of matching * records, not the records themselves; continue. */ if (recordsp == NULL) { nrecords++; continue; } /* * Allocate record; if FIND_POSITION flag is set, then we * need to allocate an extended (dt_recpos_t) record. */ if (flags & FIND_POSITION) recordp = malloc(sizeof (dt_recpos_t)); else recordp = malloc(sizeof (dt_rec_t)); if (recordp == NULL) { if ((flags & FIND_PARTIAL) == 0) retval = DSVC_NO_MEMORY; break; } /* * Fill in record; if FIND_POSITION flag is set, then pass * back additional location information. */ (void) strlcpy(recordp->dt_key, fields[DTF_KEY], sizeof (recordp->dt_key)); recordp->dt_sig = 1; recordp->dt_type = fields[DTF_TYPE][0]; recordp->dt_value = strdup(fields[DTF_VALUE]); if (recordp->dt_value == NULL) { free(recordp); if ((flags & FIND_PARTIAL) == 0) retval = DSVC_NO_MEMORY; break; } if (flags & FIND_POSITION) { ((dt_recpos_t *)recordp)->dtp_off = recoff; ((dt_recpos_t *)recordp)->dtp_size = ftello(fp) - recoff; } /* * Chuck the record on the list; up the counter. */ new_records = add_dtrec_to_list(recordp, records); if (new_records == NULL) { free_dtrec(recordp); if ((flags & FIND_PARTIAL) == 0) retval = DSVC_NO_MEMORY; break; } records = new_records; nrecords++; } free(buf); if (retval == DSVC_SUCCESS) { *nrecordsp = nrecords; if (recordsp != NULL) *recordsp = records; return (DSVC_SUCCESS); } if (records != NULL) free_dtrec_list(records); return (retval); }
/* * Internal version lookup routine used by both lookup_dn() and * update_dn(); same semantics as lookup_dn() except that the `partial' * argument has been generalized into a `flags' field. */ static int find_dn(int fd, uint_t flags, uint_t query, int count, const dn_rec_t *targetp, dn_rec_list_t **recordsp, uint_t *nrecordsp) { int retval = DSVC_SUCCESS; char *fields[DNF_FIELDS]; uint_t nrecords; dn_rec_t dn, *recordp; dn_rec_list_t *records, *new_records; unsigned int nfields; struct stat st; struct in_addr cip_nbo; char *ent0, *ent, *entend; char cip[INET_ADDRSTRLEN + 2]; /* * Page the whole container into memory via mmap() so we can scan it * quickly; map it MAP_PRIVATE so that we can change newlines to * NULs without changing the actual container itself. */ if (fstat(fd, &st) == -1 || st.st_size < 1) return (DSVC_INTERNAL); ent0 = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (ent0 == MAP_FAILED) return (DSVC_INTERNAL); /* * NUL-terminate the last byte (which should be a newline) so that * we can safely use string functions on the mapped container. */ ent0[st.st_size - 1] = '\0'; /* * If we're searching by client IP address, then build a target * string we can use to find it quickly. */ if (DSVC_QISEQ(query, DN_QCIP)) { cip[0] = '\n'; cip_nbo.s_addr = htonl(targetp->dn_cip.s_addr); (void) inet_ntop(AF_INET, &cip_nbo, cip + 1, INET_ADDRSTRLEN); (void) strlcat(cip, "|", sizeof (cip)); } records = NULL; ent = ent0; for (nrecords = 0; count < 0 || nrecords < count; ent = entend + 1) { /* * Bail if we've reached the end of the container. */ if (ent - ent0 >= st.st_size) break; /* * If we're searching by client IP address, locate it * quickly using strstr(3C); if we can't find it by this * technique then it's not in the container. */ if (DSVC_QISEQ(query, DN_QCIP)) { /* * If we've already found the DN_QCIP record, bail. */ if (nrecords > 0) break; ent = strstr(ent, cip); if (ent == NULL) break; ent++; } /* * Find the end of the record and change it a NUL byte so * that it is interpreted correctly with field_split() and * record_match() below. If we can't find a trailing * newline, then it must be the last record (whose newline * we already changed to a NUL above). */ entend = strchr(ent, '\n'); if (entend != NULL) *entend = '\0'; else entend = &ent0[st.st_size - 1]; /* * Skip pure comment lines; for now this just skips the * header information at the top of the container. */ if (ent[0] == DNF_COMMENT_CHAR) continue; /* * Split the buffer up into DNF_FIELDS fields. */ nfields = field_split(ent, DNF_FIELDS, fields, "|"); if (nfields < DNF_FIELDS) continue; /* * See if we've got a match, filling in dnf.dnf_rec as * we go. If record_match() succeeds, dnf.dnf_rec will * be completely filled in. */ if (!record_match(fields, &dn, targetp, query)) continue; /* * Caller just wants a count of the number of matching * records, not the records themselves; continue. */ if (recordsp == NULL) { nrecords++; continue; } /* * Allocate record; if FIND_POSITION flag is set, then * we need to allocate an extended (dn_recpos_t) record. */ if (flags & FIND_POSITION) recordp = malloc(sizeof (dn_recpos_t)); else recordp = malloc(sizeof (dn_rec_t)); if (recordp == NULL) { if ((flags & FIND_PARTIAL) == 0) retval = DSVC_NO_MEMORY; break; } /* * Fill in record; do a structure copy from our automatic * dn. If FIND_POSITION flag is on, pass back additional * position information. */ *recordp = dn; if (flags & FIND_POSITION) { ((dn_recpos_t *)recordp)->dnp_off = ent - ent0; ((dn_recpos_t *)recordp)->dnp_size = entend - ent + 1; } /* * Chuck the record on the list; up the counter. */ new_records = add_dnrec_to_list(recordp, records); if (new_records == NULL) { free(recordp); if ((flags & FIND_PARTIAL) == 0) retval = DSVC_NO_MEMORY; break; } records = new_records; nrecords++; } (void) munmap(ent0, st.st_size); if (retval == DSVC_SUCCESS) { *nrecordsp = nrecords; if (recordsp != NULL) *recordsp = records; return (DSVC_SUCCESS); } if (records != NULL) free_dnrec_list(records); return (retval); }