xref: /onnv-gate/usr/src/lib/libdhcpsvc/modules/util/util.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-2001 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  * Internal libdhcpsvc public module utility functions: a collection of
31*0Sstevel@tonic-gate  * general-purpose routines that are used by assorted public modules.
32*0Sstevel@tonic-gate  * Someday we should integrate this into the build process a bit more
33*0Sstevel@tonic-gate  * intelligently.
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include <sys/types.h>
37*0Sstevel@tonic-gate #include <sys/mman.h>
38*0Sstevel@tonic-gate #include <sys/isa_defs.h>
39*0Sstevel@tonic-gate #include <dhcp_svc_public.h>
40*0Sstevel@tonic-gate #include <assert.h>
41*0Sstevel@tonic-gate #include <stdlib.h>
42*0Sstevel@tonic-gate #include <fcntl.h>
43*0Sstevel@tonic-gate #include <errno.h>
44*0Sstevel@tonic-gate #include <string.h>
45*0Sstevel@tonic-gate #include <sys/sysmacros.h>
46*0Sstevel@tonic-gate #include <unistd.h>
47*0Sstevel@tonic-gate #include <ctype.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include "util.h"
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /*
52*0Sstevel@tonic-gate  * Open a file at path `pathname'; depending on the flags passed in through
53*0Sstevel@tonic-gate  * `dsvc_flags', this file may be optionally created or opened read-only.
54*0Sstevel@tonic-gate  * On success, DSVC_SUCCESS is returned and `fdp' points to the opened file
55*0Sstevel@tonic-gate  * descriptor.  On failure, a DSVC_* error code is returned.
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate int
open_file(const char * pathname,unsigned int dsvc_flags,int * fdp)58*0Sstevel@tonic-gate open_file(const char *pathname, unsigned int dsvc_flags, int *fdp)
59*0Sstevel@tonic-gate {
60*0Sstevel@tonic-gate 	int open_flags;
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 	/*
63*0Sstevel@tonic-gate 	 * Note that we always open with read access, independent of
64*0Sstevel@tonic-gate 	 * dsvc_flags, because an update operation (add, delete, modify)
65*0Sstevel@tonic-gate 	 * needs to lookup records to detect collisions.
66*0Sstevel@tonic-gate 	 */
67*0Sstevel@tonic-gate 	open_flags = O_RDONLY;
68*0Sstevel@tonic-gate 	if (dsvc_flags & DSVC_WRITE)
69*0Sstevel@tonic-gate 		open_flags = O_RDWR;
70*0Sstevel@tonic-gate 	if (dsvc_flags & DSVC_CREATE)
71*0Sstevel@tonic-gate 		open_flags |= O_CREAT|O_EXCL;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	*fdp = open(pathname, open_flags, 0644);
74*0Sstevel@tonic-gate 	if (*fdp == -1)
75*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
78*0Sstevel@tonic-gate }
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate /*
81*0Sstevel@tonic-gate  * Read input a chunk at a time, avoiding as much copying as possible.  To
82*0Sstevel@tonic-gate  * this end, we don't read into a temporary buffer, but rather read
83*0Sstevel@tonic-gate  * directly into dynamically reallocated storage (on the assumption that
84*0Sstevel@tonic-gate  * most of the time we will have to return something).  Returns NULL either
85*0Sstevel@tonic-gate  * on failure or EOF; use feof(3C) on `fp' to determine which condition
86*0Sstevel@tonic-gate  * occurred.
87*0Sstevel@tonic-gate  */
88*0Sstevel@tonic-gate char *
read_entry(FILE * fp)89*0Sstevel@tonic-gate read_entry(FILE *fp)
90*0Sstevel@tonic-gate {
91*0Sstevel@tonic-gate 	char		*newline, *new_result, *result = NULL;
92*0Sstevel@tonic-gate 	unsigned int	len = 0, size = 0, chunksize = BUFSIZ;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	for (;;) {
95*0Sstevel@tonic-gate 		/*
96*0Sstevel@tonic-gate 		 * See if we need to grow the buffer; we always try to read
97*0Sstevel@tonic-gate 		 * `chunksize' bytes, so we need at least `chunksize' around;
98*0Sstevel@tonic-gate 		 * grab a little more just to avoid constant realloc'ing
99*0Sstevel@tonic-gate 		 */
100*0Sstevel@tonic-gate 		if (len + chunksize > size) {
101*0Sstevel@tonic-gate 			size = len + (chunksize * 2);
102*0Sstevel@tonic-gate 			new_result = realloc(result, size);
103*0Sstevel@tonic-gate 			if (new_result == NULL) {
104*0Sstevel@tonic-gate 				free(result);
105*0Sstevel@tonic-gate 				return (NULL);
106*0Sstevel@tonic-gate 			}
107*0Sstevel@tonic-gate 		}
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 		if (fgets(&new_result[len], chunksize, fp) == NULL) {
110*0Sstevel@tonic-gate 			/*
111*0Sstevel@tonic-gate 			 * Hit EOF; if we never read any data, then free
112*0Sstevel@tonic-gate 			 * `new_result' and return NULL.  If we are
113*0Sstevel@tonic-gate 			 * returning data, it's in `new_result', not
114*0Sstevel@tonic-gate 			 * `result'.
115*0Sstevel@tonic-gate 			 */
116*0Sstevel@tonic-gate 			if (result == NULL)
117*0Sstevel@tonic-gate 				free(new_result);
118*0Sstevel@tonic-gate 			else
119*0Sstevel@tonic-gate 				result = new_result;
120*0Sstevel@tonic-gate 			break;
121*0Sstevel@tonic-gate 		}
122*0Sstevel@tonic-gate 		result = new_result;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 		/*
125*0Sstevel@tonic-gate 		 * If we read a newline, then see if the preceding
126*0Sstevel@tonic-gate 		 * character was an escape.  If so, remove the escape and
127*0Sstevel@tonic-gate 		 * continue; otherwise we're done.  Note that we need to
128*0Sstevel@tonic-gate 		 * do the strrchr() on `&result[len]' so that NUL's that
129*0Sstevel@tonic-gate 		 * may be lurking elsewhere on the line don't confuse us.
130*0Sstevel@tonic-gate 		 */
131*0Sstevel@tonic-gate 		newline = strrchr(&result[len], '\n');
132*0Sstevel@tonic-gate 		if (newline != NULL) {
133*0Sstevel@tonic-gate 			len = newline - result;
134*0Sstevel@tonic-gate 			if (newline == result || newline[-1] != '\\') {
135*0Sstevel@tonic-gate 				newline[0] = '\0';
136*0Sstevel@tonic-gate 				break;
137*0Sstevel@tonic-gate 			}
138*0Sstevel@tonic-gate 			newline[-1] = '\0';
139*0Sstevel@tonic-gate 			len -= 2;
140*0Sstevel@tonic-gate 		} else {
141*0Sstevel@tonic-gate 			/*
142*0Sstevel@tonic-gate 			 * We either `chunksize' worth of data or we hit a
143*0Sstevel@tonic-gate 			 * NUL somewhere in the data stream.  If we hit a
144*0Sstevel@tonic-gate 			 * NUL, then we can't "see" beyond the NUL; just
145*0Sstevel@tonic-gate 			 * advance to the NUL itself and continue.
146*0Sstevel@tonic-gate 			 */
147*0Sstevel@tonic-gate 			len += strlen(&result[len]);
148*0Sstevel@tonic-gate 		}
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 	return (result);
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate /*
154*0Sstevel@tonic-gate  * Given a buffer `buf' of words separated by one or more of the characters
155*0Sstevel@tonic-gate  * in `seps', split it into at most `nfields' fields, by changing the
156*0Sstevel@tonic-gate  * separator character following a field to a NUL character.  Set
157*0Sstevel@tonic-gate  * `fields[i]' to point to the beginning of field i in `buf'.  Return the
158*0Sstevel@tonic-gate  * number of fields set in `fields[]'.  This routine is quite similar to
159*0Sstevel@tonic-gate  * bufsplit(3G), but less general, faster, and also handles multiple
160*0Sstevel@tonic-gate  * multiple whitespace separator characters differently.
161*0Sstevel@tonic-gate  */
162*0Sstevel@tonic-gate unsigned int
field_split(char * buf,unsigned int nfields,char * fields[],const char * seps)163*0Sstevel@tonic-gate field_split(char *buf, unsigned int nfields, char *fields[], const char *seps)
164*0Sstevel@tonic-gate {
165*0Sstevel@tonic-gate 	unsigned int	i = 0;
166*0Sstevel@tonic-gate 	char		*ch;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	for (;;) {
169*0Sstevel@tonic-gate 		fields[i] = buf;
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 		/*
172*0Sstevel@tonic-gate 		 * Look for the field separator, byte-at-a-time; ignore
173*0Sstevel@tonic-gate 		 * separators that have been escaped.  Believe it or not,
174*0Sstevel@tonic-gate 		 * strchr(3C) will match `seps' if `*buf' is the NUL byte
175*0Sstevel@tonic-gate 		 * (which indicates we're done).
176*0Sstevel@tonic-gate 		 */
177*0Sstevel@tonic-gate 		for (;;) {
178*0Sstevel@tonic-gate 			ch = strchr(seps, *buf);
179*0Sstevel@tonic-gate 			if (ch != NULL && *ch == '\0')
180*0Sstevel@tonic-gate 				return (i + 1);
181*0Sstevel@tonic-gate 			if (ch != NULL && (buf == fields[i] || buf[-1] != '\\'))
182*0Sstevel@tonic-gate 				break;
183*0Sstevel@tonic-gate 			buf++;
184*0Sstevel@tonic-gate 		}
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 		/*
187*0Sstevel@tonic-gate 		 * If this is the last field, then consider any remaining
188*0Sstevel@tonic-gate 		 * text on the line part of the last field.  This is
189*0Sstevel@tonic-gate 		 * similar to how `read' in sh(1) works.
190*0Sstevel@tonic-gate 		 */
191*0Sstevel@tonic-gate 		if (++i == nfields)
192*0Sstevel@tonic-gate 			return (i);
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 		if (*buf == '\0')
195*0Sstevel@tonic-gate 			return (i);
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 		*buf = '\0';
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 		/*
200*0Sstevel@tonic-gate 		 * If separator is whitespace, then skip all consecutive
201*0Sstevel@tonic-gate 		 * pieces of whitespace.
202*0Sstevel@tonic-gate 		 */
203*0Sstevel@tonic-gate 		while (ch != NULL && isspace(*ch)) {
204*0Sstevel@tonic-gate 			ch = strchr(seps, buf[1]);
205*0Sstevel@tonic-gate 			if (ch != NULL && isspace(*ch))
206*0Sstevel@tonic-gate 				buf++;
207*0Sstevel@tonic-gate 		}
208*0Sstevel@tonic-gate 		buf++;
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*
213*0Sstevel@tonic-gate  * Map a standard errno into a corresponding DSVC_* code.  If there
214*0Sstevel@tonic-gate  * is no translation, default to DSVC_INTERNAL.
215*0Sstevel@tonic-gate  */
216*0Sstevel@tonic-gate int
syserr_to_dsvcerr(int error)217*0Sstevel@tonic-gate syserr_to_dsvcerr(int error)
218*0Sstevel@tonic-gate {
219*0Sstevel@tonic-gate 	switch (error) {
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	case EEXIST:
222*0Sstevel@tonic-gate 		return (DSVC_TABLE_EXISTS);
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	case ENOMEM:
225*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	case ENOSPC:
228*0Sstevel@tonic-gate 		return (DSVC_NO_RESOURCES);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	case EROFS:
231*0Sstevel@tonic-gate 	case EPERM:
232*0Sstevel@tonic-gate 	case EACCES:
233*0Sstevel@tonic-gate 		return (DSVC_ACCESS);
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	case ENOENT:
236*0Sstevel@tonic-gate 		return (DSVC_NO_TABLE);
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	default:
239*0Sstevel@tonic-gate 		break;
240*0Sstevel@tonic-gate 	}
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	return (DSVC_INTERNAL);
243*0Sstevel@tonic-gate }
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate /*
246*0Sstevel@tonic-gate  * Convert an object of `len' bytes pointed to by `srcraw' between
247*0Sstevel@tonic-gate  * network-order and host-order and store in `dstraw'.  The length `len'
248*0Sstevel@tonic-gate  * must be the actual length of the objects pointed to by `srcraw' and
249*0Sstevel@tonic-gate  * `dstraw' (or zero) or the results are undefined.  Note that `srcraw' and
250*0Sstevel@tonic-gate  * `dstraw' may be the same, in which case the object is converted
251*0Sstevel@tonic-gate  * in-place.  This routine will convert from host-order to network-order or
252*0Sstevel@tonic-gate  * network-order to host-order, since the conversion is the same.
253*0Sstevel@tonic-gate  */
254*0Sstevel@tonic-gate void
nhconvert(void * dstraw,const void * srcraw,size_t len)255*0Sstevel@tonic-gate nhconvert(void *dstraw, const void *srcraw, size_t len)
256*0Sstevel@tonic-gate {
257*0Sstevel@tonic-gate #ifdef	_LITTLE_ENDIAN
258*0Sstevel@tonic-gate 	uint8_t	b1, b2;
259*0Sstevel@tonic-gate 	uint8_t *dst, *src;
260*0Sstevel@tonic-gate 	size_t i;
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	/*
263*0Sstevel@tonic-gate 	 * If both `srcraw' and `dstraw' are 32-bit aligned and `len' is 4,
264*0Sstevel@tonic-gate 	 * then use ntohl() to do the byteswap, since it's hand-tuned.
265*0Sstevel@tonic-gate 	 */
266*0Sstevel@tonic-gate 	if (IS_P2ALIGNED(dstraw, 4) && IS_P2ALIGNED(srcraw, 4) && len == 4) {
267*0Sstevel@tonic-gate 		*(uint32_t *)dstraw = ntohl(*(uint32_t *)srcraw);
268*0Sstevel@tonic-gate 		return;
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	dst = (uint8_t *)dstraw;
272*0Sstevel@tonic-gate 	src = (uint8_t *)srcraw;
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	for (i = 0; i < len / 2; i++) {
275*0Sstevel@tonic-gate 		b1 = src[i];
276*0Sstevel@tonic-gate 		b2 = src[len - i - 1];
277*0Sstevel@tonic-gate 		dst[i] = b2;
278*0Sstevel@tonic-gate 		dst[len - i - 1] = b1;
279*0Sstevel@tonic-gate 	}
280*0Sstevel@tonic-gate #else
281*0Sstevel@tonic-gate 	if (srcraw != dstraw)
282*0Sstevel@tonic-gate 		(void) memmove(dstraw, srcraw, len);
283*0Sstevel@tonic-gate #endif
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate /*
287*0Sstevel@tonic-gate  * Positioned n-byte read: read `buflen' bytes at offset `off' at open file
288*0Sstevel@tonic-gate  * `fd' into `buffer', or "read" none at all.  Returns -1 if all `buflen'
289*0Sstevel@tonic-gate  * bytes cannot be read; otherwise, returns 0.
290*0Sstevel@tonic-gate  */
291*0Sstevel@tonic-gate int
pnread(int fd,void * buffer,size_t buflen,off_t off)292*0Sstevel@tonic-gate pnread(int fd, void *buffer, size_t buflen, off_t off)
293*0Sstevel@tonic-gate {
294*0Sstevel@tonic-gate 	size_t	nread;
295*0Sstevel@tonic-gate 	ssize_t	nbytes;
296*0Sstevel@tonic-gate 	char	*buf = buffer;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	for (nread = 0; nread < buflen; nread += nbytes) {
299*0Sstevel@tonic-gate 		nbytes = pread(fd, &buf[nread], buflen - nread, off + nread);
300*0Sstevel@tonic-gate 		if (nbytes == -1)
301*0Sstevel@tonic-gate 			return (-1);
302*0Sstevel@tonic-gate 		if (nbytes == 0) {
303*0Sstevel@tonic-gate 			errno = EIO;
304*0Sstevel@tonic-gate 			return (-1);
305*0Sstevel@tonic-gate 		}
306*0Sstevel@tonic-gate 	}
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	assert(nread == buflen);
309*0Sstevel@tonic-gate 	return (0);
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate /*
313*0Sstevel@tonic-gate  * Positioned n-byte write: write `buflen' bytes from `buffer' to offset
314*0Sstevel@tonic-gate  * `off' in open file `fd'.  Tries to write all `buflen' bytes, but does
315*0Sstevel@tonic-gate  * not attempt to "undo" what it has done in the case of failure.  Returns
316*0Sstevel@tonic-gate  * -1 if all `buflen' bytes cannot be written, otherwise returns 0.
317*0Sstevel@tonic-gate  */
318*0Sstevel@tonic-gate int
pnwrite(int fd,const void * buffer,size_t buflen,off_t off)319*0Sstevel@tonic-gate pnwrite(int fd, const void *buffer, size_t buflen, off_t off)
320*0Sstevel@tonic-gate {
321*0Sstevel@tonic-gate 	size_t		nwritten;
322*0Sstevel@tonic-gate 	ssize_t		nbytes;
323*0Sstevel@tonic-gate 	const char	*buf = buffer;
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
326*0Sstevel@tonic-gate 		nbytes = pwrite(fd, &buf[nwritten], buflen - nwritten,
327*0Sstevel@tonic-gate 		    off + nwritten);
328*0Sstevel@tonic-gate 		if (nbytes == -1)
329*0Sstevel@tonic-gate 			return (-1);
330*0Sstevel@tonic-gate 		if (nbytes == 0) {
331*0Sstevel@tonic-gate 			errno = EIO;
332*0Sstevel@tonic-gate 			return (-1);
333*0Sstevel@tonic-gate 		}
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	assert(nwritten == buflen);
337*0Sstevel@tonic-gate 	return (0);
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate /*
341*0Sstevel@tonic-gate  * Copy `nbytes' efficiently from offset `srcoff' in `srcfd' to offset
342*0Sstevel@tonic-gate  * `dstoff' in `dstfd'; returns a DSVC_* return code.  Note that we make
343*0Sstevel@tonic-gate  * `nbytes' a uint64_t (rather than a size_t) so that we can copy 2^64
344*0Sstevel@tonic-gate  * bits even when compiled ILP32.
345*0Sstevel@tonic-gate  */
346*0Sstevel@tonic-gate int
copy_range(int srcfd,off_t srcoff,int dstfd,off_t dstoff,uint64_t nbytes)347*0Sstevel@tonic-gate copy_range(int srcfd, off_t srcoff, int dstfd, off_t dstoff, uint64_t nbytes)
348*0Sstevel@tonic-gate {
349*0Sstevel@tonic-gate 	const size_t	chunksize = 16 * PAGESIZE;
350*0Sstevel@tonic-gate 	size_t		validsize;
351*0Sstevel@tonic-gate 	size_t		skip;
352*0Sstevel@tonic-gate 	uint64_t	nwritten = 0;
353*0Sstevel@tonic-gate 	int		mflags = MAP_PRIVATE;
354*0Sstevel@tonic-gate 	char		*buf = NULL;
355*0Sstevel@tonic-gate 	int		error;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	/*
358*0Sstevel@tonic-gate 	 * Handle trivial copy specially so we don't call munmap() below.
359*0Sstevel@tonic-gate 	 */
360*0Sstevel@tonic-gate 	if (nbytes == 0)
361*0Sstevel@tonic-gate 		return (DSVC_SUCCESS);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/*
364*0Sstevel@tonic-gate 	 * The `off' argument to mmap(2) must be page-aligned, so align it;
365*0Sstevel@tonic-gate 	 * compute how many bytes we need to skip over in the mmap()'d
366*0Sstevel@tonic-gate 	 * buffer as a result.
367*0Sstevel@tonic-gate 	 */
368*0Sstevel@tonic-gate 	skip = srcoff % PAGESIZE;
369*0Sstevel@tonic-gate 	srcoff -= skip;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	while (nwritten < nbytes) {
372*0Sstevel@tonic-gate 		buf = mmap(buf, chunksize, PROT_READ, mflags, srcfd, srcoff);
373*0Sstevel@tonic-gate 		if (buf == MAP_FAILED)
374*0Sstevel@tonic-gate 			return (DSVC_INTERNAL);
375*0Sstevel@tonic-gate 		mflags |= MAP_FIXED;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		validsize = MIN(chunksize, nbytes - nwritten + skip);
378*0Sstevel@tonic-gate 		if (pnwrite(dstfd, &buf[skip], validsize - skip, dstoff)
379*0Sstevel@tonic-gate 		    == -1) {
380*0Sstevel@tonic-gate 			error = errno;
381*0Sstevel@tonic-gate 			(void) munmap(buf, chunksize);
382*0Sstevel@tonic-gate 			return (syserr_to_dsvcerr(error));
383*0Sstevel@tonic-gate 		}
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 		nwritten += validsize - skip;
386*0Sstevel@tonic-gate 		dstoff += validsize - skip;
387*0Sstevel@tonic-gate 		srcoff += validsize;
388*0Sstevel@tonic-gate 		skip = 0;
389*0Sstevel@tonic-gate 	}
390*0Sstevel@tonic-gate 	(void) munmap(buf, chunksize);
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate /*
396*0Sstevel@tonic-gate  * Unescape all instances of `delimiter' in `buffer' and store result in
397*0Sstevel@tonic-gate  * `unescaped', which is `size' bytes.  To guarantee that all data is
398*0Sstevel@tonic-gate  * copied, `unescaped' should be at least as long as `buffer'.
399*0Sstevel@tonic-gate  */
400*0Sstevel@tonic-gate void
unescape(char delimiter,const char * buffer,char * unescaped,size_t size)401*0Sstevel@tonic-gate unescape(char delimiter, const char *buffer, char *unescaped, size_t size)
402*0Sstevel@tonic-gate {
403*0Sstevel@tonic-gate 	int i, j;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	size--;
406*0Sstevel@tonic-gate 	for (i = 0, j = 0; buffer[i] != '\0' && j < size; i++, j++) {
407*0Sstevel@tonic-gate 		if (buffer[i] == '\\' && buffer[i + 1] == delimiter)
408*0Sstevel@tonic-gate 			i++;
409*0Sstevel@tonic-gate 		unescaped[j] = buffer[i];
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 	unescaped[j] = '\0';
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate  * Escape all instances of `delimiter' in `buffer' and store result in
416*0Sstevel@tonic-gate  * `escaped', which is `size' bytes.  To guarantee that all data is
417*0Sstevel@tonic-gate  * copied, `escaped' should be at least twice as long as `buffer'.
418*0Sstevel@tonic-gate  */
419*0Sstevel@tonic-gate void
escape(char delimiter,const char * buffer,char * escaped,size_t size)420*0Sstevel@tonic-gate escape(char delimiter, const char *buffer, char *escaped, size_t size)
421*0Sstevel@tonic-gate {
422*0Sstevel@tonic-gate 	int i, j;
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	size--;
425*0Sstevel@tonic-gate 	for (i = 0, j = 0; buffer[i] != '\0' && j < size; i++, j++) {
426*0Sstevel@tonic-gate 		if (buffer[i] == delimiter)
427*0Sstevel@tonic-gate 			escaped[j++] = '\\';
428*0Sstevel@tonic-gate 		escaped[j] = buffer[i];
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 	escaped[j] = '\0';
431*0Sstevel@tonic-gate }
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate /*
434*0Sstevel@tonic-gate  * Generate a signature for a new record.  The signature is conceptually
435*0Sstevel@tonic-gate  * divided into two pieces: a random 16-bit "generation number" and a
436*0Sstevel@tonic-gate  * 48-bit monotonically increasing integer.  The generation number protects
437*0Sstevel@tonic-gate  * against stale updates to records that have been deleted and since
438*0Sstevel@tonic-gate  * recreated.
439*0Sstevel@tonic-gate  */
440*0Sstevel@tonic-gate uint64_t
gensig(void)441*0Sstevel@tonic-gate gensig(void)
442*0Sstevel@tonic-gate {
443*0Sstevel@tonic-gate 	static int seeded = 0;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (seeded == 0) {
446*0Sstevel@tonic-gate 		srand48((long)gethrtime());
447*0Sstevel@tonic-gate 		seeded++;
448*0Sstevel@tonic-gate 	}
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	return ((uint64_t)lrand48() << 48 | 1);
451*0Sstevel@tonic-gate }
452