]>
git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/parser.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * bootstrap -- fundamental service initiator and port server
26 * Mike DeMoney, NeXT, Inc.
27 * Copyright, 1990. All rights reserved.
29 * parser.c -- configuration file parser
31 #import <mach/boolean.h>
40 #import "bootstrap_internal.h"
49 #define MAX_TOKEN_LEN 128
51 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
52 #define LAST_ELEMENT(x) ((x)[NELEM(x)-1])
53 #define STREQ(a, b) (strcmp(a, b) == 0)
54 #define NEW(type, num) ((type *)ckmalloc(sizeof(type) * (num)))
57 ASSIGN_TKN
, EOF_TKN
, FORWARD_TKN
, INIT_TKN
, NUM_TKN
,
58 RESTARTABLE_TKN
, SELF_TKN
, SEMICOLON_TKN
, SERVER_TKN
, SERVICES_TKN
,
59 STRING_TKN
, ERROR_TKN
, PRI_TKN
67 static keyword_t keywords
[] = {
68 { "forward", FORWARD_TKN
},
70 { "priority", PRI_TKN
},
71 { "restartable", RESTARTABLE_TKN
},
73 { "server", SERVER_TKN
},
74 { "services", SERVICES_TKN
},
79 static int (*charget
)(void);
80 static const char *default_conf_ptr
;
82 static char token_string
[MAX_TOKEN_LEN
];
83 static token_t current_token
;
85 static int token_priority
;
88 static int get_from_conf(void);
89 static int get_from_default(void);
90 static boolean_t
parse_conf_file(void);
91 static boolean_t
parse_self(void);
92 static boolean_t
parse_server(void);
93 static boolean_t
parse_service(server_t
*serverp
);
94 static boolean_t
parse_pri(void);
95 static void advance_token(void);
96 static token_t
keyword_lookup(void);
99 * init_config -- read configuration file and build-up initial server and
102 * If can't find a suitable bootstrap.conf, use configuration given in
103 * bootstrap.c to get system booted so someone can correct bootstrap.conf
110 conf
= fopen(conf_file
, "r");
112 charget
= get_from_conf
;
114 error("Can't open %s -- using default configuration", conf_file
);
115 charget
= get_from_default
;
118 parse_ok
= parse_conf_file();
119 if ( ! parse_ok
&& charget
== get_from_conf
) {
120 error("Can't parse %s -- using default configuration", conf_file
);
121 charget
= get_from_default
;
124 parse_ok
= parse_conf_file();
127 fatal("Can't parse default configuration file");
131 * Function pointer "charget" points at get_from_conf or get_from_default
140 get_from_default(void)
144 if (default_conf_ptr
== NULL
)
145 default_conf_ptr
= default_conf
;
147 if (c
= *default_conf_ptr
)
155 * What follows is a simple recursive descent parser
156 * ("we don't need no stinkin' yacc")
159 parse_conf_file(void)
161 boolean_t parse_ok
, good_parse
;
164 * Configuration file syntax (and parsing routines).
167 * CONF_FILE := STMT [ ; STMT ]* [ ; ]
168 * STMT := SERVER | SERVICE | SELF | forward | initpri
171 * SERVER := [ restartable ] ( server | init ) SERVER_PATH_ARGS [ SERVICE ]
174 * SERVICE := services [ SERVICE_DECL ]+
175 * SERVICE_DECL := SERVICE_NAME
178 * SELF := self [ priority = NUM ] SERVICE_DECL
180 * Or more simply, just a list of:
182 * [[restartable] (server|init) SERVER_PATH_ARGS] [ priority = NUM ]
183 * [services SERVICE_NAME [ SERVICE_NAME [ = NUM ]]*] ;
185 * self [ SERVICE_NAME ]+
191 if (current_token
== EOF_TKN
) {
192 error("Empty configuration file: %s", conf_file
);
197 while (current_token
!= EOF_TKN
) {
199 switch (current_token
) {
200 case RESTARTABLE_TKN
:
203 parse_ok
= parse_server();
206 parse_ok
= parse_service(NULL
);
209 parse_ok
= parse_self();
221 parse_error(token_string
, "start of new declaration");
225 switch (current_token
) {
233 parse_error(token_string
, "expected ';'");
234 /* Try to re-sync with input */
235 while (current_token
!= SEMICOLON_TKN
&& current_token
!= EOF_TKN
)
251 ASSERT(current_token
== SELF_TKN
);
252 advance_token(); /* Skip SELF_TKN */
253 if (current_token
== PRI_TKN
) {
258 init_priority
= token_priority
;
260 while (current_token
== STRING_TKN
) {
261 if (strlen(token_string
) >= sizeof(name_t
)) {
262 parse_error(token_string
, "Service name too long");
265 if (lookup_service_by_name(&bootstraps
, token_string
) != NULL
)
267 parse_error(token_string
, "Service name previously declared");
270 strcpy(name
, token_string
);
272 (void) new_service(&bootstraps
, name
, MACH_PORT_NULL
, ACTIVE
, SELF
,
282 servertype_t servertype
= SERVER
;
284 if (current_token
== RESTARTABLE_TKN
) {
286 servertype
= RESTARTABLE
;
288 switch (current_token
) {
293 if (find_init_server() != NULL
) {
294 parse_error(token_string
,
295 "Can't specify multiple init servers");
298 if (servertype
== RESTARTABLE
) {
299 parse_error(token_string
,
300 "Init server can not be restartable");
303 servertype
= ETCINIT
;
307 parse_error(token_string
, "expected \"server\" or \"init\"");
310 if (current_token
== PRI_TKN
) {
316 token_priority
= BASEPRI_USER
;
317 if (current_token
!= STRING_TKN
) {
318 parse_error(token_string
,
319 "expected string giving server to exec");
322 serverp
= new_server(servertype
, token_string
, token_priority
);
324 if (current_token
== SERVICES_TKN
)
325 return parse_service(serverp
);
330 parse_service(server_t
*serverp
)
334 ASSERT(current_token
== SERVICES_TKN
);
335 advance_token(); /* Skip SERVICES_TKN */
336 while (current_token
== STRING_TKN
) {
337 if (strlen(token_string
) >= sizeof(name_t
)) {
338 parse_error(token_string
, "Service name too long");
341 if (lookup_service_by_name(&bootstraps
, token_string
) != NULL
)
343 parse_error(token_string
, "Service name previously declared");
346 strcpy(name
, token_string
);
348 (void) new_service(&bootstraps
, name
, MACH_PORT_NULL
, !ACTIVE
,
360 ASSERT(current_token
== PRI_TKN
);
361 advance_token(); /* Skip PRI_TKN */
362 if (current_token
!= ASSIGN_TKN
) {
363 parse_error(token_string
, "expected '='");
366 advance_token(); /* Skip = */
367 if (current_token
!= NUM_TKN
) {
368 parse_error(token_string
, "expected NUM");
371 advance_token(); /* Skip NUM */
372 token_priority
= token_num
;
376 * advance_token -- advances input to next token
377 * Anything from a '#' on is comment and ignored
380 * current_token contains token_t of next token
381 * token_string contains string value of next token
382 * if token was number, token_num contains numeric value of token
390 while (peekc
== '\0' || isspace(peekc
))
391 peekc
= (*charget
)();
395 while (peekc
!= EOF
&& peekc
!= '\n')
396 peekc
= (*charget
)();
404 current_token
= EOF_TKN
;
408 if (isalpha(peekc
) || peekc
== '\\') {
410 * this only allows names to be alphanumerics, '_', and
411 * backslash escaped characters.
412 * If you want something fancier, use "..."
414 current_token
= STRING_TKN
; /* guarantee it's not ERROR_TKN */
415 for (; isalnum(peekc
) || peekc
== '_' || peekc
== '\\';
416 peekc
= (*charget
)()) {
417 if (cp
>= &LAST_ELEMENT(token_string
)) {
419 parse_error(token_string
, "token too long");
420 current_token
= ERROR_TKN
;
423 peekc
= (*charget
)();
427 if (current_token
!= ERROR_TKN
)
428 current_token
= keyword_lookup();
432 /* Handle "-quoted strings */
434 peekc
= (*charget
)();
435 for (; peekc
!= EOF
&& peekc
!= '"'; peekc
= (*charget
)()) {
436 if (cp
>= &LAST_ELEMENT(token_string
)) {
438 parse_error(token_string
, "token too long");
439 current_token
= ERROR_TKN
;
442 peekc
= (*charget
)();
445 parse_error(token_string
, "Missing \"");
446 current_token
= ERROR_TKN
;
452 parse_error(token_string
, "Missing \"");
453 current_token
= ERROR_TKN
;
455 peekc
= (*charget
)(); /* skip closing " */
457 if (current_token
!= ERROR_TKN
)
458 current_token
= STRING_TKN
;
462 if (isdigit(peekc
)) {
463 for (token_num
= 0; isdigit(peekc
); peekc
= (*charget
)())
464 token_num
= token_num
* 10 + peekc
- '0';
465 current_token
= NUM_TKN
;
470 peekc
= (*charget
)();
471 current_token
= SEMICOLON_TKN
;
476 peekc
= (*charget
)();
477 current_token
= ASSIGN_TKN
;
481 current_token
= ERROR_TKN
;
490 for (kwp
= keywords
; kwp
->string
; kwp
++)
491 if (STREQ(kwp
->string
, token_string
))