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