]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - usr.sbin/ctld/parse.y
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.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 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_option
348         |
349         portal_group_redirect
350         |
351         portal_group_tag
352         ;
353
354 portal_group_discovery_auth_group:      DISCOVERY_AUTH_GROUP STR
355         {
356                 if (portal_group->pg_discovery_auth_group != NULL) {
357                         log_warnx("discovery-auth-group for portal-group "
358                             "\"%s\" specified more than once",
359                             portal_group->pg_name);
360                         return (1);
361                 }
362                 portal_group->pg_discovery_auth_group =
363                     auth_group_find(conf, $2);
364                 if (portal_group->pg_discovery_auth_group == NULL) {
365                         log_warnx("unknown discovery-auth-group \"%s\" "
366                             "for portal-group \"%s\"",
367                             $2, portal_group->pg_name);
368                         return (1);
369                 }
370                 free($2);
371         }
372         ;
373
374 portal_group_discovery_filter:  DISCOVERY_FILTER STR
375         {
376                 int error;
377
378                 error = portal_group_set_filter(portal_group, $2);
379                 free($2);
380                 if (error != 0)
381                         return (1);
382         }
383         ;
384
385 portal_group_foreign:   FOREIGN
386         {
387
388                 portal_group->pg_foreign = 1;
389         }
390         ;
391
392 portal_group_listen:    LISTEN STR
393         {
394                 int error;
395
396                 error = portal_group_add_listen(portal_group, $2, false);
397                 free($2);
398                 if (error != 0)
399                         return (1);
400         }
401         ;
402
403 portal_group_listen_iser:       LISTEN_ISER STR
404         {
405                 int error;
406
407                 error = portal_group_add_listen(portal_group, $2, true);
408                 free($2);
409                 if (error != 0)
410                         return (1);
411         }
412         ;
413
414 portal_group_option:    OPTION STR STR
415         {
416                 struct option *o;
417
418                 o = option_new(&portal_group->pg_options, $2, $3);
419                 free($2);
420                 free($3);
421                 if (o == NULL)
422                         return (1);
423         }
424         ;
425
426 portal_group_redirect:  REDIRECT STR
427         {
428                 int error;
429
430                 error = portal_group_set_redirection(portal_group, $2);
431                 free($2);
432                 if (error != 0)
433                         return (1);
434         }
435         ;
436
437 portal_group_tag:       TAG STR
438         {
439                 uint64_t tmp;
440
441                 if (expand_number($2, &tmp) != 0) {
442                         yyerror("invalid numeric value");
443                         free($2);
444                         return (1);
445                 }
446
447                 portal_group->pg_tag = tmp;
448         }
449         ;
450
451 lun:    LUN lun_name
452     OPENING_BRACKET lun_entries CLOSING_BRACKET
453         {
454                 lun = NULL;
455         }
456         ;
457
458 lun_name:       STR
459         {
460                 lun = lun_new(conf, $1);
461                 free($1);
462                 if (lun == NULL)
463                         return (1);
464         }
465         ;
466
467 target: TARGET target_name
468     OPENING_BRACKET target_entries CLOSING_BRACKET
469         {
470                 target = NULL;
471         }
472         ;
473
474 target_name:    STR
475         {
476                 target = target_new(conf, $1);
477                 free($1);
478                 if (target == NULL)
479                         return (1);
480         }
481         ;
482
483 target_entries:
484         |
485         target_entries target_entry
486         |
487         target_entries target_entry SEMICOLON
488         ;
489
490 target_entry:
491         target_alias
492         |
493         target_auth_group
494         |
495         target_auth_type
496         |
497         target_chap
498         |
499         target_chap_mutual
500         |
501         target_initiator_name
502         |
503         target_initiator_portal
504         |
505         target_portal_group
506         |
507         target_port
508         |
509         target_redirect
510         |
511         target_lun
512         |
513         target_lun_ref
514         ;
515
516 target_alias:   ALIAS STR
517         {
518                 if (target->t_alias != NULL) {
519                         log_warnx("alias for target \"%s\" "
520                             "specified more than once", target->t_name);
521                         return (1);
522                 }
523                 target->t_alias = $2;
524         }
525         ;
526
527 target_auth_group:      AUTH_GROUP STR
528         {
529                 if (target->t_auth_group != NULL) {
530                         if (target->t_auth_group->ag_name != NULL)
531                                 log_warnx("auth-group for target \"%s\" "
532                                     "specified more than once", target->t_name);
533                         else
534                                 log_warnx("cannot use both auth-group and explicit "
535                                     "authorisations for target \"%s\"",
536                                     target->t_name);
537                         return (1);
538                 }
539                 target->t_auth_group = auth_group_find(conf, $2);
540                 if (target->t_auth_group == NULL) {
541                         log_warnx("unknown auth-group \"%s\" for target "
542                             "\"%s\"", $2, target->t_name);
543                         return (1);
544                 }
545                 free($2);
546         }
547         ;
548
549 target_auth_type:       AUTH_TYPE STR
550         {
551                 int error;
552
553                 if (target->t_auth_group != NULL) {
554                         if (target->t_auth_group->ag_name != NULL) {
555                                 log_warnx("cannot use both auth-group and "
556                                     "auth-type for target \"%s\"",
557                                     target->t_name);
558                                 return (1);
559                         }
560                 } else {
561                         target->t_auth_group = auth_group_new(conf, NULL);
562                         if (target->t_auth_group == NULL) {
563                                 free($2);
564                                 return (1);
565                         }
566                         target->t_auth_group->ag_target = target;
567                 }
568                 error = auth_group_set_type(target->t_auth_group, $2);
569                 free($2);
570                 if (error != 0)
571                         return (1);
572         }
573         ;
574
575 target_chap:    CHAP STR STR
576         {
577                 const struct auth *ca;
578
579                 if (target->t_auth_group != NULL) {
580                         if (target->t_auth_group->ag_name != NULL) {
581                                 log_warnx("cannot use both auth-group and "
582                                     "chap for target \"%s\"",
583                                     target->t_name);
584                                 free($2);
585                                 free($3);
586                                 return (1);
587                         }
588                 } else {
589                         target->t_auth_group = auth_group_new(conf, NULL);
590                         if (target->t_auth_group == NULL) {
591                                 free($2);
592                                 free($3);
593                                 return (1);
594                         }
595                         target->t_auth_group->ag_target = target;
596                 }
597                 ca = auth_new_chap(target->t_auth_group, $2, $3);
598                 free($2);
599                 free($3);
600                 if (ca == NULL)
601                         return (1);
602         }
603         ;
604
605 target_chap_mutual:     CHAP_MUTUAL STR STR STR STR
606         {
607                 const struct auth *ca;
608
609                 if (target->t_auth_group != NULL) {
610                         if (target->t_auth_group->ag_name != NULL) {
611                                 log_warnx("cannot use both auth-group and "
612                                     "chap-mutual for target \"%s\"",
613                                     target->t_name);
614                                 free($2);
615                                 free($3);
616                                 free($4);
617                                 free($5);
618                                 return (1);
619                         }
620                 } else {
621                         target->t_auth_group = auth_group_new(conf, NULL);
622                         if (target->t_auth_group == NULL) {
623                                 free($2);
624                                 free($3);
625                                 free($4);
626                                 free($5);
627                                 return (1);
628                         }
629                         target->t_auth_group->ag_target = target;
630                 }
631                 ca = auth_new_chap_mutual(target->t_auth_group,
632                     $2, $3, $4, $5);
633                 free($2);
634                 free($3);
635                 free($4);
636                 free($5);
637                 if (ca == NULL)
638                         return (1);
639         }
640         ;
641
642 target_initiator_name:  INITIATOR_NAME STR
643         {
644                 const struct auth_name *an;
645
646                 if (target->t_auth_group != NULL) {
647                         if (target->t_auth_group->ag_name != NULL) {
648                                 log_warnx("cannot use both auth-group and "
649                                     "initiator-name for target \"%s\"",
650                                     target->t_name);
651                                 free($2);
652                                 return (1);
653                         }
654                 } else {
655                         target->t_auth_group = auth_group_new(conf, NULL);
656                         if (target->t_auth_group == NULL) {
657                                 free($2);
658                                 return (1);
659                         }
660                         target->t_auth_group->ag_target = target;
661                 }
662                 an = auth_name_new(target->t_auth_group, $2);
663                 free($2);
664                 if (an == NULL)
665                         return (1);
666         }
667         ;
668
669 target_initiator_portal:        INITIATOR_PORTAL STR
670         {
671                 const struct auth_portal *ap;
672
673                 if (target->t_auth_group != NULL) {
674                         if (target->t_auth_group->ag_name != NULL) {
675                                 log_warnx("cannot use both auth-group and "
676                                     "initiator-portal for target \"%s\"",
677                                     target->t_name);
678                                 free($2);
679                                 return (1);
680                         }
681                 } else {
682                         target->t_auth_group = auth_group_new(conf, NULL);
683                         if (target->t_auth_group == NULL) {
684                                 free($2);
685                                 return (1);
686                         }
687                         target->t_auth_group->ag_target = target;
688                 }
689                 ap = auth_portal_new(target->t_auth_group, $2);
690                 free($2);
691                 if (ap == NULL)
692                         return (1);
693         }
694         ;
695
696 target_portal_group:    PORTAL_GROUP STR STR
697         {
698                 struct portal_group *tpg;
699                 struct auth_group *tag;
700                 struct port *tp;
701
702                 tpg = portal_group_find(conf, $2);
703                 if (tpg == NULL) {
704                         log_warnx("unknown portal-group \"%s\" for target "
705                             "\"%s\"", $2, target->t_name);
706                         free($2);
707                         free($3);
708                         return (1);
709                 }
710                 tag = auth_group_find(conf, $3);
711                 if (tag == NULL) {
712                         log_warnx("unknown auth-group \"%s\" for target "
713                             "\"%s\"", $3, target->t_name);
714                         free($2);
715                         free($3);
716                         return (1);
717                 }
718                 tp = port_new(conf, target, tpg);
719                 if (tp == NULL) {
720                         log_warnx("can't link portal-group \"%s\" to target "
721                             "\"%s\"", $2, target->t_name);
722                         free($2);
723                         return (1);
724                 }
725                 tp->p_auth_group = tag;
726                 free($2);
727                 free($3);
728         }
729         |               PORTAL_GROUP STR
730         {
731                 struct portal_group *tpg;
732                 struct port *tp;
733
734                 tpg = portal_group_find(conf, $2);
735                 if (tpg == NULL) {
736                         log_warnx("unknown portal-group \"%s\" for target "
737                             "\"%s\"", $2, target->t_name);
738                         free($2);
739                         return (1);
740                 }
741                 tp = port_new(conf, target, tpg);
742                 if (tp == NULL) {
743                         log_warnx("can't link portal-group \"%s\" to target "
744                             "\"%s\"", $2, target->t_name);
745                         free($2);
746                         return (1);
747                 }
748                 free($2);
749         }
750         ;
751
752 target_port:    PORT STR
753         {
754                 struct pport *pp;
755                 struct port *tp;
756
757                 pp = pport_find(conf, $2);
758                 if (pp == NULL) {
759                         log_warnx("unknown port \"%s\" for target \"%s\"",
760                             $2, target->t_name);
761                         free($2);
762                         return (1);
763                 }
764                 if (!TAILQ_EMPTY(&pp->pp_ports)) {
765                         log_warnx("can't link port \"%s\" to target \"%s\", "
766                             "port already linked to some target",
767                             $2, target->t_name);
768                         free($2);
769                         return (1);
770                 }
771                 tp = port_new_pp(conf, target, pp);
772                 if (tp == NULL) {
773                         log_warnx("can't link port \"%s\" to target \"%s\"",
774                             $2, target->t_name);
775                         free($2);
776                         return (1);
777                 }
778                 free($2);
779         }
780         ;
781
782 target_redirect:        REDIRECT STR
783         {
784                 int error;
785
786                 error = target_set_redirection(target, $2);
787                 free($2);
788                 if (error != 0)
789                         return (1);
790         }
791         ;
792
793 target_lun:     LUN lun_number
794     OPENING_BRACKET lun_entries CLOSING_BRACKET
795         {
796                 lun = NULL;
797         }
798         ;
799
800 lun_number:     STR
801         {
802                 uint64_t tmp;
803                 int ret;
804                 char *name;
805
806                 if (expand_number($1, &tmp) != 0) {
807                         yyerror("invalid numeric value");
808                         free($1);
809                         return (1);
810                 }
811
812                 ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
813                 if (ret <= 0)
814                         log_err(1, "asprintf");
815                 lun = lun_new(conf, name);
816                 if (lun == NULL)
817                         return (1);
818
819                 lun_set_scsiname(lun, name);
820                 target->t_luns[tmp] = lun;
821         }
822         ;
823
824 target_lun_ref: LUN STR STR
825         {
826                 uint64_t tmp;
827
828                 if (expand_number($2, &tmp) != 0) {
829                         yyerror("invalid numeric value");
830                         free($2);
831                         free($3);
832                         return (1);
833                 }
834                 free($2);
835
836                 lun = lun_find(conf, $3);
837                 free($3);
838                 if (lun == NULL)
839                         return (1);
840
841                 target->t_luns[tmp] = lun;
842         }
843         ;
844
845 lun_entries:
846         |
847         lun_entries lun_entry
848         |
849         lun_entries lun_entry SEMICOLON
850         ;
851
852 lun_entry:
853         lun_backend
854         |
855         lun_blocksize
856         |
857         lun_device_id
858         |
859         lun_device_type
860         |
861         lun_ctl_lun
862         |
863         lun_option
864         |
865         lun_path
866         |
867         lun_serial
868         |
869         lun_size
870         ;
871
872 lun_backend:    BACKEND STR
873         {
874                 if (lun->l_backend != NULL) {
875                         log_warnx("backend for lun \"%s\" "
876                             "specified more than once",
877                             lun->l_name);
878                         free($2);
879                         return (1);
880                 }
881                 lun_set_backend(lun, $2);
882                 free($2);
883         }
884         ;
885
886 lun_blocksize:  BLOCKSIZE STR
887         {
888                 uint64_t tmp;
889
890                 if (expand_number($2, &tmp) != 0) {
891                         yyerror("invalid numeric value");
892                         free($2);
893                         return (1);
894                 }
895
896                 if (lun->l_blocksize != 0) {
897                         log_warnx("blocksize for lun \"%s\" "
898                             "specified more than once",
899                             lun->l_name);
900                         return (1);
901                 }
902                 lun_set_blocksize(lun, tmp);
903         }
904         ;
905
906 lun_device_id:  DEVICE_ID STR
907         {
908                 if (lun->l_device_id != NULL) {
909                         log_warnx("device_id for lun \"%s\" "
910                             "specified more than once",
911                             lun->l_name);
912                         free($2);
913                         return (1);
914                 }
915                 lun_set_device_id(lun, $2);
916                 free($2);
917         }
918         ;
919
920 lun_device_type:        DEVICE_TYPE STR
921         {
922                 uint64_t tmp;
923
924                 if (strcasecmp($2, "disk") == 0 ||
925                     strcasecmp($2, "direct") == 0)
926                         tmp = 0;
927                 else if (strcasecmp($2, "processor") == 0)
928                         tmp = 3;
929                 else if (strcasecmp($2, "cd") == 0 ||
930                     strcasecmp($2, "cdrom") == 0 ||
931                     strcasecmp($2, "dvd") == 0 ||
932                     strcasecmp($2, "dvdrom") == 0)
933                         tmp = 5;
934                 else if (expand_number($2, &tmp) != 0 ||
935                     tmp > 15) {
936                         yyerror("invalid numeric value");
937                         free($2);
938                         return (1);
939                 }
940
941                 lun_set_device_type(lun, tmp);
942         }
943         ;
944
945 lun_ctl_lun:    CTL_LUN STR
946         {
947                 uint64_t tmp;
948
949                 if (expand_number($2, &tmp) != 0) {
950                         yyerror("invalid numeric value");
951                         free($2);
952                         return (1);
953                 }
954
955                 if (lun->l_ctl_lun >= 0) {
956                         log_warnx("ctl_lun for lun \"%s\" "
957                             "specified more than once",
958                             lun->l_name);
959                         return (1);
960                 }
961                 lun_set_ctl_lun(lun, tmp);
962         }
963         ;
964
965 lun_option:     OPTION STR STR
966         {
967                 struct option *o;
968
969                 o = option_new(&lun->l_options, $2, $3);
970                 free($2);
971                 free($3);
972                 if (o == NULL)
973                         return (1);
974         }
975         ;
976
977 lun_path:       PATH STR
978         {
979                 if (lun->l_path != NULL) {
980                         log_warnx("path for lun \"%s\" "
981                             "specified more than once",
982                             lun->l_name);
983                         free($2);
984                         return (1);
985                 }
986                 lun_set_path(lun, $2);
987                 free($2);
988         }
989         ;
990
991 lun_serial:     SERIAL STR
992         {
993                 if (lun->l_serial != NULL) {
994                         log_warnx("serial for lun \"%s\" "
995                             "specified more than once",
996                             lun->l_name);
997                         free($2);
998                         return (1);
999                 }
1000                 lun_set_serial(lun, $2);
1001                 free($2);
1002         }
1003         ;
1004
1005 lun_size:       SIZE STR
1006         {
1007                 uint64_t tmp;
1008
1009                 if (expand_number($2, &tmp) != 0) {
1010                         yyerror("invalid numeric value");
1011                         free($2);
1012                         return (1);
1013                 }
1014
1015                 if (lun->l_size != 0) {
1016                         log_warnx("size for lun \"%s\" "
1017                             "specified more than once",
1018                             lun->l_name);
1019                         return (1);
1020                 }
1021                 lun_set_size(lun, tmp);
1022         }
1023         ;
1024 %%
1025
1026 void
1027 yyerror(const char *str)
1028 {
1029
1030         log_warnx("error in configuration file at line %d near '%s': %s",
1031             lineno, yytext, str);
1032 }
1033
1034 static void
1035 check_perms(const char *path)
1036 {
1037         struct stat sb;
1038         int error;
1039
1040         error = stat(path, &sb);
1041         if (error != 0) {
1042                 log_warn("stat");
1043                 return;
1044         }
1045         if (sb.st_mode & S_IWOTH) {
1046                 log_warnx("%s is world-writable", path);
1047         } else if (sb.st_mode & S_IROTH) {
1048                 log_warnx("%s is world-readable", path);
1049         } else if (sb.st_mode & S_IXOTH) {
1050                 /*
1051                  * Ok, this one doesn't matter, but still do it,
1052                  * just for consistency.
1053                  */
1054                 log_warnx("%s is world-executable", path);
1055         }
1056
1057         /*
1058          * XXX: Should we also check for owner != 0?
1059          */
1060 }
1061
1062 struct conf *
1063 conf_new_from_file(const char *path, struct conf *oldconf)
1064 {
1065         struct auth_group *ag;
1066         struct portal_group *pg;
1067         struct pport *pp;
1068         int error;
1069
1070         log_debugx("obtaining configuration from %s", path);
1071
1072         conf = conf_new();
1073
1074         TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
1075                 pport_copy(pp, conf);
1076
1077         ag = auth_group_new(conf, "default");
1078         assert(ag != NULL);
1079
1080         ag = auth_group_new(conf, "no-authentication");
1081         assert(ag != NULL);
1082         ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
1083
1084         ag = auth_group_new(conf, "no-access");
1085         assert(ag != NULL);
1086         ag->ag_type = AG_TYPE_DENY;
1087
1088         pg = portal_group_new(conf, "default");
1089         assert(pg != NULL);
1090
1091         yyin = fopen(path, "r");
1092         if (yyin == NULL) {
1093                 log_warn("unable to open configuration file %s", path);
1094                 conf_delete(conf);
1095                 return (NULL);
1096         }
1097         check_perms(path);
1098         lineno = 1;
1099         yyrestart(yyin);
1100         error = yyparse();
1101         auth_group = NULL;
1102         portal_group = NULL;
1103         target = NULL;
1104         lun = NULL;
1105         fclose(yyin);
1106         if (error != 0) {
1107                 conf_delete(conf);
1108                 return (NULL);
1109         }
1110
1111         if (conf->conf_default_ag_defined == false) {
1112                 log_debugx("auth-group \"default\" not defined; "
1113                     "going with defaults");
1114                 ag = auth_group_find(conf, "default");
1115                 assert(ag != NULL);
1116                 ag->ag_type = AG_TYPE_DENY;
1117         }
1118
1119         if (conf->conf_default_pg_defined == false) {
1120                 log_debugx("portal-group \"default\" not defined; "
1121                     "going with defaults");
1122                 pg = portal_group_find(conf, "default");
1123                 assert(pg != NULL);
1124                 portal_group_add_listen(pg, "0.0.0.0:3260", false);
1125                 portal_group_add_listen(pg, "[::]:3260", false);
1126         }
1127
1128         conf->conf_kernel_port_on = true;
1129
1130         error = conf_verify(conf);
1131         if (error != 0) {
1132                 conf_delete(conf);
1133                 return (NULL);
1134         }
1135
1136         return (conf);
1137 }