1 /*************************************************
2 * rpld - an IBM style RIPL server *
3 *************************************************/
5 /* Copyright (c) 1999,2000,2001 James McKenzie.
7 * Copyright (c) 1998,2000,2001 Christopher Lightfoot.
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENCE file which can be found at the top level of
12 * the rpld distribution.
14 * IBM is a trademark of IBM corp.
19 * YACC grammar for RPLD conf file parser
21 * $Log: rpld_conf.y,v $
22 * Revision 1.8 2001/11/01 15:23:59 root
25 * Revision 1.7 2000/07/23 19:14:19 root
28 * Revision 1.6 2000/07/17 11:59:45 root
31 * Revision 1.5 2000/07/17 10:43:34 root
34 * Revision 1.4 2000/07/16 14:05:28 root
37 * Revision 1.3 2000/07/16 13:18:10 root
40 * Revision 1.1 2000/07/16 13:16:33 root
43 * Revision 1.2 1999/09/13 11:17:35 root
46 * Revision 1.1 1999/09/13 11:04:13 root
49 * Revision 1.10 1999/09/12 19:45:03 chris
50 * *** empty log message ***
52 * Revision 1.9 1999/09/12 19:14:07 chris
53 * Error messages now report name of last token scanned, instead of current yytext.
55 * Revision 1.8 1999/09/12 17:39:01 chris
56 * Configuration file now correctly builds structures; various minor problems fixed.
58 * Revision 1.7 1999/09/12 04:21:29 chris
59 * Wrote back-end to parser.
61 * Revision 1.6 1999/09/12 03:27:35 chris
62 * Added better error reporting.
64 * Revision 1.5 1999/09/12 01:05:00 chris
65 * Supports detecting start and end of blocks.
67 * Revision 1.4 1999/09/12 00:58:02 chris
68 * Added named block syntax.
70 * Revision 1.3 1999/09/11 19:00:51 chris
71 * Added support for nested blocks.
73 * Revision 1.2 1999/09/11 18:53:41 chris
74 * Added a comment to say what the file does.
81 static char rcsid[]="$Id: rpld_conf.y,v 1.8 2001/11/01 15:23:59 root Exp $";
85 // state machine stuff
87 typedef enum {START, BLOCK_START, BLOCK_END, ASSERTION, ASSIGNMENT} THING ;
88 typedef enum {INIT, GLOBALBLOCK, HOSTBLOCK, FILEBLOCK} STATE ;
90 //void process_thing(THING thing, char *name, int type, YYSTYPE *pvalue);
94 %token BLOCK_START BLOCK_END NAME TEXT NUMBER MACADDR MACADDR_PARTIAL
111 block_list: block ';'
112 | block_list block ';'
115 block: block_start statement_list BLOCK_END { process_thing(BLOCK_END, "", 0, NULL); }
116 | block_start BLOCK_END { process_thing(BLOCK_END, "", 0, NULL); }
118 block_start: NAME BLOCK_START { process_thing(BLOCK_START, $1.name, 0, NULL); }
119 | BLOCK_START { process_thing(BLOCK_START, "", 0, NULL); }
123 | statement_list statement ';'
126 statement: NAME { process_thing(ASSERTION, $1.name, 0, NULL); }
127 | NAME '=' TEXT { process_thing(ASSIGNMENT, $1.name, TEXT, &$3); }
128 | NAME '=' NUMBER { process_thing(ASSIGNMENT, $1.name, NUMBER, &$3); }
129 | NAME '=' MACADDR { process_thing(ASSIGNMENT, $1.name, MACADDR, &$3); }
130 | NAME '=' MACADDR_PARTIAL { process_thing(ASSIGNMENT, $1.name, MACADDR_PARTIAL, &$3); }
139 // the lineno variable from our parser
142 // the yytext variable from lex for error reporting
145 void yyerror(char *s)
147 fprintf(stderr, "rpld: config line %d: %s near `%s'\n", lineno, s, yytext);
151 // CONFIGURATION PROCESSOR
154 // This is the bit that actually does the work
156 #define strsame(a, b) (!strcmp((a), (b)))
158 struct global_parameters
185 extern struct client *clients;
187 // hideous, we need to cope with a semicolon after this
188 //#define THROW_ERROR(a) do { yyerror((a)); exit(1); } while(0)
189 #define THROW_ERROR(a) do { fprintf(stderr, "rpld: config line %d: %s near `%s'\n", lineno, (a), name); exit(1); } while(0)
191 void process_thing(THING thing, char *name, int type, YYSTYPE *pvalue)
194 static struct client *pc;
195 static struct clientinfo ci;
196 static struct clfile *pcf;
197 static struct clfileinfo cfi;
201 // boot the state machine
207 // Blocks, which contain related options
212 // in initial state, move to GLOBALBLOCK or HOSTBLOCK
214 if (strsame(name, "GLOBAL")) {
217 } else if (strsame(name, "HOST") || strsame(name, "CLIENT")) {
218 // construct a new client entity
219 pc = (struct client*)malloc(sizeof(struct client));
220 bzero(pc, sizeof(struct client));
221 // reset info about what options have been set for this client
222 bzero(&ci, sizeof(ci));
224 pc->blocklen=MY_BLOCK_LEN;
225 pc->framelen=MY_FRAME_LEN;
226 pc->pacing=MY_PACING;
230 } else THROW_ERROR("Unknown top-level parameter block");
232 // in a HOST block, this must be a FILE
233 else if (state == HOSTBLOCK) {
234 if (strsame(name, "FILE")) {
235 // construct a new file entity
236 pcf = (struct clfile*)malloc(sizeof(struct clfile));
237 bzero(pcf, sizeof(struct clfile));
239 // reset info about options set for this file
240 bzero(&cfi, sizeof(cfi));
244 } else THROW_ERROR("Only a FILE parameter block can be included in a HOST block");
249 yyerror("Unknown parameter block");
254 // end of a block, we should have a bunch of info now
257 if (state == GLOBALBLOCK) {
258 // no more global params, at least for the moment
261 else if (state == HOSTBLOCK) {
262 // should have a complete host specification
263 if (!ci.have_mac) THROW_ERROR("Must specify an ethernet (MAC) address for host");
264 else if (!ci.have_run_addr) THROW_ERROR("Must specify an initial execute address for host");
265 else if (!ci.have_files) THROW_ERROR("Must specify at least one file to load for host");
267 // OK, should have an entire host spec, so copy it in
271 // finished this host spec
276 else if (state == FILEBLOCK) {
277 // should have a complete file specification
278 if (!cfi.have_path) THROW_ERROR("Must specify a path for file");
279 else if (!cfi.have_load_addr) THROW_ERROR("Must specify a load address for file");
281 // have an entire file spec, copy it into the host spec
282 pcf->next = pc->files;
293 // The various things that go inside blocks
297 if (state == GLOBALBLOCK) {
298 // no global assertions ATM
299 THROW_ERROR("Unknown directive");
300 } else if (state == HOSTBLOCK) {
301 // no host assertions ATM
302 if (strsame(name,"nospew")) {
303 if (ci.have_pacing) THROW_ERROR("Directive nospew incompatible with pacing ");
304 if (ci.have_nospew) THROW_ERROR("Repeated directive");
307 } else THROW_ERROR("Unknown directive");
308 } else if (state == FILEBLOCK) {
309 if (strsame(name,"linux")) {
310 if (!cfi.have_path) THROW_ERROR("A path to a valid kernel must precede linux");
312 do_linux_kernel(pc,pcf);
313 cfi.have_load_addr=1;
318 THROW_ERROR("Unknown directive");
320 } else THROW_ERROR("Unknown directive");
324 if (state == GLOBALBLOCK) {
325 // no global assignments ATM
326 THROW_ERROR("Unknown directive");
327 } else if (state == HOSTBLOCK) {
329 if (strsame(name, "ethernet") || strsame(name, "mac")) {
330 if (type != MACADDR && type != MACADDR_PARTIAL)
331 THROW_ERROR("Directive must be followed by a (partial or complete) ethernet address");
332 else if (ci.have_mac) THROW_ERROR("Repeated directive");
334 if (type == MACADDR) {
335 // set MAC address; this is non-partial, so len = ETH_ALEN
336 bcopy(pvalue->mac_address, pc->mac, ETH_ALEN);
337 pc->partial_mac_len = ETH_ALEN;
339 bcopy(pvalue->pm.mac_address, pc->mac, pvalue->pm.mac_len);
340 pc->partial_mac_len = pvalue->pm.mac_len;
346 else if (strsame(name, "execute") || strsame(name, "run")) {
347 if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
348 else if (ci.have_run_addr==2) THROW_ERROR("Repeated directive");
351 pc->run_addr = pvalue->number;
352 ci.have_run_addr = 2;
354 else if (strsame(name, "blocksize")) {
355 if (type != NUMBER) THROW_ERROR("Directive must be followed by an integer ");
356 else if (ci.have_blocksize) THROW_ERROR("Repeated directive");
359 pc->blocklen = pvalue->number;
360 ci.have_blocksize = 1;
362 else if (strsame(name, "framesize")) {
363 if (type != NUMBER) THROW_ERROR("Directive must be followed by an integer ");
364 else if (ci.have_framesize) THROW_ERROR("Repeated directive");
367 pc->framelen = pvalue->number;
368 ci.have_framesize = 1;
370 else if (strsame(name,"pacing")) {
371 if (type != NUMBER) THROW_ERROR("Directive must be followed by an integer ");
372 if (ci.have_nospew) THROW_ERROR("Directive pacing incompatible with nospew ");
373 if (ci.have_pacing) THROW_ERROR("Repeated directive");
374 pc->pacing = pvalue->number;
377 else THROW_ERROR("Unknown directive");
378 } else if (state == FILEBLOCK) {
380 if (strsame(name, "path")) {
381 if (type != TEXT) THROW_ERROR("Directive must be followed by a filename");
382 else if (cfi.have_path) THROW_ERROR("Repeated directive");
385 pcf->path = pvalue->text;
389 else if (strsame(name, "load")) {
390 if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
391 else if (cfi.have_load_addr) THROW_ERROR("Repeated directive");
394 pcf->load_addr = pvalue->number;
395 cfi.have_load_addr = 1;
398 else if (strsame(name, "offset")) {
399 if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
400 else if (cfi.have_offset) THROW_ERROR("Repeated directive");
403 pcf->offset = pvalue->number;
407 else if (strsame(name, "length")) {
408 if (type != NUMBER) THROW_ERROR("Directive must be followed by a memory address");
409 else if (cfi.have_length) THROW_ERROR("Repeated directive");
412 pcf->length = pvalue->number;
415 else THROW_ERROR("Unknown directive");
419 default: THROW_ERROR("Mistake");