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