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