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