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