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