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