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