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