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