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