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 65int debug = 0; 66static char *output = NULL; 67static void *table = NULL; 68static size_t table_size; 69static char *map_name; 70static int map_type; 71static u_int32_t dst_invalid, dst_ilseq, oob_mode, dst_unit_bits; 72static void (*putfunc)(void *, size_t, u_int32_t) = 0; 73 74static u_int32_t src_next; 75 76static 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 85static linear_zone_t rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX]; 86static size_t rowcol_len = 0; 87static u_int32_t rowcol_bits = 0, rowcol_mask = 0; 88 89static void dump_file(void); 90static void setup_map(void); 91static void set_type(int); 92static void set_name(char *); 93static void set_src_zone(u_int32_t); 94static void set_dst_invalid(u_int32_t); 95static void set_dst_ilseq(u_int32_t); 96static void set_dst_unit_bits(u_int32_t); 97static void set_oob_mode(u_int32_t); 98static int check_src(u_int32_t, u_int32_t); 99static void store(const linear_zone_t *, u_int32_t, int); 100static void put8(void *, size_t, u_int32_t); 101static void put16(void *, size_t, u_int32_t); 102static void put32(void *, size_t, u_int32_t); 103static void set_range(u_int32_t, u_int32_t); 104static 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 126file : property mapping lns 127 { dump_file(); } 128 129property : /* 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 139name : R_NAME L_STRING { set_name($2); $2 = NULL; } 140type : R_TYPE types { set_type($2); } 141types : R_ROWCOL { $$ = R_ROWCOL; } 142range : L_IMM '-' L_IMM { set_range($1, $3); } 143 144ranges : /* empty */ 145 | ranges range '/' 146 147src_zone : R_SRC_ZONE zone { set_src_zone($2); } 148zone : range { 149 $$ = 32; 150 } 151 | range '/' range '/' ranges L_IMM { 152 $$ = $6; 153 } 154 155dst_invalid : R_DST_INVALID L_IMM { set_dst_invalid($2); } 156dst_ilseq : R_DST_ILSEQ L_IMM { set_dst_ilseq($2); } 157dst_unit_bits : R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); } 158oob_mode : R_OOB_MODE oob_mode_sel { set_oob_mode($2); } 159 160oob_mode_sel : R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; } 161 | R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; } 162 163mapping : begin_map map_elems R_END_MAP 164begin_map : R_BEGIN_MAP lns { setup_map(); } 165 166map_elems : /* empty */ 167 | map_elems map_elem lns 168 169map_elem : src '=' dst 170 { store(&$1, $3, 0); } 171 | src '=' L_IMM '-' 172 { store(&$1, $3, 1); } 173dst : L_IMM 174 { 175 $$ = $1; 176 } 177 | R_INVALID 178 { 179 $$ = dst_invalid; 180 } 181 | R_ILSEQ 182 { 183 $$ = dst_ilseq; 184 } 185 186src : /* 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 } 202lns : R_LN 203 | lns R_LN 204 205%% 206 207static void 208warning(const char *s) 209{ 210 fprintf(stderr, "%s in %d\n", s, line_number); 211} 212 213int 214yyerror(const char *s) 215{ 216 warning(s); 217 exit(1); 218} 219 220void 221put8(void *ptr, size_t ofs, u_int32_t val) 222{ 223 *((u_int8_t *)ptr + ofs) = val; 224} 225 226void 227put16(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 233void 234put32(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 240static void 241alloc_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 274static void 275setup_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 297static void 298create_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 333static void 334create_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) \ 351do { \ 352 ret = func a; \ 353 if (ret) \ 354 errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret)); \ 355} while (/*CONSTCOND*/0) 356 357static void 358dump_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 417static void 418/*ARGSUSED*/ 419set_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} 431static void 432/*ARGSUSED*/ 433set_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} 445static void 446set_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 477bad: 478 yyerror("Illegal argument for SRC_ZONE"); 479} 480static void 481set_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} 493static void 494set_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} 506static void 507set_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} 519static void 520set_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} 546static int 547check_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} 576static void 577store(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} 596static void 597set_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 612bad: 613 yyerror("Illegal argument for SRC_ZONE"); 614} 615static void 616set_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 629static void 630do_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 650static void 651do_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 674usage(void) 675{ 676 fprintf(stderr, "Usage: %s [-d] [-m|-p] [-o outfile] [infile]\n", 677 getprogname()); 678 exit(EXIT_FAILURE); 679} 680 681int 682main(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