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