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 target->t_pport = strdup($2); 836 837 free($2); 838 } 839 ; 840 841 target_redirect: REDIRECT STR 842 { 843 int error; 844 845 error = target_set_redirection(target, $2); 846 free($2); 847 if (error != 0) 848 return (1); 849 } 850 ; 851 852 target_lun: LUN lun_number 853 OPENING_BRACKET lun_entries CLOSING_BRACKET 854 { 855 lun = NULL; 856 } 857 ; 858 859 lun_number: STR 860 { 861 uint64_t tmp; 862 int ret; 863 char *name; 864 865 if (expand_number($1, &tmp) != 0) { 866 yyerror("invalid numeric value"); 867 free($1); 868 return (1); 869 } 870 if (tmp >= MAX_LUNS) { 871 yyerror("LU number is too big"); 872 free($1); 873 return (1); 874 } 875 876 ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp); 877 if (ret <= 0) 878 log_err(1, "asprintf"); 879 lun = lun_new(conf, name); 880 if (lun == NULL) 881 return (1); 882 883 lun_set_scsiname(lun, name); 884 target->t_luns[tmp] = lun; 885 } 886 ; 887 888 target_lun_ref: LUN STR STR 889 { 890 uint64_t tmp; 891 892 if (expand_number($2, &tmp) != 0) { 893 yyerror("invalid numeric value"); 894 free($2); 895 free($3); 896 return (1); 897 } 898 free($2); 899 if (tmp >= MAX_LUNS) { 900 yyerror("LU number is too big"); 901 free($3); 902 return (1); 903 } 904 905 lun = lun_find(conf, $3); 906 free($3); 907 if (lun == NULL) 908 return (1); 909 910 target->t_luns[tmp] = lun; 911 } 912 ; 913 914 lun_entries: 915 | 916 lun_entries lun_entry 917 | 918 lun_entries lun_entry SEMICOLON 919 ; 920 921 lun_entry: 922 lun_backend 923 | 924 lun_blocksize 925 | 926 lun_device_id 927 | 928 lun_device_type 929 | 930 lun_ctl_lun 931 | 932 lun_option 933 | 934 lun_path 935 | 936 lun_serial 937 | 938 lun_size 939 ; 940 941 lun_backend: BACKEND STR 942 { 943 if (lun->l_backend != NULL) { 944 log_warnx("backend for lun \"%s\" " 945 "specified more than once", 946 lun->l_name); 947 free($2); 948 return (1); 949 } 950 lun_set_backend(lun, $2); 951 free($2); 952 } 953 ; 954 955 lun_blocksize: BLOCKSIZE STR 956 { 957 uint64_t tmp; 958 959 if (expand_number($2, &tmp) != 0) { 960 yyerror("invalid numeric value"); 961 free($2); 962 return (1); 963 } 964 965 if (lun->l_blocksize != 0) { 966 log_warnx("blocksize for lun \"%s\" " 967 "specified more than once", 968 lun->l_name); 969 return (1); 970 } 971 lun_set_blocksize(lun, tmp); 972 } 973 ; 974 975 lun_device_id: DEVICE_ID STR 976 { 977 if (lun->l_device_id != NULL) { 978 log_warnx("device_id for lun \"%s\" " 979 "specified more than once", 980 lun->l_name); 981 free($2); 982 return (1); 983 } 984 lun_set_device_id(lun, $2); 985 free($2); 986 } 987 ; 988 989 lun_device_type: DEVICE_TYPE STR 990 { 991 uint64_t tmp; 992 993 if (strcasecmp($2, "disk") == 0 || 994 strcasecmp($2, "direct") == 0) 995 tmp = 0; 996 else if (strcasecmp($2, "processor") == 0) 997 tmp = 3; 998 else if (strcasecmp($2, "cd") == 0 || 999 strcasecmp($2, "cdrom") == 0 || 1000 strcasecmp($2, "dvd") == 0 || 1001 strcasecmp($2, "dvdrom") == 0) 1002 tmp = 5; 1003 else if (expand_number($2, &tmp) != 0 || 1004 tmp > 15) { 1005 yyerror("invalid numeric value"); 1006 free($2); 1007 return (1); 1008 } 1009 1010 lun_set_device_type(lun, tmp); 1011 } 1012 ; 1013 1014 lun_ctl_lun: CTL_LUN STR 1015 { 1016 uint64_t tmp; 1017 1018 if (expand_number($2, &tmp) != 0) { 1019 yyerror("invalid numeric value"); 1020 free($2); 1021 return (1); 1022 } 1023 1024 if (lun->l_ctl_lun >= 0) { 1025 log_warnx("ctl_lun for lun \"%s\" " 1026 "specified more than once", 1027 lun->l_name); 1028 return (1); 1029 } 1030 lun_set_ctl_lun(lun, tmp); 1031 } 1032 ; 1033 1034 lun_option: OPTION STR STR 1035 { 1036 struct option *o; 1037 1038 o = option_new(&lun->l_options, $2, $3); 1039 free($2); 1040 free($3); 1041 if (o == NULL) 1042 return (1); 1043 } 1044 ; 1045 1046 lun_path: PATH STR 1047 { 1048 if (lun->l_path != NULL) { 1049 log_warnx("path for lun \"%s\" " 1050 "specified more than once", 1051 lun->l_name); 1052 free($2); 1053 return (1); 1054 } 1055 lun_set_path(lun, $2); 1056 free($2); 1057 } 1058 ; 1059 1060 lun_serial: SERIAL STR 1061 { 1062 if (lun->l_serial != NULL) { 1063 log_warnx("serial for lun \"%s\" " 1064 "specified more than once", 1065 lun->l_name); 1066 free($2); 1067 return (1); 1068 } 1069 lun_set_serial(lun, $2); 1070 free($2); 1071 } 1072 ; 1073 1074 lun_size: SIZE STR 1075 { 1076 uint64_t tmp; 1077 1078 if (expand_number($2, &tmp) != 0) { 1079 yyerror("invalid numeric value"); 1080 free($2); 1081 return (1); 1082 } 1083 1084 if (lun->l_size != 0) { 1085 log_warnx("size for lun \"%s\" " 1086 "specified more than once", 1087 lun->l_name); 1088 return (1); 1089 } 1090 lun_set_size(lun, tmp); 1091 } 1092 ; 1093 %% 1094 1095 void 1096 yyerror(const char *str) 1097 { 1098 1099 log_warnx("error in configuration file at line %d near '%s': %s", 1100 lineno, yytext, str); 1101 } 1102 1103 int 1104 parse_conf(struct conf *newconf, const char *path) 1105 { 1106 int error; 1107 1108 conf = newconf; 1109 yyin = fopen(path, "r"); 1110 if (yyin == NULL) { 1111 log_warn("unable to open configuration file %s", path); 1112 return (1); 1113 } 1114 1115 lineno = 1; 1116 yyrestart(yyin); 1117 error = yyparse(); 1118 auth_group = NULL; 1119 portal_group = NULL; 1120 target = NULL; 1121 lun = NULL; 1122 fclose(yyin); 1123 1124 return (error); 1125 } 1126