1/* $FreeBSD: stable/11/usr.bin/mkcsmapper/yacc.y 330449 2018-03-05 07:26:05Z eadler $ */
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
61extern FILE		*yyin;
62
63int			 debug = 0;
64
65static linear_zone_t	 rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX];
66static char		*map_name;
67static char		*output = NULL;
68static void		*table = NULL;
69static size_t		 rowcol_len = 0;
70static size_t		 table_size;
71static u_int32_t	 done_flag = 0;
72static u_int32_t	 dst_ilseq, dst_invalid, dst_unit_bits, oob_mode;
73static u_int32_t	 rowcol_bits = 0, rowcol_mask = 0;
74static u_int32_t	 src_next;
75static int		 map_type;
76static 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
86static void	dump_file(void);
87static void	setup_map(void);
88static void	set_type(int);
89static void	set_name(char *);
90static void	set_src_zone(u_int32_t);
91static void	set_dst_invalid(u_int32_t);
92static void	set_dst_ilseq(u_int32_t);
93static void	set_dst_unit_bits(u_int32_t);
94static void	set_oob_mode(u_int32_t);
95static int	check_src(u_int32_t, u_int32_t);
96static void	store(const linear_zone_t *, u_int32_t, int);
97static void	put8(void *, size_t, u_int32_t);
98static void	put16(void *, size_t, u_int32_t);
99static void	put32(void *, size_t, u_int32_t);
100static void	set_range(u_int32_t, u_int32_t);
101static 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
123file		: property mapping lns
124		{ dump_file(); }
125
126property	: /* 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
136name		: R_NAME L_STRING { set_name($2); $2 = NULL; }
137type		: R_TYPE types { set_type($2); }
138types		: R_ROWCOL { $$ = R_ROWCOL; }
139range		: L_IMM '-' L_IMM { set_range($1, $3); }
140
141ranges		: /* empty */
142		| ranges range '/'
143
144src_zone	: R_SRC_ZONE zone { set_src_zone($2); }
145zone		: range {
146			$$ = 32;
147		}
148		| range '/' range '/' ranges L_IMM {
149			$$ = $6;
150		}
151
152dst_invalid	: R_DST_INVALID L_IMM { set_dst_invalid($2); }
153dst_ilseq	: R_DST_ILSEQ L_IMM { set_dst_ilseq($2); }
154dst_unit_bits	: R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); }
155oob_mode	: R_OOB_MODE oob_mode_sel { set_oob_mode($2); }
156
157oob_mode_sel	: R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
158		| R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
159
160mapping		: begin_map map_elems R_END_MAP
161begin_map	: R_BEGIN_MAP lns { setup_map(); }
162
163map_elems	: /* empty */
164		| map_elems map_elem lns
165
166map_elem	: src '=' dst
167		{ store(&$1, $3, 0); }
168		| src '=' L_IMM '-'
169		{ store(&$1, $3, 1); }
170dst		: L_IMM
171		{
172			$$ = $1;
173		}
174		| R_INVALID
175		{
176			$$ = dst_invalid;
177		}
178		| R_ILSEQ
179		{
180			$$ = dst_ilseq;
181		}
182
183src		: /* 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		}
199lns		: R_LN
200		| lns R_LN
201
202%%
203
204static void
205warning(const char *s)
206{
207
208	fprintf(stderr, "%s in %d\n", s, linenumber);
209}
210
211int
212yyerror(const char *s)
213{
214
215	warning(s);
216	exit(1);
217}
218
219void
220put8(void *ptr, size_t ofs, u_int32_t val)
221{
222
223	*((u_int8_t *)ptr + ofs) = val;
224}
225
226void
227put16(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
234void
235put32(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
242static void
243alloc_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
276static void
277setup_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
299static void
300create_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
335static void
336create_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)						\
353do {									\
354	ret = func a;							\
355	if (ret)							\
356		errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret));	\
357} while (/*CONSTCOND*/0)
358
359static void
360dump_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
415static void
416/*ARGSUSED*/
417set_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
430static void
431/*ARGSUSED*/
432set_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
445static void
446set_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 = 1 << (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
476bad:
477	yyerror("Illegal argument for SRC_ZONE");
478}
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}
493
494static void
495set_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
508static void
509set_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
522static void
523set_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
550static int
551check_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
580static void
581store(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
601static void
602set_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
617bad:
618	yyerror("Illegal argument for SRC_ZONE");
619}
620
621static void
622set_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
634static void
635do_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
652static void
653do_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
672static void
673usage(void)
674{
675	fprintf(stderr, "Usage: %s [-d] [-m|-p] [-o outfile] [infile]\n",
676	    getprogname());
677	exit(EXIT_FAILURE);
678}
679
680int
681main(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