Exemple #1
0
/*
 * 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);
}
Exemple #2
0
/*
 * 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);
}