xref: /onnv-gate/usr/src/lib/libdhcpsvc/modules/files/dhcp_network.c (revision 871:f917b2ed7d21)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*871Scasper  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*871Scasper  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This file contains public functions for managing DHCP network
310Sstevel@tonic-gate  * containers.  For the semantics of these functions, please see the
320Sstevel@tonic-gate  * Enterprise DHCP Architecture Document.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/socket.h>
370Sstevel@tonic-gate #include <netinet/in.h>
380Sstevel@tonic-gate #include <stdlib.h>
390Sstevel@tonic-gate #include <arpa/inet.h>
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate #include <string.h>
420Sstevel@tonic-gate #include <errno.h>
430Sstevel@tonic-gate #include <unistd.h>
440Sstevel@tonic-gate #include <fcntl.h>
450Sstevel@tonic-gate #include <alloca.h>
460Sstevel@tonic-gate #include <dhcp_svc_public.h>
470Sstevel@tonic-gate #include <dirent.h>
480Sstevel@tonic-gate #include <libgen.h>
490Sstevel@tonic-gate #include <libinetutil.h>
500Sstevel@tonic-gate #include <sys/mman.h>
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include "dhcp_network.h"
530Sstevel@tonic-gate #include "util.h"
540Sstevel@tonic-gate 
550Sstevel@tonic-gate static void net2path(char *, size_t, const char *, ipaddr_t, const char *);
560Sstevel@tonic-gate static boolean_t record_match(char *[], dn_rec_t *, const dn_rec_t *, uint_t);
570Sstevel@tonic-gate static int write_rec(int, dn_rec_t *, off_t);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /* ARGSUSED */
600Sstevel@tonic-gate int
open_dn(void ** handlep,const char * location,uint_t flags,const struct in_addr * netp,const struct in_addr * maskp)610Sstevel@tonic-gate open_dn(void **handlep, const char *location, uint_t flags,
620Sstevel@tonic-gate     const struct in_addr *netp, const struct in_addr *maskp)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate 	char		connet[INET_ADDRSTRLEN];
650Sstevel@tonic-gate 	char		dnpath[MAXPATHLEN];
660Sstevel@tonic-gate 	unsigned int	conver;
670Sstevel@tonic-gate 	dn_handle_t	*dhp;
680Sstevel@tonic-gate 	FILE		*fp;
690Sstevel@tonic-gate 	int		retval;
700Sstevel@tonic-gate 	int		i, nelems;
710Sstevel@tonic-gate 	char		nl;
720Sstevel@tonic-gate 	struct in_addr	net_nbo;
730Sstevel@tonic-gate 	int		fd;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	dhp = malloc(sizeof (dn_handle_t));
760Sstevel@tonic-gate 	if (dhp == NULL)
770Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	dhp->dh_net = netp->s_addr;
800Sstevel@tonic-gate 	dhp->dh_oflags = flags;
810Sstevel@tonic-gate 	(void) strlcpy(dhp->dh_location, location, MAXPATHLEN);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	net2path(dnpath, MAXPATHLEN, location, netp->s_addr, "");
840Sstevel@tonic-gate 	retval = open_file(dnpath, flags, &fd);
850Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS) {
860Sstevel@tonic-gate 		free(dhp);
870Sstevel@tonic-gate 		return (retval);
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	fp = fdopen(fd, flags & DSVC_WRITE ? "r+" : "r");
910Sstevel@tonic-gate 	if (fp == NULL) {
920Sstevel@tonic-gate 		(void) close(fd);
930Sstevel@tonic-gate 		free(dhp);
940Sstevel@tonic-gate 		return (DSVC_INTERNAL);
950Sstevel@tonic-gate 	}
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	if (flags & DSVC_CREATE) {
980Sstevel@tonic-gate 		/*
990Sstevel@tonic-gate 		 * We just created the per-network container; put the
1000Sstevel@tonic-gate 		 * header on for future use...
1010Sstevel@tonic-gate 		 */
1020Sstevel@tonic-gate 		net_nbo.s_addr = htonl(netp->s_addr);
1030Sstevel@tonic-gate 		(void) inet_ntop(AF_INET, &net_nbo, connet, INET_ADDRSTRLEN);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 		for (i = 0; connet[i] != '\0'; i++)
1060Sstevel@tonic-gate 			if (connet[i] == '.')
1070Sstevel@tonic-gate 				connet[i] = '_';
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 		retval = fprintf(fp, "# SUNWfiles%u_%s\n", DSVC_CONVER, connet);
1100Sstevel@tonic-gate 		if (retval < 0 || fflush(fp) == EOF) {
1110Sstevel@tonic-gate 			(void) fclose(fp);
1120Sstevel@tonic-gate 			(void) free(dhp);
1130Sstevel@tonic-gate 			return (DSVC_INTERNAL);
1140Sstevel@tonic-gate 		}
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 		(void) fprintf(fp, "#\n# Do NOT edit this file by hand -- use");
1170Sstevel@tonic-gate 		(void) fprintf(fp, " pntadm(1M) or dhcpmgr(1M) instead\n#\n");
1180Sstevel@tonic-gate 	} else {
1190Sstevel@tonic-gate 		/*
1200Sstevel@tonic-gate 		 * Container already exists; sanity check against the
1210Sstevel@tonic-gate 		 * header that's on-disk.
1220Sstevel@tonic-gate 		 */
1230Sstevel@tonic-gate 		nelems = fscanf(fp, "#%*1[ ]SUNWfiles%u_%15s%c", &conver,
1240Sstevel@tonic-gate 		    connet, &nl);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 		for (i = 0; connet[i] != '\0'; i++)
1270Sstevel@tonic-gate 			if (connet[i] == '_')
1280Sstevel@tonic-gate 				connet[i] = '.';
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 		if (nelems != 3 || inet_addr(connet) != htonl(netp->s_addr) ||
1310Sstevel@tonic-gate 		    conver != DSVC_CONVER || nl != '\n') {
1320Sstevel@tonic-gate 			(void) fclose(fp);
1330Sstevel@tonic-gate 			(void) free(dhp);
1340Sstevel@tonic-gate 			return (DSVC_INTERNAL);
1350Sstevel@tonic-gate 		}
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	(void) fclose(fp);
1390Sstevel@tonic-gate 	*handlep = dhp;
1400Sstevel@tonic-gate 	return (DSVC_SUCCESS);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate int
close_dn(void ** handlep)1440Sstevel@tonic-gate close_dn(void **handlep)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	free(*handlep);
1470Sstevel@tonic-gate 	return (DSVC_SUCCESS);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate int
remove_dn(const char * dir,const struct in_addr * netp)1510Sstevel@tonic-gate remove_dn(const char *dir, const struct in_addr *netp)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	char dnpath[MAXPATHLEN];
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	net2path(dnpath, MAXPATHLEN, dir, netp->s_addr, "");
1560Sstevel@tonic-gate 	if (unlink(dnpath) == -1)
1570Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	return (DSVC_SUCCESS);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate  * Internal version lookup routine used by both lookup_dn() and
1640Sstevel@tonic-gate  * update_dn(); same semantics as lookup_dn() except that the `partial'
1650Sstevel@tonic-gate  * argument has been generalized into a `flags' field.
1660Sstevel@tonic-gate  */
1670Sstevel@tonic-gate 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)1680Sstevel@tonic-gate find_dn(int fd, uint_t flags, uint_t query, int count, const dn_rec_t *targetp,
1690Sstevel@tonic-gate     dn_rec_list_t **recordsp, uint_t *nrecordsp)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	int		retval = DSVC_SUCCESS;
1720Sstevel@tonic-gate 	char		*fields[DNF_FIELDS];
1730Sstevel@tonic-gate 	uint_t		nrecords;
1740Sstevel@tonic-gate 	dn_rec_t	dn, *recordp;
1750Sstevel@tonic-gate 	dn_rec_list_t	*records, *new_records;
1760Sstevel@tonic-gate 	unsigned int	nfields;
1770Sstevel@tonic-gate 	struct stat	st;
1780Sstevel@tonic-gate 	struct in_addr	cip_nbo;
1790Sstevel@tonic-gate 	char		*ent0, *ent, *entend;
1800Sstevel@tonic-gate 	char		cip[INET_ADDRSTRLEN + 2];
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/*
1830Sstevel@tonic-gate 	 * Page the whole container into memory via mmap() so we can scan it
1840Sstevel@tonic-gate 	 * quickly; map it MAP_PRIVATE so that we can change newlines to
1850Sstevel@tonic-gate 	 * NULs without changing the actual container itself.
1860Sstevel@tonic-gate 	 */
1870Sstevel@tonic-gate 	if (fstat(fd, &st) == -1 || st.st_size < 1)
1880Sstevel@tonic-gate 		return (DSVC_INTERNAL);
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	ent0 = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
1910Sstevel@tonic-gate 	if (ent0 == MAP_FAILED)
1920Sstevel@tonic-gate 		return (DSVC_INTERNAL);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/*
1950Sstevel@tonic-gate 	 * NUL-terminate the last byte (which should be a newline) so that
1960Sstevel@tonic-gate 	 * we can safely use string functions on the mapped container.
1970Sstevel@tonic-gate 	 */
1980Sstevel@tonic-gate 	ent0[st.st_size - 1] = '\0';
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/*
2010Sstevel@tonic-gate 	 * If we're searching by client IP address, then build a target
2020Sstevel@tonic-gate 	 * string we can use to find it quickly.
2030Sstevel@tonic-gate 	 */
2040Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DN_QCIP)) {
2050Sstevel@tonic-gate 		cip[0] = '\n';
2060Sstevel@tonic-gate 		cip_nbo.s_addr = htonl(targetp->dn_cip.s_addr);
2070Sstevel@tonic-gate 		(void) inet_ntop(AF_INET, &cip_nbo, cip + 1, INET_ADDRSTRLEN);
2080Sstevel@tonic-gate 		(void) strlcat(cip, "|", sizeof (cip));
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	records = NULL;
2120Sstevel@tonic-gate 	ent = ent0;
2130Sstevel@tonic-gate 	for (nrecords = 0; count < 0 || nrecords < count; ent = entend + 1) {
2140Sstevel@tonic-gate 		/*
2150Sstevel@tonic-gate 		 * Bail if we've reached the end of the container.
2160Sstevel@tonic-gate 		 */
2170Sstevel@tonic-gate 		if (ent - ent0 >= st.st_size)
2180Sstevel@tonic-gate 			break;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 		/*
2210Sstevel@tonic-gate 		 * If we're searching by client IP address, locate it
2220Sstevel@tonic-gate 		 * quickly using strstr(3C); if we can't find it by this
2230Sstevel@tonic-gate 		 * technique then it's not in the container.
2240Sstevel@tonic-gate 		 */
2250Sstevel@tonic-gate 		if (DSVC_QISEQ(query, DN_QCIP)) {
2260Sstevel@tonic-gate 			/*
2270Sstevel@tonic-gate 			 * If we've already found the DN_QCIP record, bail.
2280Sstevel@tonic-gate 			 */
2290Sstevel@tonic-gate 			if (nrecords > 0)
2300Sstevel@tonic-gate 				break;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 			ent = strstr(ent, cip);
2330Sstevel@tonic-gate 			if (ent == NULL)
2340Sstevel@tonic-gate 				break;
2350Sstevel@tonic-gate 			ent++;
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		/*
2390Sstevel@tonic-gate 		 * Find the end of the record and change it a NUL byte so
2400Sstevel@tonic-gate 		 * that it is interpreted correctly with field_split() and
2410Sstevel@tonic-gate 		 * record_match() below.  If we can't find a trailing
2420Sstevel@tonic-gate 		 * newline, then it must be the last record (whose newline
2430Sstevel@tonic-gate 		 * we already changed to a NUL above).
2440Sstevel@tonic-gate 		 */
2450Sstevel@tonic-gate 		entend = strchr(ent, '\n');
2460Sstevel@tonic-gate 		if (entend != NULL)
2470Sstevel@tonic-gate 			*entend = '\0';
2480Sstevel@tonic-gate 		else
2490Sstevel@tonic-gate 			entend = &ent0[st.st_size - 1];
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		/*
2520Sstevel@tonic-gate 		 * Skip pure comment lines; for now this just skips the
2530Sstevel@tonic-gate 		 * header information at the top of the container.
2540Sstevel@tonic-gate 		 */
2550Sstevel@tonic-gate 		if (ent[0] == DNF_COMMENT_CHAR)
2560Sstevel@tonic-gate 			continue;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 		/*
2590Sstevel@tonic-gate 		 * Split the buffer up into DNF_FIELDS fields.
2600Sstevel@tonic-gate 		 */
2610Sstevel@tonic-gate 		nfields = field_split(ent, DNF_FIELDS, fields, "|");
2620Sstevel@tonic-gate 		if (nfields < DNF_FIELDS)
2630Sstevel@tonic-gate 			continue;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		/*
2660Sstevel@tonic-gate 		 * See if we've got a match, filling in dnf.dnf_rec as
2670Sstevel@tonic-gate 		 * we go.  If record_match() succeeds, dnf.dnf_rec will
2680Sstevel@tonic-gate 		 * be completely filled in.
2690Sstevel@tonic-gate 		 */
2700Sstevel@tonic-gate 		if (!record_match(fields, &dn, targetp, query))
2710Sstevel@tonic-gate 			continue;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 		/*
2740Sstevel@tonic-gate 		 * Caller just wants a count of the number of matching
2750Sstevel@tonic-gate 		 * records, not the records themselves; continue.
2760Sstevel@tonic-gate 		 */
2770Sstevel@tonic-gate 		if (recordsp == NULL) {
2780Sstevel@tonic-gate 			nrecords++;
2790Sstevel@tonic-gate 			continue;
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 		/*
2830Sstevel@tonic-gate 		 * Allocate record; if FIND_POSITION flag is set, then
2840Sstevel@tonic-gate 		 * we need to allocate an extended (dn_recpos_t) record.
2850Sstevel@tonic-gate 		 */
2860Sstevel@tonic-gate 		if (flags & FIND_POSITION)
2870Sstevel@tonic-gate 			recordp = malloc(sizeof (dn_recpos_t));
2880Sstevel@tonic-gate 		else
2890Sstevel@tonic-gate 			recordp = malloc(sizeof (dn_rec_t));
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		if (recordp == NULL) {
2920Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
2930Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
2940Sstevel@tonic-gate 			break;
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 		/*
2980Sstevel@tonic-gate 		 * Fill in record; do a structure copy from our automatic
2990Sstevel@tonic-gate 		 * dn.  If FIND_POSITION flag is on, pass back additional
3000Sstevel@tonic-gate 		 * position information.
3010Sstevel@tonic-gate 		 */
3020Sstevel@tonic-gate 		*recordp = dn;
3030Sstevel@tonic-gate 		if (flags & FIND_POSITION) {
3040Sstevel@tonic-gate 			((dn_recpos_t *)recordp)->dnp_off = ent - ent0;
3050Sstevel@tonic-gate 			((dn_recpos_t *)recordp)->dnp_size = entend - ent + 1;
3060Sstevel@tonic-gate 		}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		/*
3090Sstevel@tonic-gate 		 * Chuck the record on the list; up the counter.
3100Sstevel@tonic-gate 		 */
3110Sstevel@tonic-gate 		new_records = add_dnrec_to_list(recordp, records);
3120Sstevel@tonic-gate 		if (new_records == NULL) {
3130Sstevel@tonic-gate 			free(recordp);
3140Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
3150Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
3160Sstevel@tonic-gate 			break;
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		records = new_records;
3200Sstevel@tonic-gate 		nrecords++;
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	(void) munmap(ent0, st.st_size);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	if (retval == DSVC_SUCCESS) {
3260Sstevel@tonic-gate 		*nrecordsp = nrecords;
3270Sstevel@tonic-gate 		if (recordsp != NULL)
3280Sstevel@tonic-gate 			*recordsp = records;
3290Sstevel@tonic-gate 		return (DSVC_SUCCESS);
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	if (records != NULL)
3330Sstevel@tonic-gate 		free_dnrec_list(records);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	return (retval);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate int
lookup_dn(void * handle,boolean_t partial,uint_t query,int count,const dn_rec_t * targetp,dn_rec_list_t ** recordsp,uint_t * nrecordsp)3390Sstevel@tonic-gate lookup_dn(void *handle, boolean_t partial, uint_t query, int count,
3400Sstevel@tonic-gate     const dn_rec_t *targetp, dn_rec_list_t **recordsp, uint_t *nrecordsp)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate 	int		retval;
3430Sstevel@tonic-gate 	char		dnpath[MAXPATHLEN];
3440Sstevel@tonic-gate 	int		fd;
3450Sstevel@tonic-gate 	dn_handle_t	*dhp = (dn_handle_t *)handle;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_READ) == 0)
3480Sstevel@tonic-gate 		return (DSVC_ACCESS);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	net2path(dnpath, MAXPATHLEN, dhp->dh_location, dhp->dh_net, "");
3510Sstevel@tonic-gate 	fd = open(dnpath, O_RDONLY);
3520Sstevel@tonic-gate 	if (fd == -1)
3530Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	retval = find_dn(fd, partial ? FIND_PARTIAL : 0, query, count, targetp,
3560Sstevel@tonic-gate 	    recordsp, nrecordsp);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	(void) close(fd);
3590Sstevel@tonic-gate 	return (retval);
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate  * Compares the fields in fields[] agains the fields in target `targetp',
3640Sstevel@tonic-gate  * using `query' to decide what fields to compare.  Returns B_TRUE if `dnp'
3650Sstevel@tonic-gate  * matches `targetp', B_FALSE if not.  On success, `dnp' is completely
3660Sstevel@tonic-gate  * filled in.
3670Sstevel@tonic-gate  */
3680Sstevel@tonic-gate static boolean_t
record_match(char * fields[],dn_rec_t * dnp,const dn_rec_t * targetp,uint_t query)3690Sstevel@tonic-gate record_match(char *fields[], dn_rec_t *dnp, const dn_rec_t *targetp,
3700Sstevel@tonic-gate     uint_t query)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	unsigned int	qflags[] = { DN_QFDYNAMIC, DN_QFAUTOMATIC, DN_QFMANUAL,
3730Sstevel@tonic-gate 				    DN_QFUNUSABLE, DN_QFBOOTP_ONLY };
3740Sstevel@tonic-gate 	unsigned int	flags[]  = { DN_FDYNAMIC, DN_FAUTOMATIC, DN_FMANUAL,
3750Sstevel@tonic-gate 				    DN_FUNUSABLE, DN_FBOOTP_ONLY };
3760Sstevel@tonic-gate 	unsigned int	i;
3770Sstevel@tonic-gate 	uint_t		dn_cid_len;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	dnp->dn_cip.s_addr = ntohl(inet_addr(fields[DNF_CIP]));
3800Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DN_QCIP) &&
3810Sstevel@tonic-gate 	    dnp->dn_cip.s_addr != targetp->dn_cip.s_addr)
3820Sstevel@tonic-gate 		return (B_FALSE);
3830Sstevel@tonic-gate 	if (DSVC_QISNEQ(query, DN_QCIP) &&
3840Sstevel@tonic-gate 	    dnp->dn_cip.s_addr == targetp->dn_cip.s_addr)
3850Sstevel@tonic-gate 		return (B_FALSE);
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	dnp->dn_lease = atoi(fields[DNF_LEASE]);
3880Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DN_QLEASE) && targetp->dn_lease != dnp->dn_lease)
3890Sstevel@tonic-gate 		return (B_FALSE);
3900Sstevel@tonic-gate 	if (DSVC_QISNEQ(query, DN_QLEASE) && targetp->dn_lease == dnp->dn_lease)
3910Sstevel@tonic-gate 		return (B_FALSE);
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	/*
3940Sstevel@tonic-gate 	 * We use dn_cid_len since dnp->dn_cid_len is of type uchar_t but
3950Sstevel@tonic-gate 	 * hexascii_to_octet() expects an uint_t *
3960Sstevel@tonic-gate 	 */
3970Sstevel@tonic-gate 	dn_cid_len = DN_MAX_CID_LEN;
3980Sstevel@tonic-gate 	if (hexascii_to_octet(fields[DNF_CID], strlen(fields[DNF_CID]),
3990Sstevel@tonic-gate 	    dnp->dn_cid, &dn_cid_len) != 0)
4000Sstevel@tonic-gate 		return (B_FALSE);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	dnp->dn_cid_len = dn_cid_len;
4030Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DN_QCID) &&
4040Sstevel@tonic-gate 	    (dnp->dn_cid_len != targetp->dn_cid_len ||
4050Sstevel@tonic-gate 	    (memcmp(dnp->dn_cid, targetp->dn_cid, dnp->dn_cid_len) != 0)))
4060Sstevel@tonic-gate 		return (B_FALSE);
4070Sstevel@tonic-gate 	if (DSVC_QISNEQ(query, DN_QCID) &&
4080Sstevel@tonic-gate 	    (dnp->dn_cid_len == targetp->dn_cid_len &&
4090Sstevel@tonic-gate 	    (memcmp(dnp->dn_cid, targetp->dn_cid, dnp->dn_cid_len) == 0)))
4100Sstevel@tonic-gate 		return (B_FALSE);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	dnp->dn_sip.s_addr = ntohl(inet_addr(fields[DNF_SIP]));
4130Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DN_QSIP) &&
4140Sstevel@tonic-gate 	    dnp->dn_sip.s_addr != targetp->dn_sip.s_addr)
4150Sstevel@tonic-gate 		return (B_FALSE);
4160Sstevel@tonic-gate 	if (DSVC_QISNEQ(query, DN_QSIP) &&
4170Sstevel@tonic-gate 	    dnp->dn_sip.s_addr == targetp->dn_sip.s_addr)
4180Sstevel@tonic-gate 		return (B_FALSE);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	unescape('|', fields[DNF_MACRO], dnp->dn_macro, sizeof (dnp->dn_macro));
4210Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DN_QMACRO) &&
4220Sstevel@tonic-gate 	    strcmp(targetp->dn_macro, dnp->dn_macro) != 0)
4230Sstevel@tonic-gate 		return (B_FALSE);
4240Sstevel@tonic-gate 	if (DSVC_QISNEQ(query, DN_QMACRO) &&
4250Sstevel@tonic-gate 	    strcmp(targetp->dn_macro, dnp->dn_macro) == 0)
4260Sstevel@tonic-gate 		return (B_FALSE);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	dnp->dn_flags = atoi(fields[DNF_FLAGS]);
4290Sstevel@tonic-gate 	for (i = 0; i < sizeof (qflags) / sizeof (unsigned int); i++) {
4300Sstevel@tonic-gate 		if (DSVC_QISEQ(query, qflags[i]) &&
4310Sstevel@tonic-gate 		    (dnp->dn_flags & flags[i]) !=
4320Sstevel@tonic-gate 		    (targetp->dn_flags & flags[i]))
4330Sstevel@tonic-gate 			return (B_FALSE);
4340Sstevel@tonic-gate 		if (DSVC_QISNEQ(query, qflags[i]) &&
4350Sstevel@tonic-gate 		    (dnp->dn_flags & flags[i]) ==
4360Sstevel@tonic-gate 		    (targetp->dn_flags & flags[i]))
4370Sstevel@tonic-gate 			return (B_FALSE);
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	dnp->dn_sig = atoll(fields[DNF_SIG]);
4410Sstevel@tonic-gate 	unescape('|', fields[DNF_COMMENT], dnp->dn_comment,
4420Sstevel@tonic-gate 	    sizeof (dnp->dn_comment));
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	return (B_TRUE);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate  * Internal dhcp_network record update routine, used to factor out the
4490Sstevel@tonic-gate  * common code between add_dn(), delete_dn(), and modify_dn().  If
4500Sstevel@tonic-gate  * `origp' is NULL, then act like add_dn(); if `newp' is NULL, then
4510Sstevel@tonic-gate  * act like delete_dn(); otherwise act like modify_dn().
4520Sstevel@tonic-gate  */
4530Sstevel@tonic-gate static int
update_dn(const dn_handle_t * dhp,const dn_rec_t * origp,dn_rec_t * newp)4540Sstevel@tonic-gate update_dn(const dn_handle_t *dhp, const dn_rec_t *origp, dn_rec_t *newp)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	char		dnpath[MAXPATHLEN], newpath[MAXPATHLEN];
4570Sstevel@tonic-gate 	int		retval = DSVC_SUCCESS;
4580Sstevel@tonic-gate 	off_t		recoff, recnext;
4590Sstevel@tonic-gate 	dn_rec_list_t	*reclist;
4600Sstevel@tonic-gate 	int		fd, newfd;
4610Sstevel@tonic-gate 	uint_t		found;
4620Sstevel@tonic-gate 	int		query;
4630Sstevel@tonic-gate 	struct stat	st;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_WRITE) == 0)
4670Sstevel@tonic-gate 		return (DSVC_ACCESS);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/*
4700Sstevel@tonic-gate 	 * Open the container to update and a new container file which we
4710Sstevel@tonic-gate 	 * will store the updated version of the container in.  When the
4720Sstevel@tonic-gate 	 * update is done, rename the new file to be the real container.
4730Sstevel@tonic-gate 	 */
4740Sstevel@tonic-gate 	net2path(dnpath, MAXPATHLEN, dhp->dh_location, dhp->dh_net, "");
4750Sstevel@tonic-gate 	fd = open(dnpath, O_RDONLY);
4760Sstevel@tonic-gate 	if (fd == -1)
4770Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	net2path(newpath, MAXPATHLEN, dhp->dh_location, dhp->dh_net, ".new");
4800Sstevel@tonic-gate 	newfd = open(newpath, O_CREAT|O_TRUNC|O_WRONLY, 0644);
4810Sstevel@tonic-gate 	if (newfd == -1) {
4820Sstevel@tonic-gate 		(void) close(fd);
4830Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	DSVC_QINIT(query);
4870Sstevel@tonic-gate 	DSVC_QEQ(query, DN_QCIP);
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	/*
4900Sstevel@tonic-gate 	 * If we're changing the key for this record, make sure the key
4910Sstevel@tonic-gate 	 * we're changing to doesn't already exist.
4920Sstevel@tonic-gate 	 */
4930Sstevel@tonic-gate 	if (origp != NULL && newp != NULL) {
4940Sstevel@tonic-gate 		if (origp->dn_cip.s_addr != newp->dn_cip.s_addr) {
4950Sstevel@tonic-gate 			retval = find_dn(fd, 0, query, 1, newp, NULL, &found);
4960Sstevel@tonic-gate 			if (retval != DSVC_SUCCESS)
4970Sstevel@tonic-gate 				goto out;
4980Sstevel@tonic-gate 			if (found != 0) {
4990Sstevel@tonic-gate 				retval = DSVC_EXISTS;
5000Sstevel@tonic-gate 				goto out;
5010Sstevel@tonic-gate 			}
5020Sstevel@tonic-gate 		}
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/*
5060Sstevel@tonic-gate 	 * If we're adding a new record, make sure the record doesn't
5070Sstevel@tonic-gate 	 * already exist.
5080Sstevel@tonic-gate 	 */
5090Sstevel@tonic-gate 	if (newp != NULL && origp == NULL) {
5100Sstevel@tonic-gate 		retval = find_dn(fd, 0, query, 1, newp, NULL, &found);
5110Sstevel@tonic-gate 		if (retval != DSVC_SUCCESS)
5120Sstevel@tonic-gate 			goto out;
5130Sstevel@tonic-gate 		if (found != 0) {
5140Sstevel@tonic-gate 			retval = DSVC_EXISTS;
5150Sstevel@tonic-gate 			goto out;
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	/*
5200Sstevel@tonic-gate 	 * If we're deleting or modifying record, make sure the record
5210Sstevel@tonic-gate 	 * still exists and that our copy isn't stale.  Note that we don't
5220Sstevel@tonic-gate 	 * check signatures if we're deleting the record and origp->dn_sig
5230Sstevel@tonic-gate 	 * is zero, so that records that weren't looked up can be deleted.
5240Sstevel@tonic-gate 	 */
5250Sstevel@tonic-gate 	if (origp != NULL) {
5260Sstevel@tonic-gate 		retval = find_dn(fd, FIND_POSITION, query, 1, origp, &reclist,
5270Sstevel@tonic-gate 		    &found);
5280Sstevel@tonic-gate 		if (retval != DSVC_SUCCESS)
5290Sstevel@tonic-gate 			goto out;
5300Sstevel@tonic-gate 		if (found == 0) {
5310Sstevel@tonic-gate 			retval = DSVC_NOENT;
5320Sstevel@tonic-gate 			goto out;
5330Sstevel@tonic-gate 		}
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 		if (reclist->dnl_rec->dn_sig != origp->dn_sig) {
5360Sstevel@tonic-gate 			if (newp != NULL || origp->dn_sig != 0) {
5370Sstevel@tonic-gate 				free_dnrec_list(reclist);
5380Sstevel@tonic-gate 				retval = DSVC_COLLISION;
5390Sstevel@tonic-gate 				goto out;
5400Sstevel@tonic-gate 			}
5410Sstevel@tonic-gate 		}
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 		/*
5440Sstevel@tonic-gate 		 * Note the offset of the record we're modifying or deleting
5450Sstevel@tonic-gate 		 * for use down below.
5460Sstevel@tonic-gate 		 */
5470Sstevel@tonic-gate 		recoff  = ((dn_recpos_t *)reclist->dnl_rec)->dnp_off;
5480Sstevel@tonic-gate 		recnext = recoff + ((dn_recpos_t *)reclist->dnl_rec)->dnp_size;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 		free_dnrec_list(reclist);
5510Sstevel@tonic-gate 	} else {
5520Sstevel@tonic-gate 		/*
5530Sstevel@tonic-gate 		 * No record to modify or delete, so set `recoff' and
5540Sstevel@tonic-gate 		 * `recnext' appropriately.
5550Sstevel@tonic-gate 		 */
5560Sstevel@tonic-gate 		recoff = 0;
5570Sstevel@tonic-gate 		recnext = 0;
5580Sstevel@tonic-gate 	}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	/*
5610Sstevel@tonic-gate 	 * Make a new copy of the container.  If we're deleting or
5620Sstevel@tonic-gate 	 * modifying a record, don't copy that record to the new container.
5630Sstevel@tonic-gate 	 */
5640Sstevel@tonic-gate 	if (fstat(fd, &st) == -1) {
5650Sstevel@tonic-gate 		retval = DSVC_INTERNAL;
5660Sstevel@tonic-gate 		goto out;
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	retval = copy_range(fd, 0, newfd, 0, recoff);
5700Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
5710Sstevel@tonic-gate 		goto out;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	retval = copy_range(fd, recnext, newfd, recoff, st.st_size - recnext);
5740Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
5750Sstevel@tonic-gate 		goto out;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * If there's a new/modified record, append it to the new container.
5790Sstevel@tonic-gate 	 */
5800Sstevel@tonic-gate 	if (newp != NULL) {
5810Sstevel@tonic-gate 		if (origp == NULL)
5820Sstevel@tonic-gate 			newp->dn_sig = gensig();
5830Sstevel@tonic-gate 		else
5840Sstevel@tonic-gate 			newp->dn_sig = origp->dn_sig + 1;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 		retval = write_rec(newfd, newp, recoff + st.st_size - recnext);
5870Sstevel@tonic-gate 		if (retval != DSVC_SUCCESS)
5880Sstevel@tonic-gate 			goto out;
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/*
5920Sstevel@tonic-gate 	 * Note: we close these descriptors before the rename(2) (rather
5930Sstevel@tonic-gate 	 * than just having the `out:' label clean them up) to save NFS
5940Sstevel@tonic-gate 	 * some work (otherwise, NFS has to save `dnpath' to an alternate
5950Sstevel@tonic-gate 	 * name since its vnode would still be active).
5960Sstevel@tonic-gate 	 */
5970Sstevel@tonic-gate 	(void) close(fd);
5980Sstevel@tonic-gate 	(void) close(newfd);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (rename(newpath, dnpath) == -1)
6010Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	return (retval);
6040Sstevel@tonic-gate out:
6050Sstevel@tonic-gate 	(void) close(fd);
6060Sstevel@tonic-gate 	(void) close(newfd);
6070Sstevel@tonic-gate 	(void) unlink(newpath);
6080Sstevel@tonic-gate 	return (retval);
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate int
add_dn(void * handle,dn_rec_t * addp)6120Sstevel@tonic-gate add_dn(void *handle, dn_rec_t *addp)
6130Sstevel@tonic-gate {
6140Sstevel@tonic-gate 	return (update_dn((dn_handle_t *)handle, NULL, addp));
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate int
modify_dn(void * handle,const dn_rec_t * origp,dn_rec_t * newp)6180Sstevel@tonic-gate modify_dn(void *handle, const dn_rec_t *origp, dn_rec_t *newp)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 	return (update_dn((dn_handle_t *)handle, origp, newp));
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate int
delete_dn(void * handle,const dn_rec_t * delp)6240Sstevel@tonic-gate delete_dn(void *handle, const dn_rec_t *delp)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	return (update_dn((dn_handle_t *)handle, delp, NULL));
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate int
list_dn(const char * location,char *** listppp,uint_t * countp)6300Sstevel@tonic-gate list_dn(const char *location, char ***listppp, uint_t *countp)
6310Sstevel@tonic-gate {
6320Sstevel@tonic-gate 	char		ipaddr[INET_ADDRSTRLEN];
633*871Scasper 	struct dirent	*result;
6340Sstevel@tonic-gate 	DIR		*dirp;
6350Sstevel@tonic-gate 	unsigned int	i, count = 0;
6360Sstevel@tonic-gate 	char		*re, **new_listpp, **listpp = NULL;
6370Sstevel@tonic-gate 	char		conver[4];
6380Sstevel@tonic-gate 	int		error;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	dirp = opendir(location);
6410Sstevel@tonic-gate 	if (dirp == NULL) {
6420Sstevel@tonic-gate 		switch (errno) {
6430Sstevel@tonic-gate 		case EACCES:
6440Sstevel@tonic-gate 		case EPERM:
6450Sstevel@tonic-gate 			return (DSVC_ACCESS);
6460Sstevel@tonic-gate 		case ENOENT:
6470Sstevel@tonic-gate 			return (DSVC_NO_LOCATION);
6480Sstevel@tonic-gate 		default:
6490Sstevel@tonic-gate 			break;
6500Sstevel@tonic-gate 		}
6510Sstevel@tonic-gate 		return (DSVC_INTERNAL);
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/*
6550Sstevel@tonic-gate 	 * Compile a regular expression matching "SUNWfilesX_" (where X is
6560Sstevel@tonic-gate 	 * a container version number) followed by an IP address (roughly
6570Sstevel@tonic-gate 	 * speaking).  Note that the $N constructions allow us to get the
6580Sstevel@tonic-gate 	 * container version and IP address when calling regex(3C).
6590Sstevel@tonic-gate 	 */
6600Sstevel@tonic-gate 	re = regcmp("^SUNWfiles([0-9]{1,3})$0_"
6610Sstevel@tonic-gate 	    "(([0-9]{1,3}_){3}[0-9]{1,3})$1$", (char *)0);
6620Sstevel@tonic-gate 	if (re == NULL)
6630Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
6640Sstevel@tonic-gate 
665*871Scasper 	while ((result = readdir(dirp)) != NULL) {
6660Sstevel@tonic-gate 		if (regex(re, result->d_name, conver, ipaddr) != NULL) {
6670Sstevel@tonic-gate 			if (atoi(conver) != DSVC_CONVER)
6680Sstevel@tonic-gate 				continue;
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 			for (i = 0; ipaddr[i] != '\0'; i++)
6710Sstevel@tonic-gate 				if (ipaddr[i] == '_')
6720Sstevel@tonic-gate 					ipaddr[i] = '.';
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 			new_listpp = realloc(listpp,
6750Sstevel@tonic-gate 			    (sizeof (char **)) * (count + 1));
6760Sstevel@tonic-gate 			if (new_listpp == NULL) {
6770Sstevel@tonic-gate 				error = DSVC_NO_MEMORY;
6780Sstevel@tonic-gate 				goto fail;
6790Sstevel@tonic-gate 			}
6800Sstevel@tonic-gate 			listpp = new_listpp;
6810Sstevel@tonic-gate 			listpp[count] = strdup(ipaddr);
6820Sstevel@tonic-gate 			if (listpp[count] == NULL) {
6830Sstevel@tonic-gate 				error = DSVC_NO_MEMORY;
6840Sstevel@tonic-gate 				goto fail;
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 			count++;
6870Sstevel@tonic-gate 		}
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 	free(re);
6900Sstevel@tonic-gate 	(void) closedir(dirp);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	*countp = count;
6930Sstevel@tonic-gate 	*listppp = listpp;
6940Sstevel@tonic-gate 	return (DSVC_SUCCESS);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate fail:
6970Sstevel@tonic-gate 	free(re);
6980Sstevel@tonic-gate 	(void) closedir(dirp);
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	for (i = 0; i < count; i++)
7010Sstevel@tonic-gate 		free(listpp[i]);
7020Sstevel@tonic-gate 	free(listpp);
7030Sstevel@tonic-gate 	return (error);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate /*
7070Sstevel@tonic-gate  * Given a buffer `path' of `pathlen' bytes, fill it in with a path to the
7080Sstevel@tonic-gate  * DHCP Network table for IP network `ip' located in directory `dir' with a
7090Sstevel@tonic-gate  * suffix of `suffix'.
7100Sstevel@tonic-gate  */
7110Sstevel@tonic-gate static void
net2path(char * path,size_t pathlen,const char * dir,ipaddr_t ip,const char * suffix)7120Sstevel@tonic-gate net2path(char *path, size_t pathlen, const char *dir, ipaddr_t ip,
7130Sstevel@tonic-gate     const char *suffix)
7140Sstevel@tonic-gate {
7150Sstevel@tonic-gate 	(void) snprintf(path, pathlen, "%s/SUNWfiles%u_%d_%d_%d_%d%s", dir,
7160Sstevel@tonic-gate 	    DSVC_CONVER, ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff,
7170Sstevel@tonic-gate 	    ip & 0xff, suffix);
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate  * Write the dn_rec_t `recp' into the open container `fd' at offset
7220Sstevel@tonic-gate  * `recoff'.  Returns DSVC_* error code.
7230Sstevel@tonic-gate  */
7240Sstevel@tonic-gate static int
write_rec(int fd,dn_rec_t * recp,off_t recoff)7250Sstevel@tonic-gate write_rec(int fd, dn_rec_t *recp, off_t recoff)
7260Sstevel@tonic-gate {
7270Sstevel@tonic-gate 	char		entbuf[1024], *ent = entbuf;
7280Sstevel@tonic-gate 	size_t		entsize = sizeof (entbuf);
7290Sstevel@tonic-gate 	int		entlen;
7300Sstevel@tonic-gate 	dn_filerec_t	dnf;
7310Sstevel@tonic-gate 	struct in_addr	nip;
7320Sstevel@tonic-gate 	unsigned int	cid_len = sizeof (dnf.dnf_cid);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	/*
7350Sstevel@tonic-gate 	 * Copy data into a dn_filerec_t, since that's what we can
7360Sstevel@tonic-gate 	 * actually put on disk.
7370Sstevel@tonic-gate 	 */
7380Sstevel@tonic-gate 	if (octet_to_hexascii(recp->dn_cid, recp->dn_cid_len, dnf.dnf_cid,
7390Sstevel@tonic-gate 	    &cid_len) != 0)
7400Sstevel@tonic-gate 		return (DSVC_INTERNAL);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	nip.s_addr = htonl(recp->dn_cip.s_addr);
7430Sstevel@tonic-gate 	(void) inet_ntop(AF_INET, &nip, dnf.dnf_cip, sizeof (dnf.dnf_cip));
7440Sstevel@tonic-gate 	nip.s_addr = htonl(recp->dn_sip.s_addr);
7450Sstevel@tonic-gate 	(void) inet_ntop(AF_INET, &nip, dnf.dnf_sip, sizeof (dnf.dnf_cip));
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	dnf.dnf_sig	= recp->dn_sig;
7480Sstevel@tonic-gate 	dnf.dnf_flags	= recp->dn_flags;
7490Sstevel@tonic-gate 	dnf.dnf_lease	= recp->dn_lease;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	escape('|', recp->dn_macro, dnf.dnf_macro, sizeof (dnf.dnf_macro));
7520Sstevel@tonic-gate 	escape('|', recp->dn_comment, dnf.dnf_comment,
7530Sstevel@tonic-gate 	    sizeof (dnf.dnf_comment));
7540Sstevel@tonic-gate again:
7550Sstevel@tonic-gate 	entlen = snprintf(ent, entsize, "%s|%s|%02hu|%s|%u|%llu|%s|%s\n",
7560Sstevel@tonic-gate 	    dnf.dnf_cip, dnf.dnf_cid, dnf.dnf_flags, dnf.dnf_sip,
7570Sstevel@tonic-gate 	    dnf.dnf_lease, dnf.dnf_sig, dnf.dnf_macro, dnf.dnf_comment);
7580Sstevel@tonic-gate 	if (entlen == -1)
7590Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	if (entlen > entsize) {
7620Sstevel@tonic-gate 		entsize = entlen;
7630Sstevel@tonic-gate 		ent = alloca(entlen);
7640Sstevel@tonic-gate 		goto again;
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	if (pnwrite(fd, ent, entlen, recoff) == -1)
7680Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	return (DSVC_SUCCESS);
7710Sstevel@tonic-gate }
772