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 PIDFILE PORT PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR 69 %token 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 364 portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR 365 { 366 if (portal_group->pg_discovery_auth_group != NULL) { 367 log_warnx("discovery-auth-group for portal-group " 368 "\"%s\" specified more than once", 369 portal_group->pg_name); 370 return (1); 371 } 372 portal_group->pg_discovery_auth_group = 373 auth_group_find(conf, $2); 374 if (portal_group->pg_discovery_auth_group == NULL) { 375 log_warnx("unknown discovery-auth-group \"%s\" " 376 "for portal-group \"%s\"", 377 $2, portal_group->pg_name); 378 return (1); 379 } 380 free($2); 381 } 382 ; 383 384 portal_group_discovery_filter: DISCOVERY_FILTER STR 385 { 386 int error; 387 388 error = portal_group_set_filter(portal_group, $2); 389 free($2); 390 if (error != 0) 391 return (1); 392 } 393 ; 394 395 portal_group_foreign: FOREIGN 396 { 397 398 portal_group->pg_foreign = 1; 399 } 400 ; 401 402 portal_group_listen: LISTEN STR 403 { 404 int error; 405 406 error = portal_group_add_listen(portal_group, $2, false); 407 free($2); 408 if (error != 0) 409 return (1); 410 } 411 ; 412 413 portal_group_listen_iser: LISTEN_ISER STR 414 { 415 int error; 416 417 error = portal_group_add_listen(portal_group, $2, true); 418 free($2); 419 if (error != 0) 420 return (1); 421 } 422 ; 423 424 portal_group_offload: OFFLOAD STR 425 { 426 int error; 427 428 error = portal_group_set_offload(portal_group, $2); 429 free($2); 430 if (error != 0) 431 return (1); 432 } 433 ; 434 435 portal_group_option: OPTION STR STR 436 { 437 struct option *o; 438 439 o = option_new(&portal_group->pg_options, $2, $3); 440 free($2); 441 free($3); 442 if (o == NULL) 443 return (1); 444 } 445 ; 446 447 portal_group_redirect: REDIRECT STR 448 { 449 int error; 450 451 error = portal_group_set_redirection(portal_group, $2); 452 free($2); 453 if (error != 0) 454 return (1); 455 } 456 ; 457 458 portal_group_tag: TAG STR 459 { 460 uint64_t tmp; 461 462 if (expand_number($2, &tmp) != 0) { 463 yyerror("invalid numeric value"); 464 free($2); 465 return (1); 466 } 467 468 portal_group->pg_tag = tmp; 469 } 470 ; 471 472 portal_group_dscp 473 : DSCP STR 474 { 475 uint64_t tmp; 476 477 if (strcmp($2, "0x") == 0) { 478 tmp = strtol($2 + 2, NULL, 16); 479 } else if (expand_number($2, &tmp) != 0) { 480 yyerror("invalid numeric value"); 481 free($2); 482 return(1); 483 } 484 if (tmp >= 0x40) { 485 yyerror("invalid dscp value"); 486 return(1); 487 } 488 489 portal_group->pg_dscp = tmp; 490 } 491 | DSCP BE { portal_group->pg_dscp = IPTOS_DSCP_CS0 >> 2 ; } 492 | DSCP EF { portal_group->pg_dscp = IPTOS_DSCP_EF >> 2 ; } 493 | DSCP CS0 { portal_group->pg_dscp = IPTOS_DSCP_CS0 >> 2 ; } 494 | DSCP CS1 { portal_group->pg_dscp = IPTOS_DSCP_CS1 >> 2 ; } 495 | DSCP CS2 { portal_group->pg_dscp = IPTOS_DSCP_CS2 >> 2 ; } 496 | DSCP CS3 { portal_group->pg_dscp = IPTOS_DSCP_CS3 >> 2 ; } 497 | DSCP CS4 { portal_group->pg_dscp = IPTOS_DSCP_CS4 >> 2 ; } 498 | DSCP CS5 { portal_group->pg_dscp = IPTOS_DSCP_CS5 >> 2 ; } 499 | DSCP CS6 { portal_group->pg_dscp = IPTOS_DSCP_CS6 >> 2 ; } 500 | DSCP CS7 { portal_group->pg_dscp = IPTOS_DSCP_CS7 >> 2 ; } 501 | DSCP AF11 { portal_group->pg_dscp = IPTOS_DSCP_AF11 >> 2 ; } 502 | DSCP AF12 { portal_group->pg_dscp = IPTOS_DSCP_AF12 >> 2 ; } 503 | DSCP AF13 { portal_group->pg_dscp = IPTOS_DSCP_AF13 >> 2 ; } 504 | DSCP AF21 { portal_group->pg_dscp = IPTOS_DSCP_AF21 >> 2 ; } 505 | DSCP AF22 { portal_group->pg_dscp = IPTOS_DSCP_AF22 >> 2 ; } 506 | DSCP AF23 { portal_group->pg_dscp = IPTOS_DSCP_AF23 >> 2 ; } 507 | DSCP AF31 { portal_group->pg_dscp = IPTOS_DSCP_AF31 >> 2 ; } 508 | DSCP AF32 { portal_group->pg_dscp = IPTOS_DSCP_AF32 >> 2 ; } 509 | DSCP AF33 { portal_group->pg_dscp = IPTOS_DSCP_AF33 >> 2 ; } 510 | DSCP AF41 { portal_group->pg_dscp = IPTOS_DSCP_AF41 >> 2 ; } 511 | DSCP AF42 { portal_group->pg_dscp = IPTOS_DSCP_AF42 >> 2 ; } 512 | DSCP AF43 { portal_group->pg_dscp = IPTOS_DSCP_AF43 >> 2 ; } 513 ; 514 515 516 lun: LUN lun_name 517 OPENING_BRACKET lun_entries CLOSING_BRACKET 518 { 519 lun = NULL; 520 } 521 ; 522 523 lun_name: STR 524 { 525 lun = lun_new(conf, $1); 526 free($1); 527 if (lun == NULL) 528 return (1); 529 } 530 ; 531 532 target: TARGET target_name 533 OPENING_BRACKET target_entries CLOSING_BRACKET 534 { 535 target = NULL; 536 } 537 ; 538 539 target_name: STR 540 { 541 target = target_new(conf, $1); 542 free($1); 543 if (target == NULL) 544 return (1); 545 } 546 ; 547 548 target_entries: 549 | 550 target_entries target_entry 551 | 552 target_entries target_entry SEMICOLON 553 ; 554 555 target_entry: 556 target_alias 557 | 558 target_auth_group 559 | 560 target_auth_type 561 | 562 target_chap 563 | 564 target_chap_mutual 565 | 566 target_initiator_name 567 | 568 target_initiator_portal 569 | 570 target_portal_group 571 | 572 target_port 573 | 574 target_redirect 575 | 576 target_lun 577 | 578 target_lun_ref 579 ; 580 581 target_alias: ALIAS STR 582 { 583 if (target->t_alias != NULL) { 584 log_warnx("alias for target \"%s\" " 585 "specified more than once", target->t_name); 586 return (1); 587 } 588 target->t_alias = $2; 589 } 590 ; 591 592 target_auth_group: AUTH_GROUP STR 593 { 594 if (target->t_auth_group != NULL) { 595 if (target->t_auth_group->ag_name != NULL) 596 log_warnx("auth-group for target \"%s\" " 597 "specified more than once", target->t_name); 598 else 599 log_warnx("cannot use both auth-group and explicit " 600 "authorisations for target \"%s\"", 601 target->t_name); 602 return (1); 603 } 604 target->t_auth_group = auth_group_find(conf, $2); 605 if (target->t_auth_group == NULL) { 606 log_warnx("unknown auth-group \"%s\" for target " 607 "\"%s\"", $2, target->t_name); 608 return (1); 609 } 610 free($2); 611 } 612 ; 613 614 target_auth_type: AUTH_TYPE STR 615 { 616 int error; 617 618 if (target->t_auth_group != NULL) { 619 if (target->t_auth_group->ag_name != NULL) { 620 log_warnx("cannot use both auth-group and " 621 "auth-type for target \"%s\"", 622 target->t_name); 623 return (1); 624 } 625 } else { 626 target->t_auth_group = auth_group_new(conf, NULL); 627 if (target->t_auth_group == NULL) { 628 free($2); 629 return (1); 630 } 631 target->t_auth_group->ag_target = target; 632 } 633 error = auth_group_set_type(target->t_auth_group, $2); 634 free($2); 635 if (error != 0) 636 return (1); 637 } 638 ; 639 640 target_chap: CHAP STR STR 641 { 642 const struct auth *ca; 643 644 if (target->t_auth_group != NULL) { 645 if (target->t_auth_group->ag_name != NULL) { 646 log_warnx("cannot use both auth-group and " 647 "chap for target \"%s\"", 648 target->t_name); 649 free($2); 650 free($3); 651 return (1); 652 } 653 } else { 654 target->t_auth_group = auth_group_new(conf, NULL); 655 if (target->t_auth_group == NULL) { 656 free($2); 657 free($3); 658 return (1); 659 } 660 target->t_auth_group->ag_target = target; 661 } 662 ca = auth_new_chap(target->t_auth_group, $2, $3); 663 free($2); 664 free($3); 665 if (ca == NULL) 666 return (1); 667 } 668 ; 669 670 target_chap_mutual: CHAP_MUTUAL STR STR 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-mutual for target \"%s\"", 678 target->t_name); 679 free($2); 680 free($3); 681 free($4); 682 free($5); 683 return (1); 684 } 685 } else { 686 target->t_auth_group = auth_group_new(conf, NULL); 687 if (target->t_auth_group == NULL) { 688 free($2); 689 free($3); 690 free($4); 691 free($5); 692 return (1); 693 } 694 target->t_auth_group->ag_target = target; 695 } 696 ca = auth_new_chap_mutual(target->t_auth_group, 697 $2, $3, $4, $5); 698 free($2); 699 free($3); 700 free($4); 701 free($5); 702 if (ca == NULL) 703 return (1); 704 } 705 ; 706 707 target_initiator_name: INITIATOR_NAME STR 708 { 709 const struct auth_name *an; 710 711 if (target->t_auth_group != NULL) { 712 if (target->t_auth_group->ag_name != NULL) { 713 log_warnx("cannot use both auth-group and " 714 "initiator-name for target \"%s\"", 715 target->t_name); 716 free($2); 717 return (1); 718 } 719 } else { 720 target->t_auth_group = auth_group_new(conf, NULL); 721 if (target->t_auth_group == NULL) { 722 free($2); 723 return (1); 724 } 725 target->t_auth_group->ag_target = target; 726 } 727 an = auth_name_new(target->t_auth_group, $2); 728 free($2); 729 if (an == NULL) 730 return (1); 731 } 732 ; 733 734 target_initiator_portal: INITIATOR_PORTAL STR 735 { 736 const struct auth_portal *ap; 737 738 if (target->t_auth_group != NULL) { 739 if (target->t_auth_group->ag_name != NULL) { 740 log_warnx("cannot use both auth-group and " 741 "initiator-portal for target \"%s\"", 742 target->t_name); 743 free($2); 744 return (1); 745 } 746 } else { 747 target->t_auth_group = auth_group_new(conf, NULL); 748 if (target->t_auth_group == NULL) { 749 free($2); 750 return (1); 751 } 752 target->t_auth_group->ag_target = target; 753 } 754 ap = auth_portal_new(target->t_auth_group, $2); 755 free($2); 756 if (ap == NULL) 757 return (1); 758 } 759 ; 760 761 target_portal_group: PORTAL_GROUP STR STR 762 { 763 struct portal_group *tpg; 764 struct auth_group *tag; 765 struct port *tp; 766 767 tpg = portal_group_find(conf, $2); 768 if (tpg == NULL) { 769 log_warnx("unknown portal-group \"%s\" for target " 770 "\"%s\"", $2, target->t_name); 771 free($2); 772 free($3); 773 return (1); 774 } 775 tag = auth_group_find(conf, $3); 776 if (tag == NULL) { 777 log_warnx("unknown auth-group \"%s\" for target " 778 "\"%s\"", $3, target->t_name); 779 free($2); 780 free($3); 781 return (1); 782 } 783 tp = port_new(conf, target, tpg); 784 if (tp == NULL) { 785 log_warnx("can't link portal-group \"%s\" to target " 786 "\"%s\"", $2, target->t_name); 787 free($2); 788 return (1); 789 } 790 tp->p_auth_group = tag; 791 free($2); 792 free($3); 793 } 794 | PORTAL_GROUP STR 795 { 796 struct portal_group *tpg; 797 struct port *tp; 798 799 tpg = portal_group_find(conf, $2); 800 if (tpg == NULL) { 801 log_warnx("unknown portal-group \"%s\" for target " 802 "\"%s\"", $2, target->t_name); 803 free($2); 804 return (1); 805 } 806 tp = port_new(conf, target, tpg); 807 if (tp == NULL) { 808 log_warnx("can't link portal-group \"%s\" to target " 809 "\"%s\"", $2, target->t_name); 810 free($2); 811 return (1); 812 } 813 free($2); 814 } 815 ; 816 817 target_port: PORT STR 818 { 819 struct pport *pp; 820 struct port *tp; 821 int ret, i_pp, i_vp = 0; 822 823 ret = sscanf($2, "ioctl/%d/%d", &i_pp, &i_vp); 824 if (ret > 0) { 825 tp = port_new_ioctl(conf, target, i_pp, i_vp); 826 if (tp == NULL) { 827 log_warnx("can't create new ioctl port for " 828 "target \"%s\"", target->t_name); 829 free($2); 830 return (1); 831 } 832 } else { 833 pp = pport_find(conf, $2); 834 if (pp == NULL) { 835 log_warnx("unknown port \"%s\" for target \"%s\"", 836 $2, target->t_name); 837 free($2); 838 return (1); 839 } 840 if (!TAILQ_EMPTY(&pp->pp_ports)) { 841 log_warnx("can't link port \"%s\" to target \"%s\", " 842 "port already linked to some target", 843 $2, target->t_name); 844 free($2); 845 return (1); 846 } 847 tp = port_new_pp(conf, target, pp); 848 if (tp == NULL) { 849 log_warnx("can't link port \"%s\" to target \"%s\"", 850 $2, target->t_name); 851 free($2); 852 return (1); 853 } 854 } 855 856 free($2); 857 } 858 ; 859 860 target_redirect: REDIRECT STR 861 { 862 int error; 863 864 error = target_set_redirection(target, $2); 865 free($2); 866 if (error != 0) 867 return (1); 868 } 869 ; 870 871 target_lun: LUN lun_number 872 OPENING_BRACKET lun_entries CLOSING_BRACKET 873 { 874 lun = NULL; 875 } 876 ; 877 878 lun_number: STR 879 { 880 uint64_t tmp; 881 int ret; 882 char *name; 883 884 if (expand_number($1, &tmp) != 0) { 885 yyerror("invalid numeric value"); 886 free($1); 887 return (1); 888 } 889 if (tmp >= MAX_LUNS) { 890 yyerror("LU number is too big"); 891 free($1); 892 return (1); 893 } 894 895 ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp); 896 if (ret <= 0) 897 log_err(1, "asprintf"); 898 lun = lun_new(conf, name); 899 if (lun == NULL) 900 return (1); 901 902 lun_set_scsiname(lun, name); 903 target->t_luns[tmp] = lun; 904 } 905 ; 906 907 target_lun_ref: LUN STR STR 908 { 909 uint64_t tmp; 910 911 if (expand_number($2, &tmp) != 0) { 912 yyerror("invalid numeric value"); 913 free($2); 914 free($3); 915 return (1); 916 } 917 free($2); 918 if (tmp >= MAX_LUNS) { 919 yyerror("LU number is too big"); 920 free($3); 921 return (1); 922 } 923 924 lun = lun_find(conf, $3); 925 free($3); 926 if (lun == NULL) 927 return (1); 928 929 target->t_luns[tmp] = lun; 930 } 931 ; 932 933 lun_entries: 934 | 935 lun_entries lun_entry 936 | 937 lun_entries lun_entry SEMICOLON 938 ; 939 940 lun_entry: 941 lun_backend 942 | 943 lun_blocksize 944 | 945 lun_device_id 946 | 947 lun_device_type 948 | 949 lun_ctl_lun 950 | 951 lun_option 952 | 953 lun_path 954 | 955 lun_serial 956 | 957 lun_size 958 ; 959 960 lun_backend: BACKEND STR 961 { 962 if (lun->l_backend != NULL) { 963 log_warnx("backend for lun \"%s\" " 964 "specified more than once", 965 lun->l_name); 966 free($2); 967 return (1); 968 } 969 lun_set_backend(lun, $2); 970 free($2); 971 } 972 ; 973 974 lun_blocksize: BLOCKSIZE STR 975 { 976 uint64_t tmp; 977 978 if (expand_number($2, &tmp) != 0) { 979 yyerror("invalid numeric value"); 980 free($2); 981 return (1); 982 } 983 984 if (lun->l_blocksize != 0) { 985 log_warnx("blocksize for lun \"%s\" " 986 "specified more than once", 987 lun->l_name); 988 return (1); 989 } 990 lun_set_blocksize(lun, tmp); 991 } 992 ; 993 994 lun_device_id: DEVICE_ID STR 995 { 996 if (lun->l_device_id != NULL) { 997 log_warnx("device_id for lun \"%s\" " 998 "specified more than once", 999 lun->l_name); 1000 free($2); 1001 return (1); 1002 } 1003 lun_set_device_id(lun, $2); 1004 free($2); 1005 } 1006 ; 1007 1008 lun_device_type: DEVICE_TYPE STR 1009 { 1010 uint64_t tmp; 1011 1012 if (strcasecmp($2, "disk") == 0 || 1013 strcasecmp($2, "direct") == 0) 1014 tmp = 0; 1015 else if (strcasecmp($2, "processor") == 0) 1016 tmp = 3; 1017 else if (strcasecmp($2, "cd") == 0 || 1018 strcasecmp($2, "cdrom") == 0 || 1019 strcasecmp($2, "dvd") == 0 || 1020 strcasecmp($2, "dvdrom") == 0) 1021 tmp = 5; 1022 else if (expand_number($2, &tmp) != 0 || 1023 tmp > 15) { 1024 yyerror("invalid numeric value"); 1025 free($2); 1026 return (1); 1027 } 1028 1029 lun_set_device_type(lun, tmp); 1030 } 1031 ; 1032 1033 lun_ctl_lun: CTL_LUN STR 1034 { 1035 uint64_t tmp; 1036 1037 if (expand_number($2, &tmp) != 0) { 1038 yyerror("invalid numeric value"); 1039 free($2); 1040 return (1); 1041 } 1042 1043 if (lun->l_ctl_lun >= 0) { 1044 log_warnx("ctl_lun for lun \"%s\" " 1045 "specified more than once", 1046 lun->l_name); 1047 return (1); 1048 } 1049 lun_set_ctl_lun(lun, tmp); 1050 } 1051 ; 1052 1053 lun_option: OPTION STR STR 1054 { 1055 struct option *o; 1056 1057 o = option_new(&lun->l_options, $2, $3); 1058 free($2); 1059 free($3); 1060 if (o == NULL) 1061 return (1); 1062 } 1063 ; 1064 1065 lun_path: PATH STR 1066 { 1067 if (lun->l_path != NULL) { 1068 log_warnx("path for lun \"%s\" " 1069 "specified more than once", 1070 lun->l_name); 1071 free($2); 1072 return (1); 1073 } 1074 lun_set_path(lun, $2); 1075 free($2); 1076 } 1077 ; 1078 1079 lun_serial: SERIAL STR 1080 { 1081 if (lun->l_serial != NULL) { 1082 log_warnx("serial for lun \"%s\" " 1083 "specified more than once", 1084 lun->l_name); 1085 free($2); 1086 return (1); 1087 } 1088 lun_set_serial(lun, $2); 1089 free($2); 1090 } 1091 ; 1092 1093 lun_size: SIZE STR 1094 { 1095 uint64_t tmp; 1096 1097 if (expand_number($2, &tmp) != 0) { 1098 yyerror("invalid numeric value"); 1099 free($2); 1100 return (1); 1101 } 1102 1103 if (lun->l_size != 0) { 1104 log_warnx("size for lun \"%s\" " 1105 "specified more than once", 1106 lun->l_name); 1107 return (1); 1108 } 1109 lun_set_size(lun, tmp); 1110 } 1111 ; 1112 %% 1113 1114 void 1115 yyerror(const char *str) 1116 { 1117 1118 log_warnx("error in configuration file at line %d near '%s': %s", 1119 lineno, yytext, str); 1120 } 1121 1122 int 1123 parse_conf(struct conf *newconf, const char *path) 1124 { 1125 int error; 1126 1127 conf = newconf; 1128 yyin = fopen(path, "r"); 1129 if (yyin == NULL) { 1130 log_warn("unable to open configuration file %s", path); 1131 return (1); 1132 } 1133 1134 lineno = 1; 1135 yyrestart(yyin); 1136 error = yyparse(); 1137 auth_group = NULL; 1138 portal_group = NULL; 1139 target = NULL; 1140 lun = NULL; 1141 fclose(yyin); 1142 1143 return (error); 1144 } 1145