xref: /freebsd/usr.bin/mkcsmapper/yacc.y (revision edf8578117e8844e02c0121147f45e4609b30680)
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