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 * $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 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