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 212 yyerror(const char *s) 213 { 214 215 warning(s); 216 exit(1); 217 } 218 219 void 220 put8(void *ptr, size_t ofs, u_int32_t val) 221 { 222 223 *((u_int8_t *)ptr + ofs) = val; 224 } 225 226 void 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 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 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 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 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 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 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*/ 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*/ 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 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 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 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 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 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 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 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 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 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 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 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 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 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