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