xref: /onnv-gate/usr/src/lib/libdhcpsvc/modules/binfiles/dhcptab.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 2000 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * This file contains public functions for managing the dhcptab container.
31*0Sstevel@tonic-gate  * For the semantics of these functions, please see the Enterprise DHCP
32*0Sstevel@tonic-gate  * Architecture Document.
33*0Sstevel@tonic-gate  *
34*0Sstevel@tonic-gate  * This module uses synchronization guarantees provided by dsvclockd(1M);
35*0Sstevel@tonic-gate  * please see $SRC/lib/libdhcpsvc/private/README.synch for details.
36*0Sstevel@tonic-gate  *
37*0Sstevel@tonic-gate  * Big Theory Statement for the SUNWbinfiles DHCP Table Module
38*0Sstevel@tonic-gate  * ===========================================================
39*0Sstevel@tonic-gate  *
40*0Sstevel@tonic-gate  * Since the dhcptab container does not have any performance-critical
41*0Sstevel@tonic-gate  * consumers, this module focuses on being simple and robust rather than
42*0Sstevel@tonic-gate  * fast.  The on-disk structure consists of a minimal header followed by a
43*0Sstevel@tonic-gate  * list of dt_filerec_t's in no particular order.  Note that the dt_rec_t's
44*0Sstevel@tonic-gate  * dt_value can be arbitrarily large, which means each dt_filerec_t is also
45*0Sstevel@tonic-gate  * of arbitrary size; we deal with this by storing the on-disk size of each
46*0Sstevel@tonic-gate  * record in the record itself.
47*0Sstevel@tonic-gate  *
48*0Sstevel@tonic-gate  * To meet our robustness requirements (see the Big Theory Statement in
49*0Sstevel@tonic-gate  * dhcp_network.c), each update operation does its work on a copy of the
50*0Sstevel@tonic-gate  * dhcptab, which is then atomically renamed to the name of the actual
51*0Sstevel@tonic-gate  * dhcptab upon completion (yes, this is *very slow*).  To speed this up a
52*0Sstevel@tonic-gate  * little, we use mmap(2) to generate the copy, which is about twice as
53*0Sstevel@tonic-gate  * fast as using read(2)/write(2).
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #include <unistd.h>
57*0Sstevel@tonic-gate #include <sys/types.h>
58*0Sstevel@tonic-gate #include <sys/socket.h>
59*0Sstevel@tonic-gate #include <netinet/in.h>
60*0Sstevel@tonic-gate #include <dhcp_svc_public.h>
61*0Sstevel@tonic-gate #include <sys/stat.h>
62*0Sstevel@tonic-gate #include <sys/isa_defs.h>
63*0Sstevel@tonic-gate #include <fcntl.h>
64*0Sstevel@tonic-gate #include <stdlib.h>
65*0Sstevel@tonic-gate #include <stddef.h>
66*0Sstevel@tonic-gate #include <string.h>
67*0Sstevel@tonic-gate #include <errno.h>
68*0Sstevel@tonic-gate #include <stdio.h>
69*0Sstevel@tonic-gate #include <alloca.h>
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate #include "dhcptab.h"
72*0Sstevel@tonic-gate #include "util.h"
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * We compute the RECSIZE using the offset of `rec_dtval' rather than the
76*0Sstevel@tonic-gate  * sizeof (dt_filerec_t) so that we don't include any trailing structure
77*0Sstevel@tonic-gate  * padding in the size calculation.
78*0Sstevel@tonic-gate  */
79*0Sstevel@tonic-gate #define	RECSIZE(rec) (offsetof(dt_filerec_t, rec_dtval) + ((rec).rec_dtvalsize))
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static int	read_header(int, dt_header_t *);
82*0Sstevel@tonic-gate static int	write_header(int, dt_header_t *);
83*0Sstevel@tonic-gate static int	read_rec(int, dt_filerec_t *, off_t);
84*0Sstevel@tonic-gate static int	write_rec(int, dt_filerec_t *, off_t);
85*0Sstevel@tonic-gate static void	dt2path(char *, size_t, const char *, const char *);
86*0Sstevel@tonic-gate static boolean_t record_match(const dt_rec_t *, const dt_rec_t *, uint_t);
87*0Sstevel@tonic-gate static int	find_dt(int, uint_t, uint_t, int, const dt_rec_t *,
88*0Sstevel@tonic-gate 		    dt_rec_list_t **, uint_t *);
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate int
open_dt(void ** handlep,const char * location,uint_t flags)91*0Sstevel@tonic-gate open_dt(void **handlep, const char *location, uint_t flags)
92*0Sstevel@tonic-gate {
93*0Sstevel@tonic-gate 	dt_handle_t	*dhp;
94*0Sstevel@tonic-gate 	dt_header_t	header = { 0 };
95*0Sstevel@tonic-gate 	char		dtpath[MAXPATHLEN];
96*0Sstevel@tonic-gate 	int		retval;
97*0Sstevel@tonic-gate 	int		fd;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	dhp = malloc(sizeof (dt_handle_t));
100*0Sstevel@tonic-gate 	if (dhp == NULL)
101*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	dhp->dh_oflags = flags;
104*0Sstevel@tonic-gate 	(void) strlcpy(dhp->dh_location, location, MAXPATHLEN);
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, location, "");
107*0Sstevel@tonic-gate 	retval = open_file(dtpath, flags, &fd);
108*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS) {
109*0Sstevel@tonic-gate 		free(dhp);
110*0Sstevel@tonic-gate 		return (retval);
111*0Sstevel@tonic-gate 	}
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	if (flags & DSVC_CREATE) {
114*0Sstevel@tonic-gate 		/*
115*0Sstevel@tonic-gate 		 * We just created the per-network container; initialize
116*0Sstevel@tonic-gate 		 * the header and put it out on disk.
117*0Sstevel@tonic-gate 		 */
118*0Sstevel@tonic-gate 		header.dth_magic   = DT_MAGIC;
119*0Sstevel@tonic-gate 		header.dth_version = DSVC_CONVER;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 		if (write_header(fd, &header) == -1) {
122*0Sstevel@tonic-gate 			retval = syserr_to_dsvcerr(errno);
123*0Sstevel@tonic-gate 			(void) close(fd);
124*0Sstevel@tonic-gate 			(void) remove_dt(location);
125*0Sstevel@tonic-gate 			(void) close_dt((void **)&dhp);
126*0Sstevel@tonic-gate 			return (retval);
127*0Sstevel@tonic-gate 		}
128*0Sstevel@tonic-gate 	} else {
129*0Sstevel@tonic-gate 		/*
130*0Sstevel@tonic-gate 		 * Container already exists; sanity check against the
131*0Sstevel@tonic-gate 		 * header that's on-disk.
132*0Sstevel@tonic-gate 		 */
133*0Sstevel@tonic-gate 		if (read_header(fd, &header) == -1) {
134*0Sstevel@tonic-gate 			retval = syserr_to_dsvcerr(errno);
135*0Sstevel@tonic-gate 			(void) close(fd);
136*0Sstevel@tonic-gate 			(void) close_dt((void **)&dhp);
137*0Sstevel@tonic-gate 			return (retval);
138*0Sstevel@tonic-gate 		}
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 		if (header.dth_magic != DT_MAGIC ||
141*0Sstevel@tonic-gate 		    header.dth_version != DSVC_CONVER) {
142*0Sstevel@tonic-gate 			(void) close(fd);
143*0Sstevel@tonic-gate 			(void) close_dt((void **)&dhp);
144*0Sstevel@tonic-gate 			return (DSVC_INTERNAL);
145*0Sstevel@tonic-gate 		}
146*0Sstevel@tonic-gate 	}
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	(void) close(fd);
149*0Sstevel@tonic-gate 	*handlep = dhp;
150*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate int
close_dt(void ** handlep)154*0Sstevel@tonic-gate close_dt(void **handlep)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	free(*handlep);
157*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate int
remove_dt(const char * location)161*0Sstevel@tonic-gate remove_dt(const char *location)
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	char dtpath[MAXPATHLEN];
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, location, "");
166*0Sstevel@tonic-gate 	if (unlink(dtpath) == -1)
167*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
170*0Sstevel@tonic-gate }
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate int
lookup_dt(void * handle,boolean_t partial,uint_t query,int count,const dt_rec_t * targetp,dt_rec_list_t ** recordsp,uint_t * nrecordsp)173*0Sstevel@tonic-gate lookup_dt(void *handle, boolean_t partial, uint_t query, int count,
174*0Sstevel@tonic-gate     const dt_rec_t *targetp, dt_rec_list_t **recordsp, uint_t *nrecordsp)
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate 	int		fd;
177*0Sstevel@tonic-gate 	int		retval;
178*0Sstevel@tonic-gate 	char		dtpath[MAXPATHLEN];
179*0Sstevel@tonic-gate 	dt_handle_t	*dhp = (dt_handle_t *)handle;
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_READ) == 0)
182*0Sstevel@tonic-gate 		return (DSVC_ACCESS);
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, dhp->dh_location, "");
185*0Sstevel@tonic-gate 	fd = open(dtpath, O_RDONLY);
186*0Sstevel@tonic-gate 	if (fd == -1)
187*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	retval = find_dt(fd, partial ? FIND_PARTIAL : 0, query, count, targetp,
190*0Sstevel@tonic-gate 	    recordsp, nrecordsp);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	(void) close(fd);
193*0Sstevel@tonic-gate 	return (retval);
194*0Sstevel@tonic-gate }
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate /*
197*0Sstevel@tonic-gate  * Internal version of lookup_dt() used by lookup_dt(), modify_dt(),
198*0Sstevel@tonic-gate  * add_dt(), and delete_dt(); same semantics as lookup_dt() except that the
199*0Sstevel@tonic-gate  * `partial' argument has been generalized into a `flags' field and the
200*0Sstevel@tonic-gate  * handle has been turned into a file descriptor.
201*0Sstevel@tonic-gate  */
202*0Sstevel@tonic-gate static int
find_dt(int fd,uint_t flags,uint_t query,int count,const dt_rec_t * targetp,dt_rec_list_t ** recordsp,uint_t * nrecordsp)203*0Sstevel@tonic-gate find_dt(int fd, uint_t flags, uint_t query, int count,
204*0Sstevel@tonic-gate     const dt_rec_t *targetp, dt_rec_list_t **recordsp, uint_t *nrecordsp)
205*0Sstevel@tonic-gate {
206*0Sstevel@tonic-gate 	int		retval = DSVC_SUCCESS;
207*0Sstevel@tonic-gate 	uint_t		nrecords = 0, n = 0;
208*0Sstevel@tonic-gate 	dt_rec_t	*recordp;
209*0Sstevel@tonic-gate 	dt_rec_list_t	*records, *new_records;
210*0Sstevel@tonic-gate 	dt_header_t	header;
211*0Sstevel@tonic-gate 	dt_filerec_t	rec;
212*0Sstevel@tonic-gate 	off_t		recoff = sizeof (dt_header_t);
213*0Sstevel@tonic-gate 	struct stat	st;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	if (read_header(fd, &header) == -1)
216*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	if (fstat(fd, &st) == -1)
219*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	records = NULL;
222*0Sstevel@tonic-gate 	for (; (recoff < st.st_size) && (count < 0 || nrecords < count);
223*0Sstevel@tonic-gate 	    n++, recoff += RECSIZE(rec)) {
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 		if (read_rec(fd, &rec, recoff) == -1) {
226*0Sstevel@tonic-gate 			retval = syserr_to_dsvcerr(errno);
227*0Sstevel@tonic-gate 			break;
228*0Sstevel@tonic-gate 		}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 		/*
231*0Sstevel@tonic-gate 		 * See if we've got a match...
232*0Sstevel@tonic-gate 		 */
233*0Sstevel@tonic-gate 		if (!record_match(&rec.rec_dt, targetp, query))
234*0Sstevel@tonic-gate 			continue;
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 		/*
237*0Sstevel@tonic-gate 		 * Caller just wants a count of the number of matching
238*0Sstevel@tonic-gate 		 * records, not the records themselves; continue.
239*0Sstevel@tonic-gate 		 */
240*0Sstevel@tonic-gate 		if (recordsp == NULL) {
241*0Sstevel@tonic-gate 			nrecords++;
242*0Sstevel@tonic-gate 			continue;
243*0Sstevel@tonic-gate 		}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 		/*
246*0Sstevel@tonic-gate 		 * Allocate record; if FIND_POSITION flag is set, then
247*0Sstevel@tonic-gate 		 * we need to allocate an extended (dt_recpos_t) record.
248*0Sstevel@tonic-gate 		 */
249*0Sstevel@tonic-gate 		if (flags & FIND_POSITION)
250*0Sstevel@tonic-gate 			recordp = malloc(sizeof (dt_recpos_t));
251*0Sstevel@tonic-gate 		else
252*0Sstevel@tonic-gate 			recordp = malloc(sizeof (dt_rec_t));
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 		if (recordp == NULL) {
255*0Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
256*0Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
257*0Sstevel@tonic-gate 			break;
258*0Sstevel@tonic-gate 		}
259*0Sstevel@tonic-gate 		/*
260*0Sstevel@tonic-gate 		 * Fill in record; do a structure copy from our automatic
261*0Sstevel@tonic-gate 		 * record.  If FIND_POSITION flag is on, pass back
262*0Sstevel@tonic-gate 		 * additional location information.
263*0Sstevel@tonic-gate 		 */
264*0Sstevel@tonic-gate 		*recordp = rec.rec_dt;
265*0Sstevel@tonic-gate 		recordp->dt_value = malloc(rec.rec_dtvalsize);
266*0Sstevel@tonic-gate 		if (recordp->dt_value == NULL) {
267*0Sstevel@tonic-gate 			free_dtrec(recordp);
268*0Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
269*0Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
270*0Sstevel@tonic-gate 			break;
271*0Sstevel@tonic-gate 		}
272*0Sstevel@tonic-gate 		if (pnread(fd, recordp->dt_value, rec.rec_dtvalsize,
273*0Sstevel@tonic-gate 		    recoff + offsetof(dt_filerec_t, rec_dtval)) == -1) {
274*0Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
275*0Sstevel@tonic-gate 				retval = syserr_to_dsvcerr(errno);
276*0Sstevel@tonic-gate 			free_dtrec(recordp);
277*0Sstevel@tonic-gate 			break;
278*0Sstevel@tonic-gate 		}
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 		if (flags & FIND_POSITION) {
281*0Sstevel@tonic-gate 			((dt_recpos_t *)recordp)->dtp_off  = recoff;
282*0Sstevel@tonic-gate 			((dt_recpos_t *)recordp)->dtp_size = RECSIZE(rec);
283*0Sstevel@tonic-gate 		}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 		/*
286*0Sstevel@tonic-gate 		 * Chuck the record on the list and up the counter.
287*0Sstevel@tonic-gate 		 */
288*0Sstevel@tonic-gate 		new_records = add_dtrec_to_list(recordp, records);
289*0Sstevel@tonic-gate 		if (new_records == NULL) {
290*0Sstevel@tonic-gate 			free_dtrec(recordp);
291*0Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
292*0Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
293*0Sstevel@tonic-gate 			break;
294*0Sstevel@tonic-gate 		}
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 		records = new_records;
297*0Sstevel@tonic-gate 		nrecords++;
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	if (retval == DSVC_SUCCESS) {
301*0Sstevel@tonic-gate 		*nrecordsp = nrecords;
302*0Sstevel@tonic-gate 		if (recordsp != NULL)
303*0Sstevel@tonic-gate 			*recordsp = records;
304*0Sstevel@tonic-gate 		return (DSVC_SUCCESS);
305*0Sstevel@tonic-gate 	}
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	if (records != NULL)
308*0Sstevel@tonic-gate 		free_dtrec_list(records);
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	return (retval);
311*0Sstevel@tonic-gate }
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate /*
314*0Sstevel@tonic-gate  * Compares `dtp' to the target `targetp', using `query' to decide what
315*0Sstevel@tonic-gate  * fields to compare.  Returns B_TRUE if `dtp' matches `targetp', B_FALSE
316*0Sstevel@tonic-gate  * if not.
317*0Sstevel@tonic-gate  */
318*0Sstevel@tonic-gate static boolean_t
record_match(const dt_rec_t * dtp,const dt_rec_t * targetp,uint_t query)319*0Sstevel@tonic-gate record_match(const dt_rec_t *dtp, const dt_rec_t *targetp, uint_t query)
320*0Sstevel@tonic-gate {
321*0Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DT_QTYPE) && targetp->dt_type != dtp->dt_type)
322*0Sstevel@tonic-gate 		return (B_FALSE);
323*0Sstevel@tonic-gate 	if (DSVC_QISNEQ(query, DT_QTYPE) && targetp->dt_type == dtp->dt_type)
324*0Sstevel@tonic-gate 		return (B_FALSE);
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	if (DSVC_QISEQ(query, DT_QKEY) &&
327*0Sstevel@tonic-gate 	    strcmp(targetp->dt_key, dtp->dt_key) != 0)
328*0Sstevel@tonic-gate 		return (B_FALSE);
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	if (DSVC_QISNEQ(query, DT_QKEY) &&
331*0Sstevel@tonic-gate 	    strcmp(targetp->dt_key, dtp->dt_key) == 0)
332*0Sstevel@tonic-gate 		return (B_FALSE);
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	return (B_TRUE);
335*0Sstevel@tonic-gate }
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate int
add_dt(void * handle,dt_rec_t * addp)338*0Sstevel@tonic-gate add_dt(void *handle, dt_rec_t *addp)
339*0Sstevel@tonic-gate {
340*0Sstevel@tonic-gate 	unsigned int	found;
341*0Sstevel@tonic-gate 	int		query;
342*0Sstevel@tonic-gate 	int		fd, newfd;
343*0Sstevel@tonic-gate 	int		retval;
344*0Sstevel@tonic-gate 	dt_filerec_t	*rec;
345*0Sstevel@tonic-gate 	struct stat	st;
346*0Sstevel@tonic-gate 	dt_handle_t	*dhp = (dt_handle_t *)handle;
347*0Sstevel@tonic-gate 	char		newpath[MAXPATHLEN], dtpath[MAXPATHLEN];
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_WRITE) == 0)
350*0Sstevel@tonic-gate 		return (DSVC_ACCESS);
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, dhp->dh_location, "");
353*0Sstevel@tonic-gate 	fd = open(dtpath, O_RDWR);
354*0Sstevel@tonic-gate 	if (fd == -1)
355*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	/*
358*0Sstevel@tonic-gate 	 * Make sure the record wasn't created when we weren't looking.
359*0Sstevel@tonic-gate 	 */
360*0Sstevel@tonic-gate 	DSVC_QINIT(query);
361*0Sstevel@tonic-gate 	DSVC_QEQ(query, DT_QKEY|DT_QTYPE);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	retval = find_dt(fd, 0, query, 1, addp, NULL, &found);
364*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS) {
365*0Sstevel@tonic-gate 		(void) close(fd);
366*0Sstevel@tonic-gate 		return (retval);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 	if (found != 0) {
369*0Sstevel@tonic-gate 		(void) close(fd);
370*0Sstevel@tonic-gate 		return (DSVC_EXISTS);
371*0Sstevel@tonic-gate 	}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	/*
374*0Sstevel@tonic-gate 	 * Make a new copy of the dhcptab with the new record appended.
375*0Sstevel@tonic-gate 	 * Once done, atomically rename the new dhcptab to the old name.
376*0Sstevel@tonic-gate 	 */
377*0Sstevel@tonic-gate 	if (fstat(fd, &st) == -1) {
378*0Sstevel@tonic-gate 		(void) close(fd);
379*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
380*0Sstevel@tonic-gate 	}
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	dt2path(newpath, MAXPATHLEN, dhp->dh_location, ".new");
383*0Sstevel@tonic-gate 	(void) unlink(newpath);
384*0Sstevel@tonic-gate 	newfd = open(newpath, O_WRONLY|O_CREAT|O_EXCL, 0644);
385*0Sstevel@tonic-gate 	if (newfd == -1) {
386*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
387*0Sstevel@tonic-gate 		goto out;
388*0Sstevel@tonic-gate 	}
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	retval = copy_range(fd, 0, newfd, 0, st.st_size);
391*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
392*0Sstevel@tonic-gate 		goto out;
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	addp->dt_sig = gensig();
395*0Sstevel@tonic-gate 	rec = alloca(sizeof (dt_filerec_t) + strlen(addp->dt_value));
396*0Sstevel@tonic-gate 	rec->rec_dt = *addp;
397*0Sstevel@tonic-gate 	rec->rec_dtvalsize = strlen(addp->dt_value) + 1;
398*0Sstevel@tonic-gate 	(void) strcpy(rec->rec_dtval, addp->dt_value);
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	if (write_rec(newfd, rec, st.st_size) == -1) {
401*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
402*0Sstevel@tonic-gate 		goto out;
403*0Sstevel@tonic-gate 	}
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	/*
406*0Sstevel@tonic-gate 	 * Note: we close these descriptors before the rename(2) (rather
407*0Sstevel@tonic-gate 	 * than just having the `out:' label clean them up) to save NFS
408*0Sstevel@tonic-gate 	 * some work (otherwise, NFS has to save `dtpath' to an alternate
409*0Sstevel@tonic-gate 	 * name since its vnode would still be active).
410*0Sstevel@tonic-gate 	 */
411*0Sstevel@tonic-gate 	(void) close(fd);
412*0Sstevel@tonic-gate 	(void) close(newfd);
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	if (rename(newpath, dtpath) == -1)
415*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	return (retval);
418*0Sstevel@tonic-gate out:
419*0Sstevel@tonic-gate 	(void) close(fd);
420*0Sstevel@tonic-gate 	(void) close(newfd);
421*0Sstevel@tonic-gate 	(void) unlink(newpath);
422*0Sstevel@tonic-gate 	return (retval);
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate int
modify_dt(void * handle,const dt_rec_t * origp,dt_rec_t * newp)426*0Sstevel@tonic-gate modify_dt(void *handle, const dt_rec_t *origp, dt_rec_t *newp)
427*0Sstevel@tonic-gate {
428*0Sstevel@tonic-gate 	unsigned int	found;
429*0Sstevel@tonic-gate 	int		query;
430*0Sstevel@tonic-gate 	int		fd, newfd;
431*0Sstevel@tonic-gate 	int		retval;
432*0Sstevel@tonic-gate 	dt_filerec_t	*rec;
433*0Sstevel@tonic-gate 	off_t		recoff, recnext;
434*0Sstevel@tonic-gate 	dt_rec_list_t	*reclist;
435*0Sstevel@tonic-gate 	struct stat	st;
436*0Sstevel@tonic-gate 	dt_handle_t	*dhp = (dt_handle_t *)handle;
437*0Sstevel@tonic-gate 	char		newpath[MAXPATHLEN], dtpath[MAXPATHLEN];
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_WRITE) == 0)
440*0Sstevel@tonic-gate 		return (DSVC_ACCESS);
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, dhp->dh_location, "");
443*0Sstevel@tonic-gate 	fd = open(dtpath, O_RDWR);
444*0Sstevel@tonic-gate 	if (fd == -1)
445*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	DSVC_QINIT(query);
448*0Sstevel@tonic-gate 	DSVC_QEQ(query, DT_QKEY|DT_QTYPE);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	/*
451*0Sstevel@tonic-gate 	 * If we're changing the key for this record, make sure the key
452*0Sstevel@tonic-gate 	 * we're changing to doesn't already exist.
453*0Sstevel@tonic-gate 	 */
454*0Sstevel@tonic-gate 	if (origp->dt_type != newp->dt_type ||
455*0Sstevel@tonic-gate 	    strcmp(origp->dt_key, newp->dt_key) != 0) {
456*0Sstevel@tonic-gate 		retval = find_dt(fd, 0, query, 1, newp, NULL, &found);
457*0Sstevel@tonic-gate 		if (retval != DSVC_SUCCESS) {
458*0Sstevel@tonic-gate 			(void) close(fd);
459*0Sstevel@tonic-gate 			return (retval);
460*0Sstevel@tonic-gate 		}
461*0Sstevel@tonic-gate 		if (found != 0) {
462*0Sstevel@tonic-gate 			(void) close(fd);
463*0Sstevel@tonic-gate 			return (DSVC_EXISTS);
464*0Sstevel@tonic-gate 		}
465*0Sstevel@tonic-gate 	}
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	/*
468*0Sstevel@tonic-gate 	 * Fetch the original again to make sure it didn't go stale.
469*0Sstevel@tonic-gate 	 */
470*0Sstevel@tonic-gate 	retval = find_dt(fd, FIND_POSITION, query, 1, origp, &reclist, &found);
471*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS) {
472*0Sstevel@tonic-gate 		(void) close(fd);
473*0Sstevel@tonic-gate 		return (retval);
474*0Sstevel@tonic-gate 	}
475*0Sstevel@tonic-gate 	if (found == 0) {
476*0Sstevel@tonic-gate 		(void) close(fd);
477*0Sstevel@tonic-gate 		return (DSVC_NOENT);
478*0Sstevel@tonic-gate 	}
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	if (reclist->dtl_rec->dt_sig != origp->dt_sig) {
481*0Sstevel@tonic-gate 		(void) close(fd);
482*0Sstevel@tonic-gate 		free_dtrec_list(reclist);
483*0Sstevel@tonic-gate 		return (DSVC_COLLISION);
484*0Sstevel@tonic-gate 	}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	recoff  = ((dt_recpos_t *)reclist->dtl_rec)->dtp_off;
487*0Sstevel@tonic-gate 	recnext = recoff + ((dt_recpos_t *)reclist->dtl_rec)->dtp_size;
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	free_dtrec_list(reclist);
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	/*
492*0Sstevel@tonic-gate 	 * Make a new copy of the dhcptab, sans the record we're modifying,
493*0Sstevel@tonic-gate 	 * then append modified record at the end.  Once done, atomically
494*0Sstevel@tonic-gate 	 * rename the new dhcptab to the old name.
495*0Sstevel@tonic-gate 	 */
496*0Sstevel@tonic-gate 	if (fstat(fd, &st) == -1) {
497*0Sstevel@tonic-gate 		(void) close(fd);
498*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
499*0Sstevel@tonic-gate 	}
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	dt2path(newpath, MAXPATHLEN, dhp->dh_location, ".new");
502*0Sstevel@tonic-gate 	(void) unlink(newpath);
503*0Sstevel@tonic-gate 	newfd = open(newpath, O_WRONLY|O_CREAT|O_EXCL, 0644);
504*0Sstevel@tonic-gate 	if (newfd == -1) {
505*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
506*0Sstevel@tonic-gate 		goto out;
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	retval = copy_range(fd, 0, newfd, 0, recoff);
510*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
511*0Sstevel@tonic-gate 		goto out;
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 	retval = copy_range(fd, recnext, newfd, recoff, st.st_size - recnext);
514*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
515*0Sstevel@tonic-gate 		goto out;
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	newp->dt_sig = origp->dt_sig + 1;
518*0Sstevel@tonic-gate 	rec = alloca(sizeof (dt_filerec_t) + strlen(newp->dt_value));
519*0Sstevel@tonic-gate 	rec->rec_dt = *newp;
520*0Sstevel@tonic-gate 	rec->rec_dtvalsize = strlen(newp->dt_value) + 1;
521*0Sstevel@tonic-gate 	(void) strcpy(rec->rec_dtval, newp->dt_value);
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	if (write_rec(newfd, rec, st.st_size - (recnext - recoff)) == -1) {
524*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
525*0Sstevel@tonic-gate 		goto out;
526*0Sstevel@tonic-gate 	}
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	/*
529*0Sstevel@tonic-gate 	 * See comment in add_dt() regarding the next two lines.
530*0Sstevel@tonic-gate 	 */
531*0Sstevel@tonic-gate 	(void) close(fd);
532*0Sstevel@tonic-gate 	(void) close(newfd);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	if (rename(newpath, dtpath) == -1)
535*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	return (retval);
538*0Sstevel@tonic-gate out:
539*0Sstevel@tonic-gate 	(void) close(fd);
540*0Sstevel@tonic-gate 	(void) close(newfd);
541*0Sstevel@tonic-gate 	(void) unlink(newpath);
542*0Sstevel@tonic-gate 	return (retval);
543*0Sstevel@tonic-gate }
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate int
delete_dt(void * handle,const dt_rec_t * delp)546*0Sstevel@tonic-gate delete_dt(void *handle, const dt_rec_t *delp)
547*0Sstevel@tonic-gate {
548*0Sstevel@tonic-gate 	unsigned int	found;
549*0Sstevel@tonic-gate 	int		query;
550*0Sstevel@tonic-gate 	int		fd, newfd;
551*0Sstevel@tonic-gate 	int		retval;
552*0Sstevel@tonic-gate 	off_t		recoff, recnext;
553*0Sstevel@tonic-gate 	dt_rec_list_t	*reclist;
554*0Sstevel@tonic-gate 	struct stat	st;
555*0Sstevel@tonic-gate 	dt_handle_t	*dhp = (dt_handle_t *)handle;
556*0Sstevel@tonic-gate 	char		newpath[MAXPATHLEN], dtpath[MAXPATHLEN];
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_WRITE) == 0)
559*0Sstevel@tonic-gate 		return (DSVC_ACCESS);
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, dhp->dh_location, "");
562*0Sstevel@tonic-gate 	fd = open(dtpath, O_RDWR);
563*0Sstevel@tonic-gate 	if (fd == -1)
564*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	/*
567*0Sstevel@tonic-gate 	 * Make sure the record exists and also that the signatures match;
568*0Sstevel@tonic-gate 	 * if `delp->dt_sig' is zero, then skip signature comparison (this
569*0Sstevel@tonic-gate 	 * is so one can delete records that were not looked up).
570*0Sstevel@tonic-gate 	 */
571*0Sstevel@tonic-gate 	DSVC_QINIT(query);
572*0Sstevel@tonic-gate 	DSVC_QEQ(query, DT_QKEY|DT_QTYPE);
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	retval = find_dt(fd, FIND_POSITION, query, 1, delp, &reclist, &found);
575*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS) {
576*0Sstevel@tonic-gate 		(void) close(fd);
577*0Sstevel@tonic-gate 		return (retval);
578*0Sstevel@tonic-gate 	}
579*0Sstevel@tonic-gate 	if (found == 0) {
580*0Sstevel@tonic-gate 		(void) close(fd);
581*0Sstevel@tonic-gate 		return (DSVC_NOENT);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	if (delp->dt_sig != 0 && reclist->dtl_rec->dt_sig != delp->dt_sig) {
585*0Sstevel@tonic-gate 		(void) close(fd);
586*0Sstevel@tonic-gate 		free_dtrec_list(reclist);
587*0Sstevel@tonic-gate 		return (DSVC_COLLISION);
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	recoff  = ((dt_recpos_t *)reclist->dtl_rec)->dtp_off;
591*0Sstevel@tonic-gate 	recnext = recoff + ((dt_recpos_t *)reclist->dtl_rec)->dtp_size;
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	free_dtrec_list(reclist);
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	/*
596*0Sstevel@tonic-gate 	 * Make a new copy of the dhcptab, sans the record we're deleting.
597*0Sstevel@tonic-gate 	 * Once done, atomically rename the new dhcptab to the old name.
598*0Sstevel@tonic-gate 	 */
599*0Sstevel@tonic-gate 	if (fstat(fd, &st) == -1) {
600*0Sstevel@tonic-gate 		(void) close(fd);
601*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
602*0Sstevel@tonic-gate 	}
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	dt2path(newpath, MAXPATHLEN, dhp->dh_location, ".new");
605*0Sstevel@tonic-gate 	(void) unlink(newpath);
606*0Sstevel@tonic-gate 	newfd = open(newpath, O_WRONLY|O_CREAT|O_EXCL, 0644);
607*0Sstevel@tonic-gate 	if (newfd == -1) {
608*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
609*0Sstevel@tonic-gate 		goto out;
610*0Sstevel@tonic-gate 	}
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	retval = copy_range(fd, 0, newfd, 0, recoff);
613*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
614*0Sstevel@tonic-gate 		goto out;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	retval = copy_range(fd, recnext, newfd, recoff, st.st_size - recnext);
617*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
618*0Sstevel@tonic-gate 		goto out;
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	/*
621*0Sstevel@tonic-gate 	 * See comment in add_dt() regarding the next two lines.
622*0Sstevel@tonic-gate 	 */
623*0Sstevel@tonic-gate 	(void) close(fd);
624*0Sstevel@tonic-gate 	(void) close(newfd);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	if (rename(newpath, dtpath) == -1)
627*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	return (retval);
630*0Sstevel@tonic-gate out:
631*0Sstevel@tonic-gate 	(void) close(fd);
632*0Sstevel@tonic-gate 	(void) close(newfd);
633*0Sstevel@tonic-gate 	(void) unlink(newpath);
634*0Sstevel@tonic-gate 	return (retval);
635*0Sstevel@tonic-gate }
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate int
list_dt(const char * location,char *** listppp,uint_t * countp)638*0Sstevel@tonic-gate list_dt(const char *location, char ***listppp, uint_t *countp)
639*0Sstevel@tonic-gate {
640*0Sstevel@tonic-gate 	char	dtpath[MAXPATHLEN];
641*0Sstevel@tonic-gate 	char	**listpp;
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	if (access(location, F_OK|R_OK) == -1) {
644*0Sstevel@tonic-gate 		switch (errno) {
645*0Sstevel@tonic-gate 		case EACCES:
646*0Sstevel@tonic-gate 		case EPERM:
647*0Sstevel@tonic-gate 			return (DSVC_ACCESS);
648*0Sstevel@tonic-gate 		case ENOENT:
649*0Sstevel@tonic-gate 			return (DSVC_NO_LOCATION);
650*0Sstevel@tonic-gate 		default:
651*0Sstevel@tonic-gate 			break;
652*0Sstevel@tonic-gate 		}
653*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
654*0Sstevel@tonic-gate 	}
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, location, "");
657*0Sstevel@tonic-gate 	if (access(dtpath, F_OK|R_OK) == -1) {
658*0Sstevel@tonic-gate 		*countp = 0;
659*0Sstevel@tonic-gate 		*listppp = NULL;
660*0Sstevel@tonic-gate 		return (DSVC_SUCCESS);
661*0Sstevel@tonic-gate 	}
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	listpp = malloc(sizeof (char **));
664*0Sstevel@tonic-gate 	if (listpp == NULL)
665*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
666*0Sstevel@tonic-gate 	listpp[0] = strdup(DT_DHCPTAB);
667*0Sstevel@tonic-gate 	if (listpp[0] == NULL) {
668*0Sstevel@tonic-gate 		free(listpp);
669*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
670*0Sstevel@tonic-gate 	}
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	*listppp = listpp;
673*0Sstevel@tonic-gate 	*countp = 1;
674*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
675*0Sstevel@tonic-gate }
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate /*
678*0Sstevel@tonic-gate  * Given a buffer `path' of `pathlen' bytes, fill it in with a path to the
679*0Sstevel@tonic-gate  * dhcptab in directory `dir' with a suffix of `suffix'.
680*0Sstevel@tonic-gate  */
681*0Sstevel@tonic-gate static void
dt2path(char * path,size_t pathlen,const char * dir,const char * suffix)682*0Sstevel@tonic-gate dt2path(char *path, size_t pathlen, const char *dir, const char *suffix)
683*0Sstevel@tonic-gate {
684*0Sstevel@tonic-gate 	(void) snprintf(path, pathlen, "%s/SUNWbinfiles%u_%s%s", dir,
685*0Sstevel@tonic-gate 	    DSVC_CONVER, DT_DHCPTAB, suffix);
686*0Sstevel@tonic-gate }
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate /*
689*0Sstevel@tonic-gate  * Convert dt_header_t pointed to by `headerp' from native (host) to
690*0Sstevel@tonic-gate  * network order or the other way.
691*0Sstevel@tonic-gate  */
692*0Sstevel@tonic-gate /* ARGSUSED */
693*0Sstevel@tonic-gate static void
nhconvert_header(dt_header_t * headerp)694*0Sstevel@tonic-gate nhconvert_header(dt_header_t *headerp)
695*0Sstevel@tonic-gate {
696*0Sstevel@tonic-gate #ifdef	_LITTLE_ENDIAN
697*0Sstevel@tonic-gate 	nhconvert(&headerp->dth_magic, &headerp->dth_magic, sizeof (uint32_t));
698*0Sstevel@tonic-gate #endif
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate /*
702*0Sstevel@tonic-gate  * Convert dt_filerec_t pointed to by `rec' from native (host) to network
703*0Sstevel@tonic-gate  * order or the other way.
704*0Sstevel@tonic-gate  */
705*0Sstevel@tonic-gate /* ARGSUSED */
706*0Sstevel@tonic-gate static void
nhconvert_rec(dt_filerec_t * rec)707*0Sstevel@tonic-gate nhconvert_rec(dt_filerec_t *rec)
708*0Sstevel@tonic-gate {
709*0Sstevel@tonic-gate #ifdef	_LITTLE_ENDIAN
710*0Sstevel@tonic-gate 	dt_rec_t *dtp = &rec->rec_dt;
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	nhconvert(&rec->rec_dtvalsize, &rec->rec_dtvalsize, sizeof (uint32_t));
713*0Sstevel@tonic-gate 	nhconvert(&dtp->dt_sig, &dtp->dt_sig, sizeof (uint64_t));
714*0Sstevel@tonic-gate #endif
715*0Sstevel@tonic-gate }
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate /*
718*0Sstevel@tonic-gate  * Read the dt_header_t in the container at open file `fd' into the header
719*0Sstevel@tonic-gate  * pointed to by `headerp'.  Returns 0 on success, -1 on failure (errno is
720*0Sstevel@tonic-gate  * set).
721*0Sstevel@tonic-gate  */
722*0Sstevel@tonic-gate static int
read_header(int fd,dt_header_t * headerp)723*0Sstevel@tonic-gate read_header(int fd, dt_header_t *headerp)
724*0Sstevel@tonic-gate {
725*0Sstevel@tonic-gate 	if (pnread(fd, headerp, sizeof (dt_header_t), 0) == -1)
726*0Sstevel@tonic-gate 		return (-1);
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	nhconvert_header(headerp);
729*0Sstevel@tonic-gate 	return (0);
730*0Sstevel@tonic-gate }
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate /*
733*0Sstevel@tonic-gate  * Write the dt_header_t pointed to by `headerp' to the container at open
734*0Sstevel@tonic-gate  * file `fd'.  Returns 0 on success, -1 on failure (errno is set).
735*0Sstevel@tonic-gate  */
736*0Sstevel@tonic-gate static int
write_header(int fd,dt_header_t * headerp)737*0Sstevel@tonic-gate write_header(int fd, dt_header_t *headerp)
738*0Sstevel@tonic-gate {
739*0Sstevel@tonic-gate 	int retval;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	nhconvert_header(headerp);
742*0Sstevel@tonic-gate 	retval = pnwrite(fd, headerp, sizeof (dt_header_t), 0);
743*0Sstevel@tonic-gate 	nhconvert_header(headerp);
744*0Sstevel@tonic-gate 	return (retval);
745*0Sstevel@tonic-gate }
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate /*
749*0Sstevel@tonic-gate  * Read the dt_filerec_t in the container from offset `recoff' in the
750*0Sstevel@tonic-gate  * container at open file `fd'.  Note that this only returns the fixed
751*0Sstevel@tonic-gate  * sized part of the dt_filerec_t; the caller must retrieve `rev_dtval' on
752*0Sstevel@tonic-gate  * their own.  Returns 0 on success, -1 on failure (errno is set).
753*0Sstevel@tonic-gate  */
754*0Sstevel@tonic-gate static int
read_rec(int fd,dt_filerec_t * rec,off_t recoff)755*0Sstevel@tonic-gate read_rec(int fd, dt_filerec_t *rec, off_t recoff)
756*0Sstevel@tonic-gate {
757*0Sstevel@tonic-gate 	if (pnread(fd, rec, sizeof (dt_filerec_t), recoff) == -1)
758*0Sstevel@tonic-gate 		return (-1);
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	nhconvert_rec(rec);
761*0Sstevel@tonic-gate 	return (0);
762*0Sstevel@tonic-gate }
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate /*
765*0Sstevel@tonic-gate  * Write the dt_filerec_t pointed to be `rec' to offset `recoff' in the
766*0Sstevel@tonic-gate  * container at open file `fd'.  Returns 0 on success, -1 on failure (errno
767*0Sstevel@tonic-gate  * is set).
768*0Sstevel@tonic-gate  */
769*0Sstevel@tonic-gate static int
write_rec(int fd,dt_filerec_t * rec,off_t recoff)770*0Sstevel@tonic-gate write_rec(int fd, dt_filerec_t *rec, off_t recoff)
771*0Sstevel@tonic-gate {
772*0Sstevel@tonic-gate 	int	retval;
773*0Sstevel@tonic-gate 	size_t	recsize = RECSIZE(*rec);
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	nhconvert_rec(rec);
776*0Sstevel@tonic-gate 	retval = pnwrite(fd, rec, recsize, recoff);
777*0Sstevel@tonic-gate 	nhconvert_rec(rec);
778*0Sstevel@tonic-gate 	return (retval);
779*0Sstevel@tonic-gate }
780