]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/parse.y
trim(8): Fix a few issues reported by mandoc
[FreeBSD/FreeBSD.git] / usr.sbin / ctld / parse.y
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 }