1 /* $NetBSD: yacc.y,v 1.11 2016/06/28 09:22:16 wiz Exp $ */
2
3 %{
4 /*-
5 * Copyright (c)2003, 2006 Citrus Project,
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #if HAVE_NBTOOL_CONFIG_H
31 #include "nbtool_config.h"
32 #endif
33
34 #include <sys/cdefs.h>
35 #if !defined(lint)
36 __RCSID("$NetBSD: yacc.y,v 1.11 2016/06/28 09:22:16 wiz Exp $");
37 #endif /* not lint */
38
39 #include <assert.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <limits.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <arpa/inet.h>
48 #include <sys/types.h>
49
50 #include "ldef.h"
51
52 #ifndef __packed
53 #define __packed
54 #endif
55
56 #include "citrus_namespace.h"
57 #include "citrus_types.h"
58 #include "citrus_mapper_std_file.h"
59 #include "citrus_region.h"
60 #include "citrus_db_factory.h"
61 #include "citrus_db_hash.h"
62 #include "citrus_lookup_factory.h"
63 #include "citrus_pivot_factory.h"
64
65 int debug = 0;
66 static char *output = NULL;
67 static void *table = NULL;
68 static size_t table_size;
69 static char *map_name;
70 static int map_type;
71 static u_int32_t dst_invalid, dst_ilseq, oob_mode, dst_unit_bits;
72 static void (*putfunc)(void *, size_t, u_int32_t) = 0;
73
74 static u_int32_t src_next;
75
76 static u_int32_t done_flag = 0;
77 #define DF_TYPE 0x00000001
78 #define DF_NAME 0x00000002
79 #define DF_SRC_ZONE 0x00000004
80 #define DF_DST_INVALID 0x00000008
81 #define DF_DST_ILSEQ 0x00000010
82 #define DF_DST_UNIT_BITS 0x00000020
83 #define DF_OOB_MODE 0x00000040
84
85 static linear_zone_t rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX];
86 static size_t rowcol_len = 0;
87 static u_int32_t rowcol_bits = 0, rowcol_mask = 0;
88
89 static void dump_file(void);
90 static void setup_map(void);
91 static void set_type(int);
92 static void set_name(char *);
93 static void set_src_zone(u_int32_t);
94 static void set_dst_invalid(u_int32_t);
95 static void set_dst_ilseq(u_int32_t);
96 static void set_dst_unit_bits(u_int32_t);
97 static void set_oob_mode(u_int32_t);
98 static int check_src(u_int32_t, u_int32_t);
99 static void store(const linear_zone_t *, u_int32_t, int);
100 static void put8(void *, size_t, u_int32_t);
101 static void put16(void *, size_t, u_int32_t);
102 static void put32(void *, size_t, u_int32_t);
103 static void set_range(u_int32_t, u_int32_t);
104 static void set_src(linear_zone_t *, u_int32_t, u_int32_t);
105 %}
106
107 %union {
108 u_int32_t i_value;
109 char *s_value;
110 linear_zone_t lz_value;
111 }
112
113 %token R_TYPE R_NAME R_SRC_ZONE R_DST_UNIT_BITS
114 %token R_DST_INVALID R_DST_ILSEQ
115 %token R_BEGIN_MAP R_END_MAP R_INVALID R_ROWCOL
116 %token R_ILSEQ R_OOB_MODE
117 %token R_LN
118 %token <i_value> L_IMM
119 %token <s_value> L_STRING
120
121 %type <lz_value> src
122 %type <i_value> dst types oob_mode_sel zone
123
124 %%
125
126 file : property mapping lns
127 { dump_file(); }
128
129 property : /* empty */
130 | property R_LN
131 | property name
132 | property type
133 | property src_zone
134 | property dst_invalid
135 | property dst_ilseq
136 | property dst_unit_bits
137 | property oob_mode
138
139 name : R_NAME L_STRING { set_name($2); $2 = NULL; }
140 type : R_TYPE types { set_type($2); }
141 types : R_ROWCOL { $$ = R_ROWCOL; }
142 range : L_IMM '-' L_IMM { set_range($1, $3); }
143
144 ranges : /* empty */
145 | ranges range '/'
146
147 src_zone : R_SRC_ZONE zone { set_src_zone($2); }
148 zone : range {
149 $$ = 32;
150 }
151 | range '/' range '/' ranges L_IMM {
152 $$ = $6;
153 }
154
155 dst_invalid : R_DST_INVALID L_IMM { set_dst_invalid($2); }
156 dst_ilseq : R_DST_ILSEQ L_IMM { set_dst_ilseq($2); }
157 dst_unit_bits : R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); }
158 oob_mode : R_OOB_MODE oob_mode_sel { set_oob_mode($2); }
159
160 oob_mode_sel : R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
161 | R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
162
163 mapping : begin_map map_elems R_END_MAP
164 begin_map : R_BEGIN_MAP lns { setup_map(); }
165
166 map_elems : /* empty */
167 | map_elems map_elem lns
168
169 map_elem : src '=' dst
170 { store(&$1, $3, 0); }
171 | src '=' L_IMM '-'
172 { store(&$1, $3, 1); }
173 dst : L_IMM
174 {
175 $$ = $1;
176 }
177 | R_INVALID
178 {
179 $$ = dst_invalid;
180 }
181 | R_ILSEQ
182 {
183 $$ = dst_ilseq;
184 }
185
186 src : /* empty */
187 {
188 set_src(&$$, src_next, src_next);
189 }
190 | L_IMM
191 {
192 set_src(&$$, $1, $1);
193 }
194 | L_IMM '-' L_IMM
195 {
196 set_src(&$$, $1, $3);
197 }
198 | '-' L_IMM
199 {
200 set_src(&$$, src_next, $2);
201 }
202 lns : R_LN
203 | lns R_LN
204
205 %%
206
207 static void
208 warning(const char *s)
209 {
210 fprintf(stderr, "%s in %d\n", s, line_number);
211 }
212
213 int
yyerror(const char * s)214 yyerror(const char *s)
215 {
216 warning(s);
217 exit(1);
218 }
219
220 void
put8(void * ptr,size_t ofs,u_int32_t val)221 put8(void *ptr, size_t ofs, u_int32_t val)
222 {
223 *((u_int8_t *)ptr + ofs) = val;
224 }
225
226 void
put16(void * ptr,size_t ofs,u_int32_t val)227 put16(void *ptr, size_t ofs, u_int32_t val)
228 {
229 u_int16_t oval = htons(val);
230 memcpy((u_int16_t *)ptr + ofs, &oval, 2);
231 }
232
233 void
put32(void * ptr,size_t ofs,u_int32_t val)234 put32(void *ptr, size_t ofs, u_int32_t val)
235 {
236 u_int32_t oval = htonl(val);
237 memcpy((u_int32_t *)ptr + ofs, &oval, 4);
238 }
239
240 static void
alloc_table(void)241 alloc_table(void)
242 {
243 size_t i;
244 u_int32_t val = 0;
245 linear_zone_t *p;
246
247 i = rowcol_len;
248 p = &rowcol[--i];
249 table_size = p->width;
250 while (i > 0) {
251 p = &rowcol[--i];
252 table_size *= p->width;
253 }
254 table = (void *)malloc(table_size * dst_unit_bits / 8);
255 if (table == NULL) {
256 perror("malloc");
257 exit(1);
258 }
259
260 switch (oob_mode) {
261 case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
262 val = dst_invalid;
263 break;
264 case _CITRUS_MAPPER_STD_OOB_ILSEQ:
265 val = dst_ilseq;
266 break;
267 default:
268 _DIAGASSERT(0);
269 }
270 for (i = 0; i < table_size; i++)
271 (*putfunc)(table, i, val);
272 }
273
274 static void
setup_map(void)275 setup_map(void)
276 {
277
278 if ((done_flag & DF_SRC_ZONE)==0) {
279 fprintf(stderr, "SRC_ZONE is mandatory.\n");
280 exit(1);
281 }
282 if ((done_flag & DF_DST_UNIT_BITS)==0) {
283 fprintf(stderr, "DST_UNIT_BITS is mandatory.\n");
284 exit(1);
285 }
286
287 if ((done_flag & DF_DST_INVALID) == 0)
288 dst_invalid = 0xFFFFFFFF;
289 if ((done_flag & DF_DST_ILSEQ) == 0)
290 dst_ilseq = 0xFFFFFFFE;
291 if ((done_flag & DF_OOB_MODE) == 0)
292 oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
293
294 alloc_table();
295 }
296
297 static void
create_rowcol_info(struct _region * r)298 create_rowcol_info(struct _region *r)
299 {
300 void *ptr;
301 size_t ofs, i, len;
302
303 ofs = 0;
304 ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE);
305 if (ptr == NULL)
306 err(EXIT_FAILURE, "malloc");
307 put32(ptr, ofs, rowcol_bits); ofs++;
308 put32(ptr, ofs, dst_invalid); ofs++;
309
310 /* XXX: keep backward compatibility */
311 switch (rowcol_len) {
312 case 1:
313 put32(ptr, ofs, 0); ofs++;
314 put32(ptr, ofs, 0); ofs++;
315 /*FALLTHROUGH*/
316 case 2:
317 len = 0;
318 break;
319 default:
320 len = rowcol_len;
321 }
322 for (i = 0; i < rowcol_len; ++i) {
323 put32(ptr, ofs, rowcol[i].begin); ofs++;
324 put32(ptr, ofs, rowcol[i].end); ofs++;
325 }
326 put32(ptr, ofs, dst_unit_bits); ofs++;
327 put32(ptr, ofs, len); ofs++;
328
329 _region_init(r, ptr, ofs * 4);
330 }
331
332
333 static void
create_rowcol_ext_ilseq_info(struct _region * r)334 create_rowcol_ext_ilseq_info(struct _region *r)
335 {
336 void *ptr;
337 size_t ofs;
338
339 ofs = 0;
340 ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
341 if (ptr==NULL)
342 err(EXIT_FAILURE, "malloc");
343
344 put32(ptr, ofs, oob_mode); ofs++;
345 put32(ptr, ofs, dst_ilseq); ofs++;
346
347 _region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
348 }
349
350 #define CHKERR(ret, func, a) \
351 do { \
352 ret = func a; \
353 if (ret) \
354 errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret)); \
355 } while (/*CONSTCOND*/0)
356
357 static void
dump_file(void)358 dump_file(void)
359 {
360 FILE *fp;
361 int ret;
362 struct _db_factory *df;
363 struct _region data;
364 void *serialized;
365 size_t size;
366
367 /*
368 * build database
369 */
370 CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
371
372 /* store type */
373 CHKERR(ret, _db_factory_addstr_by_s,
374 (df, _CITRUS_MAPPER_STD_SYM_TYPE,
375 _CITRUS_MAPPER_STD_TYPE_ROWCOL));
376
377 /* store info */
378 create_rowcol_info(&data);
379 CHKERR(ret, _db_factory_add_by_s,
380 (df, _CITRUS_MAPPER_STD_SYM_INFO, &data, 1));
381
382 /* ilseq extension */
383 create_rowcol_ext_ilseq_info(&data);
384 CHKERR(ret, _db_factory_add_by_s,
385 (df, _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &data, 1));
386
387 /* store table */
388 _region_init(&data, table, table_size*dst_unit_bits/8);
389 CHKERR(ret, _db_factory_add_by_s,
390 (df, _CITRUS_MAPPER_STD_SYM_TABLE, &data, 1));
391
392 /*
393 * dump database to file
394 */
395 if (output)
396 fp = fopen(output, "wb");
397 else
398 fp = stdout;
399
400 if (fp == NULL) {
401 perror("fopen");
402 exit(1);
403 }
404
405 /* dump database body */
406 size = _db_factory_calc_size(df);
407 serialized = malloc(size);
408 _region_init(&data, serialized, size);
409 CHKERR(ret, _db_factory_serialize,
410 (df, _CITRUS_MAPPER_STD_MAGIC, &data));
411 if (fwrite(serialized, size, 1, fp) != 1)
412 err(EXIT_FAILURE, "fwrite");
413
414 fclose(fp);
415 }
416
417 static void
418 /*ARGSUSED*/
set_type(int type)419 set_type(int type)
420 {
421
422 if (done_flag & DF_TYPE) {
423 warning("TYPE is duplicated. ignored this one");
424 return;
425 }
426
427 map_type = type;
428
429 done_flag |= DF_TYPE;
430 }
431 static void
432 /*ARGSUSED*/
set_name(char * str)433 set_name(char *str)
434 {
435
436 if (done_flag & DF_NAME) {
437 warning("NAME is duplicated. ignored this one");
438 return;
439 }
440
441 map_name = str;
442
443 done_flag |= DF_NAME;
444 }
445 static void
set_src_zone(u_int32_t val)446 set_src_zone(u_int32_t val)
447 {
448 size_t i;
449 linear_zone_t *p;
450
451 if (done_flag & DF_SRC_ZONE) {
452 warning("SRC_ZONE is duplicated. ignored this one");
453 return;
454 }
455 rowcol_bits = val;
456
457 /* sanity check */
458 switch (rowcol_bits) {
459 case 8: case 16: case 32:
460 if (rowcol_len <= 32 / rowcol_bits)
461 break;
462 /*FALLTHROUGH*/
463 default:
464 goto bad;
465 }
466 rowcol_mask = 1 << (rowcol_bits - 1);
467 rowcol_mask |= rowcol_mask - 1;
468 for (i = 0; i < rowcol_len; ++i) {
469 p = &rowcol[i];
470 _DIAGASSERT(p->begin <= p->end);
471 if (p->end > rowcol_mask)
472 goto bad;
473 }
474 done_flag |= DF_SRC_ZONE;
475 return;
476
477 bad:
478 yyerror("Illegal argument for SRC_ZONE");
479 }
480 static void
set_dst_invalid(u_int32_t val)481 set_dst_invalid(u_int32_t val)
482 {
483
484 if (done_flag & DF_DST_INVALID) {
485 warning("DST_INVALID is duplicated. ignored this one");
486 return;
487 }
488
489 dst_invalid = val;
490
491 done_flag |= DF_DST_INVALID;
492 }
493 static void
set_dst_ilseq(u_int32_t val)494 set_dst_ilseq(u_int32_t val)
495 {
496
497 if (done_flag & DF_DST_ILSEQ) {
498 warning("DST_ILSEQ is duplicated. ignored this one");
499 return;
500 }
501
502 dst_ilseq = val;
503
504 done_flag |= DF_DST_ILSEQ;
505 }
506 static void
set_oob_mode(u_int32_t val)507 set_oob_mode(u_int32_t val)
508 {
509
510 if (done_flag & DF_OOB_MODE) {
511 warning("OOB_MODE is duplicated. ignored this one");
512 return;
513 }
514
515 oob_mode = val;
516
517 done_flag |= DF_OOB_MODE;
518 }
519 static void
set_dst_unit_bits(u_int32_t val)520 set_dst_unit_bits(u_int32_t val)
521 {
522
523 if (done_flag & DF_DST_UNIT_BITS) {
524 warning("DST_UNIT_BITS is duplicated. ignored this one");
525 return;
526 }
527
528 switch (val) {
529 case 8:
530 putfunc = &put8;
531 dst_unit_bits = val;
532 break;
533 case 16:
534 putfunc = &put16;
535 dst_unit_bits = val;
536 break;
537 case 32:
538 putfunc = &put32;
539 dst_unit_bits = val;
540 break;
541 default:
542 yyerror("Illegal argument for DST_UNIT_BITS");
543 }
544 done_flag |= DF_DST_UNIT_BITS;
545 }
546 static int
check_src(u_int32_t begin,u_int32_t end)547 check_src(u_int32_t begin, u_int32_t end)
548 {
549 size_t i;
550 linear_zone_t *p;
551 u_int32_t m, n;
552
553 if (begin > end)
554 return 1;
555 if (begin < end) {
556 m = begin & ~rowcol_mask;
557 n = end & ~rowcol_mask;
558 if (m != n)
559 return 1;
560 }
561 for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
562 i -= rowcol_bits;
563 m = (begin >> i) & rowcol_mask;
564 if (m < p->begin || m > p->end)
565 return 1;
566 }
567 if (begin < end) {
568 n = end & rowcol_mask;
569 _DIAGASSERT(p > rowcol);
570 --p;
571 if (n < p->begin || n > p->end)
572 return 1;
573 }
574 return 0;
575 }
576 static void
store(const linear_zone_t * lz,u_int32_t dst,int inc)577 store(const linear_zone_t *lz, u_int32_t dst, int inc)
578 {
579 size_t i, ofs;
580 linear_zone_t *p;
581 u_int32_t n;
582
583 ofs = 0;
584 for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
585 i -= rowcol_bits;
586 n = ((lz->begin >> i) & rowcol_mask) - p->begin;
587 ofs = (ofs * p->width) + n;
588 }
589 n = lz->width;
590 while (n-- > 0) {
591 (*putfunc)(table, ofs++, dst);
592 if (inc)
593 dst++;
594 }
595 }
596 static void
set_range(u_int32_t begin,u_int32_t end)597 set_range(u_int32_t begin, u_int32_t end)
598 {
599 linear_zone_t *p;
600
601 if (rowcol_len >= _CITRUS_MAPPER_STD_ROWCOL_MAX)
602 goto bad;
603 p = &rowcol[rowcol_len++];
604
605 if (begin > end)
606 goto bad;
607 p->begin = begin, p->end = end;
608 p->width = end - begin + 1;
609
610 return;
611
612 bad:
613 yyerror("Illegal argument for SRC_ZONE");
614 }
615 static void
set_src(linear_zone_t * lz,u_int32_t begin,u_int32_t end)616 set_src(linear_zone_t *lz, u_int32_t begin, u_int32_t end)
617 {
618 _DIAGASSERT(lz != NULL);
619
620 if (check_src(begin, end) != 0)
621 yyerror("illegal zone");
622
623 lz->begin = begin, lz->end = end;
624 lz->width = end - begin + 1;
625
626 src_next = end + 1;
627 }
628
629 static void
do_mkdb(FILE * in)630 do_mkdb(FILE *in)
631 {
632 int ret;
633 FILE *out;
634
635 /* dump DB to file */
636 if (output)
637 out = fopen(output, "wb");
638 else
639 out = stdout;
640
641 if (out==NULL)
642 err(EXIT_FAILURE, "fopen");
643
644 ret = _lookup_factory_convert(out, in);
645 fclose(out);
646 if (ret && output)
647 unlink(output); /* dump failure */
648 }
649
650 static void
do_mkpv(FILE * in)651 do_mkpv(FILE *in)
652 {
653 int ret;
654 FILE *out;
655
656 /* dump pivot to file */
657 if (output)
658 out = fopen(output, "wb");
659 else
660 out = stdout;
661
662 if (out == NULL)
663 err(EXIT_FAILURE, "fopen");
664
665 ret = _pivot_factory_convert(out, in);
666 fclose(out);
667 if (ret && output)
668 unlink(output); /* dump failure */
669 if (ret)
670 errc(EXIT_FAILURE, ret, "");
671 }
672
673 __dead static void
usage(void)674 usage(void)
675 {
676 fprintf(stderr, "Usage: %s [-d] [-m|-p] [-o outfile] [infile]\n",
677 getprogname());
678 exit(EXIT_FAILURE);
679 }
680
681 int
main(int argc,char ** argv)682 main(int argc, char **argv)
683 {
684 int ch;
685 extern char *optarg;
686 extern int optind;
687 FILE *in = NULL;
688 int mkdb = 0, mkpv = 0;
689
690 while ((ch=getopt(argc, argv, "do:mp")) != EOF) {
691 switch (ch) {
692 case 'd':
693 debug=1;
694 break;
695 case 'o':
696 output = strdup(optarg);
697 break;
698 case 'm':
699 mkdb = 1;
700 break;
701 case 'p':
702 mkpv = 1;
703 break;
704 default:
705 usage();
706 }
707 }
708
709 argc-=optind;
710 argv+=optind;
711 switch (argc) {
712 case 0:
713 in = stdin;
714 break;
715 case 1:
716 in = fopen(argv[0], "r");
717 if (!in)
718 err(EXIT_FAILURE, "%s", argv[0]);
719 break;
720 default:
721 usage();
722 }
723
724 if (mkdb)
725 do_mkdb(in);
726 else if (mkpv)
727 do_mkpv(in);
728 else {
729 yyin = in;
730 yyparse();
731 }
732
733 return (0);
734 }
735