xref: /onnv-gate/usr/src/lib/libdhcpsvc/tests/test_private.c (revision 0:68f95e015346)
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) 2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <alloca.h>
32 #include <strings.h>
33 #include <sys/types.h>
34 #include <arpa/inet.h>
35 #include <sys/socket.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <dhcp_svc_confopt.h>
39 #include <dhcp_svc_private.h>
40 #include <dhcp_svc_public.h>
41 #include <libinetutil.h>
42 
43 /*
44  * Argument: resource, and path in that resource.
45  */
46 int
main(int argc,char * argv[])47 main(int argc, char *argv[])
48 {
49 	int			nmods, i, error;
50 	boolean_t		dsp_valid = B_FALSE;
51 	char			**mods, **listpp;
52 	uint32_t		count;
53 	dsvc_datastore_t	dsp;
54 	dsvc_handle_t		handle;
55 	char			cid[DN_MAX_CID_LEN * 2 + 1];
56 	uint_t			cidlen;
57 	char			cip[INET_ADDRSTRLEN], sip[INET_ADDRSTRLEN];
58 	uint32_t		query;
59 	dt_rec_t		dt, *dtp, *ntp;
60 	dt_rec_list_t		*resdtp, *wtp;
61 	dn_rec_t		dn, *dnp;
62 	dn_rec_list_t		*resdnp, *wnp;
63 
64 	if (argc != 3) {
65 		(void) fprintf(stderr, "Usage: %s <resource> <path>\n",
66 		    argv[0]);
67 		return (1);
68 	}
69 
70 	/* enumerate_dd() */
71 	(void) printf("enumerate_dd: ... ");
72 	error = enumerate_dd(&mods, &nmods);
73 	(void) printf("%s\n", dhcpsvc_errmsg(error));
74 
75 	if (error != DSVC_SUCCESS)
76 		return (1);
77 
78 	(void) printf("enumerate_dd: count of modules: %d\n", nmods);
79 	for (i = 0; i < nmods; i++) {
80 		(void) printf("    %d is: %s\n", i, mods[i]);
81 		if (strcmp(argv[1], mods[i]) == 0) {
82 			dsp.d_location = argv[2];
83 			dsp.d_resource = strdup(mods[i]);
84 			dsp.d_conver = DSVC_CUR_CONVER;
85 			dsp_valid = B_TRUE;
86 		}
87 		free(mods[i]);
88 	}
89 	free(mods);
90 
91 	if (!dsp_valid) {
92 		(void) printf("%s: no module for resource `%s'\n", argv[0],
93 		    argv[1]);
94 		return (1);
95 	}
96 
97 	(void) printf("\nstarting testing on %s, tables @ %s\n",
98 	    argv[1], argv[2]);
99 
100 	/*
101 	 * Using the datastore struct we built from arguments, begin poking
102 	 * at the user selected public module.
103 	 */
104 
105 	/* status_dd */
106 	(void) printf("status_dd: ... ");
107 	error = status_dd(&dsp);
108 	(void) printf("%s\n", dhcpsvc_errmsg(error));
109 
110 	(void) printf("Datastore version is %d\n", dsp.d_conver);
111 
112 	/* mklocation_dd */
113 	(void) printf("mklocation_dd of %s: ... ", dsp.d_location);
114 	error = mklocation_dd(&dsp);
115 	(void) printf("%s\n", dhcpsvc_errmsg(error));
116 
117 	/* list_dd - dhcptab */
118 	(void) printf("\nlist_dd of dhcptab containers: ... ");
119 	error = list_dd(&dsp, DSVC_DHCPTAB, &listpp, &count);
120 	(void) printf("    %s\n", dhcpsvc_errmsg(error));
121 	if (error == DSVC_SUCCESS) {
122 		(void) printf("    %d dhcptab container(s): ", count);
123 		for (i = 0; i < count; i++) {
124 			(void) printf("%s ", listpp[i] != NULL ?
125 			    listpp[i] : "NULL");
126 			free(listpp[i]);
127 		}
128 		(void) printf("\n");
129 		free(listpp);
130 	} else {
131 		(void) printf("list_dd: listpp: 0x%p, count: %d\n",
132 		    (void *)listpp, count);
133 	}
134 
135 	/* open_dd - dhcptab (create) */
136 	(void) printf("open_dd: dhcptab: ... ");
137 	error = open_dd(&handle, &dsp, DSVC_DHCPTAB, "dhcptab",
138 	    DSVC_CREATE | DSVC_READ | DSVC_WRITE);
139 	(void) printf("%s\n", dhcpsvc_errmsg(error));
140 	if (error != DSVC_SUCCESS)
141 		return (1);
142 
143 	/* add_dd_entry - dhcptab */
144 	{
145 		dt_rec_t recs[5];
146 
147 		(void) strcpy(recs[0].dt_key, "172.21.0.0");
148 		recs[0].dt_type = DT_MACRO;
149 		recs[0].dt_value = ":Router=172.21.0.1:Subnet=255.255.0.0:";
150 
151 		(void) strcpy(recs[1].dt_key, "172.20.64.0");
152 		recs[1].dt_type = DT_MACRO;
153 		recs[1].dt_value =
154 		    ":Router=172.20.64.2:Subnet=255.255.255.192:";
155 
156 		(void) strcpy(recs[2].dt_key, "172.20.64.64");
157 		recs[2].dt_type = DT_MACRO;
158 		recs[2].dt_value =
159 		    ":Router=172.20.64.65:Subnet=255.255.255.192:";
160 
161 		(void) strcpy(recs[3].dt_key, "172.20.64.128");
162 		recs[3].dt_type = DT_MACRO;
163 		recs[3].dt_value =
164 		    ":Router=172.20.64.129:Subnet=255.255.255.128:";
165 
166 		(void) strcpy(recs[4].dt_key, "172.22.0.0");
167 		recs[4].dt_type = DT_MACRO;
168 		recs[4].dt_value =
169 		    ":Router=172.22.0.1:Subnet=255.255.0.0:MTU=4532:";
170 
171 		(void) printf("add_dd_entry: ... key type value\n");
172 		for (i = 0; i < sizeof (recs) / sizeof (dt_rec_t); i++) {
173 			(void) printf("    %s %c %s ... ",
174 			    recs[i].dt_key, recs[i].dt_type, recs[i].dt_value);
175 			error = add_dd_entry(handle, &recs[i]);
176 			(void) printf("%s\n", dhcpsvc_errmsg(error));
177 			if (error != DSVC_SUCCESS)
178 				break;
179 		}
180 	}
181 
182 	/* lookup_dd - dhcptab - macro called '172.20.64.128', then delete it */
183 
184 	DSVC_QINIT(query);
185 	DSVC_QEQ(query, DT_QKEY);
186 	DSVC_QEQ(query, DT_QTYPE);
187 
188 	(void) memset(&dt, 0, sizeof (dt));
189 	(void) strcpy(dt.dt_key, "172.20.64.128");
190 	dt.dt_type = 'm';
191 
192 	(void) printf("lookup_dd: macro %s ... ", dt.dt_key);
193 	error = lookup_dd(handle, B_FALSE, query, -1, &dt, (void **)&resdtp,
194 	    &count);
195 	(void) printf("%s\n", dhcpsvc_errmsg(error));
196 
197 	if (error == DSVC_SUCCESS) {
198 		if (count != 1) {
199 			(void) printf("lookup_dd: expected 1 record,  got %d\n",
200 			    count);
201 		}
202 
203 		for (i = 0, wtp = resdtp; i < count && wtp != NULL; i++) {
204 			dtp = wtp->dtl_rec;
205 			(void) printf("    %s %c %s\n",
206 			    dtp->dt_key, dtp->dt_type, dtp->dt_value);
207 			wtp = wtp->dtl_next;
208 		}
209 		free_dd_list(handle, resdtp);
210 	}
211 
212 	/* Delete it */
213 	(void) printf("delete_dd_entry: %s ... ", dt.dt_key);
214 	error = delete_dd_entry(handle, &dt);
215 	(void) printf("%s\n", dhcpsvc_errmsg(error));
216 
217 
218 	/*
219 	 * lookup_dd - dhcptab - macro called '172.21.0.0', and modify its
220 	 * definition and replace the value.
221 	 */
222 
223 	DSVC_QINIT(query);
224 	DSVC_QEQ(query, DT_QKEY);
225 
226 	(void) memset(&dt, 0, sizeof (dt));
227 	(void) strcpy(dt.dt_key, "172.21.0.0");
228 
229 	(void) printf("lookup_dd: macro %s ... ", dt.dt_key);
230 	error = lookup_dd(handle, B_FALSE, query, 1, &dt, (void **)&resdtp,
231 	    &count);
232 	(void) printf("%s\n", dhcpsvc_errmsg(error));
233 
234 	if (error == DSVC_SUCCESS) {
235 		if (count != 1) {
236 			(void) printf("lookup_dd: expected 1 record, "
237 			    "got %d\n", count);
238 		} else {
239 			dtp = resdtp->dtl_rec;
240 			(void) printf("    %s %c %s\n", dtp->dt_key,
241 			    dtp->dt_type, dtp->dt_value);
242 
243 			ntp = alloc_dtrec(dtp->dt_key, dtp->dt_type,
244 			    ":Subnet=255.255.0.0:Router=172.21.0.1 "
245 			    "172.21.0.2:MTU=1500:");
246 			if (ntp != NULL) {
247 				ntp->dt_sig = dtp->dt_sig;
248 
249 				/* Modify it */
250 				(void) printf("modify_dd_entry: macro %s ... ",
251 				    dt.dt_key);
252 				error = modify_dd_entry(handle, dtp, ntp);
253 				(void) printf("%s\n", dhcpsvc_errmsg(error));
254 				free_dd(handle, ntp);
255 			}
256 		}
257 		free_dd_list(handle, resdtp);
258 	}
259 
260 	/* lookup_dd - all records */
261 
262 	DSVC_QINIT(query);
263 
264 	(void) printf("lookup_dd: all records ... ");
265 	error = lookup_dd(handle, B_FALSE, query, -1, &dt, (void **)&resdtp,
266 	    &count);
267 	(void) printf("%s\n", dhcpsvc_errmsg(error));
268 	if (error == DSVC_SUCCESS) {
269 		for (i = 0, wtp = resdtp; i < count && wtp != NULL; i++) {
270 			dtp = wtp->dtl_rec;
271 			(void) printf("    %s %c %s\n", dtp->dt_key,
272 			    dtp->dt_type, dtp->dt_value);
273 			wtp = wtp->dtl_next;
274 		}
275 		free_dd_list(handle, resdtp);
276 	}
277 
278 	/* close_dd - dhcptab */
279 	(void) printf("close_dd: dhcptab ... ");
280 	error = close_dd(&handle);
281 	(void) printf("%s\n", dhcpsvc_errmsg(error));
282 
283 	/* list_dd - dhcp network containers */
284 	(void) printf("list_dd: dhcptab ... ");
285 	error = list_dd(&dsp, DSVC_DHCPTAB, &listpp, &count);
286 	(void) printf("%s\n", dhcpsvc_errmsg(error));
287 	if (error == DSVC_SUCCESS) {
288 		(void) printf("    %d dhcp network container(s): ", count);
289 		for (i = 0; i < count; i++) {
290 			(void) printf("%s ", listpp[i] != NULL ?
291 			    listpp[i] : "NULL");
292 			free(listpp[i]);
293 		}
294 		free(listpp);
295 		(void) printf("\n");
296 	} else {
297 		(void) printf("list_dd: listpp: 0x%p, count: %d\n",
298 		    (void *)listpp, count);
299 	}
300 
301 	/* remove_dd - dhcptab */
302 	(void) printf("remove_dd: dhcptab ... ");
303 	error = remove_dd(&dsp, DSVC_DHCPTAB, NULL);
304 	(void) printf("%s\n", dhcpsvc_errmsg(error));
305 
306 	/* open_dd - 129.148.5.0 create */
307 	(void) printf("\nopen_dd: 129.148.5.0: ... ");
308 	error = open_dd(&handle, &dsp, DSVC_DHCPNETWORK, "129.148.5.0",
309 	    DSVC_CREATE | DSVC_READ | DSVC_WRITE);
310 	(void) printf("%s\n", dhcpsvc_errmsg(error));
311 	if (error  != DSVC_SUCCESS)
312 		return (1);
313 
314 	/* add_dd_entry - 129.148.5.0 */
315 	{
316 		uchar_t cid0[7] = { 0x01, 0x08, 0x00, 0x20, 0x00, 0x00, 0x01 };
317 		dn_rec_t recs[5] = { 0 };
318 
319 		recs[0].dn_cid_len = sizeof (cid0);
320 		recs[0].dn_flags = 2;
321 		recs[0].dn_cip.s_addr = 0x81940502;
322 		recs[0].dn_sip.s_addr = 0x81940501;
323 		(void) memcpy(recs[0].dn_cid, cid0, sizeof (cid0));
324 		(void) strlcpy(recs[0].dn_macro, "myserv", DSVC_MAX_MACSYM_LEN);
325 		(void) strlcpy(recs[0].dn_comment, "dave", DN_MAX_COMMENT_LEN);
326 
327 		recs[1].dn_cid_len = 1;
328 		recs[1].dn_flags = 1;
329 		recs[1].dn_cip.s_addr = 0x81940503;
330 		recs[1].dn_sip.s_addr = 0x81940501;
331 		(void) strlcpy(recs[1].dn_macro, "myserv", DSVC_MAX_MACSYM_LEN);
332 		(void) strlcpy(recs[1].dn_comment, "meem", DN_MAX_COMMENT_LEN);
333 
334 		recs[2].dn_cid_len = 1;
335 		recs[2].dn_cip.s_addr = 0x81940504;
336 		recs[2].dn_sip.s_addr = 0x81940501;
337 		(void) strlcpy(recs[2].dn_macro, "myserv", DSVC_MAX_MACSYM_LEN);
338 		(void) strlcpy(recs[2].dn_comment, "cpj", DN_MAX_COMMENT_LEN);
339 
340 		recs[3].dn_cid_len = 1;
341 		recs[3].dn_cip.s_addr = 0x81940505;
342 		recs[3].dn_sip.s_addr = 0x81940501;
343 		(void) strlcpy(recs[3].dn_macro, "myserv", DSVC_MAX_MACSYM_LEN);
344 		(void) strlcpy(recs[3].dn_comment, "mwc", DN_MAX_COMMENT_LEN);
345 
346 		recs[4].dn_cid_len = 1;
347 		recs[4].dn_cip.s_addr = 0x81940506;
348 		recs[4].dn_sip.s_addr = 0x81940501;
349 		(void) strlcpy(recs[4].dn_macro, "myserv", DSVC_MAX_MACSYM_LEN);
350 		(void) strlcpy(recs[4].dn_comment, "markh", DN_MAX_COMMENT_LEN);
351 
352 		(void) printf("add_dd_entry: ... cid flag cip sip lease "
353 		    "macro comment\n");
354 		for (i = 0; i < sizeof (recs) / sizeof (dn_rec_t); i++) {
355 			cidlen = sizeof (cid);
356 			(void) octet_to_hexascii(recs[i].dn_cid,
357 			    recs[i].dn_cid_len, cid, &cidlen);
358 			(void) printf("    %s %d %s %s %u %s %s ... ",
359 			    cid, recs[i].dn_flags,
360 			    inet_ntop(AF_INET, &recs[i].dn_cip, cip,
361 			    INET_ADDRSTRLEN),
362 			    inet_ntop(AF_INET, &recs[i].dn_sip, sip,
363 			    INET_ADDRSTRLEN),
364 			    recs[i].dn_lease, recs[i].dn_macro,
365 			    recs[i].dn_comment);
366 
367 			error = add_dd_entry(handle, &recs[i]);
368 			(void) printf("%s\n", dhcpsvc_errmsg(error));
369 			if (error != DSVC_SUCCESS)
370 				break;
371 		}
372 	}
373 
374 	/* lookup_dd - lookup all records. */
375 	DSVC_QINIT(query);
376 
377 	(void) printf("lookup_dd: 129.148.5.0 ... ");
378 	error = lookup_dd(handle, B_FALSE, query, -1, &dn, (void **)&resdnp,
379 	    &count);
380 	(void) printf("%s\n", dhcpsvc_errmsg(error));
381 	if (error == DSVC_SUCCESS) {
382 		for (i = 0, wnp = resdnp; i < count && wnp != NULL; i++) {
383 			dnp = wnp->dnl_rec;
384 			cidlen = sizeof (cid);
385 			(void) octet_to_hexascii(dnp->dn_cid,
386 			    dnp->dn_cid_len, cid, &cidlen);
387 			(void) inet_ntop(AF_INET, &dnp->dn_cip,
388 			    cip, INET_ADDRSTRLEN);
389 			(void) inet_ntop(AF_INET, &dnp->dn_sip,
390 			    sip, INET_ADDRSTRLEN);
391 			(void) printf("    %s %02u %s %s %u '%s' #%s\n",
392 			    cid, dnp->dn_flags, cip, sip, dnp->dn_lease,
393 			    dnp->dn_macro, dnp->dn_comment);
394 			wnp = wnp->dnl_next;
395 		}
396 		free_dd_list(handle, resdnp);
397 	}
398 
399 	/* delete_dd_entry - 129.148.5.3 */
400 	dn.dn_sig = 0;
401 	dn.dn_cip.s_addr = ntohl(inet_addr("129.148.5.3"));
402 	(void) printf("delete_dd_entry: 129.148.5.3 ... ");
403 	error = delete_dd_entry(handle, &dn);
404 	(void) printf("%s\n", dhcpsvc_errmsg(error));
405 
406 	/*
407 	 * lookup_dd - 129.148.5.0 - record with cid of 01080020000001, modify
408 	 * flags to MANUAL+BOOTP, lease to -1, macro to foobar, and server to
409 	 * 129.148.174.27.
410 	 */
411 	DSVC_QINIT(query);
412 	DSVC_QEQ(query, DN_QCID);
413 
414 	(void) memset(&dn, 0, sizeof (dn));
415 	dn.dn_cid[0] = 0x1;
416 	dn.dn_cid[1] = 0x8;
417 	dn.dn_cid[2] = 0x0;
418 	dn.dn_cid[3] = 0x20;
419 	dn.dn_cid[4] = 0x0;
420 	dn.dn_cid[5] = 0x0;
421 	dn.dn_cid[6] = 0x1;
422 	dn.dn_cid_len = 7;
423 
424 	(void) printf("lookup_dd: 01080020000001 ... ");
425 	error = lookup_dd(handle, B_FALSE, query, 1, &dn, (void **)&resdnp,
426 	    &count);
427 	(void) printf("%s\n", dhcpsvc_errmsg(error));
428 
429 	if (error == DSVC_SUCCESS) {
430 		if (count != 1) {
431 			(void) printf("lookup_dd: expected 1 record, got %d\n",
432 			    count);
433 		} else {
434 			dnp = resdnp->dnl_rec;
435 			dn = *dnp; /* struct copy */
436 
437 			dn.dn_flags = DN_FMANUAL | DN_FBOOTP_ONLY;
438 			dn.dn_lease = DHCP_PERM;
439 			(void) strcpy(dn.dn_macro, "foobar");
440 			dn.dn_sip.s_addr = ntohl(inet_addr("129.148.174.27"));
441 
442 			/* Modify it */
443 			(void) printf("modify_dd_entry: 01080020000001 ... ");
444 			error = modify_dd_entry(handle, dnp, &dn);
445 			(void) printf("%s\n", dhcpsvc_errmsg(error));
446 		}
447 		free_dd_list(handle, resdnp);
448 	}
449 
450 	/* lookup_dd - lookup all fields with DN_FMANUAL set */
451 
452 	DSVC_QINIT(query);
453 	DSVC_QEQ(query, DN_QFMANUAL);
454 
455 	(void) memset(&dn, 0, sizeof (dn));
456 	dn.dn_flags = DN_FMANUAL;
457 
458 	(void) printf("lookup_dd: F_MANUAL ... ");
459 	error = lookup_dd(handle, B_FALSE, query, 1, &dn, (void **)&resdnp,
460 	    &count);
461 	(void) printf("%s\n", dhcpsvc_errmsg(error));
462 
463 	if (error == DSVC_SUCCESS) {
464 		if (count != 1) {
465 			(void) printf("lookup_dd: expected 1 record, "
466 			    "got %d\n", count);
467 		} else {
468 			dnp = resdnp->dnl_rec;
469 			cidlen = sizeof (cid);
470 			(void) octet_to_hexascii(dnp->dn_cid,
471 			    dnp->dn_cid_len, cid, &cidlen);
472 			(void) inet_ntop(AF_INET, &dnp->dn_cip,
473 			    cip, INET_ADDRSTRLEN);
474 			(void) inet_ntop(AF_INET, &dnp->dn_sip,
475 			    sip, INET_ADDRSTRLEN);
476 			(void) printf("    %s %02u %s %s %u '%s' #%s\n",
477 			    cid, dnp->dn_flags, cip, sip, dnp->dn_lease,
478 			    dnp->dn_macro, dnp->dn_comment);
479 		}
480 		free_dd_list(handle, resdnp);
481 	}
482 
483 	/* lookup_dd - lookup all records. */
484 
485 	DSVC_QINIT(query);
486 
487 	(void) printf("lookup_dd: 129.148.5.0  ...");
488 	error = lookup_dd(handle, B_FALSE, query, -1, &dn, (void **)&resdnp,
489 	    &count);
490 	(void) printf("%s\n", dhcpsvc_errmsg(error));
491 
492 	if (error == DSVC_SUCCESS) {
493 		for (i = 0, wnp = resdnp; i < count && wnp != NULL; i++) {
494 			cidlen = sizeof (cid);
495 			dnp = wnp->dnl_rec;
496 			(void) octet_to_hexascii(dnp->dn_cid,
497 			    dnp->dn_cid_len, cid, &cidlen);
498 			(void) inet_ntop(AF_INET, &dnp->dn_cip,
499 			    cip, INET_ADDRSTRLEN);
500 			(void) inet_ntop(AF_INET, &dnp->dn_sip,
501 			    sip, INET_ADDRSTRLEN);
502 			(void) printf("    %s %02u %s %s %u '%s' #%s\n",
503 			    cid, dnp->dn_flags, cip, sip, dnp->dn_lease,
504 			    dnp->dn_macro, dnp->dn_comment);
505 			wnp = wnp->dnl_next;
506 		}
507 		free_dd_list(handle, resdnp);
508 	}
509 
510 	/* close_dd - 129.148.5.0 */
511 	(void) printf("close_dd: 129.148.5.0 ... ");
512 	error = close_dd(&handle);
513 	(void) printf("%s\n", dhcpsvc_errmsg(error));
514 
515 	/* list_dd - dhcp network containers */
516 	(void) printf("list_dd: ... ");
517 	error = list_dd(&dsp, DSVC_DHCPNETWORK, &listpp, &count);
518 	(void) printf("%s\n", dhcpsvc_errmsg(error));
519 	if (error == DSVC_SUCCESS) {
520 		(void) printf("    %d dhcp network container(s): ", count);
521 		for (i = 0; i < count; i++) {
522 			(void) printf("%s ", listpp[i] != NULL ?
523 			    listpp[i] : "NULL");
524 			free(listpp[i]);
525 		}
526 		free(listpp);
527 		(void) printf("\n");
528 	} else {
529 		(void) printf("list_dd: listpp: 0x%p, count: %d\n",
530 		    (void *)listpp, count);
531 	}
532 
533 	/* remove_dd - 129.148.5.0 */
534 	(void) printf("remove_dd_entry: 129.148.5.0 ... ");
535 	error = remove_dd(&dsp, DSVC_DHCPNETWORK, "129.148.5.0");
536 	(void) printf("%s\n", dhcpsvc_errmsg(error));
537 
538 	return (0);
539 }
540