1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012 The FreeBSD Foundation 5 * 6 * This software was developed by Edward Tomasz Napierala under sponsorship 7 * from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/types.h> 36 #include <sys/time.h> 37 #include <sys/ioctl.h> 38 #include <sys/param.h> 39 #include <sys/linker.h> 40 #include <sys/socket.h> 41 #include <sys/capsicum.h> 42 #include <sys/wait.h> 43 #include <netinet/in.h> 44 #include <assert.h> 45 #include <capsicum_helpers.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <libutil.h> 49 #include <netdb.h> 50 #include <signal.h> 51 #include <stdbool.h> 52 #include <stdint.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 58 #include "iscsid.h" 59 60 static bool timed_out(void); 61 #ifdef ICL_KERNEL_PROXY 62 static void pdu_receive_proxy(struct pdu *pdu); 63 static void pdu_send_proxy(struct pdu *pdu); 64 #endif /* ICL_KERNEL_PROXY */ 65 66 static volatile bool sigalrm_received = false; 67 68 static int nchildren = 0; 69 70 static struct connection_ops conn_ops = { 71 .timed_out = timed_out, 72 #ifdef ICL_KERNEL_PROXY 73 .pdu_receive_proxy = pdu_receive_proxy, 74 .pdu_send_proxy = pdu_send_proxy, 75 #endif 76 .fail = fail, 77 }; 78 79 static void 80 usage(void) 81 { 82 83 fprintf(stderr, "usage: iscsid [-P pidfile][-d][-m maxproc][-t timeout]\n"); 84 exit(1); 85 } 86 87 #ifdef ICL_KERNEL_PROXY 88 89 static void 90 pdu_receive_proxy(struct pdu *pdu) 91 { 92 struct iscsid_connection *conn; 93 struct iscsi_daemon_receive idr; 94 size_t len; 95 int error; 96 97 conn = (struct iscsid_connection *)pdu->pdu_connection; 98 assert(conn->conn_conf.isc_iser != 0); 99 100 pdu->pdu_data = malloc(conn->conn.conn_max_recv_data_segment_length); 101 if (pdu->pdu_data == NULL) 102 log_err(1, "malloc"); 103 104 memset(&idr, 0, sizeof(idr)); 105 idr.idr_session_id = conn->conn_session_id; 106 idr.idr_bhs = pdu->pdu_bhs; 107 idr.idr_data_segment_len = conn->conn.conn_max_recv_data_segment_length; 108 idr.idr_data_segment = pdu->pdu_data; 109 110 error = ioctl(conn->conn_iscsi_fd, ISCSIDRECEIVE, &idr); 111 if (error != 0) 112 log_err(1, "ISCSIDRECEIVE"); 113 114 len = pdu_ahs_length(pdu); 115 if (len > 0) 116 log_errx(1, "protocol error: non-empty AHS"); 117 118 len = pdu_data_segment_length(pdu); 119 assert(len <= (size_t)conn->conn.conn_max_recv_data_segment_length); 120 pdu->pdu_data_len = len; 121 } 122 123 static void 124 pdu_send_proxy(struct pdu *pdu) 125 { 126 struct iscsid_connection *conn; 127 struct iscsi_daemon_send ids; 128 int error; 129 130 conn = (struct iscsid_connection *)pdu->pdu_connection; 131 assert(conn->conn_conf.isc_iser != 0); 132 133 pdu_set_data_segment_length(pdu, pdu->pdu_data_len); 134 135 memset(&ids, 0, sizeof(ids)); 136 ids.ids_session_id = conn->conn_session_id; 137 ids.ids_bhs = pdu->pdu_bhs; 138 ids.ids_data_segment_len = pdu->pdu_data_len; 139 ids.ids_data_segment = pdu->pdu_data; 140 141 error = ioctl(conn->conn_iscsi_fd, ISCSIDSEND, &ids); 142 if (error != 0) 143 log_err(1, "ISCSIDSEND"); 144 } 145 146 #endif /* ICL_KERNEL_PROXY */ 147 148 static void 149 resolve_addr(const struct connection *conn, const char *address, 150 struct addrinfo **ai, bool initiator_side) 151 { 152 struct addrinfo hints; 153 char *arg, *addr, *ch, *tofree; 154 const char *port; 155 int error, colons = 0; 156 157 tofree = arg = checked_strdup(address); 158 159 if (arg[0] == '\0') { 160 fail(conn, "empty address"); 161 log_errx(1, "empty address"); 162 } 163 if (arg[0] == '[') { 164 /* 165 * IPv6 address in square brackets, perhaps with port. 166 */ 167 arg++; 168 addr = strsep(&arg, "]"); 169 if (arg == NULL) { 170 fail(conn, "malformed address"); 171 log_errx(1, "malformed address %s", address); 172 } 173 if (arg[0] == '\0') { 174 port = NULL; 175 } else if (arg[0] == ':') { 176 port = arg + 1; 177 } else { 178 fail(conn, "malformed address"); 179 log_errx(1, "malformed address %s", address); 180 } 181 } else { 182 /* 183 * Either IPv6 address without brackets - and without 184 * a port - or IPv4 address. Just count the colons. 185 */ 186 for (ch = arg; *ch != '\0'; ch++) { 187 if (*ch == ':') 188 colons++; 189 } 190 if (colons > 1) { 191 addr = arg; 192 port = NULL; 193 } else { 194 addr = strsep(&arg, ":"); 195 if (arg == NULL) 196 port = NULL; 197 else 198 port = arg; 199 } 200 } 201 202 if (port == NULL && !initiator_side) 203 port = "3260"; 204 205 memset(&hints, 0, sizeof(hints)); 206 hints.ai_family = PF_UNSPEC; 207 hints.ai_socktype = SOCK_STREAM; 208 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; 209 if (initiator_side) 210 hints.ai_flags |= AI_PASSIVE; 211 212 error = getaddrinfo(addr, port, &hints, ai); 213 if (error != 0) { 214 fail(conn, gai_strerror(error)); 215 log_errx(1, "getaddrinfo for %s failed: %s", 216 address, gai_strerror(error)); 217 } 218 219 free(tofree); 220 } 221 222 static struct iscsid_connection * 223 connection_new(int iscsi_fd, const struct iscsi_daemon_request *request) 224 { 225 struct iscsid_connection *conn; 226 struct iscsi_session_limits *isl; 227 struct addrinfo *from_ai, *to_ai; 228 const char *from_addr, *to_addr; 229 #ifdef ICL_KERNEL_PROXY 230 struct iscsi_daemon_connect idc; 231 #endif 232 int error, optval; 233 234 conn = calloc(1, sizeof(*conn)); 235 if (conn == NULL) 236 log_err(1, "calloc"); 237 238 connection_init(&conn->conn, &conn_ops, 239 request->idr_conf.isc_iser != 0); 240 conn->conn_protocol_level = 0; 241 conn->conn_initial_r2t = true; 242 conn->conn_iscsi_fd = iscsi_fd; 243 244 conn->conn_session_id = request->idr_session_id; 245 memcpy(&conn->conn_conf, &request->idr_conf, sizeof(conn->conn_conf)); 246 memcpy(&conn->conn.conn_isid, &request->idr_isid, 247 sizeof(conn->conn.conn_isid)); 248 conn->conn.conn_tsih = request->idr_tsih; 249 250 /* 251 * Read the driver limits and provide reasonable defaults for the ones 252 * the driver doesn't care about. If a max_snd_dsl is not explicitly 253 * provided by the driver then we'll make sure both conn->max_snd_dsl 254 * and isl->max_snd_dsl are set to the rcv_dsl. This preserves historic 255 * behavior. 256 */ 257 isl = &conn->conn_limits; 258 memcpy(isl, &request->idr_limits, sizeof(*isl)); 259 if (isl->isl_max_recv_data_segment_length == 0) 260 isl->isl_max_recv_data_segment_length = (1 << 24) - 1; 261 if (isl->isl_max_send_data_segment_length == 0) 262 isl->isl_max_send_data_segment_length = 263 isl->isl_max_recv_data_segment_length; 264 if (isl->isl_max_burst_length == 0) 265 isl->isl_max_burst_length = (1 << 24) - 1; 266 if (isl->isl_first_burst_length == 0) 267 isl->isl_first_burst_length = (1 << 24) - 1; 268 if (isl->isl_first_burst_length > isl->isl_max_burst_length) 269 isl->isl_first_burst_length = isl->isl_max_burst_length; 270 271 /* 272 * Limit default send length in case it won't be negotiated. 273 * We can't do it for other limits, since they may affect both 274 * sender and receiver operation, and we must obey defaults. 275 */ 276 if (conn->conn.conn_max_send_data_segment_length > 277 isl->isl_max_send_data_segment_length) { 278 conn->conn.conn_max_send_data_segment_length = 279 isl->isl_max_send_data_segment_length; 280 } 281 282 from_addr = conn->conn_conf.isc_initiator_addr; 283 to_addr = conn->conn_conf.isc_target_addr; 284 285 if (from_addr[0] != '\0') 286 resolve_addr(&conn->conn, from_addr, &from_ai, true); 287 else 288 from_ai = NULL; 289 290 resolve_addr(&conn->conn, to_addr, &to_ai, false); 291 292 #ifdef ICL_KERNEL_PROXY 293 if (conn->conn_conf.isc_iser) { 294 memset(&idc, 0, sizeof(idc)); 295 idc.idc_session_id = conn->conn_session_id; 296 if (conn->conn_conf.isc_iser) 297 idc.idc_iser = 1; 298 idc.idc_domain = to_ai->ai_family; 299 idc.idc_socktype = to_ai->ai_socktype; 300 idc.idc_protocol = to_ai->ai_protocol; 301 if (from_ai != NULL) { 302 idc.idc_from_addr = from_ai->ai_addr; 303 idc.idc_from_addrlen = from_ai->ai_addrlen; 304 } 305 idc.idc_to_addr = to_ai->ai_addr; 306 idc.idc_to_addrlen = to_ai->ai_addrlen; 307 308 log_debugx("connecting to %s using ICL kernel proxy", to_addr); 309 error = ioctl(iscsi_fd, ISCSIDCONNECT, &idc); 310 if (error != 0) { 311 fail(&conn->conn, strerror(errno)); 312 log_err(1, "failed to connect to %s " 313 "using ICL kernel proxy: ISCSIDCONNECT", to_addr); 314 } 315 316 if (from_ai != NULL) 317 freeaddrinfo(from_ai); 318 freeaddrinfo(to_ai); 319 320 return (conn); 321 } 322 #endif /* ICL_KERNEL_PROXY */ 323 324 if (conn->conn_conf.isc_iser) { 325 fail(&conn->conn, "iSER not supported"); 326 log_errx(1, "iscsid(8) compiled without ICL_KERNEL_PROXY " 327 "does not support iSER"); 328 } 329 330 conn->conn.conn_socket = socket(to_ai->ai_family, to_ai->ai_socktype, 331 to_ai->ai_protocol); 332 if (conn->conn.conn_socket < 0) { 333 fail(&conn->conn, strerror(errno)); 334 log_err(1, "failed to create socket for %s", from_addr); 335 } 336 optval = SOCKBUF_SIZE; 337 if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_RCVBUF, 338 &optval, sizeof(optval)) == -1) 339 log_warn("setsockopt(SO_RCVBUF) failed"); 340 optval = SOCKBUF_SIZE; 341 if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_SNDBUF, 342 &optval, sizeof(optval)) == -1) 343 log_warn("setsockopt(SO_SNDBUF) failed"); 344 optval = 1; 345 if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_NO_DDP, 346 &optval, sizeof(optval)) == -1) 347 log_warn("setsockopt(SO_NO_DDP) failed"); 348 if (conn->conn_conf.isc_dscp != -1) { 349 int tos = conn->conn_conf.isc_dscp << 2; 350 if (to_ai->ai_family == AF_INET) { 351 if (setsockopt(conn->conn.conn_socket, 352 IPPROTO_IP, IP_TOS, 353 &tos, sizeof(tos)) == -1) 354 log_warn("setsockopt(IP_TOS) " 355 "failed for %s", 356 from_addr); 357 } else 358 if (to_ai->ai_family == AF_INET6) { 359 if (setsockopt(conn->conn.conn_socket, 360 IPPROTO_IPV6, IPV6_TCLASS, 361 &tos, sizeof(tos)) == -1) 362 log_warn("setsockopt(IPV6_TCLASS) " 363 "failed for %s", 364 from_addr); 365 } 366 } 367 if (conn->conn_conf.isc_pcp != -1) { 368 int pcp = conn->conn_conf.isc_pcp; 369 if (to_ai->ai_family == AF_INET) { 370 if (setsockopt(conn->conn.conn_socket, 371 IPPROTO_IP, IP_VLAN_PCP, 372 &pcp, sizeof(pcp)) == -1) 373 log_warn("setsockopt(IP_VLAN_PCP) " 374 "failed for %s", 375 from_addr); 376 } else 377 if (to_ai->ai_family == AF_INET6) { 378 if (setsockopt(conn->conn.conn_socket, 379 IPPROTO_IPV6, IPV6_VLAN_PCP, 380 &pcp, sizeof(pcp)) == -1) 381 log_warn("setsockopt(IPV6_VLAN_PCP) " 382 "failed for %s", 383 from_addr); 384 } 385 } 386 if (from_ai != NULL) { 387 error = bind(conn->conn.conn_socket, from_ai->ai_addr, 388 from_ai->ai_addrlen); 389 if (error != 0) { 390 fail(&conn->conn, strerror(errno)); 391 log_err(1, "failed to bind to %s", from_addr); 392 } 393 } 394 log_debugx("connecting to %s", to_addr); 395 error = connect(conn->conn.conn_socket, to_ai->ai_addr, 396 to_ai->ai_addrlen); 397 if (error != 0) { 398 fail(&conn->conn, strerror(errno)); 399 log_err(1, "failed to connect to %s", to_addr); 400 } 401 402 if (from_ai != NULL) 403 freeaddrinfo(from_ai); 404 freeaddrinfo(to_ai); 405 406 return (conn); 407 } 408 409 static void 410 handoff(struct iscsid_connection *conn) 411 { 412 struct iscsi_daemon_handoff idh; 413 int error; 414 415 log_debugx("handing off connection to the kernel"); 416 417 memset(&idh, 0, sizeof(idh)); 418 idh.idh_session_id = conn->conn_session_id; 419 idh.idh_socket = conn->conn.conn_socket; 420 strlcpy(idh.idh_target_alias, conn->conn_target_alias, 421 sizeof(idh.idh_target_alias)); 422 idh.idh_tsih = conn->conn.conn_tsih; 423 idh.idh_statsn = conn->conn.conn_statsn; 424 idh.idh_protocol_level = conn->conn_protocol_level; 425 idh.idh_header_digest = conn->conn.conn_header_digest; 426 idh.idh_data_digest = conn->conn.conn_data_digest; 427 idh.idh_initial_r2t = conn->conn_initial_r2t; 428 idh.idh_immediate_data = conn->conn.conn_immediate_data; 429 idh.idh_max_recv_data_segment_length = 430 conn->conn.conn_max_recv_data_segment_length; 431 idh.idh_max_send_data_segment_length = 432 conn->conn.conn_max_send_data_segment_length; 433 idh.idh_max_burst_length = conn->conn.conn_max_burst_length; 434 idh.idh_first_burst_length = conn->conn.conn_first_burst_length; 435 436 error = ioctl(conn->conn_iscsi_fd, ISCSIDHANDOFF, &idh); 437 if (error != 0) 438 log_err(1, "ISCSIDHANDOFF"); 439 } 440 441 void 442 fail(const struct connection *base_conn, const char *reason) 443 { 444 const struct iscsid_connection *conn; 445 struct iscsi_daemon_fail idf; 446 int error, saved_errno; 447 448 conn = (const struct iscsid_connection *)base_conn; 449 saved_errno = errno; 450 451 memset(&idf, 0, sizeof(idf)); 452 idf.idf_session_id = conn->conn_session_id; 453 strlcpy(idf.idf_reason, reason, sizeof(idf.idf_reason)); 454 455 error = ioctl(conn->conn_iscsi_fd, ISCSIDFAIL, &idf); 456 if (error != 0) 457 log_err(1, "ISCSIDFAIL"); 458 459 errno = saved_errno; 460 } 461 462 /* 463 * XXX: I CANT INTO LATIN 464 */ 465 static void 466 capsicate(struct iscsid_connection *conn) 467 { 468 cap_rights_t rights; 469 #ifdef ICL_KERNEL_PROXY 470 const unsigned long cmds[] = { ISCSIDCONNECT, ISCSIDSEND, ISCSIDRECEIVE, 471 ISCSIDHANDOFF, ISCSIDFAIL, ISCSISADD, ISCSISREMOVE, ISCSISMODIFY }; 472 #else 473 const unsigned long cmds[] = { ISCSIDHANDOFF, ISCSIDFAIL, ISCSISADD, 474 ISCSISREMOVE, ISCSISMODIFY }; 475 #endif 476 477 cap_rights_init(&rights, CAP_IOCTL); 478 if (caph_rights_limit(conn->conn_iscsi_fd, &rights) < 0) 479 log_err(1, "cap_rights_limit"); 480 481 if (caph_ioctls_limit(conn->conn_iscsi_fd, cmds, nitems(cmds)) < 0) 482 log_err(1, "cap_ioctls_limit"); 483 484 if (caph_enter() != 0) 485 log_err(1, "cap_enter"); 486 487 if (cap_sandboxed()) 488 log_debugx("Capsicum capability mode enabled"); 489 else 490 log_warnx("Capsicum capability mode not supported"); 491 } 492 493 static bool 494 timed_out(void) 495 { 496 497 return (sigalrm_received); 498 } 499 500 static void 501 sigalrm_handler(int dummy __unused) 502 { 503 /* 504 * It would be easiest to just log an error and exit. We can't 505 * do this, though, because log_errx() is not signal safe, since 506 * it calls syslog(3). Instead, set a flag checked by pdu_send() 507 * and pdu_receive(), to call log_errx() there. Should they fail 508 * to notice, we'll exit here one second later. 509 */ 510 if (sigalrm_received) { 511 /* 512 * Oh well. Just give up and quit. 513 */ 514 _exit(2); 515 } 516 517 sigalrm_received = true; 518 } 519 520 static void 521 set_timeout(int timeout) 522 { 523 struct sigaction sa; 524 struct itimerval itv; 525 int error; 526 527 if (timeout <= 0) { 528 log_debugx("session timeout disabled"); 529 return; 530 } 531 532 bzero(&sa, sizeof(sa)); 533 sa.sa_handler = sigalrm_handler; 534 sigfillset(&sa.sa_mask); 535 error = sigaction(SIGALRM, &sa, NULL); 536 if (error != 0) 537 log_err(1, "sigaction"); 538 539 /* 540 * First SIGALRM will arive after conf_timeout seconds. 541 * If we do nothing, another one will arrive a second later. 542 */ 543 bzero(&itv, sizeof(itv)); 544 itv.it_interval.tv_sec = 1; 545 itv.it_value.tv_sec = timeout; 546 547 log_debugx("setting session timeout to %d seconds", 548 timeout); 549 error = setitimer(ITIMER_REAL, &itv, NULL); 550 if (error != 0) 551 log_err(1, "setitimer"); 552 } 553 554 static void 555 sigchld_handler(int dummy __unused) 556 { 557 558 /* 559 * The only purpose of this handler is to make SIGCHLD 560 * interrupt the ISCSIDWAIT ioctl(2), so we can call 561 * wait_for_children(). 562 */ 563 } 564 565 static void 566 register_sigchld(void) 567 { 568 struct sigaction sa; 569 int error; 570 571 bzero(&sa, sizeof(sa)); 572 sa.sa_handler = sigchld_handler; 573 sigfillset(&sa.sa_mask); 574 error = sigaction(SIGCHLD, &sa, NULL); 575 if (error != 0) 576 log_err(1, "sigaction"); 577 578 } 579 580 static void 581 handle_request(int iscsi_fd, const struct iscsi_daemon_request *request, int timeout) 582 { 583 struct iscsid_connection *conn; 584 585 log_set_peer_addr(request->idr_conf.isc_target_addr); 586 if (request->idr_conf.isc_target[0] != '\0') { 587 log_set_peer_name(request->idr_conf.isc_target); 588 setproctitle("%s (%s)", request->idr_conf.isc_target_addr, request->idr_conf.isc_target); 589 } else { 590 setproctitle("%s", request->idr_conf.isc_target_addr); 591 } 592 593 conn = connection_new(iscsi_fd, request); 594 set_timeout(timeout); 595 capsicate(conn); 596 login(conn); 597 if (conn->conn_conf.isc_discovery != 0) 598 discovery(conn); 599 else 600 handoff(conn); 601 602 log_debugx("nothing more to do; exiting"); 603 exit (0); 604 } 605 606 static int 607 wait_for_children(bool block) 608 { 609 pid_t pid; 610 int status; 611 int num = 0; 612 613 for (;;) { 614 /* 615 * If "block" is true, wait for at least one process. 616 */ 617 if (block && num == 0) 618 pid = wait4(-1, &status, 0, NULL); 619 else 620 pid = wait4(-1, &status, WNOHANG, NULL); 621 if (pid <= 0) 622 break; 623 if (WIFSIGNALED(status)) { 624 log_warnx("child process %d terminated with signal %d", 625 pid, WTERMSIG(status)); 626 } else if (WEXITSTATUS(status) != 0) { 627 log_warnx("child process %d terminated with exit status %d", 628 pid, WEXITSTATUS(status)); 629 } else { 630 log_debugx("child process %d terminated gracefully", pid); 631 } 632 num++; 633 } 634 635 return (num); 636 } 637 638 int 639 main(int argc, char **argv) 640 { 641 int ch, debug = 0, error, iscsi_fd, maxproc = 30, retval, saved_errno, 642 timeout = 60; 643 bool dont_daemonize = false; 644 struct pidfh *pidfh; 645 pid_t pid, otherpid; 646 const char *pidfile_path = DEFAULT_PIDFILE; 647 struct iscsi_daemon_request request; 648 649 while ((ch = getopt(argc, argv, "P:dl:m:t:")) != -1) { 650 switch (ch) { 651 case 'P': 652 pidfile_path = optarg; 653 break; 654 case 'd': 655 dont_daemonize = true; 656 debug++; 657 break; 658 case 'l': 659 debug = atoi(optarg); 660 break; 661 case 'm': 662 maxproc = atoi(optarg); 663 break; 664 case 't': 665 timeout = atoi(optarg); 666 break; 667 case '?': 668 default: 669 usage(); 670 } 671 } 672 argc -= optind; 673 if (argc != 0) 674 usage(); 675 676 log_init(debug); 677 678 pidfh = pidfile_open(pidfile_path, 0600, &otherpid); 679 if (pidfh == NULL) { 680 if (errno == EEXIST) 681 log_errx(1, "daemon already running, pid: %jd.", 682 (intmax_t)otherpid); 683 log_err(1, "cannot open or create pidfile \"%s\"", 684 pidfile_path); 685 } 686 687 iscsi_fd = open(ISCSI_PATH, O_RDWR); 688 if (iscsi_fd < 0 && errno == ENOENT) { 689 saved_errno = errno; 690 retval = kldload("iscsi"); 691 if (retval != -1) 692 iscsi_fd = open(ISCSI_PATH, O_RDWR); 693 else 694 errno = saved_errno; 695 } 696 if (iscsi_fd < 0) 697 log_err(1, "failed to open %s", ISCSI_PATH); 698 699 if (dont_daemonize == false) { 700 if (daemon(0, 0) == -1) { 701 log_warn("cannot daemonize"); 702 pidfile_remove(pidfh); 703 exit(1); 704 } 705 } 706 707 pidfile_write(pidfh); 708 709 register_sigchld(); 710 711 for (;;) { 712 log_debugx("waiting for request from the kernel"); 713 714 memset(&request, 0, sizeof(request)); 715 error = ioctl(iscsi_fd, ISCSIDWAIT, &request); 716 if (error != 0) { 717 if (errno == EINTR) { 718 nchildren -= wait_for_children(false); 719 assert(nchildren >= 0); 720 continue; 721 } 722 723 log_err(1, "ISCSIDWAIT"); 724 } 725 726 if (dont_daemonize) { 727 log_debugx("not forking due to -d flag; " 728 "will exit after servicing a single request"); 729 } else { 730 nchildren -= wait_for_children(false); 731 assert(nchildren >= 0); 732 733 while (maxproc > 0 && nchildren >= maxproc) { 734 log_debugx("maxproc limit of %d child processes hit; " 735 "waiting for child process to exit", maxproc); 736 nchildren -= wait_for_children(true); 737 assert(nchildren >= 0); 738 } 739 log_debugx("incoming connection; forking child process #%d", 740 nchildren); 741 nchildren++; 742 743 pid = fork(); 744 if (pid < 0) 745 log_err(1, "fork"); 746 if (pid > 0) 747 continue; 748 } 749 750 pidfile_close(pidfh); 751 handle_request(iscsi_fd, &request, timeout); 752 } 753 754 return (0); 755 } 756