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