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