xref: /onnv-gate/usr/src/lib/libdhcpsvc/modules/files/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 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
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 API functions for managing the dhcptab
31*0Sstevel@tonic-gate  * container.  For the semantics of these functions, please see the
32*0Sstevel@tonic-gate  * Enterprise DHCP Architecture Document.
33*0Sstevel@tonic-gate  */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/socket.h>
37*0Sstevel@tonic-gate #include <unistd.h>
38*0Sstevel@tonic-gate #include <netinet/in.h>
39*0Sstevel@tonic-gate #include <sys/stat.h>
40*0Sstevel@tonic-gate #include <fcntl.h>
41*0Sstevel@tonic-gate #include <alloca.h>
42*0Sstevel@tonic-gate #include <stdlib.h>
43*0Sstevel@tonic-gate #include <stdio.h>
44*0Sstevel@tonic-gate #include <string.h>
45*0Sstevel@tonic-gate #include <errno.h>
46*0Sstevel@tonic-gate #include <dhcp_svc_public.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include "dhcptab.h"
49*0Sstevel@tonic-gate #include "util.h"
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate static void dt2path(char *, size_t, const char *, const char *);
52*0Sstevel@tonic-gate static int write_rec(int, dt_rec_t *, off_t);
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate int
open_dt(void ** handlep,const char * location,uint_t flags)55*0Sstevel@tonic-gate open_dt(void **handlep, const char *location, uint_t flags)
56*0Sstevel@tonic-gate {
57*0Sstevel@tonic-gate 	dt_handle_t	*dhp;
58*0Sstevel@tonic-gate 	unsigned int	conver;
59*0Sstevel@tonic-gate 	int		nelems;
60*0Sstevel@tonic-gate 	int		retval;
61*0Sstevel@tonic-gate 	char		nl;
62*0Sstevel@tonic-gate 	int		fd;
63*0Sstevel@tonic-gate 	char		dtpath[MAXPATHLEN];
64*0Sstevel@tonic-gate 	FILE		*fp;
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 	dhp = malloc(sizeof (dt_handle_t));
67*0Sstevel@tonic-gate 	if (dhp == NULL)
68*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	dhp->dh_oflags = flags;
71*0Sstevel@tonic-gate 	(void) strlcpy(dhp->dh_location, location, MAXPATHLEN);
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, location, "");
74*0Sstevel@tonic-gate 	retval = open_file(dtpath, flags, &fd);
75*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS) {
76*0Sstevel@tonic-gate 		free(dhp);
77*0Sstevel@tonic-gate 		return (retval);
78*0Sstevel@tonic-gate 	}
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	fp = fdopen(fd, flags & DSVC_WRITE ? "r+" : "r");
81*0Sstevel@tonic-gate 	if (fp == NULL) {
82*0Sstevel@tonic-gate 		(void) close(fd);
83*0Sstevel@tonic-gate 		free(dhp);
84*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
85*0Sstevel@tonic-gate 	}
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	if (flags & DSVC_CREATE) {
88*0Sstevel@tonic-gate 		/*
89*0Sstevel@tonic-gate 		 * We just created the per-network container; put the
90*0Sstevel@tonic-gate 		 * header on for future use...
91*0Sstevel@tonic-gate 		 */
92*0Sstevel@tonic-gate 		retval = fprintf(fp, "# SUNWfiles%u_dhcptab\n", DSVC_CONVER);
93*0Sstevel@tonic-gate 		if (retval < 0 || fflush(fp) == EOF) {
94*0Sstevel@tonic-gate 			(void) fclose(fp);
95*0Sstevel@tonic-gate 			(void) free(dhp);
96*0Sstevel@tonic-gate 			return (DSVC_INTERNAL);
97*0Sstevel@tonic-gate 		}
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 		(void) fprintf(fp, "#\n# Do NOT edit this file by hand -- use");
100*0Sstevel@tonic-gate 		(void) fprintf(fp, " dhtadm(1M) or dhcpmgr(1M) instead\n#\n");
101*0Sstevel@tonic-gate 	} else {
102*0Sstevel@tonic-gate 		/*
103*0Sstevel@tonic-gate 		 * Container already exists; sanity check against the
104*0Sstevel@tonic-gate 		 * header that's on-disk.
105*0Sstevel@tonic-gate 		 */
106*0Sstevel@tonic-gate 		nelems = fscanf(fp, "#%*1[ ]SUNWfiles%u_dhcptab%c", &conver,
107*0Sstevel@tonic-gate 		    &nl);
108*0Sstevel@tonic-gate 		if (nelems != 2 || conver != DSVC_CONVER || nl != '\n') {
109*0Sstevel@tonic-gate 			(void) fclose(fp);
110*0Sstevel@tonic-gate 			free(dhp);
111*0Sstevel@tonic-gate 			return (DSVC_INTERNAL);
112*0Sstevel@tonic-gate 		}
113*0Sstevel@tonic-gate 	}
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	(void) fclose(fp);
116*0Sstevel@tonic-gate 	*handlep = dhp;
117*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
118*0Sstevel@tonic-gate }
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate int
close_dt(void ** handlep)121*0Sstevel@tonic-gate close_dt(void **handlep)
122*0Sstevel@tonic-gate {
123*0Sstevel@tonic-gate 	free(*handlep);
124*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate int
remove_dt(const char * location)128*0Sstevel@tonic-gate remove_dt(const char *location)
129*0Sstevel@tonic-gate {
130*0Sstevel@tonic-gate 	char dtpath[MAXPATHLEN];
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, location, "");
133*0Sstevel@tonic-gate 	if (unlink(dtpath) == -1)
134*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate /*
140*0Sstevel@tonic-gate  * Internal version of lookup_dt() used by both lookup_dt() and
141*0Sstevel@tonic-gate  * update_dt(); same semantics as lookup_dt() except that the `partial'
142*0Sstevel@tonic-gate  * argument has been generalized into a `flags' field and the handle has
143*0Sstevel@tonic-gate  * been turned into a FILE pointer.
144*0Sstevel@tonic-gate  */
145*0Sstevel@tonic-gate static int
find_dt(FILE * fp,uint_t flags,uint_t query,int count,const dt_rec_t * targetp,dt_rec_list_t ** recordsp,uint_t * nrecordsp)146*0Sstevel@tonic-gate find_dt(FILE *fp, uint_t flags, uint_t query, int count,
147*0Sstevel@tonic-gate     const dt_rec_t *targetp, dt_rec_list_t **recordsp, uint_t *nrecordsp)
148*0Sstevel@tonic-gate {
149*0Sstevel@tonic-gate 	int		retval = DSVC_SUCCESS;
150*0Sstevel@tonic-gate 	char 		*buf = NULL, *fields[DTF_FIELDS];
151*0Sstevel@tonic-gate 	uint_t		nrecords;
152*0Sstevel@tonic-gate 	dt_rec_t	dt, *recordp;
153*0Sstevel@tonic-gate 	dt_rec_list_t	*records, *new_records;
154*0Sstevel@tonic-gate 	off_t		recoff;
155*0Sstevel@tonic-gate 	unsigned int	nfields;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	if (fseek(fp, 0, SEEK_SET) == -1)
158*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	records = NULL;
161*0Sstevel@tonic-gate 	for (nrecords = 0; count < 0 || nrecords < count; ) {
162*0Sstevel@tonic-gate 		free(buf);
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 		if (flags & FIND_POSITION)
165*0Sstevel@tonic-gate 			recoff = ftello(fp);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 		buf = read_entry(fp);
168*0Sstevel@tonic-gate 		if (buf == NULL) {
169*0Sstevel@tonic-gate 			if (!feof(fp))
170*0Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
171*0Sstevel@tonic-gate 			break;
172*0Sstevel@tonic-gate 		}
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 		/*
175*0Sstevel@tonic-gate 		 * Skip pure comment lines; for now this just skips the
176*0Sstevel@tonic-gate 		 * header information at the top of the container.
177*0Sstevel@tonic-gate 		 */
178*0Sstevel@tonic-gate 		if (buf[0] == DTF_COMMENT_CHAR)
179*0Sstevel@tonic-gate 			continue;
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 		/*
182*0Sstevel@tonic-gate 		 * Split the buffer up into DTF_FIELDS fields.
183*0Sstevel@tonic-gate 		 */
184*0Sstevel@tonic-gate 		nfields = field_split(buf, DTF_FIELDS, fields, "|");
185*0Sstevel@tonic-gate 		if (nfields < DTF_FIELDS)
186*0Sstevel@tonic-gate 			continue;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 		/*
189*0Sstevel@tonic-gate 		 * See if we've got a match.  If so, allocate the new
190*0Sstevel@tonic-gate 		 * record, fill it in, and continue.
191*0Sstevel@tonic-gate 		 */
192*0Sstevel@tonic-gate 		dt.dt_type = fields[DTF_TYPE][0];
193*0Sstevel@tonic-gate 		if (DSVC_QISEQ(query, DT_QTYPE) &&
194*0Sstevel@tonic-gate 		    targetp->dt_type != dt.dt_type)
195*0Sstevel@tonic-gate 			continue;
196*0Sstevel@tonic-gate 		else if (DSVC_QISNEQ(query, DT_QTYPE) &&
197*0Sstevel@tonic-gate 		    targetp->dt_type == dt.dt_type)
198*0Sstevel@tonic-gate 			continue;
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 		unescape('|', fields[DTF_KEY], dt.dt_key, sizeof (dt.dt_key));
201*0Sstevel@tonic-gate 		if (DSVC_QISEQ(query, DT_QKEY) &&
202*0Sstevel@tonic-gate 		    strcmp(targetp->dt_key, dt.dt_key) != 0)
203*0Sstevel@tonic-gate 			continue;
204*0Sstevel@tonic-gate 		else if (DSVC_QISNEQ(query, DT_QKEY) &&
205*0Sstevel@tonic-gate 		    strcmp(targetp->dt_key, dt.dt_key) == 0)
206*0Sstevel@tonic-gate 			continue;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 		/*
209*0Sstevel@tonic-gate 		 * Caller just wants a count of the number of matching
210*0Sstevel@tonic-gate 		 * records, not the records themselves; continue.
211*0Sstevel@tonic-gate 		 */
212*0Sstevel@tonic-gate 		if (recordsp == NULL) {
213*0Sstevel@tonic-gate 			nrecords++;
214*0Sstevel@tonic-gate 			continue;
215*0Sstevel@tonic-gate 		}
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 		dt.dt_sig = atoll(fields[DTF_SIG]);
218*0Sstevel@tonic-gate 		dt.dt_value = strdup(fields[DTF_VALUE]);
219*0Sstevel@tonic-gate 		if (dt.dt_value == NULL) {
220*0Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
221*0Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
222*0Sstevel@tonic-gate 			break;
223*0Sstevel@tonic-gate 		}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 		/*
226*0Sstevel@tonic-gate 		 * Allocate record; if FIND_POSITION flag is set, then
227*0Sstevel@tonic-gate 		 * we need to allocate an extended (dt_recpos_t) record.
228*0Sstevel@tonic-gate 		 */
229*0Sstevel@tonic-gate 		if (flags & FIND_POSITION)
230*0Sstevel@tonic-gate 			recordp = malloc(sizeof (dt_recpos_t));
231*0Sstevel@tonic-gate 		else
232*0Sstevel@tonic-gate 			recordp = malloc(sizeof (dt_rec_t));
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 		if (recordp == NULL) {
235*0Sstevel@tonic-gate 			free(dt.dt_value);
236*0Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
237*0Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
238*0Sstevel@tonic-gate 			break;
239*0Sstevel@tonic-gate 		}
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 		/*
242*0Sstevel@tonic-gate 		 * Fill in record; do a structure copy from our automatic
243*0Sstevel@tonic-gate 		 * dt.  If FIND_POSITION flag is on, pass back additional
244*0Sstevel@tonic-gate 		 * location information.
245*0Sstevel@tonic-gate 		 */
246*0Sstevel@tonic-gate 		*recordp = dt;
247*0Sstevel@tonic-gate 		if (flags & FIND_POSITION) {
248*0Sstevel@tonic-gate 			((dt_recpos_t *)recordp)->dtp_off = recoff;
249*0Sstevel@tonic-gate 			((dt_recpos_t *)recordp)->dtp_size = ftello(fp) -
250*0Sstevel@tonic-gate 			    recoff;
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 		/*
254*0Sstevel@tonic-gate 		 * Chuck the record on the list; up the counter.
255*0Sstevel@tonic-gate 		 */
256*0Sstevel@tonic-gate 		new_records = add_dtrec_to_list(recordp, records);
257*0Sstevel@tonic-gate 		if (new_records == NULL) {
258*0Sstevel@tonic-gate 			free_dtrec(recordp);
259*0Sstevel@tonic-gate 			if ((flags & FIND_PARTIAL) == 0)
260*0Sstevel@tonic-gate 				retval = DSVC_NO_MEMORY;
261*0Sstevel@tonic-gate 			break;
262*0Sstevel@tonic-gate 		}
263*0Sstevel@tonic-gate 		records = new_records;
264*0Sstevel@tonic-gate 		nrecords++;
265*0Sstevel@tonic-gate 	}
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	free(buf);
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	if (retval == DSVC_SUCCESS) {
270*0Sstevel@tonic-gate 		*nrecordsp = nrecords;
271*0Sstevel@tonic-gate 		if (recordsp != NULL)
272*0Sstevel@tonic-gate 			*recordsp = records;
273*0Sstevel@tonic-gate 		return (DSVC_SUCCESS);
274*0Sstevel@tonic-gate 	}
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	if (records != NULL)
277*0Sstevel@tonic-gate 		free_dtrec_list(records);
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	return (retval);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*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)283*0Sstevel@tonic-gate lookup_dt(void *handle, boolean_t partial, uint_t query, int count,
284*0Sstevel@tonic-gate     const dt_rec_t *targetp, dt_rec_list_t **recordsp, uint_t *nrecordsp)
285*0Sstevel@tonic-gate {
286*0Sstevel@tonic-gate 	int		retval;
287*0Sstevel@tonic-gate 	char		dtpath[MAXPATHLEN];
288*0Sstevel@tonic-gate 	FILE		*fp;
289*0Sstevel@tonic-gate 	dt_handle_t	*dhp = (dt_handle_t *)handle;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_READ) == 0)
292*0Sstevel@tonic-gate 		return (DSVC_ACCESS);
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, dhp->dh_location, "");
295*0Sstevel@tonic-gate 	fp = fopen(dtpath, "r");
296*0Sstevel@tonic-gate 	if (fp == NULL)
297*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	retval = find_dt(fp, partial ? FIND_PARTIAL : 0, query, count, targetp,
300*0Sstevel@tonic-gate 	    recordsp, nrecordsp);
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	(void) fclose(fp);
303*0Sstevel@tonic-gate 	return (retval);
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate /*
307*0Sstevel@tonic-gate  * Internal dhcptab record update routine, used to factor out the
308*0Sstevel@tonic-gate  * common code between add_dt(), delete_dt(), and modify_dt().  If
309*0Sstevel@tonic-gate  * `origp' is NULL, then act like add_dt(); if `newp' is NULL, then
310*0Sstevel@tonic-gate  * act like delete_dt(); otherwise act like modify_dt().
311*0Sstevel@tonic-gate  */
312*0Sstevel@tonic-gate static int
update_dt(const dt_handle_t * dhp,const dt_rec_t * origp,dt_rec_t * newp)313*0Sstevel@tonic-gate update_dt(const dt_handle_t *dhp, const dt_rec_t *origp, dt_rec_t *newp)
314*0Sstevel@tonic-gate {
315*0Sstevel@tonic-gate 	char		dtpath[MAXPATHLEN], newpath[MAXPATHLEN];
316*0Sstevel@tonic-gate 	int		retval = DSVC_SUCCESS;
317*0Sstevel@tonic-gate 	off_t		recoff, recnext;
318*0Sstevel@tonic-gate 	dt_rec_list_t	*reclist;
319*0Sstevel@tonic-gate 	FILE		*fp;
320*0Sstevel@tonic-gate 	int		newfd;
321*0Sstevel@tonic-gate 	uint_t		found;
322*0Sstevel@tonic-gate 	int		query;
323*0Sstevel@tonic-gate 	struct stat	st;
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	if ((dhp->dh_oflags & DSVC_WRITE) == 0)
326*0Sstevel@tonic-gate 		return (DSVC_ACCESS);
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	/*
329*0Sstevel@tonic-gate 	 * Open the container to update and a new container file which we
330*0Sstevel@tonic-gate 	 * will store the updated version of the container in.  When the
331*0Sstevel@tonic-gate 	 * update is done, rename the new file to be the real container.
332*0Sstevel@tonic-gate 	 */
333*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, dhp->dh_location, "");
334*0Sstevel@tonic-gate 	fp = fopen(dtpath, "r");
335*0Sstevel@tonic-gate 	if (fp == NULL)
336*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	dt2path(newpath, MAXPATHLEN, dhp->dh_location, ".new");
339*0Sstevel@tonic-gate 	(void) unlink(newpath);
340*0Sstevel@tonic-gate 	newfd = open(newpath, O_CREAT|O_EXCL|O_WRONLY, 0644);
341*0Sstevel@tonic-gate 	if (newfd == -1) {
342*0Sstevel@tonic-gate 		(void) fclose(fp);
343*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
344*0Sstevel@tonic-gate 	}
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	DSVC_QINIT(query);
347*0Sstevel@tonic-gate 	DSVC_QEQ(query, DT_QKEY|DT_QTYPE);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	/*
350*0Sstevel@tonic-gate 	 * If we're changing the key for this record, make sure the key
351*0Sstevel@tonic-gate 	 * we're changing to doesn't already exist.
352*0Sstevel@tonic-gate 	 */
353*0Sstevel@tonic-gate 	if (origp != NULL && newp != NULL) {
354*0Sstevel@tonic-gate 		if ((origp->dt_type != newp->dt_type ||
355*0Sstevel@tonic-gate 		    strcmp(origp->dt_key, newp->dt_key) != 0)) {
356*0Sstevel@tonic-gate 			retval = find_dt(fp, 0, query, 1, newp, NULL, &found);
357*0Sstevel@tonic-gate 			if (retval != DSVC_SUCCESS)
358*0Sstevel@tonic-gate 				goto out;
359*0Sstevel@tonic-gate 			if (found != 0) {
360*0Sstevel@tonic-gate 				retval = DSVC_EXISTS;
361*0Sstevel@tonic-gate 				goto out;
362*0Sstevel@tonic-gate 			}
363*0Sstevel@tonic-gate 		}
364*0Sstevel@tonic-gate 	}
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/*
367*0Sstevel@tonic-gate 	 * If we're adding a new record, make sure the record doesn't
368*0Sstevel@tonic-gate 	 * already exist.
369*0Sstevel@tonic-gate 	 */
370*0Sstevel@tonic-gate 	if (newp != NULL && origp == NULL) {
371*0Sstevel@tonic-gate 		retval = find_dt(fp, 0, query, 1, newp, NULL, &found);
372*0Sstevel@tonic-gate 		if (retval != DSVC_SUCCESS)
373*0Sstevel@tonic-gate 			goto out;
374*0Sstevel@tonic-gate 		if (found != 0) {
375*0Sstevel@tonic-gate 			retval = DSVC_EXISTS;
376*0Sstevel@tonic-gate 			goto out;
377*0Sstevel@tonic-gate 		}
378*0Sstevel@tonic-gate 	}
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	/*
381*0Sstevel@tonic-gate 	 * If we're deleting or modifying record, make sure the record
382*0Sstevel@tonic-gate 	 * still exists and that our copy isn't stale.  Note that we don't
383*0Sstevel@tonic-gate 	 * check signatures if we're deleting the record and origp->dt_sig
384*0Sstevel@tonic-gate 	 * is zero, so that records can be deleted that weren't looked up
385*0Sstevel@tonic-gate 	 * first.
386*0Sstevel@tonic-gate 	 */
387*0Sstevel@tonic-gate 	if (origp != NULL) {
388*0Sstevel@tonic-gate 		retval = find_dt(fp, FIND_POSITION, query, 1, origp, &reclist,
389*0Sstevel@tonic-gate 		    &found);
390*0Sstevel@tonic-gate 		if (retval != DSVC_SUCCESS)
391*0Sstevel@tonic-gate 			goto out;
392*0Sstevel@tonic-gate 		if (found == 0) {
393*0Sstevel@tonic-gate 			retval = DSVC_NOENT;
394*0Sstevel@tonic-gate 			goto out;
395*0Sstevel@tonic-gate 		}
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 		if (reclist->dtl_rec->dt_sig != origp->dt_sig) {
398*0Sstevel@tonic-gate 			if (newp != NULL || origp->dt_sig != 0) {
399*0Sstevel@tonic-gate 				free_dtrec_list(reclist);
400*0Sstevel@tonic-gate 				retval = DSVC_COLLISION;
401*0Sstevel@tonic-gate 				goto out;
402*0Sstevel@tonic-gate 			}
403*0Sstevel@tonic-gate 		}
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 		/*
406*0Sstevel@tonic-gate 		 * Note the offset of the record we're modifying or deleting
407*0Sstevel@tonic-gate 		 * for use down below.
408*0Sstevel@tonic-gate 		 */
409*0Sstevel@tonic-gate 		recoff  = ((dt_recpos_t *)reclist->dtl_rec)->dtp_off;
410*0Sstevel@tonic-gate 		recnext = recoff + ((dt_recpos_t *)reclist->dtl_rec)->dtp_size;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 		free_dtrec_list(reclist);
413*0Sstevel@tonic-gate 	} else {
414*0Sstevel@tonic-gate 		/*
415*0Sstevel@tonic-gate 		 * No record to modify or delete, so set `recoff' and
416*0Sstevel@tonic-gate 		 * `recnext' appropriately.
417*0Sstevel@tonic-gate 		 */
418*0Sstevel@tonic-gate 		recoff = 0;
419*0Sstevel@tonic-gate 		recnext = 0;
420*0Sstevel@tonic-gate 	}
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	/*
423*0Sstevel@tonic-gate 	 * Make a new copy of the container.  If we're deleting or
424*0Sstevel@tonic-gate 	 * modifying a record, don't copy that record to the new container.
425*0Sstevel@tonic-gate 	 */
426*0Sstevel@tonic-gate 	if (fstat(fileno(fp), &st) == -1) {
427*0Sstevel@tonic-gate 		retval = DSVC_INTERNAL;
428*0Sstevel@tonic-gate 		goto out;
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	retval = copy_range(fileno(fp), 0, newfd, 0, recoff);
432*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
433*0Sstevel@tonic-gate 		goto out;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	retval = copy_range(fileno(fp), recnext, newfd, recoff,
436*0Sstevel@tonic-gate 	    st.st_size - recnext);
437*0Sstevel@tonic-gate 	if (retval != DSVC_SUCCESS)
438*0Sstevel@tonic-gate 		goto out;
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	/*
441*0Sstevel@tonic-gate 	 * If there's a new record, append it to the new container.
442*0Sstevel@tonic-gate 	 */
443*0Sstevel@tonic-gate 	if (newp != NULL) {
444*0Sstevel@tonic-gate 		if (origp == NULL)
445*0Sstevel@tonic-gate 			newp->dt_sig = gensig();
446*0Sstevel@tonic-gate 		else
447*0Sstevel@tonic-gate 			newp->dt_sig = origp->dt_sig + 1;
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 		if (fstat(newfd, &st) == -1) {
450*0Sstevel@tonic-gate 			retval = DSVC_INTERNAL;
451*0Sstevel@tonic-gate 			goto out;
452*0Sstevel@tonic-gate 		}
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 		retval = write_rec(newfd, newp, st.st_size);
455*0Sstevel@tonic-gate 		if (retval != DSVC_SUCCESS)
456*0Sstevel@tonic-gate 			goto out;
457*0Sstevel@tonic-gate 	}
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	/*
460*0Sstevel@tonic-gate 	 * Note: we close these descriptors before the rename(2) (rather
461*0Sstevel@tonic-gate 	 * than just having the `out:' label clean them up) to save NFS
462*0Sstevel@tonic-gate 	 * some work (otherwise, NFS has to save `dnpath' to an alternate
463*0Sstevel@tonic-gate 	 * name since its vnode would still be active).
464*0Sstevel@tonic-gate 	 */
465*0Sstevel@tonic-gate 	(void) fclose(fp);
466*0Sstevel@tonic-gate 	(void) close(newfd);
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate 	if (rename(newpath, dtpath) == -1)
469*0Sstevel@tonic-gate 		retval = syserr_to_dsvcerr(errno);
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	return (retval);
472*0Sstevel@tonic-gate out:
473*0Sstevel@tonic-gate 	(void) fclose(fp);
474*0Sstevel@tonic-gate 	(void) close(newfd);
475*0Sstevel@tonic-gate 	(void) unlink(newpath);
476*0Sstevel@tonic-gate 	return (retval);
477*0Sstevel@tonic-gate }
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate int
delete_dt(void * handle,const dt_rec_t * delp)480*0Sstevel@tonic-gate delete_dt(void *handle, const dt_rec_t *delp)
481*0Sstevel@tonic-gate {
482*0Sstevel@tonic-gate 	return (update_dt((dt_handle_t *)handle, delp, NULL));
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate int
add_dt(void * handle,dt_rec_t * addp)486*0Sstevel@tonic-gate add_dt(void *handle, dt_rec_t *addp)
487*0Sstevel@tonic-gate {
488*0Sstevel@tonic-gate 	return (update_dt((dt_handle_t *)handle, NULL, addp));
489*0Sstevel@tonic-gate }
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate int
modify_dt(void * handle,const dt_rec_t * origp,dt_rec_t * newp)492*0Sstevel@tonic-gate modify_dt(void *handle, const dt_rec_t *origp, dt_rec_t *newp)
493*0Sstevel@tonic-gate {
494*0Sstevel@tonic-gate 	return (update_dt((dt_handle_t *)handle, origp, newp));
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate int
list_dt(const char * location,char *** listppp,uint_t * countp)498*0Sstevel@tonic-gate list_dt(const char *location, char ***listppp, uint_t *countp)
499*0Sstevel@tonic-gate {
500*0Sstevel@tonic-gate 	char	dtpath[MAXPATHLEN];
501*0Sstevel@tonic-gate 	char	**listpp;
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	if (access(location, F_OK|R_OK) == -1) {
504*0Sstevel@tonic-gate 		switch (errno) {
505*0Sstevel@tonic-gate 		case EACCES:
506*0Sstevel@tonic-gate 		case EPERM:
507*0Sstevel@tonic-gate 			return (DSVC_ACCESS);
508*0Sstevel@tonic-gate 		case ENOENT:
509*0Sstevel@tonic-gate 			return (DSVC_NO_LOCATION);
510*0Sstevel@tonic-gate 		default:
511*0Sstevel@tonic-gate 			break;
512*0Sstevel@tonic-gate 		}
513*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
514*0Sstevel@tonic-gate 	}
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	dt2path(dtpath, MAXPATHLEN, location, "");
517*0Sstevel@tonic-gate 	if (access(dtpath, F_OK|R_OK) == -1) {
518*0Sstevel@tonic-gate 		*countp = 0;
519*0Sstevel@tonic-gate 		*listppp = NULL;
520*0Sstevel@tonic-gate 		return (DSVC_SUCCESS);
521*0Sstevel@tonic-gate 	}
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	listpp = malloc(sizeof (char **));
524*0Sstevel@tonic-gate 	if (listpp == NULL)
525*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
526*0Sstevel@tonic-gate 	listpp[0] = strdup(DT_DHCPTAB);
527*0Sstevel@tonic-gate 	if (listpp[0] == NULL) {
528*0Sstevel@tonic-gate 		free(listpp);
529*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
530*0Sstevel@tonic-gate 	}
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	*listppp = listpp;
533*0Sstevel@tonic-gate 	*countp = 1;
534*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
535*0Sstevel@tonic-gate }
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate /*
538*0Sstevel@tonic-gate  * Given a buffer `path' of `pathlen' bytes, fill it in with a path to the
539*0Sstevel@tonic-gate  * dhcptab in directory `dir' with a suffix of `suffix'.
540*0Sstevel@tonic-gate  */
541*0Sstevel@tonic-gate static void
dt2path(char * path,size_t pathlen,const char * dir,const char * suffix)542*0Sstevel@tonic-gate dt2path(char *path, size_t pathlen, const char *dir, const char *suffix)
543*0Sstevel@tonic-gate {
544*0Sstevel@tonic-gate 	(void) snprintf(path, pathlen, "%s/SUNWfiles%u_%s%s", dir,
545*0Sstevel@tonic-gate 	    DSVC_CONVER, DT_DHCPTAB, suffix);
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate /*
549*0Sstevel@tonic-gate  * Write the dt_rec_t pointed to by `recp' into the open container `fd' at
550*0Sstevel@tonic-gate  * offset `recoff'.  Returns DSVC_* error code.
551*0Sstevel@tonic-gate  */
552*0Sstevel@tonic-gate static int
write_rec(int fd,dt_rec_t * recp,off_t recoff)553*0Sstevel@tonic-gate write_rec(int fd, dt_rec_t *recp, off_t recoff)
554*0Sstevel@tonic-gate {
555*0Sstevel@tonic-gate 	char	escaped_key[DSVC_MAX_MACSYM_LEN * 2 + 1];
556*0Sstevel@tonic-gate 	char	entbuf[1024], *ent = entbuf;
557*0Sstevel@tonic-gate 	size_t	entsize = sizeof (entbuf);
558*0Sstevel@tonic-gate 	int	entlen;
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	escape('|', recp->dt_key, escaped_key, sizeof (escaped_key));
561*0Sstevel@tonic-gate again:
562*0Sstevel@tonic-gate 	entlen = snprintf(ent, entsize, "%s|%c|%llu|%s\n", escaped_key,
563*0Sstevel@tonic-gate 	    recp->dt_type, recp->dt_sig, recp->dt_value);
564*0Sstevel@tonic-gate 	if (entlen == -1)
565*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	if (entlen > entsize) {
568*0Sstevel@tonic-gate 		entsize = entlen;
569*0Sstevel@tonic-gate 		ent = alloca(entlen);
570*0Sstevel@tonic-gate 		goto again;
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	if (pnwrite(fd, ent, entlen, recoff) == -1)
574*0Sstevel@tonic-gate 		return (syserr_to_dsvcerr(errno));
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
577*0Sstevel@tonic-gate }
578