xref: /freebsd/usr.bin/mkcsmapper/yacc.y (revision 52fba9a943cca518d2978f7588e99a35da37e5f2)
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 = 1u << (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