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