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