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