1 /*
2   Copyright (c) 2002-2005, Miguel Mendez. All rights reserved.
3   Copyright (c) 2015, Chris Hutchinson. All rights reserved.
4 
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are met:
7 
8   * Redistributions of source code must retain the above copyright notice,
9   this list of conditions and the following disclaimer.
10   * Redistributions in binary form must reproduce the above copyright notice,
11   this list of conditions and the following disclaimer in the documentation
12   and/or other materials provided with the distribution.
13 
14   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 
25   $Id: parser.c 49 2015-11-09 11:42:43Z chrish $
26 
27 */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 
35 #include "parser.h"
36 
37 static int parseline(RC_NODE *);
38 int yylex(void);
39 
40 static int tmp_knobs, tmp_strings;
41 
42 /* RC_NODEs that look like knobs but aren't */
43 
44 static char *except[] = { "swapfile" , "pccard_ifconfig", "nisdomainname",
45 			  "ip_portrange_first", "ip_portrange_last", "gif_interfaces",
46 			  "defaultrouter", "ipv6_defaultrouter", "keymap", "keyrate",
47 			  "keybell", "keychange", "cursor", "scrnmap", "font8x16",
48 			  "font8x14", "font8x8", "saver", "mousechar_start", "dumpdev",
49 			  "rand_irqs", "ipv6_default_interface", "ipv6_faith_prefix",
50 			  "isdn_fsdev", "isdn_screenflags", "amd_map_program",
51 			  "gbde_devices", "extra_netfs_types", "pcvt_keymap",
52 			  "pcvt_keydel", "pcvt_keyrate", "pcvt_lines",
53 			  "pcvt_blanktime", "pcvt_cursorh", "pcvt_cursorl", "sendmail_enable"
54 };
55 
56 
57 static int pending;
58 
59 extern char *yytext;
60 extern FILE *yyin;
61 
62 int
build_list(char * filename,RC_CONF * my_rc)63 build_list(char *filename, RC_CONF *my_rc)
64 {
65   RC_NODE scratch;
66   RC_NODE *alpha;
67   RC_NODE *current;
68   RC_NODE *old;
69   RC_NODE *foo, *bar;
70 
71   int retval;
72 
73   tmp_knobs = 0;
74   tmp_strings = 0;
75 
76   alpha = malloc(sizeof(RC_NODE));
77   memset(alpha, 0, sizeof(RC_NODE));
78   current = alpha;
79   old = &scratch;
80 
81   pending = 0;
82   retval = 0;
83 
84   yyin = fopen(filename, "r");
85 
86   /* First pass, build linked list of nodes */
87   do {
88 
89     retval = parseline(current);
90     old = current;
91     current = malloc(sizeof(RC_NODE));
92     memset(current, 0, sizeof(RC_NODE));
93     old->next = current;
94     current->next = NULL;
95 
96   } while (retval == 0);
97 
98   /* Second pass, build knob and strings list */
99   if (tmp_knobs > 0) {
100 
101     my_rc->knobs_ptr = malloc(tmp_knobs * sizeof(RC_NODE));
102     memset(my_rc->knobs_ptr, 0, (tmp_knobs * sizeof(RC_NODE)));
103 
104   } else {
105 
106     my_rc->knobs_ptr = malloc(sizeof(RC_NODE));
107     memset(my_rc->knobs_ptr, 0, (sizeof(RC_NODE)));
108 
109   }
110 
111   if (tmp_strings > 0) {
112 
113     my_rc->string_ptr = malloc(tmp_strings * sizeof(RC_NODE));
114     memset(my_rc->string_ptr, 0, (tmp_strings * sizeof(RC_NODE)));
115 
116   } else {
117 
118     my_rc->string_ptr = malloc(sizeof(RC_NODE));
119     memset(my_rc->string_ptr, 0, (sizeof(RC_NODE)));
120 
121   }
122 
123   tmp_knobs = 0;
124   tmp_strings = 0;
125 
126   /* Preserve original pointers */
127   foo = my_rc->knobs_ptr;
128   bar = my_rc->string_ptr;
129 
130 
131   current = alpha;
132   while (current->next != NULL) {
133 
134     if (isalnum((int)*current->name)) {
135 
136       if (current->knob == IS_KNOB) {
137 
138 	*foo = *current;
139 	foo++;
140 	tmp_knobs++;
141 
142       } else {
143 
144 	*bar = *current;
145 	bar++;
146 	tmp_strings++;
147 
148       }
149 
150     }
151 
152     current = current->next;
153 
154   }
155 
156   my_rc->knobs_size = tmp_knobs;
157   my_rc->string_size = tmp_strings;
158 
159   fclose(yyin);
160   return 0;
161 
162 }
163 
164 static int
parseline(RC_NODE * current)165 parseline(RC_NODE *current)
166 {
167   char i;
168   int delta = 0,compos = 0;
169   int is_except = 0;
170   int foo;
171   int result = 1;
172 
173   if (pending == 0) {
174 
175     result = yylex();
176     if (result == 0) return(-1);
177 
178   } else {
179 
180     pending = 0;
181 
182   }
183 
184   delta = 0;
185   i = yytext[delta];
186 
187   while (i != '=') {
188 
189     current->name[delta] = i;
190     delta++;
191     i = yytext[delta];
192   }
193 
194   current->name[delta] = (char) 0;
195 
196   /* Exception list */
197   for (foo=0; foo < (sizeof(except)/sizeof(char *)); foo++) {
198 
199     if (!strncmp(current->name, except[foo], 255)) {
200 
201       is_except = 1;
202       break;
203 
204     }
205   }
206 
207 
208   result = yylex();
209   if (result == 0) return(-1);
210 
211   /* Check for KNOB_YES or KNOB_NO */
212   if (!strncmp(yytext, KNOB_YES, strlen(KNOB_YES))) {
213 
214     current->knob = IS_KNOB;
215     current->knob_val = KNOB_IS_YES;
216     current->knob_orig = KNOB_IS_YES;
217     current->modified = MODIFIED_NO;
218     tmp_knobs++;
219 
220   } else if (!strncmp(yytext, KNOB_NO, strlen(KNOB_NO)) && is_except == 0) {
221 
222     current->knob = IS_KNOB;
223     current->knob_val = KNOB_IS_NO;
224     current->knob_orig = KNOB_IS_NO;
225     current->modified = MODIFIED_NO;
226     tmp_knobs++;
227 
228   } else {
229 
230     current->knob = NOT_KNOB;
231     delta = 0;
232     i = yytext[delta];
233     current->value[delta] = i;
234     current->orig[delta] = i;
235     delta++;
236 
237     i = yytext[delta];
238 
239     while (i != '"' && i != '\n' && i != (char) 0) {
240 
241       current->value[delta] = i;
242       current->orig[delta] = i;
243       delta++;
244       i = yytext[delta];
245 
246     }
247 
248     current->value[delta] = (char) '"';
249     current->orig[delta] = (char) '"';
250     current->value[delta+1] = (char) 0;
251     current->orig[delta+1] = (char) 0;
252     current->modified = MODIFIED_NO;
253     tmp_strings++;
254 
255   }
256 
257 
258   result = yylex();
259   if (result == 0) return(-1);
260   i = *yytext;
261   delta = 0;
262   if (i == '#') {
263 
264     compos = 0;
265     delta++;
266     i = yytext[delta];
267     while (i != '\n') {
268 
269       current->comment[compos] = i;
270       delta++;
271       compos++;
272       i = yytext[delta];
273 
274     }
275 
276     current->comment[compos] = (char) 0;
277 
278   } else {
279 
280     pending = 1;
281 
282   }
283 
284   return(0);
285 
286 }
287 
288 /*
289  * merge_lists receives two tuples of lists and merges the pairs, overriding the
290  * defaults list with the values in the rc list. It also allocates extra space
291  * for possible user additions.
292  */
293 int
merge_lists(RC_CONF * my_rc_defaults,RC_CONF * my_rc)294 merge_lists(RC_CONF *my_rc_defaults, RC_CONF *my_rc)
295 {
296   RC_NODE *rc_knobs_final;
297   RC_NODE *rc_str_final;
298   RC_NODE *baz, *bar, *aux;
299   int total_nodes;
300   int foo, j, k, asize;
301   int node_present;
302 
303   total_nodes = my_rc_defaults->knobs_size;
304 
305   asize = (my_rc_defaults->knobs_size + my_rc->knobs_size) * 2;
306 
307 #ifdef VERBOSE_CONSOLE
308   printf("Allocated %i bytes for %i knobs.\n", asize * sizeof(RC_NODE), total_nodes);
309 #endif
310 
311   /* merge knobs */
312   rc_knobs_final = malloc(asize * sizeof(RC_NODE));
313   memset(rc_knobs_final, 0, (asize * sizeof(RC_NODE)));
314 
315   memcpy(rc_knobs_final, my_rc_defaults->knobs_ptr,
316 	 my_rc_defaults->knobs_size * sizeof(RC_NODE));
317 
318   baz = my_rc->knobs_ptr;
319   bar = rc_knobs_final;
320 
321   for (j = 0; j<total_nodes; j++) {
322 
323     baz = my_rc->knobs_ptr;
324     for (foo = 0; foo < my_rc->knobs_size; foo++) {
325 
326       if (!strncmp(bar->name, baz->name, 255)) {
327 #ifdef VERBOSE_CONSOLE
328 	printf("Overridden---> %s\n", bar->name);
329 #endif
330 	bar->knob_val = baz->knob_val;
331 	bar->knob_orig = baz->knob_orig;
332 
333       }
334 
335       baz++;
336 
337     }
338 
339     bar++;
340 
341   }
342 
343   /* add values present in rc.conf but not in the defaults file */
344   total_nodes = my_rc_defaults->knobs_size;
345   baz = my_rc->knobs_ptr;
346 
347   for (j = 0; j < my_rc->knobs_size; j++) {
348 
349     node_present = 0;
350     bar = my_rc_defaults->knobs_ptr;
351 
352     for (k = 0; k < my_rc_defaults->knobs_size; k++) {
353 
354       if (!strncmp(baz->name, bar->name, 255)) node_present = 1;
355       bar++;
356 
357     }
358 
359     aux = rc_knobs_final;
360     for (k = 0; k < total_nodes; k++) {
361 
362       if (!strncmp(baz->name, aux->name, 255)) {
363 
364 #ifdef VERBOSE_CONSOLE
365 	printf("Dupe -> %s\n", aux->name);
366 #endif
367 	node_present = 1;
368 	aux->knob_val = baz->knob_val;
369 	aux->knob_orig = baz->knob_orig;
370 
371       }
372 
373       aux++;
374 
375     }
376 
377     if (node_present == 0) {
378 
379       memcpy((rc_knobs_final+total_nodes), baz, sizeof(RC_NODE));
380       total_nodes++;
381 
382     }
383 
384     baz++;
385 
386   }
387 
388   my_rc_defaults->knobs_size = total_nodes;
389   my_rc_defaults->knobs_ptr = rc_knobs_final;
390 
391   asize = (my_rc_defaults->string_size + my_rc->string_size) * 2;
392 
393 #ifdef VERBOSE_CONSOLE
394   printf("Allocated %i bytes for strings.\n", asize * sizeof(RC_NODE));
395 #endif
396 
397   /* merge strings */
398   rc_str_final = malloc(asize * sizeof(RC_NODE));
399   memset(rc_str_final, 0, (asize * sizeof(RC_NODE)));
400 
401   memcpy(rc_str_final, my_rc_defaults->string_ptr,
402 	 my_rc_defaults->string_size * sizeof(RC_NODE));
403 
404   baz = my_rc->string_ptr;
405   bar = rc_str_final;
406 
407 
408   for (j = 0; j < my_rc_defaults->string_size; j++) {
409 
410     baz = my_rc->string_ptr;
411     for (foo = 0; foo < my_rc->string_size; foo++) {
412 
413       if (!strncmp(bar->name, baz->name, 255)) {
414 
415 #ifdef VERBOSE_CONSOLE
416 	fprintf(stderr,"Overridden---> %s\n", bar->name);
417 #endif
418 	memset(bar->value, 0, 255);
419 	strncpy(bar->value, baz->value, 255);
420 
421 	memset(bar->orig, 0, 255);
422 	strncpy(bar->orig, baz->orig, 255);
423 
424       }
425 
426       baz++;
427 
428     }
429 
430     bar++;
431 
432   }
433 
434   /* add values present in rc.conf but not in the defaults file */
435   total_nodes = my_rc_defaults->string_size;
436 
437   baz = my_rc->string_ptr;
438   for (j = 0; j < my_rc->string_size; j++) {
439 
440     node_present = 0;
441     bar = my_rc_defaults->string_ptr;
442 
443     for (k = 0; k < my_rc_defaults->string_size; k++) {
444 
445       if (!strncmp(baz->name, bar->name, 255)) node_present=1;
446       bar++;
447 
448     }
449 
450 
451     aux = rc_str_final;
452     for (k=0; k < total_nodes; k++) {
453 
454       if (!strncmp(baz->name, aux->name, 255)) {
455 
456 #ifdef VERBOSE_CONSOLE
457 	printf("Dupe -> %s\n", aux->name);
458 #endif
459 
460 	node_present = 1;
461 	strncpy(aux->value, baz->value, 255);
462 	strncpy(aux->orig, baz->orig, 255);
463 
464       }
465 
466       aux++;
467 
468     }
469 
470 
471     if (node_present == 0) {
472 
473 #ifdef VERBOSE_CONSOLE
474       printf("Adding new string: %s\n", baz->name);
475 #endif
476       memcpy((rc_str_final+total_nodes), baz,sizeof(RC_NODE));
477       total_nodes++;
478     }
479 
480     baz++;
481 
482   }
483 
484   my_rc_defaults->string_size = total_nodes;
485   my_rc_defaults->string_ptr = rc_str_final;
486 
487   /* everything went ok */
488   return 0;
489 
490 }
491 
492 void
list_sort(RC_NODE * rc_data,int num)493 list_sort(RC_NODE *rc_data, int num)
494 {
495   int i, j, retval, changed;
496   RC_NODE *list;
497   RC_NODE temp;
498 
499   list = rc_data;
500 
501   do {
502 
503     changed = 0;
504     for (i = 0; i < num-1; i++) {
505       for (j = i; j < num-1-i; j++) {
506 
507 	retval = strncmp(list[j].name, list[j+1].name, 255);
508 
509 	if (retval >= 1) {
510 #ifdef VERBOSE_CONSOLE
511 	  printf("Sorting: %s (%x) > %s (%x)\n", list[j].name, list+j,
512 		 list[j+1].name, list+j+1);
513 #endif
514 	  memcpy(&temp, (list+j), sizeof(RC_NODE));
515 	  memcpy((list+j), (list+j+1), sizeof(RC_NODE));
516 	  memcpy((list+j+1), &temp, sizeof(RC_NODE));
517 	  changed = 1;
518 	}
519       }
520     }
521 
522   } while (changed == 1);
523 
524 }
525