xref: /minix3/external/bsd/dhcp/dist/dhcpctl/omshell.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1 /*	$NetBSD: omshell.c,v 1.1.1.2 2014/07/12 11:57:52 spz Exp $	*/
2 /* omshell.c
3 
4    Examine and modify omapi objects. */
5 
6 /*
7  * Copyright (c) 2009-2011,2013,2014 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 2001-2003 by Internet Software Consortium
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *   Internet Systems Consortium, Inc.
24  *   950 Charter Street
25  *   Redwood City, CA 94063
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: omshell.c,v 1.1.1.2 2014/07/12 11:57:52 spz Exp $");
33 
34 #include "config.h"
35 
36 #include <time.h>
37 #include <sys/time.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <string.h>
42 //#include "result.h"
43 #include <syslog.h>
44 #include "dhcpctl.h"
45 #include "dhcpd.h"
46 
47 /* Fixups */
find_class(struct class ** c,const char * n,const char * f,int l)48 isc_result_t find_class (struct class **c, const char *n, const char *f, int l)
49 {
50 	return 0;
51 }
parse_allow_deny(struct option_cache ** oc,struct parse * cfile,int flag)52 int parse_allow_deny (struct option_cache **oc, struct parse *cfile, int flag)
53 {
54 	return 0;
55 }
dhcp(struct packet * packet)56 void dhcp (struct packet *packet) { }
bootp(struct packet * packet)57 void bootp (struct packet *packet) { }
58 
59 #ifdef DHCPv6
60 /* XXX: should we warn or something here? */
dhcpv6(struct packet * packet)61 void dhcpv6(struct packet *packet) { }
62 #endif /* DHCPv6 */
63 
check_collection(struct packet * p,struct lease * l,struct collection * c)64 int check_collection (struct packet *p, struct lease *l, struct collection *c)
65 {
66 	return 0;
67 }
classify(struct packet * packet,struct class * class)68 void classify (struct packet *packet, struct class *class) { }
69 
usage(char * s)70 static void usage (char *s) {
71 	fprintf (stderr, "Usage: %s\n", s);
72 	exit (1);
73 }
74 
check(isc_result_t status,const char * func)75 static void check (isc_result_t status, const char *func) {
76 	if (status != ISC_R_SUCCESS) {
77 		fprintf (stderr, "%s: %s\n", func, isc_result_totext (status));
78 		exit (1);
79 	}
80 }
81 
82 int
main(int argc,char ** argv)83 main(int argc, char **argv) {
84 	isc_result_t status, waitstatus;
85 	dhcpctl_handle connection;
86 	dhcpctl_handle authenticator;
87 	dhcpctl_handle oh;
88 	struct data_string secret;
89 	const char *name = 0, *algorithm = "hmac-md5";
90 	int i;
91 	int port = 7911;
92 	const char *server = "127.0.0.1";
93 	struct parse *cfile;
94 	enum dhcp_token token;
95 	const char *val;
96 	char *s;
97 	char buf[1024];
98 	char s1[1024];
99 	int connected = 0;
100 	char hex_buf[1025];
101 
102 	for (i = 1; i < argc; i++) {
103 		usage(argv[0]);
104 	}
105 
106 	/* Initially, log errors to stderr as well as to syslogd. */
107 	openlog ("omshell", LOG_NDELAY, DHCPD_LOG_FACILITY);
108 	status = dhcpctl_initialize ();
109 	if (status != ISC_R_SUCCESS) {
110 		fprintf (stderr, "dhcpctl_initialize: %s\n",
111 			 isc_result_totext (status));
112 		exit (1);
113 	}
114 
115 	memset (&oh, 0, sizeof oh);
116 
117 	do {
118 	    if (!connected) {
119 	    } else if (oh == NULL) {
120 		printf ("obj: <null>\n");
121 	    } else {
122 		dhcpctl_remote_object_t *r = (dhcpctl_remote_object_t *)oh;
123 		omapi_generic_object_t *g =
124 			(omapi_generic_object_t *)(r -> inner);
125 
126 		printf ("obj: ");
127 
128 		if (r -> rtype -> type != omapi_datatype_string) {
129 			printf ("?\n");
130 		} else {
131 			printf ("%.*s\n",
132 				(int)(r -> rtype -> u . buffer . len),
133 				r -> rtype -> u . buffer . value);
134 		}
135 
136 		for (i = 0; i < g -> nvalues; i++) {
137 		    omapi_value_t *v = g -> values [i];
138 
139 		    if (!g -> values [i])
140 			    continue;
141 
142 		    printf ("%.*s = ", (int)v -> name -> len,
143 			    v -> name -> value);
144 
145 		    if (!v -> value) {
146 			printf ("<null>\n");
147 			continue;
148 		    }
149 		    switch (v -> value -> type) {
150 			  case omapi_datatype_int:
151 			    printf ("%d\n",
152 				    v -> value -> u . integer);
153 			    break;
154 
155 			  case omapi_datatype_string:
156 			    printf ("\"%.*s\"\n",
157 				    (int) v -> value -> u.buffer.len,
158 				    v -> value -> u.buffer.value);
159 			    break;
160 
161 			  case omapi_datatype_data:
162 			    print_hex_or_string(v->value->u.buffer.len,
163 						v->value->u.buffer.value,
164 						sizeof(hex_buf), hex_buf);
165 			    printf("%s\n", hex_buf);
166 			    break;
167 
168 			  case omapi_datatype_object:
169 			    printf ("<obj>\n");
170 			    break;
171 		    }
172 		}
173 	    }
174 
175 	    fputs ("> ", stdout);
176 	    fflush (stdout);
177 	    if (fgets (buf, sizeof(buf), stdin) == NULL)
178 		break;
179 
180 	    status = new_parse (&cfile, -1, buf, strlen(buf), "<STDIN>", 1);
181 	    check(status, "new_parse()");
182 
183 	    token = next_token (&val, (unsigned *)0, cfile);
184 	    switch (token) {
185 		  default:
186 		    parse_warn (cfile, "unknown token: %s", val);
187 		    skip_to_semi (cfile);
188 		    break;
189 
190 		  case END_OF_FILE:
191 		  case ENDOFLINE: /* EOL: */
192 		    break;
193 
194 		  case TOKEN_HELP:
195 	          case QUESTIONMARK: /* '?': */
196 		    printf ("Commands:\n");
197 		    printf ("  port <server omapi port>\n");
198 		    printf ("  server <server address>\n");
199 		    printf ("  key <key name> <key value>\n");
200 		    printf ("  connect\n");
201 		    printf ("  new <object-type>\n");
202 		    printf ("  set <name> = <value>\n");
203 		    printf ("  create\n");
204 		    printf ("  open\n");
205 		    printf ("  update\n");
206 		    printf ("  unset <name>\n");
207 		    printf ("  refresh\n");
208 		    printf ("  remove\n");
209 		    skip_to_semi (cfile);
210 		    break;
211 
212 		  case PORT:
213 		    token = next_token (&val, (unsigned *)0, cfile);
214 		    if (is_identifier (token)) {
215 			    struct servent *se;
216 			    se = getservbyname (val, "tcp");
217 			    if (se)
218 				    port = ntohs (se -> s_port);
219 			    else {
220 				    printf ("unknown service name: %s\n", val);
221 				    break;
222 			    }
223 		    } else if (token == NUMBER) {
224 			    port = atoi (val);
225 		    } else {
226 			    skip_to_semi (cfile);
227 			    printf ("usage: port <port>\n");
228 			    break;
229 		    }
230 		    token = next_token (&val, (unsigned *)0, cfile);
231 		    if (token != END_OF_FILE && token != EOL) {
232 			    printf ("usage: port <server>\n");
233 			    skip_to_semi (cfile);
234 			    break;
235 		    }
236 		    break;
237 
238 		  case TOKEN_SERVER:
239 		    token = next_token (&val, (unsigned *)0, cfile);
240 		    if (token == NUMBER) {
241 			    int alen = (sizeof buf) - 1;
242 			    int len;
243 
244 			    s = &buf [0];
245 			    len = strlen (val);
246 			    if (len + 1 > alen) {
247 			      baddq:
248 				printf ("usage: server <server>\n");
249 				skip_to_semi (cfile);
250 				break;
251 			    }			    strcpy (buf, val);
252 			    s += len;
253 			    token = next_token (&val, (unsigned *)0, cfile);
254 			    if (token != DOT)
255 				    goto baddq;
256 			    *s++ = '.';
257 			    token = next_token (&val, (unsigned *)0, cfile);
258 			    if (token != NUMBER)
259 				    goto baddq;
260 			    len = strlen (val);
261 			    if (len + 1 > alen)
262 				    goto baddq;
263 			    strcpy (s, val);
264 			    s += len;
265 			    token = next_token (&val, (unsigned *)0, cfile);
266 			    if (token != DOT)
267 				    goto baddq;
268 			    *s++ = '.';
269 			    token = next_token (&val, (unsigned *)0, cfile);
270 			    if (token != NUMBER)
271 				    goto baddq;
272 			    len = strlen (val);
273 			    if (len + 1 > alen)
274 				    goto baddq;
275 			    strcpy (s, val);
276 			    s += len;
277 			    token = next_token (&val, (unsigned *)0, cfile);
278 			    if (token != DOT)
279 				    goto baddq;
280 			    *s++ = '.';
281 			    token = next_token (&val, (unsigned *)0, cfile);
282 			    if (token != NUMBER)
283 				    goto baddq;
284 			    len = strlen (val);
285 			    if (len + 1 > alen)
286 				    goto baddq;
287 			    strcpy (s, val);
288 			    val = &buf [0];
289 		    } else if (is_identifier (token)) {
290 			    /* Use val directly. */
291 		    } else {
292 			    printf ("usage: server <server>\n");
293 			    skip_to_semi (cfile);
294 			    break;
295 		    }
296 
297 		    s = dmalloc (strlen (val) + 1, MDL);
298 		    if (!server) {
299 			    printf ("no memory to store server name.\n");
300 			    skip_to_semi (cfile);
301 			    break;
302 		    }
303 		    strcpy (s, val);
304 		    server = s;
305 
306 		    token = next_token (&val, (unsigned *)0, cfile);
307 		    if (token != END_OF_FILE && token != EOL) {
308 			    printf ("usage: server <server>\n");
309 			    skip_to_semi (cfile);
310 			    break;
311 		    }
312 		    break;
313 
314 		  case KEY:
315 		    token = peek_token(&val, (unsigned *)0, cfile);
316 		    if (token == STRING) {
317 			    token = next_token (&val, (unsigned *)0, cfile);
318 			    if (!is_identifier (token)) {
319 				    printf ("usage: key <name> <value>\n");
320 				    skip_to_semi (cfile);
321 				    break;
322 			    }
323 			    s = dmalloc (strlen (val) + 1, MDL);
324 			    if (!s) {
325 				    printf ("no memory for key name.\n");
326 				    skip_to_semi (cfile);
327 				    break;
328 			    }
329 			    strcpy (s, val);
330 		    } else {
331 			    s = parse_host_name(cfile);
332 			    if (s == NULL) {
333 				    printf ("usage: key <name> <value>\n");
334 				    skip_to_semi(cfile);
335 				    break;
336 			    }
337 		    }
338 		    name = s;
339 
340 		    memset (&secret, 0, sizeof secret);
341 		    if (!parse_base64 (&secret, cfile)) {
342 			    skip_to_semi (cfile);
343 			    break;
344 		    }
345 		    token = next_token (&val, (unsigned *)0, cfile);
346 		    if (token != END_OF_FILE && token != EOL) {
347 			    printf ("usage: key <name> <secret>\n");
348 			    skip_to_semi (cfile);
349 			    break;
350 		    }
351 		    break;
352 
353 		  case CONNECT:
354 		    token = next_token (&val, (unsigned *)0, cfile);
355 		    if (token != END_OF_FILE && token != EOL) {
356 			    printf ("usage: connect\n");
357 			    skip_to_semi (cfile);
358 			    break;
359 		    }
360 
361 		    authenticator = dhcpctl_null_handle;
362 
363 		    if (name) {
364 			status = dhcpctl_new_authenticator (&authenticator,
365 							    name, algorithm,
366 							    secret.data,
367 							    secret.len);
368 
369 			if (status != ISC_R_SUCCESS) {
370 			    fprintf (stderr,
371 				     "Cannot create authenticator: %s\n",
372 				     isc_result_totext (status));
373 			    break;
374 			}
375 		    }
376 
377 		    memset (&connection, 0, sizeof connection);
378 		    status = dhcpctl_connect (&connection,
379 					      server, port, authenticator);
380 		    if (status != ISC_R_SUCCESS) {
381 			    fprintf (stderr, "dhcpctl_connect: %s\n",
382 				     isc_result_totext (status));
383 			    break;
384 		    }
385 		    connected = 1;
386 		    break;
387 
388 		  case TOKEN_NEW:
389 		    token = next_token (&val, (unsigned *)0, cfile);
390 		    if ((!is_identifier (token) && token != STRING)) {
391 			    printf ("usage: new <object-type>\n");
392 			    break;
393 		    }
394 
395 		    if (oh) {
396 			    printf ("an object is already open.\n");
397 			    skip_to_semi (cfile);
398 			    break;
399 		    }
400 
401 		    if (!connected) {
402 			    printf ("not connected.\n");
403 			    skip_to_semi (cfile);
404 			    break;
405 		    }
406 
407 		    status = dhcpctl_new_object (&oh, connection, val);
408 		    if (status != ISC_R_SUCCESS) {
409 			    printf ("can't create object: %s\n",
410 				    isc_result_totext (status));
411 			    break;
412 		    }
413 
414 		    token = next_token (&val, (unsigned *)0, cfile);
415 		    if (token != END_OF_FILE && token != EOL) {
416 			    printf ("usage: new <object-type>\n");
417 			    skip_to_semi (cfile);
418 			    break;
419 		    }
420 		    break;
421 
422 		  case TOKEN_CLOSE:
423 		    token = next_token (&val, (unsigned *)0, cfile);
424 		    if (token != END_OF_FILE && token != EOL) {
425 			    printf ("usage: close\n");
426 			    skip_to_semi (cfile);
427 			    break;
428 		    }
429 
430 		    if (!connected) {
431 			    printf ("not connected.\n");
432 			    skip_to_semi (cfile);
433 			    break;
434 		    }
435 
436 		    if (!oh) {
437 			    printf ("not open.\n");
438 			    skip_to_semi (cfile);
439 			    break;
440 		    }
441 		    omapi_object_dereference (&oh, MDL);
442 
443 		    break;
444 
445 		  case TOKEN_SET:
446 		    token = next_token (&val, (unsigned *)0, cfile);
447 
448 		    if ((!is_identifier (token) && token != STRING)) {
449 			  set_usage:
450 			    printf ("usage: set <name> = <value>\n");
451 			    skip_to_semi (cfile);
452 			    break;
453 		    }
454 
455 		    if (oh == NULL) {
456 			    printf ("no open object.\n");
457 			    skip_to_semi (cfile);
458 			    break;
459 		    }
460 
461 		    if (!connected) {
462 			    printf ("not connected.\n");
463 			    skip_to_semi (cfile);
464 			    break;
465 		    }
466 
467 #ifdef HAVE_STRLCPY
468 		    strlcpy (s1, val, sizeof(s1));
469 #else
470 		    s1[0] = 0;
471 		    strncat (s1, val, sizeof(s1)-strlen(s1)-1);
472 #endif
473 
474 		    token = next_token (&val, (unsigned *)0, cfile);
475 		    if (token != EQUAL)
476 			    goto set_usage;
477 
478 		    token = next_token (&val, (unsigned *)0, cfile);
479 		    switch (token) {
480 			  case STRING:
481 			    dhcpctl_set_string_value (oh, val, s1);
482 			    token = next_token (&val, (unsigned *)0, cfile);
483 			    break;
484 
485 			  case NUMBER:
486 			    strcpy (buf, val);
487 			    token = peek_token (&val, (unsigned *)0, cfile);
488 			    /* Colon-separated hex list? */
489 			    if (token == COLON)
490 				goto cshl;
491 			    else if (token == DOT) {
492 				s = buf;
493 				val = buf;
494 				do {
495 				    int intval = atoi (val);
496 				    if (intval > 255) {
497 					parse_warn (cfile,
498 						    "dotted octet > 255: %s",
499 						    val);
500 					skip_to_semi (cfile);
501 					goto badnum;
502 				    }
503 				    *s++ = intval;
504 				    token = next_token (&val,
505 							(unsigned *)0, cfile);
506 				    if (token != DOT)
507 					    break;
508 				    /* DOT is zero. */
509 				    while ((token = next_token (&val,
510 					(unsigned *)0, cfile)) == DOT)
511 					*s++ = 0;
512 				} while (token == NUMBER);
513 				dhcpctl_set_data_value (oh, buf,
514 							(unsigned)(s - buf),
515 							s1);
516 				break;
517 			    }
518 			    dhcpctl_set_int_value (oh, atoi (buf), s1);
519 			    token = next_token (&val, (unsigned *)0, cfile);
520 			  badnum:
521 			    break;
522 
523 			  case NUMBER_OR_NAME:
524 			    strcpy (buf, val);
525 			  cshl:
526 			    s = buf;
527 			    val = buf;
528 			    do {
529 				convert_num (cfile, (unsigned char *)s,
530 					     val, 16, 8);
531 				++s;
532 				token = next_token (&val,
533 						    (unsigned *)0, cfile);
534 				if (token != COLON)
535 				    break;
536 				token = next_token (&val,
537 						    (unsigned *)0, cfile);
538 			    } while (token == NUMBER ||
539 				     token == NUMBER_OR_NAME);
540 			    dhcpctl_set_data_value (oh, buf,
541 						    (unsigned)(s - buf), s1);
542 			    break;
543 
544 			  default:
545 			    printf ("invalid value.\n");
546 			    skip_to_semi (cfile);
547 		    }
548 
549 		    if (token != END_OF_FILE && token != EOL)
550 			    goto set_usage;
551 		    break;
552 
553 		  case UNSET:
554 		    token = next_token (&val, (unsigned *)0, cfile);
555 
556 		    if ((!is_identifier (token) && token != STRING)) {
557 			  unset_usage:
558 			    printf ("usage: unset <name>\n");
559 			    skip_to_semi (cfile);
560 			    break;
561 		    }
562 
563 		    if (!oh) {
564 			    printf ("no open object.\n");
565 			    skip_to_semi (cfile);
566 			    break;
567 		    }
568 
569 		    if (!connected) {
570 			    printf ("not connected.\n");
571 			    skip_to_semi (cfile);
572 			    break;
573 		    }
574 
575 #if HAVE_STRLCPY
576 		    strlcpy (s1, val, sizeof(s1));
577 #else
578 		    s1[0] = 0;
579 		    strncat (s1, val, sizeof(s1)-strlen(s1)-1);
580 #endif
581 
582 		    token = next_token (&val, (unsigned *)0, cfile);
583 		    if (token != END_OF_FILE && token != EOL)
584 			    goto unset_usage;
585 
586 		    dhcpctl_set_null_value (oh, s1);
587 		    break;
588 
589 
590 		  case TOKEN_CREATE:
591 		  case TOKEN_OPEN:
592 		    i = token;
593 		    token = next_token (&val, (unsigned *)0, cfile);
594 		    if (token != END_OF_FILE && token != EOL) {
595 			    printf ("usage: %s\n", val);
596 			    skip_to_semi (cfile);
597 			    break;
598 		    }
599 
600 		    if (!connected) {
601 			    printf ("not connected.\n");
602 			    skip_to_semi (cfile);
603 			    break;
604 		    }
605 
606 		    if (!oh) {
607 			    printf ("you must make a new object first!\n");
608 			    skip_to_semi (cfile);
609 			    break;
610 		    }
611 
612 		    if (i == TOKEN_CREATE)
613 			    i = DHCPCTL_CREATE | DHCPCTL_EXCL;
614 		    else
615 			    i = 0;
616 
617 		    status = dhcpctl_open_object (oh, connection, i);
618 		    if (status == ISC_R_SUCCESS)
619 			    status = dhcpctl_wait_for_completion
620 				    (oh, &waitstatus);
621 		    if (status == ISC_R_SUCCESS)
622 			    status = waitstatus;
623 		    if (status != ISC_R_SUCCESS) {
624 			    printf ("can't open object: %s\n",
625 				    isc_result_totext (status));
626 			    break;
627 		    }
628 
629 		    break;
630 
631 		  case UPDATE:
632 		    token = next_token (&val, (unsigned *)0, cfile);
633 		    if (token != END_OF_FILE && token != EOL) {
634 			    printf ("usage: %s\n", val);
635 			    skip_to_semi (cfile);
636 			    break;
637 		    }
638 
639 		    if (!connected) {
640 			    printf ("not connected.\n");
641 			    skip_to_semi (cfile);
642 			    break;
643 		    }
644 
645 		    if (!oh) {
646 			    printf ("you haven't opened an object yet!\n");
647 			    skip_to_semi (cfile);
648 			    break;
649 		    }
650 
651 		    status = dhcpctl_object_update(connection, oh);
652 		    if (status == ISC_R_SUCCESS)
653 			    status = dhcpctl_wait_for_completion
654 				    (oh, &waitstatus);
655 		    if (status == ISC_R_SUCCESS)
656 			    status = waitstatus;
657 		    if (status != ISC_R_SUCCESS) {
658 			    printf ("can't update object: %s\n",
659 				    isc_result_totext (status));
660 			    break;
661 		    }
662 
663 		    break;
664 
665 		  case REMOVE:
666 		    token = next_token (&val, (unsigned *)0, cfile);
667 		    if (token != END_OF_FILE && token != EOL) {
668 			    printf ("usage: remove\n");
669 			    skip_to_semi (cfile);
670 			    break;
671 		    }
672 
673 		    if (!connected) {
674 			    printf ("not connected.\n");
675 			    break;
676 		    }
677 
678 		    if (!oh) {
679 			    printf ("no object.\n");
680 			    break;
681 		    }
682 
683 		    status = dhcpctl_object_remove(connection, oh);
684 		    if (status == ISC_R_SUCCESS)
685 			    status = dhcpctl_wait_for_completion
686 				    (oh, &waitstatus);
687 		    if (status == ISC_R_SUCCESS)
688 			    status = waitstatus;
689 		    if (status != ISC_R_SUCCESS) {
690 			    printf ("can't destroy object: %s\n",
691 				    isc_result_totext (status));
692 			    break;
693 		    }
694 		    omapi_object_dereference (&oh, MDL);
695 		    break;
696 
697 		  case REFRESH:
698 		    token = next_token (&val, (unsigned *)0, cfile);
699 		    if (token != END_OF_FILE && token != EOL) {
700 			    printf ("usage: refresh\n");
701 			    skip_to_semi (cfile);
702 			    break;
703 		    }
704 
705 		    if (!connected) {
706 			    printf ("not connected.\n");
707 			    break;
708 		    }
709 
710 		    if (!oh) {
711 			    printf ("no object.\n");
712 			    break;
713 		    }
714 
715 		    status = dhcpctl_object_refresh(connection, oh);
716 		    if (status == ISC_R_SUCCESS)
717 			    status = dhcpctl_wait_for_completion
718 				    (oh, &waitstatus);
719 		    if (status == ISC_R_SUCCESS)
720 			    status = waitstatus;
721 		    if (status != ISC_R_SUCCESS) {
722 			    printf ("can't refresh object: %s\n",
723 				    isc_result_totext (status));
724 			    break;
725 		    }
726 
727 		    break;
728 	    }
729 	    end_parse (&cfile);
730 	} while (1);
731 
732 	exit (0);
733 }
734 
735 /* Sigh */
dhcp_set_control_state(control_object_state_t oldstate,control_object_state_t newstate)736 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
737 				     control_object_state_t newstate)
738 {
739 	if (newstate != server_shutdown)
740 		return ISC_R_SUCCESS;
741 	exit (0);
742 }
743