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