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