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