]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/ctld/parse.y
MFC r322124:
[FreeBSD/stable/10.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                 if (tmp >= MAX_LUNS) {
812                         yyerror("LU number is too big");
813                         free($1);
814                         return (1);
815                 }
816
817                 ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
818                 if (ret <= 0)
819                         log_err(1, "asprintf");
820                 lun = lun_new(conf, name);
821                 if (lun == NULL)
822                         return (1);
823
824                 lun_set_scsiname(lun, name);
825                 target->t_luns[tmp] = lun;
826         }
827         ;
828
829 target_lun_ref: LUN STR STR
830         {
831                 uint64_t tmp;
832
833                 if (expand_number($2, &tmp) != 0) {
834                         yyerror("invalid numeric value");
835                         free($2);
836                         free($3);
837                         return (1);
838                 }
839                 free($2);
840                 if (tmp >= MAX_LUNS) {
841                         yyerror("LU number is too big");
842                         free($3);
843                         return (1);
844                 }
845
846                 lun = lun_find(conf, $3);
847                 free($3);
848                 if (lun == NULL)
849                         return (1);
850
851                 target->t_luns[tmp] = lun;
852         }
853         ;
854
855 lun_entries:
856         |
857         lun_entries lun_entry
858         |
859         lun_entries lun_entry SEMICOLON
860         ;
861
862 lun_entry:
863         lun_backend
864         |
865         lun_blocksize
866         |
867         lun_device_id
868         |
869         lun_device_type
870         |
871         lun_ctl_lun
872         |
873         lun_option
874         |
875         lun_path
876         |
877         lun_serial
878         |
879         lun_size
880         ;
881
882 lun_backend:    BACKEND STR
883         {
884                 if (lun->l_backend != NULL) {
885                         log_warnx("backend for lun \"%s\" "
886                             "specified more than once",
887                             lun->l_name);
888                         free($2);
889                         return (1);
890                 }
891                 lun_set_backend(lun, $2);
892                 free($2);
893         }
894         ;
895
896 lun_blocksize:  BLOCKSIZE STR
897         {
898                 uint64_t tmp;
899
900                 if (expand_number($2, &tmp) != 0) {
901                         yyerror("invalid numeric value");
902                         free($2);
903                         return (1);
904                 }
905
906                 if (lun->l_blocksize != 0) {
907                         log_warnx("blocksize for lun \"%s\" "
908                             "specified more than once",
909                             lun->l_name);
910                         return (1);
911                 }
912                 lun_set_blocksize(lun, tmp);
913         }
914         ;
915
916 lun_device_id:  DEVICE_ID STR
917         {
918                 if (lun->l_device_id != NULL) {
919                         log_warnx("device_id for lun \"%s\" "
920                             "specified more than once",
921                             lun->l_name);
922                         free($2);
923                         return (1);
924                 }
925                 lun_set_device_id(lun, $2);
926                 free($2);
927         }
928         ;
929
930 lun_device_type:        DEVICE_TYPE STR
931         {
932                 uint64_t tmp;
933
934                 if (strcasecmp($2, "disk") == 0 ||
935                     strcasecmp($2, "direct") == 0)
936                         tmp = 0;
937                 else if (strcasecmp($2, "processor") == 0)
938                         tmp = 3;
939                 else if (strcasecmp($2, "cd") == 0 ||
940                     strcasecmp($2, "cdrom") == 0 ||
941                     strcasecmp($2, "dvd") == 0 ||
942                     strcasecmp($2, "dvdrom") == 0)
943                         tmp = 5;
944                 else if (expand_number($2, &tmp) != 0 ||
945                     tmp > 15) {
946                         yyerror("invalid numeric value");
947                         free($2);
948                         return (1);
949                 }
950
951                 lun_set_device_type(lun, tmp);
952         }
953         ;
954
955 lun_ctl_lun:    CTL_LUN STR
956         {
957                 uint64_t tmp;
958
959                 if (expand_number($2, &tmp) != 0) {
960                         yyerror("invalid numeric value");
961                         free($2);
962                         return (1);
963                 }
964
965                 if (lun->l_ctl_lun >= 0) {
966                         log_warnx("ctl_lun for lun \"%s\" "
967                             "specified more than once",
968                             lun->l_name);
969                         return (1);
970                 }
971                 lun_set_ctl_lun(lun, tmp);
972         }
973         ;
974
975 lun_option:     OPTION STR STR
976         {
977                 struct option *o;
978
979                 o = option_new(&lun->l_options, $2, $3);
980                 free($2);
981                 free($3);
982                 if (o == NULL)
983                         return (1);
984         }
985         ;
986
987 lun_path:       PATH STR
988         {
989                 if (lun->l_path != NULL) {
990                         log_warnx("path for lun \"%s\" "
991                             "specified more than once",
992                             lun->l_name);
993                         free($2);
994                         return (1);
995                 }
996                 lun_set_path(lun, $2);
997                 free($2);
998         }
999         ;
1000
1001 lun_serial:     SERIAL STR
1002         {
1003                 if (lun->l_serial != NULL) {
1004                         log_warnx("serial for lun \"%s\" "
1005                             "specified more than once",
1006                             lun->l_name);
1007                         free($2);
1008                         return (1);
1009                 }
1010                 lun_set_serial(lun, $2);
1011                 free($2);
1012         }
1013         ;
1014
1015 lun_size:       SIZE STR
1016         {
1017                 uint64_t tmp;
1018
1019                 if (expand_number($2, &tmp) != 0) {
1020                         yyerror("invalid numeric value");
1021                         free($2);
1022                         return (1);
1023                 }
1024
1025                 if (lun->l_size != 0) {
1026                         log_warnx("size for lun \"%s\" "
1027                             "specified more than once",
1028                             lun->l_name);
1029                         return (1);
1030                 }
1031                 lun_set_size(lun, tmp);
1032         }
1033         ;
1034 %%
1035
1036 void
1037 yyerror(const char *str)
1038 {
1039
1040         log_warnx("error in configuration file at line %d near '%s': %s",
1041             lineno, yytext, str);
1042 }
1043
1044 static void
1045 check_perms(const char *path)
1046 {
1047         struct stat sb;
1048         int error;
1049
1050         error = stat(path, &sb);
1051         if (error != 0) {
1052                 log_warn("stat");
1053                 return;
1054         }
1055         if (sb.st_mode & S_IWOTH) {
1056                 log_warnx("%s is world-writable", path);
1057         } else if (sb.st_mode & S_IROTH) {
1058                 log_warnx("%s is world-readable", path);
1059         } else if (sb.st_mode & S_IXOTH) {
1060                 /*
1061                  * Ok, this one doesn't matter, but still do it,
1062                  * just for consistency.
1063                  */
1064                 log_warnx("%s is world-executable", path);
1065         }
1066
1067         /*
1068          * XXX: Should we also check for owner != 0?
1069          */
1070 }
1071
1072 struct conf *
1073 conf_new_from_file(const char *path, struct conf *oldconf)
1074 {
1075         struct auth_group *ag;
1076         struct portal_group *pg;
1077         struct pport *pp;
1078         int error;
1079
1080         log_debugx("obtaining configuration from %s", path);
1081
1082         conf = conf_new();
1083
1084         TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
1085                 pport_copy(pp, conf);
1086
1087         ag = auth_group_new(conf, "default");
1088         assert(ag != NULL);
1089
1090         ag = auth_group_new(conf, "no-authentication");
1091         assert(ag != NULL);
1092         ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
1093
1094         ag = auth_group_new(conf, "no-access");
1095         assert(ag != NULL);
1096         ag->ag_type = AG_TYPE_DENY;
1097
1098         pg = portal_group_new(conf, "default");
1099         assert(pg != NULL);
1100
1101         yyin = fopen(path, "r");
1102         if (yyin == NULL) {
1103                 log_warn("unable to open configuration file %s", path);
1104                 conf_delete(conf);
1105                 return (NULL);
1106         }
1107         check_perms(path);
1108         lineno = 1;
1109         yyrestart(yyin);
1110         error = yyparse();
1111         auth_group = NULL;
1112         portal_group = NULL;
1113         target = NULL;
1114         lun = NULL;
1115         fclose(yyin);
1116         if (error != 0) {
1117                 conf_delete(conf);
1118                 return (NULL);
1119         }
1120
1121         if (conf->conf_default_ag_defined == false) {
1122                 log_debugx("auth-group \"default\" not defined; "
1123                     "going with defaults");
1124                 ag = auth_group_find(conf, "default");
1125                 assert(ag != NULL);
1126                 ag->ag_type = AG_TYPE_DENY;
1127         }
1128
1129         if (conf->conf_default_pg_defined == false) {
1130                 log_debugx("portal-group \"default\" not defined; "
1131                     "going with defaults");
1132                 pg = portal_group_find(conf, "default");
1133                 assert(pg != NULL);
1134                 portal_group_add_listen(pg, "0.0.0.0:3260", false);
1135                 portal_group_add_listen(pg, "[::]:3260", false);
1136         }
1137
1138         conf->conf_kernel_port_on = true;
1139
1140         error = conf_verify(conf);
1141         if (error != 0) {
1142                 conf_delete(conf);
1143                 return (NULL);
1144         }
1145
1146         return (conf);
1147 }