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