]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/parse.y
MFV r328323,328324:
[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
772                 pp = pport_find(conf, $2);
773                 if (pp == NULL) {
774                         log_warnx("unknown port \"%s\" for target \"%s\"",
775                             $2, target->t_name);
776                         free($2);
777                         return (1);
778                 }
779                 if (!TAILQ_EMPTY(&pp->pp_ports)) {
780                         log_warnx("can't link port \"%s\" to target \"%s\", "
781                             "port already linked to some target",
782                             $2, target->t_name);
783                         free($2);
784                         return (1);
785                 }
786                 tp = port_new_pp(conf, target, pp);
787                 if (tp == NULL) {
788                         log_warnx("can't link port \"%s\" to target \"%s\"",
789                             $2, target->t_name);
790                         free($2);
791                         return (1);
792                 }
793                 free($2);
794         }
795         ;
796
797 target_redirect:        REDIRECT STR
798         {
799                 int error;
800
801                 error = target_set_redirection(target, $2);
802                 free($2);
803                 if (error != 0)
804                         return (1);
805         }
806         ;
807
808 target_lun:     LUN lun_number
809     OPENING_BRACKET lun_entries CLOSING_BRACKET
810         {
811                 lun = NULL;
812         }
813         ;
814
815 lun_number:     STR
816         {
817                 uint64_t tmp;
818                 int ret;
819                 char *name;
820
821                 if (expand_number($1, &tmp) != 0) {
822                         yyerror("invalid numeric value");
823                         free($1);
824                         return (1);
825                 }
826                 if (tmp >= MAX_LUNS) {
827                         yyerror("LU number is too big");
828                         free($1);
829                         return (1);
830                 }
831
832                 ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
833                 if (ret <= 0)
834                         log_err(1, "asprintf");
835                 lun = lun_new(conf, name);
836                 if (lun == NULL)
837                         return (1);
838
839                 lun_set_scsiname(lun, name);
840                 target->t_luns[tmp] = lun;
841         }
842         ;
843
844 target_lun_ref: LUN STR STR
845         {
846                 uint64_t tmp;
847
848                 if (expand_number($2, &tmp) != 0) {
849                         yyerror("invalid numeric value");
850                         free($2);
851                         free($3);
852                         return (1);
853                 }
854                 free($2);
855                 if (tmp >= MAX_LUNS) {
856                         yyerror("LU number is too big");
857                         free($3);
858                         return (1);
859                 }
860
861                 lun = lun_find(conf, $3);
862                 free($3);
863                 if (lun == NULL)
864                         return (1);
865
866                 target->t_luns[tmp] = lun;
867         }
868         ;
869
870 lun_entries:
871         |
872         lun_entries lun_entry
873         |
874         lun_entries lun_entry SEMICOLON
875         ;
876
877 lun_entry:
878         lun_backend
879         |
880         lun_blocksize
881         |
882         lun_device_id
883         |
884         lun_device_type
885         |
886         lun_ctl_lun
887         |
888         lun_option
889         |
890         lun_path
891         |
892         lun_serial
893         |
894         lun_size
895         ;
896
897 lun_backend:    BACKEND STR
898         {
899                 if (lun->l_backend != NULL) {
900                         log_warnx("backend for lun \"%s\" "
901                             "specified more than once",
902                             lun->l_name);
903                         free($2);
904                         return (1);
905                 }
906                 lun_set_backend(lun, $2);
907                 free($2);
908         }
909         ;
910
911 lun_blocksize:  BLOCKSIZE STR
912         {
913                 uint64_t tmp;
914
915                 if (expand_number($2, &tmp) != 0) {
916                         yyerror("invalid numeric value");
917                         free($2);
918                         return (1);
919                 }
920
921                 if (lun->l_blocksize != 0) {
922                         log_warnx("blocksize for lun \"%s\" "
923                             "specified more than once",
924                             lun->l_name);
925                         return (1);
926                 }
927                 lun_set_blocksize(lun, tmp);
928         }
929         ;
930
931 lun_device_id:  DEVICE_ID STR
932         {
933                 if (lun->l_device_id != NULL) {
934                         log_warnx("device_id for lun \"%s\" "
935                             "specified more than once",
936                             lun->l_name);
937                         free($2);
938                         return (1);
939                 }
940                 lun_set_device_id(lun, $2);
941                 free($2);
942         }
943         ;
944
945 lun_device_type:        DEVICE_TYPE STR
946         {
947                 uint64_t tmp;
948
949                 if (strcasecmp($2, "disk") == 0 ||
950                     strcasecmp($2, "direct") == 0)
951                         tmp = 0;
952                 else if (strcasecmp($2, "processor") == 0)
953                         tmp = 3;
954                 else if (strcasecmp($2, "cd") == 0 ||
955                     strcasecmp($2, "cdrom") == 0 ||
956                     strcasecmp($2, "dvd") == 0 ||
957                     strcasecmp($2, "dvdrom") == 0)
958                         tmp = 5;
959                 else if (expand_number($2, &tmp) != 0 ||
960                     tmp > 15) {
961                         yyerror("invalid numeric value");
962                         free($2);
963                         return (1);
964                 }
965
966                 lun_set_device_type(lun, tmp);
967         }
968         ;
969
970 lun_ctl_lun:    CTL_LUN STR
971         {
972                 uint64_t tmp;
973
974                 if (expand_number($2, &tmp) != 0) {
975                         yyerror("invalid numeric value");
976                         free($2);
977                         return (1);
978                 }
979
980                 if (lun->l_ctl_lun >= 0) {
981                         log_warnx("ctl_lun for lun \"%s\" "
982                             "specified more than once",
983                             lun->l_name);
984                         return (1);
985                 }
986                 lun_set_ctl_lun(lun, tmp);
987         }
988         ;
989
990 lun_option:     OPTION STR STR
991         {
992                 struct option *o;
993
994                 o = option_new(&lun->l_options, $2, $3);
995                 free($2);
996                 free($3);
997                 if (o == NULL)
998                         return (1);
999         }
1000         ;
1001
1002 lun_path:       PATH STR
1003         {
1004                 if (lun->l_path != NULL) {
1005                         log_warnx("path for lun \"%s\" "
1006                             "specified more than once",
1007                             lun->l_name);
1008                         free($2);
1009                         return (1);
1010                 }
1011                 lun_set_path(lun, $2);
1012                 free($2);
1013         }
1014         ;
1015
1016 lun_serial:     SERIAL STR
1017         {
1018                 if (lun->l_serial != NULL) {
1019                         log_warnx("serial for lun \"%s\" "
1020                             "specified more than once",
1021                             lun->l_name);
1022                         free($2);
1023                         return (1);
1024                 }
1025                 lun_set_serial(lun, $2);
1026                 free($2);
1027         }
1028         ;
1029
1030 lun_size:       SIZE STR
1031         {
1032                 uint64_t tmp;
1033
1034                 if (expand_number($2, &tmp) != 0) {
1035                         yyerror("invalid numeric value");
1036                         free($2);
1037                         return (1);
1038                 }
1039
1040                 if (lun->l_size != 0) {
1041                         log_warnx("size for lun \"%s\" "
1042                             "specified more than once",
1043                             lun->l_name);
1044                         return (1);
1045                 }
1046                 lun_set_size(lun, tmp);
1047         }
1048         ;
1049 %%
1050
1051 void
1052 yyerror(const char *str)
1053 {
1054
1055         log_warnx("error in configuration file at line %d near '%s': %s",
1056             lineno, yytext, str);
1057 }
1058
1059 int
1060 parse_conf(struct conf *newconf, const char *path)
1061 {
1062         int error;
1063
1064         conf = newconf;
1065         yyin = fopen(path, "r");
1066         if (yyin == NULL) {
1067                 log_warn("unable to open configuration file %s", path);
1068                 return (1);
1069         }
1070
1071         lineno = 1;
1072         yyrestart(yyin);
1073         error = yyparse();
1074         auth_group = NULL;
1075         portal_group = NULL;
1076         target = NULL;
1077         lun = NULL;
1078         fclose(yyin);
1079
1080         return (error);
1081 }