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