xref: /freebsd/usr.sbin/ctld/parse.y (revision c90590dd92e3e2c30cc24f8042c77d8d2494e228)
1 %{
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2012 The FreeBSD Foundation
6  * All rights reserved.
7  *
8  * This software was developed by Edward Tomasz Napierala under sponsorship
9  * from the FreeBSD Foundation.
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  * $FreeBSD$
33  */
34 
35 #include <sys/queue.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <assert.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include "ctld.h"
44 #include <netinet/in.h>
45 #include <netinet/ip.h>
46 
47 extern FILE *yyin;
48 extern char *yytext;
49 extern int lineno;
50 
51 static struct conf *conf = NULL;
52 static struct auth_group *auth_group = NULL;
53 static struct portal_group *portal_group = NULL;
54 static struct target *target = NULL;
55 static struct lun *lun = NULL;
56 
57 extern void	yyerror(const char *);
58 extern int	yylex(void);
59 extern void	yyrestart(FILE *);
60 
61 %}
62 
63 %token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
64 %token CLOSING_BRACKET CTL_LUN DEBUG DEVICE_ID DEVICE_TYPE
65 %token DISCOVERY_AUTH_GROUP DISCOVERY_FILTER DSCP FOREIGN
66 %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
67 %token LISTEN LISTEN_ISER LUN MAXPROC OFFLOAD OPENING_BRACKET OPTION
68 %token PATH PCP PIDFILE PORT PORTAL_GROUP REDIRECT SEMICOLON SERIAL
69 %token SIZE STR TAG TARGET TIMEOUT
70 %token AF11 AF12 AF13 AF21 AF22 AF23 AF31 AF32 AF33 AF41 AF42 AF43
71 %token BE EF CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7
72 
73 %union
74 {
75 	char *str;
76 }
77 
78 %token <str> STR
79 
80 %%
81 
82 statements:
83 	|
84 	statements statement
85 	|
86 	statements statement SEMICOLON
87 	;
88 
89 statement:
90 	debug
91 	|
92 	timeout
93 	|
94 	maxproc
95 	|
96 	pidfile
97 	|
98 	isns_server
99 	|
100 	isns_period
101 	|
102 	isns_timeout
103 	|
104 	auth_group
105 	|
106 	portal_group
107 	|
108 	lun
109 	|
110 	target
111 	;
112 
113 debug:		DEBUG STR
114 	{
115 		uint64_t tmp;
116 
117 		if (expand_number($2, &tmp) != 0) {
118 			yyerror("invalid numeric value");
119 			free($2);
120 			return (1);
121 		}
122 
123 		conf->conf_debug = tmp;
124 	}
125 	;
126 
127 timeout:	TIMEOUT STR
128 	{
129 		uint64_t tmp;
130 
131 		if (expand_number($2, &tmp) != 0) {
132 			yyerror("invalid numeric value");
133 			free($2);
134 			return (1);
135 		}
136 
137 		conf->conf_timeout = tmp;
138 	}
139 	;
140 
141 maxproc:	MAXPROC STR
142 	{
143 		uint64_t tmp;
144 
145 		if (expand_number($2, &tmp) != 0) {
146 			yyerror("invalid numeric value");
147 			free($2);
148 			return (1);
149 		}
150 
151 		conf->conf_maxproc = tmp;
152 	}
153 	;
154 
155 pidfile:	PIDFILE STR
156 	{
157 		if (conf->conf_pidfile_path != NULL) {
158 			log_warnx("pidfile specified more than once");
159 			free($2);
160 			return (1);
161 		}
162 		conf->conf_pidfile_path = $2;
163 	}
164 	;
165 
166 isns_server:	ISNS_SERVER STR
167 	{
168 		int error;
169 
170 		error = isns_new(conf, $2);
171 		free($2);
172 		if (error != 0)
173 			return (1);
174 	}
175 	;
176 
177 isns_period:	ISNS_PERIOD STR
178 	{
179 		uint64_t tmp;
180 
181 		if (expand_number($2, &tmp) != 0) {
182 			yyerror("invalid numeric value");
183 			free($2);
184 			return (1);
185 		}
186 
187 		conf->conf_isns_period = tmp;
188 	}
189 	;
190 
191 isns_timeout:	ISNS_TIMEOUT STR
192 	{
193 		uint64_t tmp;
194 
195 		if (expand_number($2, &tmp) != 0) {
196 			yyerror("invalid numeric value");
197 			free($2);
198 			return (1);
199 		}
200 
201 		conf->conf_isns_timeout = tmp;
202 	}
203 	;
204 
205 auth_group:	AUTH_GROUP auth_group_name
206     OPENING_BRACKET auth_group_entries CLOSING_BRACKET
207 	{
208 		auth_group = NULL;
209 	}
210 	;
211 
212 auth_group_name:	STR
213 	{
214 		/*
215 		 * Make it possible to redefine default
216 		 * auth-group. but only once.
217 		 */
218 		if (strcmp($1, "default") == 0 &&
219 		    conf->conf_default_ag_defined == false) {
220 			auth_group = auth_group_find(conf, $1);
221 			conf->conf_default_ag_defined = true;
222 		} else {
223 			auth_group = auth_group_new(conf, $1);
224 		}
225 		free($1);
226 		if (auth_group == NULL)
227 			return (1);
228 	}
229 	;
230 
231 auth_group_entries:
232 	|
233 	auth_group_entries auth_group_entry
234 	|
235 	auth_group_entries auth_group_entry SEMICOLON
236 	;
237 
238 auth_group_entry:
239 	auth_group_auth_type
240 	|
241 	auth_group_chap
242 	|
243 	auth_group_chap_mutual
244 	|
245 	auth_group_initiator_name
246 	|
247 	auth_group_initiator_portal
248 	;
249 
250 auth_group_auth_type:	AUTH_TYPE STR
251 	{
252 		int error;
253 
254 		error = auth_group_set_type(auth_group, $2);
255 		free($2);
256 		if (error != 0)
257 			return (1);
258 	}
259 	;
260 
261 auth_group_chap:	CHAP STR STR
262 	{
263 		const struct auth *ca;
264 
265 		ca = auth_new_chap(auth_group, $2, $3);
266 		free($2);
267 		free($3);
268 		if (ca == NULL)
269 			return (1);
270 	}
271 	;
272 
273 auth_group_chap_mutual:	CHAP_MUTUAL STR STR STR STR
274 	{
275 		const struct auth *ca;
276 
277 		ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
278 		free($2);
279 		free($3);
280 		free($4);
281 		free($5);
282 		if (ca == NULL)
283 			return (1);
284 	}
285 	;
286 
287 auth_group_initiator_name:	INITIATOR_NAME STR
288 	{
289 		const struct auth_name *an;
290 
291 		an = auth_name_new(auth_group, $2);
292 		free($2);
293 		if (an == NULL)
294 			return (1);
295 	}
296 	;
297 
298 auth_group_initiator_portal:	INITIATOR_PORTAL STR
299 	{
300 		const struct auth_portal *ap;
301 
302 		ap = auth_portal_new(auth_group, $2);
303 		free($2);
304 		if (ap == NULL)
305 			return (1);
306 	}
307 	;
308 
309 portal_group:	PORTAL_GROUP portal_group_name
310     OPENING_BRACKET portal_group_entries CLOSING_BRACKET
311 	{
312 		portal_group = NULL;
313 	}
314 	;
315 
316 portal_group_name:	STR
317 	{
318 		/*
319 		 * Make it possible to redefine default
320 		 * portal-group. but only once.
321 		 */
322 		if (strcmp($1, "default") == 0 &&
323 		    conf->conf_default_pg_defined == false) {
324 			portal_group = portal_group_find(conf, $1);
325 			conf->conf_default_pg_defined = true;
326 		} else {
327 			portal_group = portal_group_new(conf, $1);
328 		}
329 		free($1);
330 		if (portal_group == NULL)
331 			return (1);
332 	}
333 	;
334 
335 portal_group_entries:
336 	|
337 	portal_group_entries portal_group_entry
338 	|
339 	portal_group_entries portal_group_entry SEMICOLON
340 	;
341 
342 portal_group_entry:
343 	portal_group_discovery_auth_group
344 	|
345 	portal_group_discovery_filter
346 	|
347 	portal_group_foreign
348 	|
349 	portal_group_listen
350 	|
351 	portal_group_listen_iser
352 	|
353 	portal_group_offload
354 	|
355 	portal_group_option
356 	|
357 	portal_group_redirect
358 	|
359 	portal_group_tag
360 	|
361 	portal_group_dscp
362 	|
363 	portal_group_pcp
364 	;
365 
366 portal_group_discovery_auth_group:	DISCOVERY_AUTH_GROUP STR
367 	{
368 		if (portal_group->pg_discovery_auth_group != NULL) {
369 			log_warnx("discovery-auth-group for portal-group "
370 			    "\"%s\" specified more than once",
371 			    portal_group->pg_name);
372 			return (1);
373 		}
374 		portal_group->pg_discovery_auth_group =
375 		    auth_group_find(conf, $2);
376 		if (portal_group->pg_discovery_auth_group == NULL) {
377 			log_warnx("unknown discovery-auth-group \"%s\" "
378 			    "for portal-group \"%s\"",
379 			    $2, portal_group->pg_name);
380 			return (1);
381 		}
382 		free($2);
383 	}
384 	;
385 
386 portal_group_discovery_filter:	DISCOVERY_FILTER STR
387 	{
388 		int error;
389 
390 		error = portal_group_set_filter(portal_group, $2);
391 		free($2);
392 		if (error != 0)
393 			return (1);
394 	}
395 	;
396 
397 portal_group_foreign:	FOREIGN
398 	{
399 
400 		portal_group->pg_foreign = 1;
401 	}
402 	;
403 
404 portal_group_listen:	LISTEN STR
405 	{
406 		int error;
407 
408 		error = portal_group_add_listen(portal_group, $2, false);
409 		free($2);
410 		if (error != 0)
411 			return (1);
412 	}
413 	;
414 
415 portal_group_listen_iser:	LISTEN_ISER STR
416 	{
417 		int error;
418 
419 		error = portal_group_add_listen(portal_group, $2, true);
420 		free($2);
421 		if (error != 0)
422 			return (1);
423 	}
424 	;
425 
426 portal_group_offload:	OFFLOAD STR
427 	{
428 		int error;
429 
430 		error = portal_group_set_offload(portal_group, $2);
431 		free($2);
432 		if (error != 0)
433 			return (1);
434 	}
435 	;
436 
437 portal_group_option:	OPTION STR STR
438 	{
439 		struct option *o;
440 
441 		o = option_new(&portal_group->pg_options, $2, $3);
442 		free($2);
443 		free($3);
444 		if (o == NULL)
445 			return (1);
446 	}
447 	;
448 
449 portal_group_redirect:	REDIRECT STR
450 	{
451 		int error;
452 
453 		error = portal_group_set_redirection(portal_group, $2);
454 		free($2);
455 		if (error != 0)
456 			return (1);
457 	}
458 	;
459 
460 portal_group_tag:	TAG STR
461 	{
462 		uint64_t tmp;
463 
464 		if (expand_number($2, &tmp) != 0) {
465 			yyerror("invalid numeric value");
466 			free($2);
467 			return (1);
468 		}
469 
470 		portal_group->pg_tag = tmp;
471 	}
472 	;
473 
474 portal_group_dscp
475 : DSCP STR
476 	{
477 		uint64_t tmp;
478 
479 		if (strcmp($2, "0x") == 0) {
480 			tmp = strtol($2 + 2, NULL, 16);
481 		} else if (expand_number($2, &tmp) != 0) {
482 			yyerror("invalid numeric value");
483 			free($2);
484 			return(1);
485 		}
486 		if (tmp >= 0x40) {
487 			yyerror("invalid dscp value");
488 			return(1);
489 		}
490 
491 		portal_group->pg_dscp = tmp;
492 	}
493 | DSCP BE	{ portal_group->pg_dscp = IPTOS_DSCP_CS0  >> 2 ; }
494 | DSCP EF	{ portal_group->pg_dscp = IPTOS_DSCP_EF   >> 2 ; }
495 | DSCP CS0	{ portal_group->pg_dscp = IPTOS_DSCP_CS0  >> 2 ; }
496 | DSCP CS1	{ portal_group->pg_dscp = IPTOS_DSCP_CS1  >> 2 ; }
497 | DSCP CS2	{ portal_group->pg_dscp = IPTOS_DSCP_CS2  >> 2 ; }
498 | DSCP CS3	{ portal_group->pg_dscp = IPTOS_DSCP_CS3  >> 2 ; }
499 | DSCP CS4	{ portal_group->pg_dscp = IPTOS_DSCP_CS4  >> 2 ; }
500 | DSCP CS5	{ portal_group->pg_dscp = IPTOS_DSCP_CS5  >> 2 ; }
501 | DSCP CS6	{ portal_group->pg_dscp = IPTOS_DSCP_CS6  >> 2 ; }
502 | DSCP CS7	{ portal_group->pg_dscp = IPTOS_DSCP_CS7  >> 2 ; }
503 | DSCP AF11	{ portal_group->pg_dscp = IPTOS_DSCP_AF11 >> 2 ; }
504 | DSCP AF12	{ portal_group->pg_dscp = IPTOS_DSCP_AF12 >> 2 ; }
505 | DSCP AF13	{ portal_group->pg_dscp = IPTOS_DSCP_AF13 >> 2 ; }
506 | DSCP AF21	{ portal_group->pg_dscp = IPTOS_DSCP_AF21 >> 2 ; }
507 | DSCP AF22	{ portal_group->pg_dscp = IPTOS_DSCP_AF22 >> 2 ; }
508 | DSCP AF23	{ portal_group->pg_dscp = IPTOS_DSCP_AF23 >> 2 ; }
509 | DSCP AF31	{ portal_group->pg_dscp = IPTOS_DSCP_AF31 >> 2 ; }
510 | DSCP AF32	{ portal_group->pg_dscp = IPTOS_DSCP_AF32 >> 2 ; }
511 | DSCP AF33	{ portal_group->pg_dscp = IPTOS_DSCP_AF33 >> 2 ; }
512 | DSCP AF41	{ portal_group->pg_dscp = IPTOS_DSCP_AF41 >> 2 ; }
513 | DSCP AF42	{ portal_group->pg_dscp = IPTOS_DSCP_AF42 >> 2 ; }
514 | DSCP AF43	{ portal_group->pg_dscp = IPTOS_DSCP_AF43 >> 2 ; }
515 	;
516 
517 portal_group_pcp:	PCP STR
518 	{
519 		uint64_t tmp;
520 
521 		if (expand_number($2, &tmp) != 0) {
522 			yyerror("invalid numeric value");
523 			free($2);
524 			return (1);
525 		}
526 		if (!((tmp >= 0) && (tmp <= 7))) {
527 			yyerror("invalid pcp value");
528 			free($2);
529 			return (1);
530 		}
531 
532 		portal_group->pg_pcp = tmp;
533 	}
534 	;
535 
536 lun:	LUN lun_name
537     OPENING_BRACKET lun_entries CLOSING_BRACKET
538 	{
539 		lun = NULL;
540 	}
541 	;
542 
543 lun_name:	STR
544 	{
545 		lun = lun_new(conf, $1);
546 		free($1);
547 		if (lun == NULL)
548 			return (1);
549 	}
550 	;
551 
552 target:	TARGET target_name
553     OPENING_BRACKET target_entries CLOSING_BRACKET
554 	{
555 		target = NULL;
556 	}
557 	;
558 
559 target_name:	STR
560 	{
561 		target = target_new(conf, $1);
562 		free($1);
563 		if (target == NULL)
564 			return (1);
565 	}
566 	;
567 
568 target_entries:
569 	|
570 	target_entries target_entry
571 	|
572 	target_entries target_entry SEMICOLON
573 	;
574 
575 target_entry:
576 	target_alias
577 	|
578 	target_auth_group
579 	|
580 	target_auth_type
581 	|
582 	target_chap
583 	|
584 	target_chap_mutual
585 	|
586 	target_initiator_name
587 	|
588 	target_initiator_portal
589 	|
590 	target_portal_group
591 	|
592 	target_port
593 	|
594 	target_redirect
595 	|
596 	target_lun
597 	|
598 	target_lun_ref
599 	;
600 
601 target_alias:	ALIAS STR
602 	{
603 		if (target->t_alias != NULL) {
604 			log_warnx("alias for target \"%s\" "
605 			    "specified more than once", target->t_name);
606 			return (1);
607 		}
608 		target->t_alias = $2;
609 	}
610 	;
611 
612 target_auth_group:	AUTH_GROUP STR
613 	{
614 		if (target->t_auth_group != NULL) {
615 			if (target->t_auth_group->ag_name != NULL)
616 				log_warnx("auth-group for target \"%s\" "
617 				    "specified more than once", target->t_name);
618 			else
619 				log_warnx("cannot use both auth-group and explicit "
620 				    "authorisations for target \"%s\"",
621 				    target->t_name);
622 			return (1);
623 		}
624 		target->t_auth_group = auth_group_find(conf, $2);
625 		if (target->t_auth_group == NULL) {
626 			log_warnx("unknown auth-group \"%s\" for target "
627 			    "\"%s\"", $2, target->t_name);
628 			return (1);
629 		}
630 		free($2);
631 	}
632 	;
633 
634 target_auth_type:	AUTH_TYPE STR
635 	{
636 		int error;
637 
638 		if (target->t_auth_group != NULL) {
639 			if (target->t_auth_group->ag_name != NULL) {
640 				log_warnx("cannot use both auth-group and "
641 				    "auth-type for target \"%s\"",
642 				    target->t_name);
643 				return (1);
644 			}
645 		} else {
646 			target->t_auth_group = auth_group_new(conf, NULL);
647 			if (target->t_auth_group == NULL) {
648 				free($2);
649 				return (1);
650 			}
651 			target->t_auth_group->ag_target = target;
652 		}
653 		error = auth_group_set_type(target->t_auth_group, $2);
654 		free($2);
655 		if (error != 0)
656 			return (1);
657 	}
658 	;
659 
660 target_chap:	CHAP STR STR
661 	{
662 		const struct auth *ca;
663 
664 		if (target->t_auth_group != NULL) {
665 			if (target->t_auth_group->ag_name != NULL) {
666 				log_warnx("cannot use both auth-group and "
667 				    "chap for target \"%s\"",
668 				    target->t_name);
669 				free($2);
670 				free($3);
671 				return (1);
672 			}
673 		} else {
674 			target->t_auth_group = auth_group_new(conf, NULL);
675 			if (target->t_auth_group == NULL) {
676 				free($2);
677 				free($3);
678 				return (1);
679 			}
680 			target->t_auth_group->ag_target = target;
681 		}
682 		ca = auth_new_chap(target->t_auth_group, $2, $3);
683 		free($2);
684 		free($3);
685 		if (ca == NULL)
686 			return (1);
687 	}
688 	;
689 
690 target_chap_mutual:	CHAP_MUTUAL STR STR STR STR
691 	{
692 		const struct auth *ca;
693 
694 		if (target->t_auth_group != NULL) {
695 			if (target->t_auth_group->ag_name != NULL) {
696 				log_warnx("cannot use both auth-group and "
697 				    "chap-mutual for target \"%s\"",
698 				    target->t_name);
699 				free($2);
700 				free($3);
701 				free($4);
702 				free($5);
703 				return (1);
704 			}
705 		} else {
706 			target->t_auth_group = auth_group_new(conf, NULL);
707 			if (target->t_auth_group == NULL) {
708 				free($2);
709 				free($3);
710 				free($4);
711 				free($5);
712 				return (1);
713 			}
714 			target->t_auth_group->ag_target = target;
715 		}
716 		ca = auth_new_chap_mutual(target->t_auth_group,
717 		    $2, $3, $4, $5);
718 		free($2);
719 		free($3);
720 		free($4);
721 		free($5);
722 		if (ca == NULL)
723 			return (1);
724 	}
725 	;
726 
727 target_initiator_name:	INITIATOR_NAME STR
728 	{
729 		const struct auth_name *an;
730 
731 		if (target->t_auth_group != NULL) {
732 			if (target->t_auth_group->ag_name != NULL) {
733 				log_warnx("cannot use both auth-group and "
734 				    "initiator-name for target \"%s\"",
735 				    target->t_name);
736 				free($2);
737 				return (1);
738 			}
739 		} else {
740 			target->t_auth_group = auth_group_new(conf, NULL);
741 			if (target->t_auth_group == NULL) {
742 				free($2);
743 				return (1);
744 			}
745 			target->t_auth_group->ag_target = target;
746 		}
747 		an = auth_name_new(target->t_auth_group, $2);
748 		free($2);
749 		if (an == NULL)
750 			return (1);
751 	}
752 	;
753 
754 target_initiator_portal:	INITIATOR_PORTAL STR
755 	{
756 		const struct auth_portal *ap;
757 
758 		if (target->t_auth_group != NULL) {
759 			if (target->t_auth_group->ag_name != NULL) {
760 				log_warnx("cannot use both auth-group and "
761 				    "initiator-portal for target \"%s\"",
762 				    target->t_name);
763 				free($2);
764 				return (1);
765 			}
766 		} else {
767 			target->t_auth_group = auth_group_new(conf, NULL);
768 			if (target->t_auth_group == NULL) {
769 				free($2);
770 				return (1);
771 			}
772 			target->t_auth_group->ag_target = target;
773 		}
774 		ap = auth_portal_new(target->t_auth_group, $2);
775 		free($2);
776 		if (ap == NULL)
777 			return (1);
778 	}
779 	;
780 
781 target_portal_group:	PORTAL_GROUP STR STR
782 	{
783 		struct portal_group *tpg;
784 		struct auth_group *tag;
785 		struct port *tp;
786 
787 		tpg = portal_group_find(conf, $2);
788 		if (tpg == NULL) {
789 			log_warnx("unknown portal-group \"%s\" for target "
790 			    "\"%s\"", $2, target->t_name);
791 			free($2);
792 			free($3);
793 			return (1);
794 		}
795 		tag = auth_group_find(conf, $3);
796 		if (tag == NULL) {
797 			log_warnx("unknown auth-group \"%s\" for target "
798 			    "\"%s\"", $3, target->t_name);
799 			free($2);
800 			free($3);
801 			return (1);
802 		}
803 		tp = port_new(conf, target, tpg);
804 		if (tp == NULL) {
805 			log_warnx("can't link portal-group \"%s\" to target "
806 			    "\"%s\"", $2, target->t_name);
807 			free($2);
808 			return (1);
809 		}
810 		tp->p_auth_group = tag;
811 		free($2);
812 		free($3);
813 	}
814 	|		PORTAL_GROUP STR
815 	{
816 		struct portal_group *tpg;
817 		struct port *tp;
818 
819 		tpg = portal_group_find(conf, $2);
820 		if (tpg == NULL) {
821 			log_warnx("unknown portal-group \"%s\" for target "
822 			    "\"%s\"", $2, target->t_name);
823 			free($2);
824 			return (1);
825 		}
826 		tp = port_new(conf, target, tpg);
827 		if (tp == NULL) {
828 			log_warnx("can't link portal-group \"%s\" to target "
829 			    "\"%s\"", $2, target->t_name);
830 			free($2);
831 			return (1);
832 		}
833 		free($2);
834 	}
835 	;
836 
837 target_port:	PORT STR
838 	{
839 		struct pport *pp;
840 		struct port *tp;
841 		int ret, i_pp, i_vp = 0;
842 
843 		ret = sscanf($2, "ioctl/%d/%d", &i_pp, &i_vp);
844 		if (ret > 0) {
845 			tp = port_new_ioctl(conf, target, i_pp, i_vp);
846 			if (tp == NULL) {
847 				log_warnx("can't create new ioctl port for "
848 				    "target \"%s\"", target->t_name);
849 				free($2);
850 				return (1);
851 			}
852 		} else {
853 			pp = pport_find(conf, $2);
854 			if (pp == NULL) {
855 				log_warnx("unknown port \"%s\" for target \"%s\"",
856 				    $2, target->t_name);
857 				free($2);
858 				return (1);
859 			}
860 			if (!TAILQ_EMPTY(&pp->pp_ports)) {
861 				log_warnx("can't link port \"%s\" to target \"%s\", "
862 				    "port already linked to some target",
863 				    $2, target->t_name);
864 				free($2);
865 				return (1);
866 			}
867 			tp = port_new_pp(conf, target, pp);
868 			if (tp == NULL) {
869 				log_warnx("can't link port \"%s\" to target \"%s\"",
870 				    $2, target->t_name);
871 				free($2);
872 				return (1);
873 			}
874 		}
875 
876 		free($2);
877 	}
878 	;
879 
880 target_redirect:	REDIRECT STR
881 	{
882 		int error;
883 
884 		error = target_set_redirection(target, $2);
885 		free($2);
886 		if (error != 0)
887 			return (1);
888 	}
889 	;
890 
891 target_lun:	LUN lun_number
892     OPENING_BRACKET lun_entries CLOSING_BRACKET
893 	{
894 		lun = NULL;
895 	}
896 	;
897 
898 lun_number:	STR
899 	{
900 		uint64_t tmp;
901 		int ret;
902 		char *name;
903 
904 		if (expand_number($1, &tmp) != 0) {
905 			yyerror("invalid numeric value");
906 			free($1);
907 			return (1);
908 		}
909 		if (tmp >= MAX_LUNS) {
910 			yyerror("LU number is too big");
911 			free($1);
912 			return (1);
913 		}
914 
915 		ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
916 		if (ret <= 0)
917 			log_err(1, "asprintf");
918 		lun = lun_new(conf, name);
919 		if (lun == NULL)
920 			return (1);
921 
922 		lun_set_scsiname(lun, name);
923 		target->t_luns[tmp] = lun;
924 	}
925 	;
926 
927 target_lun_ref:	LUN STR STR
928 	{
929 		uint64_t tmp;
930 
931 		if (expand_number($2, &tmp) != 0) {
932 			yyerror("invalid numeric value");
933 			free($2);
934 			free($3);
935 			return (1);
936 		}
937 		free($2);
938 		if (tmp >= MAX_LUNS) {
939 			yyerror("LU number is too big");
940 			free($3);
941 			return (1);
942 		}
943 
944 		lun = lun_find(conf, $3);
945 		free($3);
946 		if (lun == NULL)
947 			return (1);
948 
949 		target->t_luns[tmp] = lun;
950 	}
951 	;
952 
953 lun_entries:
954 	|
955 	lun_entries lun_entry
956 	|
957 	lun_entries lun_entry SEMICOLON
958 	;
959 
960 lun_entry:
961 	lun_backend
962 	|
963 	lun_blocksize
964 	|
965 	lun_device_id
966 	|
967 	lun_device_type
968 	|
969 	lun_ctl_lun
970 	|
971 	lun_option
972 	|
973 	lun_path
974 	|
975 	lun_serial
976 	|
977 	lun_size
978 	;
979 
980 lun_backend:	BACKEND STR
981 	{
982 		if (lun->l_backend != NULL) {
983 			log_warnx("backend for lun \"%s\" "
984 			    "specified more than once",
985 			    lun->l_name);
986 			free($2);
987 			return (1);
988 		}
989 		lun_set_backend(lun, $2);
990 		free($2);
991 	}
992 	;
993 
994 lun_blocksize:	BLOCKSIZE STR
995 	{
996 		uint64_t tmp;
997 
998 		if (expand_number($2, &tmp) != 0) {
999 			yyerror("invalid numeric value");
1000 			free($2);
1001 			return (1);
1002 		}
1003 
1004 		if (lun->l_blocksize != 0) {
1005 			log_warnx("blocksize for lun \"%s\" "
1006 			    "specified more than once",
1007 			    lun->l_name);
1008 			return (1);
1009 		}
1010 		lun_set_blocksize(lun, tmp);
1011 	}
1012 	;
1013 
1014 lun_device_id:	DEVICE_ID STR
1015 	{
1016 		if (lun->l_device_id != NULL) {
1017 			log_warnx("device_id for lun \"%s\" "
1018 			    "specified more than once",
1019 			    lun->l_name);
1020 			free($2);
1021 			return (1);
1022 		}
1023 		lun_set_device_id(lun, $2);
1024 		free($2);
1025 	}
1026 	;
1027 
1028 lun_device_type:	DEVICE_TYPE STR
1029 	{
1030 		uint64_t tmp;
1031 
1032 		if (strcasecmp($2, "disk") == 0 ||
1033 		    strcasecmp($2, "direct") == 0)
1034 			tmp = 0;
1035 		else if (strcasecmp($2, "processor") == 0)
1036 			tmp = 3;
1037 		else if (strcasecmp($2, "cd") == 0 ||
1038 		    strcasecmp($2, "cdrom") == 0 ||
1039 		    strcasecmp($2, "dvd") == 0 ||
1040 		    strcasecmp($2, "dvdrom") == 0)
1041 			tmp = 5;
1042 		else if (expand_number($2, &tmp) != 0 ||
1043 		    tmp > 15) {
1044 			yyerror("invalid numeric value");
1045 			free($2);
1046 			return (1);
1047 		}
1048 
1049 		lun_set_device_type(lun, tmp);
1050 	}
1051 	;
1052 
1053 lun_ctl_lun:	CTL_LUN STR
1054 	{
1055 		uint64_t tmp;
1056 
1057 		if (expand_number($2, &tmp) != 0) {
1058 			yyerror("invalid numeric value");
1059 			free($2);
1060 			return (1);
1061 		}
1062 
1063 		if (lun->l_ctl_lun >= 0) {
1064 			log_warnx("ctl_lun for lun \"%s\" "
1065 			    "specified more than once",
1066 			    lun->l_name);
1067 			return (1);
1068 		}
1069 		lun_set_ctl_lun(lun, tmp);
1070 	}
1071 	;
1072 
1073 lun_option:	OPTION STR STR
1074 	{
1075 		struct option *o;
1076 
1077 		o = option_new(&lun->l_options, $2, $3);
1078 		free($2);
1079 		free($3);
1080 		if (o == NULL)
1081 			return (1);
1082 	}
1083 	;
1084 
1085 lun_path:	PATH STR
1086 	{
1087 		if (lun->l_path != NULL) {
1088 			log_warnx("path for lun \"%s\" "
1089 			    "specified more than once",
1090 			    lun->l_name);
1091 			free($2);
1092 			return (1);
1093 		}
1094 		lun_set_path(lun, $2);
1095 		free($2);
1096 	}
1097 	;
1098 
1099 lun_serial:	SERIAL STR
1100 	{
1101 		if (lun->l_serial != NULL) {
1102 			log_warnx("serial for lun \"%s\" "
1103 			    "specified more than once",
1104 			    lun->l_name);
1105 			free($2);
1106 			return (1);
1107 		}
1108 		lun_set_serial(lun, $2);
1109 		free($2);
1110 	}
1111 	;
1112 
1113 lun_size:	SIZE STR
1114 	{
1115 		uint64_t tmp;
1116 
1117 		if (expand_number($2, &tmp) != 0) {
1118 			yyerror("invalid numeric value");
1119 			free($2);
1120 			return (1);
1121 		}
1122 
1123 		if (lun->l_size != 0) {
1124 			log_warnx("size for lun \"%s\" "
1125 			    "specified more than once",
1126 			    lun->l_name);
1127 			return (1);
1128 		}
1129 		lun_set_size(lun, tmp);
1130 	}
1131 	;
1132 %%
1133 
1134 void
1135 yyerror(const char *str)
1136 {
1137 
1138 	log_warnx("error in configuration file at line %d near '%s': %s",
1139 	    lineno, yytext, str);
1140 }
1141 
1142 int
1143 parse_conf(struct conf *newconf, const char *path)
1144 {
1145 	int error;
1146 
1147 	conf = newconf;
1148 	yyin = fopen(path, "r");
1149 	if (yyin == NULL) {
1150 		log_warn("unable to open configuration file %s", path);
1151 		return (1);
1152 	}
1153 
1154 	lineno = 1;
1155 	yyrestart(yyin);
1156 	error = yyparse();
1157 	auth_group = NULL;
1158 	portal_group = NULL;
1159 	target = NULL;
1160 	lun = NULL;
1161 	fclose(yyin);
1162 
1163 	return (error);
1164 }
1165