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