]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/parse.y
Update the Arm Optimized Routine library to v24.01
[FreeBSD/FreeBSD.git] / usr.sbin / ctld / parse.y
1 %{
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause
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
32 #include <sys/queue.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "ctld.h"
41 #include <netinet/in.h>
42 #include <netinet/ip.h>
43
44 extern FILE *yyin;
45 extern char *yytext;
46 extern int lineno;
47
48 static struct conf *conf = NULL;
49 static struct auth_group *auth_group = NULL;
50 static struct portal_group *portal_group = NULL;
51 static struct target *target = NULL;
52 static struct lun *lun = NULL;
53
54 extern void     yyerror(const char *);
55 extern 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 DSCP 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 PCP PIDFILE PORT PORTAL_GROUP REDIRECT SEMICOLON SERIAL
65 %token SIZE STR TAG TARGET TIMEOUT
66 %token AF11 AF12 AF13 AF21 AF22 AF23 AF31 AF32 AF33 AF41 AF42 AF43
67 %token BE EF CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7
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         portal_group_dscp
358         |
359         portal_group_pcp
360         ;
361
362 portal_group_discovery_auth_group:      DISCOVERY_AUTH_GROUP STR
363         {
364                 if (portal_group->pg_discovery_auth_group != NULL) {
365                         log_warnx("discovery-auth-group for portal-group "
366                             "\"%s\" specified more than once",
367                             portal_group->pg_name);
368                         return (1);
369                 }
370                 portal_group->pg_discovery_auth_group =
371                     auth_group_find(conf, $2);
372                 if (portal_group->pg_discovery_auth_group == NULL) {
373                         log_warnx("unknown discovery-auth-group \"%s\" "
374                             "for portal-group \"%s\"",
375                             $2, portal_group->pg_name);
376                         return (1);
377                 }
378                 free($2);
379         }
380         ;
381
382 portal_group_discovery_filter:  DISCOVERY_FILTER STR
383         {
384                 int error;
385
386                 error = portal_group_set_filter(portal_group, $2);
387                 free($2);
388                 if (error != 0)
389                         return (1);
390         }
391         ;
392
393 portal_group_foreign:   FOREIGN
394         {
395
396                 portal_group->pg_foreign = 1;
397         }
398         ;
399
400 portal_group_listen:    LISTEN STR
401         {
402                 int error;
403
404                 error = portal_group_add_listen(portal_group, $2, false);
405                 free($2);
406                 if (error != 0)
407                         return (1);
408         }
409         ;
410
411 portal_group_listen_iser:       LISTEN_ISER STR
412         {
413                 int error;
414
415                 error = portal_group_add_listen(portal_group, $2, true);
416                 free($2);
417                 if (error != 0)
418                         return (1);
419         }
420         ;
421
422 portal_group_offload:   OFFLOAD STR
423         {
424                 int error;
425
426                 error = portal_group_set_offload(portal_group, $2);
427                 free($2);
428                 if (error != 0)
429                         return (1);
430         }
431         ;
432
433 portal_group_option:    OPTION STR STR
434         {
435                 struct option *o;
436
437                 o = option_new(&portal_group->pg_options, $2, $3);
438                 free($2);
439                 free($3);
440                 if (o == NULL)
441                         return (1);
442         }
443         ;
444
445 portal_group_redirect:  REDIRECT STR
446         {
447                 int error;
448
449                 error = portal_group_set_redirection(portal_group, $2);
450                 free($2);
451                 if (error != 0)
452                         return (1);
453         }
454         ;
455
456 portal_group_tag:       TAG STR
457         {
458                 uint64_t tmp;
459
460                 if (expand_number($2, &tmp) != 0) {
461                         yyerror("invalid numeric value");
462                         free($2);
463                         return (1);
464                 }
465
466                 portal_group->pg_tag = tmp;
467         }
468         ;
469
470 portal_group_dscp
471 : DSCP STR
472         {
473                 uint64_t tmp;
474
475                 if (strcmp($2, "0x") == 0) {
476                         tmp = strtol($2 + 2, NULL, 16);
477                 } else if (expand_number($2, &tmp) != 0) {
478                         yyerror("invalid numeric value");
479                         free($2);
480                         return(1);
481                 }
482                 if (tmp >= 0x40) {
483                         yyerror("invalid dscp value");
484                         return(1);
485                 }
486
487                 portal_group->pg_dscp = tmp;
488         }
489 | DSCP BE       { portal_group->pg_dscp = IPTOS_DSCP_CS0  >> 2 ; }
490 | DSCP EF       { portal_group->pg_dscp = IPTOS_DSCP_EF   >> 2 ; }
491 | DSCP CS0      { portal_group->pg_dscp = IPTOS_DSCP_CS0  >> 2 ; }
492 | DSCP CS1      { portal_group->pg_dscp = IPTOS_DSCP_CS1  >> 2 ; }
493 | DSCP CS2      { portal_group->pg_dscp = IPTOS_DSCP_CS2  >> 2 ; }
494 | DSCP CS3      { portal_group->pg_dscp = IPTOS_DSCP_CS3  >> 2 ; }
495 | DSCP CS4      { portal_group->pg_dscp = IPTOS_DSCP_CS4  >> 2 ; }
496 | DSCP CS5      { portal_group->pg_dscp = IPTOS_DSCP_CS5  >> 2 ; }
497 | DSCP CS6      { portal_group->pg_dscp = IPTOS_DSCP_CS6  >> 2 ; }
498 | DSCP CS7      { portal_group->pg_dscp = IPTOS_DSCP_CS7  >> 2 ; }
499 | DSCP AF11     { portal_group->pg_dscp = IPTOS_DSCP_AF11 >> 2 ; }
500 | DSCP AF12     { portal_group->pg_dscp = IPTOS_DSCP_AF12 >> 2 ; }
501 | DSCP AF13     { portal_group->pg_dscp = IPTOS_DSCP_AF13 >> 2 ; }
502 | DSCP AF21     { portal_group->pg_dscp = IPTOS_DSCP_AF21 >> 2 ; }
503 | DSCP AF22     { portal_group->pg_dscp = IPTOS_DSCP_AF22 >> 2 ; }
504 | DSCP AF23     { portal_group->pg_dscp = IPTOS_DSCP_AF23 >> 2 ; }
505 | DSCP AF31     { portal_group->pg_dscp = IPTOS_DSCP_AF31 >> 2 ; }
506 | DSCP AF32     { portal_group->pg_dscp = IPTOS_DSCP_AF32 >> 2 ; }
507 | DSCP AF33     { portal_group->pg_dscp = IPTOS_DSCP_AF33 >> 2 ; }
508 | DSCP AF41     { portal_group->pg_dscp = IPTOS_DSCP_AF41 >> 2 ; }
509 | DSCP AF42     { portal_group->pg_dscp = IPTOS_DSCP_AF42 >> 2 ; }
510 | DSCP AF43     { portal_group->pg_dscp = IPTOS_DSCP_AF43 >> 2 ; }
511         ;
512
513 portal_group_pcp:       PCP STR
514         {
515                 uint64_t tmp;
516
517                 if (expand_number($2, &tmp) != 0) {
518                         yyerror("invalid numeric value");
519                         free($2);
520                         return (1);
521                 }
522                 if (tmp > 7) {
523                         yyerror("invalid pcp value");
524                         free($2);
525                         return (1);
526                 }
527
528                 portal_group->pg_pcp = tmp;
529         }
530         ;
531
532 lun:    LUN lun_name
533     OPENING_BRACKET lun_entries CLOSING_BRACKET
534         {
535                 lun = NULL;
536         }
537         ;
538
539 lun_name:       STR
540         {
541                 lun = lun_new(conf, $1);
542                 free($1);
543                 if (lun == NULL)
544                         return (1);
545         }
546         ;
547
548 target: TARGET target_name
549     OPENING_BRACKET target_entries CLOSING_BRACKET
550         {
551                 target = NULL;
552         }
553         ;
554
555 target_name:    STR
556         {
557                 target = target_new(conf, $1);
558                 free($1);
559                 if (target == NULL)
560                         return (1);
561         }
562         ;
563
564 target_entries:
565         |
566         target_entries target_entry
567         |
568         target_entries target_entry SEMICOLON
569         ;
570
571 target_entry:
572         target_alias
573         |
574         target_auth_group
575         |
576         target_auth_type
577         |
578         target_chap
579         |
580         target_chap_mutual
581         |
582         target_initiator_name
583         |
584         target_initiator_portal
585         |
586         target_portal_group
587         |
588         target_port
589         |
590         target_redirect
591         |
592         target_lun
593         |
594         target_lun_ref
595         ;
596
597 target_alias:   ALIAS STR
598         {
599                 if (target->t_alias != NULL) {
600                         log_warnx("alias for target \"%s\" "
601                             "specified more than once", target->t_name);
602                         return (1);
603                 }
604                 target->t_alias = $2;
605         }
606         ;
607
608 target_auth_group:      AUTH_GROUP STR
609         {
610                 if (target->t_auth_group != NULL) {
611                         if (target->t_auth_group->ag_name != NULL)
612                                 log_warnx("auth-group for target \"%s\" "
613                                     "specified more than once", target->t_name);
614                         else
615                                 log_warnx("cannot use both auth-group and explicit "
616                                     "authorisations for target \"%s\"",
617                                     target->t_name);
618                         return (1);
619                 }
620                 target->t_auth_group = auth_group_find(conf, $2);
621                 if (target->t_auth_group == NULL) {
622                         log_warnx("unknown auth-group \"%s\" for target "
623                             "\"%s\"", $2, target->t_name);
624                         return (1);
625                 }
626                 free($2);
627         }
628         ;
629
630 target_auth_type:       AUTH_TYPE STR
631         {
632                 int error;
633
634                 if (target->t_auth_group != NULL) {
635                         if (target->t_auth_group->ag_name != NULL) {
636                                 log_warnx("cannot use both auth-group and "
637                                     "auth-type for target \"%s\"",
638                                     target->t_name);
639                                 return (1);
640                         }
641                 } else {
642                         target->t_auth_group = auth_group_new(conf, NULL);
643                         if (target->t_auth_group == NULL) {
644                                 free($2);
645                                 return (1);
646                         }
647                         target->t_auth_group->ag_target = target;
648                 }
649                 error = auth_group_set_type(target->t_auth_group, $2);
650                 free($2);
651                 if (error != 0)
652                         return (1);
653         }
654         ;
655
656 target_chap:    CHAP STR STR
657         {
658                 const struct auth *ca;
659
660                 if (target->t_auth_group != NULL) {
661                         if (target->t_auth_group->ag_name != NULL) {
662                                 log_warnx("cannot use both auth-group and "
663                                     "chap for target \"%s\"",
664                                     target->t_name);
665                                 free($2);
666                                 free($3);
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                                 free($3);
674                                 return (1);
675                         }
676                         target->t_auth_group->ag_target = target;
677                 }
678                 ca = auth_new_chap(target->t_auth_group, $2, $3);
679                 free($2);
680                 free($3);
681                 if (ca == NULL)
682                         return (1);
683         }
684         ;
685
686 target_chap_mutual:     CHAP_MUTUAL STR STR STR STR
687         {
688                 const struct auth *ca;
689
690                 if (target->t_auth_group != NULL) {
691                         if (target->t_auth_group->ag_name != NULL) {
692                                 log_warnx("cannot use both auth-group and "
693                                     "chap-mutual for target \"%s\"",
694                                     target->t_name);
695                                 free($2);
696                                 free($3);
697                                 free($4);
698                                 free($5);
699                                 return (1);
700                         }
701                 } else {
702                         target->t_auth_group = auth_group_new(conf, NULL);
703                         if (target->t_auth_group == NULL) {
704                                 free($2);
705                                 free($3);
706                                 free($4);
707                                 free($5);
708                                 return (1);
709                         }
710                         target->t_auth_group->ag_target = target;
711                 }
712                 ca = auth_new_chap_mutual(target->t_auth_group,
713                     $2, $3, $4, $5);
714                 free($2);
715                 free($3);
716                 free($4);
717                 free($5);
718                 if (ca == NULL)
719                         return (1);
720         }
721         ;
722
723 target_initiator_name:  INITIATOR_NAME STR
724         {
725                 const struct auth_name *an;
726
727                 if (target->t_auth_group != NULL) {
728                         if (target->t_auth_group->ag_name != NULL) {
729                                 log_warnx("cannot use both auth-group and "
730                                     "initiator-name for target \"%s\"",
731                                     target->t_name);
732                                 free($2);
733                                 return (1);
734                         }
735                 } else {
736                         target->t_auth_group = auth_group_new(conf, NULL);
737                         if (target->t_auth_group == NULL) {
738                                 free($2);
739                                 return (1);
740                         }
741                         target->t_auth_group->ag_target = target;
742                 }
743                 an = auth_name_new(target->t_auth_group, $2);
744                 free($2);
745                 if (an == NULL)
746                         return (1);
747         }
748         ;
749
750 target_initiator_portal:        INITIATOR_PORTAL STR
751         {
752                 const struct auth_portal *ap;
753
754                 if (target->t_auth_group != NULL) {
755                         if (target->t_auth_group->ag_name != NULL) {
756                                 log_warnx("cannot use both auth-group and "
757                                     "initiator-portal for target \"%s\"",
758                                     target->t_name);
759                                 free($2);
760                                 return (1);
761                         }
762                 } else {
763                         target->t_auth_group = auth_group_new(conf, NULL);
764                         if (target->t_auth_group == NULL) {
765                                 free($2);
766                                 return (1);
767                         }
768                         target->t_auth_group->ag_target = target;
769                 }
770                 ap = auth_portal_new(target->t_auth_group, $2);
771                 free($2);
772                 if (ap == NULL)
773                         return (1);
774         }
775         ;
776
777 target_portal_group:    PORTAL_GROUP STR STR
778         {
779                 struct portal_group *tpg;
780                 struct auth_group *tag;
781                 struct port *tp;
782
783                 tpg = portal_group_find(conf, $2);
784                 if (tpg == NULL) {
785                         log_warnx("unknown portal-group \"%s\" for target "
786                             "\"%s\"", $2, target->t_name);
787                         free($2);
788                         free($3);
789                         return (1);
790                 }
791                 tag = auth_group_find(conf, $3);
792                 if (tag == NULL) {
793                         log_warnx("unknown auth-group \"%s\" for target "
794                             "\"%s\"", $3, target->t_name);
795                         free($2);
796                         free($3);
797                         return (1);
798                 }
799                 tp = port_new(conf, target, tpg);
800                 if (tp == NULL) {
801                         log_warnx("can't link portal-group \"%s\" to target "
802                             "\"%s\"", $2, target->t_name);
803                         free($2);
804                         return (1);
805                 }
806                 tp->p_auth_group = tag;
807                 free($2);
808                 free($3);
809         }
810         |               PORTAL_GROUP STR
811         {
812                 struct portal_group *tpg;
813                 struct port *tp;
814
815                 tpg = portal_group_find(conf, $2);
816                 if (tpg == NULL) {
817                         log_warnx("unknown portal-group \"%s\" for target "
818                             "\"%s\"", $2, target->t_name);
819                         free($2);
820                         return (1);
821                 }
822                 tp = port_new(conf, target, tpg);
823                 if (tp == NULL) {
824                         log_warnx("can't link portal-group \"%s\" to target "
825                             "\"%s\"", $2, target->t_name);
826                         free($2);
827                         return (1);
828                 }
829                 free($2);
830         }
831         ;
832
833 target_port:    PORT STR
834         {
835                 struct pport *pp;
836                 struct port *tp;
837                 int ret, i_pp, i_vp = 0;
838
839                 ret = sscanf($2, "ioctl/%d/%d", &i_pp, &i_vp);
840                 if (ret > 0) {
841                         tp = port_new_ioctl(conf, target, i_pp, i_vp);
842                         if (tp == NULL) {
843                                 log_warnx("can't create new ioctl port for "
844                                     "target \"%s\"", target->t_name);
845                                 free($2);
846                                 return (1);
847                         }
848                 } else {
849                         pp = pport_find(conf, $2);
850                         if (pp == NULL) {
851                                 log_warnx("unknown port \"%s\" for target \"%s\"",
852                                     $2, target->t_name);
853                                 free($2);
854                                 return (1);
855                         }
856                         if (!TAILQ_EMPTY(&pp->pp_ports)) {
857                                 log_warnx("can't link port \"%s\" to target \"%s\", "
858                                     "port already linked to some target",
859                                     $2, target->t_name);
860                                 free($2);
861                                 return (1);
862                         }
863                         tp = port_new_pp(conf, target, pp);
864                         if (tp == NULL) {
865                                 log_warnx("can't link port \"%s\" to target \"%s\"",
866                                     $2, target->t_name);
867                                 free($2);
868                                 return (1);
869                         }
870                 }
871
872                 free($2);
873         }
874         ;
875
876 target_redirect:        REDIRECT STR
877         {
878                 int error;
879
880                 error = target_set_redirection(target, $2);
881                 free($2);
882                 if (error != 0)
883                         return (1);
884         }
885         ;
886
887 target_lun:     LUN lun_number
888     OPENING_BRACKET lun_entries CLOSING_BRACKET
889         {
890                 lun = NULL;
891         }
892         ;
893
894 lun_number:     STR
895         {
896                 uint64_t tmp;
897                 int ret;
898                 char *name;
899
900                 if (expand_number($1, &tmp) != 0) {
901                         yyerror("invalid numeric value");
902                         free($1);
903                         return (1);
904                 }
905                 if (tmp >= MAX_LUNS) {
906                         yyerror("LU number is too big");
907                         free($1);
908                         return (1);
909                 }
910
911                 ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
912                 if (ret <= 0)
913                         log_err(1, "asprintf");
914                 lun = lun_new(conf, name);
915                 if (lun == NULL)
916                         return (1);
917
918                 lun_set_scsiname(lun, name);
919                 target->t_luns[tmp] = lun;
920         }
921         ;
922
923 target_lun_ref: LUN STR STR
924         {
925                 uint64_t tmp;
926
927                 if (expand_number($2, &tmp) != 0) {
928                         yyerror("invalid numeric value");
929                         free($2);
930                         free($3);
931                         return (1);
932                 }
933                 free($2);
934                 if (tmp >= MAX_LUNS) {
935                         yyerror("LU number is too big");
936                         free($3);
937                         return (1);
938                 }
939
940                 lun = lun_find(conf, $3);
941                 free($3);
942                 if (lun == NULL)
943                         return (1);
944
945                 target->t_luns[tmp] = lun;
946         }
947         ;
948
949 lun_entries:
950         |
951         lun_entries lun_entry
952         |
953         lun_entries lun_entry SEMICOLON
954         ;
955
956 lun_entry:
957         lun_backend
958         |
959         lun_blocksize
960         |
961         lun_device_id
962         |
963         lun_device_type
964         |
965         lun_ctl_lun
966         |
967         lun_option
968         |
969         lun_path
970         |
971         lun_serial
972         |
973         lun_size
974         ;
975
976 lun_backend:    BACKEND STR
977         {
978                 if (lun->l_backend != NULL) {
979                         log_warnx("backend for lun \"%s\" "
980                             "specified more than once",
981                             lun->l_name);
982                         free($2);
983                         return (1);
984                 }
985                 lun_set_backend(lun, $2);
986                 free($2);
987         }
988         ;
989
990 lun_blocksize:  BLOCKSIZE STR
991         {
992                 uint64_t tmp;
993
994                 if (expand_number($2, &tmp) != 0) {
995                         yyerror("invalid numeric value");
996                         free($2);
997                         return (1);
998                 }
999
1000                 if (lun->l_blocksize != 0) {
1001                         log_warnx("blocksize for lun \"%s\" "
1002                             "specified more than once",
1003                             lun->l_name);
1004                         return (1);
1005                 }
1006                 lun_set_blocksize(lun, tmp);
1007         }
1008         ;
1009
1010 lun_device_id:  DEVICE_ID STR
1011         {
1012                 if (lun->l_device_id != NULL) {
1013                         log_warnx("device_id for lun \"%s\" "
1014                             "specified more than once",
1015                             lun->l_name);
1016                         free($2);
1017                         return (1);
1018                 }
1019                 lun_set_device_id(lun, $2);
1020                 free($2);
1021         }
1022         ;
1023
1024 lun_device_type:        DEVICE_TYPE STR
1025         {
1026                 uint64_t tmp;
1027
1028                 if (strcasecmp($2, "disk") == 0 ||
1029                     strcasecmp($2, "direct") == 0)
1030                         tmp = 0;
1031                 else if (strcasecmp($2, "processor") == 0)
1032                         tmp = 3;
1033                 else if (strcasecmp($2, "cd") == 0 ||
1034                     strcasecmp($2, "cdrom") == 0 ||
1035                     strcasecmp($2, "dvd") == 0 ||
1036                     strcasecmp($2, "dvdrom") == 0)
1037                         tmp = 5;
1038                 else if (expand_number($2, &tmp) != 0 ||
1039                     tmp > 15) {
1040                         yyerror("invalid numeric value");
1041                         free($2);
1042                         return (1);
1043                 }
1044
1045                 lun_set_device_type(lun, tmp);
1046         }
1047         ;
1048
1049 lun_ctl_lun:    CTL_LUN STR
1050         {
1051                 uint64_t tmp;
1052
1053                 if (expand_number($2, &tmp) != 0) {
1054                         yyerror("invalid numeric value");
1055                         free($2);
1056                         return (1);
1057                 }
1058
1059                 if (lun->l_ctl_lun >= 0) {
1060                         log_warnx("ctl_lun for lun \"%s\" "
1061                             "specified more than once",
1062                             lun->l_name);
1063                         return (1);
1064                 }
1065                 lun_set_ctl_lun(lun, tmp);
1066         }
1067         ;
1068
1069 lun_option:     OPTION STR STR
1070         {
1071                 struct option *o;
1072
1073                 o = option_new(&lun->l_options, $2, $3);
1074                 free($2);
1075                 free($3);
1076                 if (o == NULL)
1077                         return (1);
1078         }
1079         ;
1080
1081 lun_path:       PATH STR
1082         {
1083                 if (lun->l_path != NULL) {
1084                         log_warnx("path for lun \"%s\" "
1085                             "specified more than once",
1086                             lun->l_name);
1087                         free($2);
1088                         return (1);
1089                 }
1090                 lun_set_path(lun, $2);
1091                 free($2);
1092         }
1093         ;
1094
1095 lun_serial:     SERIAL STR
1096         {
1097                 if (lun->l_serial != NULL) {
1098                         log_warnx("serial for lun \"%s\" "
1099                             "specified more than once",
1100                             lun->l_name);
1101                         free($2);
1102                         return (1);
1103                 }
1104                 lun_set_serial(lun, $2);
1105                 free($2);
1106         }
1107         ;
1108
1109 lun_size:       SIZE STR
1110         {
1111                 uint64_t tmp;
1112
1113                 if (expand_number($2, &tmp) != 0) {
1114                         yyerror("invalid numeric value");
1115                         free($2);
1116                         return (1);
1117                 }
1118
1119                 if (lun->l_size != 0) {
1120                         log_warnx("size for lun \"%s\" "
1121                             "specified more than once",
1122                             lun->l_name);
1123                         return (1);
1124                 }
1125                 lun_set_size(lun, tmp);
1126         }
1127         ;
1128 %%
1129
1130 void
1131 yyerror(const char *str)
1132 {
1133
1134         log_warnx("error in configuration file at line %d near '%s': %s",
1135             lineno, yytext, str);
1136 }
1137
1138 int
1139 parse_conf(struct conf *newconf, const char *path)
1140 {
1141         int error;
1142
1143         conf = newconf;
1144         yyin = fopen(path, "r");
1145         if (yyin == NULL) {
1146                 log_warn("unable to open configuration file %s", path);
1147                 return (1);
1148         }
1149
1150         lineno = 1;
1151         yyrestart(yyin);
1152         error = yyparse();
1153         auth_group = NULL;
1154         portal_group = NULL;
1155         target = NULL;
1156         lun = NULL;
1157         fclose(yyin);
1158
1159         return (error);
1160 }