1009ea47eSEdward Tomasz Napierala /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 4009ea47eSEdward Tomasz Napierala * Copyright (c) 2012 The FreeBSD Foundation 5009ea47eSEdward Tomasz Napierala * All rights reserved. 6009ea47eSEdward Tomasz Napierala * 7009ea47eSEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship 8009ea47eSEdward Tomasz Napierala * from the FreeBSD Foundation. 9009ea47eSEdward Tomasz Napierala * 10009ea47eSEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 11009ea47eSEdward Tomasz Napierala * modification, are permitted provided that the following conditions 12009ea47eSEdward Tomasz Napierala * are met: 13009ea47eSEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 14009ea47eSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 15009ea47eSEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 16009ea47eSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 17009ea47eSEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 18009ea47eSEdward Tomasz Napierala * 19009ea47eSEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20009ea47eSEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21009ea47eSEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22009ea47eSEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23009ea47eSEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24009ea47eSEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25009ea47eSEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26009ea47eSEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27009ea47eSEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28009ea47eSEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29009ea47eSEdward Tomasz Napierala * SUCH DAMAGE. 30009ea47eSEdward Tomasz Napierala * 31009ea47eSEdward Tomasz Napierala */ 32009ea47eSEdward Tomasz Napierala 33b7a65e39SEdward Tomasz Napierala #include <sys/cdefs.h> 34b7a65e39SEdward Tomasz Napierala __FBSDID("$FreeBSD$"); 35b7a65e39SEdward Tomasz Napierala 36009ea47eSEdward Tomasz Napierala #include <sys/types.h> 37009ea47eSEdward Tomasz Napierala #include <sys/time.h> 38009ea47eSEdward Tomasz Napierala #include <sys/ioctl.h> 39009ea47eSEdward Tomasz Napierala #include <sys/param.h> 40009ea47eSEdward Tomasz Napierala #include <sys/linker.h> 41009ea47eSEdward Tomasz Napierala #include <sys/socket.h> 42b881b8beSRobert Watson #include <sys/capsicum.h> 43009ea47eSEdward Tomasz Napierala #include <sys/wait.h> 44*bfabdadeSRichard Scheffenegger #include <netinet/in.h> 45009ea47eSEdward Tomasz Napierala #include <assert.h> 461489776dSMariusz Zaborski #include <capsicum_helpers.h> 47009ea47eSEdward Tomasz Napierala #include <errno.h> 48009ea47eSEdward Tomasz Napierala #include <fcntl.h> 49592d6e85SEdward Tomasz Napierala #include <libutil.h> 50009ea47eSEdward Tomasz Napierala #include <netdb.h> 51009ea47eSEdward Tomasz Napierala #include <signal.h> 52009ea47eSEdward Tomasz Napierala #include <stdbool.h> 53009ea47eSEdward Tomasz Napierala #include <stdint.h> 54009ea47eSEdward Tomasz Napierala #include <stdio.h> 55009ea47eSEdward Tomasz Napierala #include <stdlib.h> 56009ea47eSEdward Tomasz Napierala #include <string.h> 57009ea47eSEdward Tomasz Napierala #include <unistd.h> 58009ea47eSEdward Tomasz Napierala 59009ea47eSEdward Tomasz Napierala #include "iscsid.h" 60009ea47eSEdward Tomasz Napierala 61009ea47eSEdward Tomasz Napierala static volatile bool sigalrm_received = false; 62009ea47eSEdward Tomasz Napierala 63009ea47eSEdward Tomasz Napierala static int nchildren = 0; 64009ea47eSEdward Tomasz Napierala 65009ea47eSEdward Tomasz Napierala static void 66009ea47eSEdward Tomasz Napierala usage(void) 67009ea47eSEdward Tomasz Napierala { 68009ea47eSEdward Tomasz Napierala 69009ea47eSEdward Tomasz Napierala fprintf(stderr, "usage: iscsid [-P pidfile][-d][-m maxproc][-t timeout]\n"); 70009ea47eSEdward Tomasz Napierala exit(1); 71009ea47eSEdward Tomasz Napierala } 72009ea47eSEdward Tomasz Napierala 73009ea47eSEdward Tomasz Napierala char * 74009ea47eSEdward Tomasz Napierala checked_strdup(const char *s) 75009ea47eSEdward Tomasz Napierala { 76009ea47eSEdward Tomasz Napierala char *c; 77009ea47eSEdward Tomasz Napierala 78009ea47eSEdward Tomasz Napierala c = strdup(s); 79009ea47eSEdward Tomasz Napierala if (c == NULL) 80009ea47eSEdward Tomasz Napierala log_err(1, "strdup"); 81009ea47eSEdward Tomasz Napierala return (c); 82009ea47eSEdward Tomasz Napierala } 83009ea47eSEdward Tomasz Napierala 841f90f282SEdward Tomasz Napierala static void 851f90f282SEdward Tomasz Napierala resolve_addr(const struct connection *conn, const char *address, 861f90f282SEdward Tomasz Napierala struct addrinfo **ai, bool initiator_side) 87009ea47eSEdward Tomasz Napierala { 88009ea47eSEdward Tomasz Napierala struct addrinfo hints; 89009ea47eSEdward Tomasz Napierala char *arg, *addr, *ch; 90009ea47eSEdward Tomasz Napierala const char *port; 91009ea47eSEdward Tomasz Napierala int error, colons = 0; 92009ea47eSEdward Tomasz Napierala 93009ea47eSEdward Tomasz Napierala arg = checked_strdup(address); 94009ea47eSEdward Tomasz Napierala 95009ea47eSEdward Tomasz Napierala if (arg[0] == '\0') { 961f90f282SEdward Tomasz Napierala fail(conn, "empty address"); 971f90f282SEdward Tomasz Napierala log_errx(1, "empty address"); 98009ea47eSEdward Tomasz Napierala } 99009ea47eSEdward Tomasz Napierala if (arg[0] == '[') { 100009ea47eSEdward Tomasz Napierala /* 101009ea47eSEdward Tomasz Napierala * IPv6 address in square brackets, perhaps with port. 102009ea47eSEdward Tomasz Napierala */ 103009ea47eSEdward Tomasz Napierala arg++; 104009ea47eSEdward Tomasz Napierala addr = strsep(&arg, "]"); 105009ea47eSEdward Tomasz Napierala if (arg == NULL) { 1061f90f282SEdward Tomasz Napierala fail(conn, "malformed address"); 1071f90f282SEdward Tomasz Napierala log_errx(1, "malformed address %s", address); 108009ea47eSEdward Tomasz Napierala } 109009ea47eSEdward Tomasz Napierala if (arg[0] == '\0') { 1101f90f282SEdward Tomasz Napierala port = NULL; 111009ea47eSEdward Tomasz Napierala } else if (arg[0] == ':') { 112009ea47eSEdward Tomasz Napierala port = arg + 1; 113009ea47eSEdward Tomasz Napierala } else { 1141f90f282SEdward Tomasz Napierala fail(conn, "malformed address"); 1151f90f282SEdward Tomasz Napierala log_errx(1, "malformed address %s", address); 116009ea47eSEdward Tomasz Napierala } 117009ea47eSEdward Tomasz Napierala } else { 118009ea47eSEdward Tomasz Napierala /* 119009ea47eSEdward Tomasz Napierala * Either IPv6 address without brackets - and without 120009ea47eSEdward Tomasz Napierala * a port - or IPv4 address. Just count the colons. 121009ea47eSEdward Tomasz Napierala */ 122009ea47eSEdward Tomasz Napierala for (ch = arg; *ch != '\0'; ch++) { 123009ea47eSEdward Tomasz Napierala if (*ch == ':') 124009ea47eSEdward Tomasz Napierala colons++; 125009ea47eSEdward Tomasz Napierala } 126009ea47eSEdward Tomasz Napierala if (colons > 1) { 127009ea47eSEdward Tomasz Napierala addr = arg; 1281f90f282SEdward Tomasz Napierala port = NULL; 129009ea47eSEdward Tomasz Napierala } else { 130009ea47eSEdward Tomasz Napierala addr = strsep(&arg, ":"); 131009ea47eSEdward Tomasz Napierala if (arg == NULL) 1321f90f282SEdward Tomasz Napierala port = NULL; 133009ea47eSEdward Tomasz Napierala else 134009ea47eSEdward Tomasz Napierala port = arg; 135009ea47eSEdward Tomasz Napierala } 136009ea47eSEdward Tomasz Napierala } 137009ea47eSEdward Tomasz Napierala 1381f90f282SEdward Tomasz Napierala if (port == NULL && !initiator_side) 1391f90f282SEdward Tomasz Napierala port = "3260"; 1401f90f282SEdward Tomasz Napierala 141009ea47eSEdward Tomasz Napierala memset(&hints, 0, sizeof(hints)); 142009ea47eSEdward Tomasz Napierala hints.ai_family = PF_UNSPEC; 143009ea47eSEdward Tomasz Napierala hints.ai_socktype = SOCK_STREAM; 1441f90f282SEdward Tomasz Napierala hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; 1451f90f282SEdward Tomasz Napierala if (initiator_side) 1461f90f282SEdward Tomasz Napierala hints.ai_flags |= AI_PASSIVE; 147009ea47eSEdward Tomasz Napierala 148009ea47eSEdward Tomasz Napierala error = getaddrinfo(addr, port, &hints, ai); 149009ea47eSEdward Tomasz Napierala if (error != 0) { 1501f90f282SEdward Tomasz Napierala fail(conn, gai_strerror(error)); 1511f90f282SEdward Tomasz Napierala log_errx(1, "getaddrinfo for %s failed: %s", 152009ea47eSEdward Tomasz Napierala address, gai_strerror(error)); 153009ea47eSEdward Tomasz Napierala } 154009ea47eSEdward Tomasz Napierala } 155009ea47eSEdward Tomasz Napierala 156009ea47eSEdward Tomasz Napierala static struct connection * 15783f37561SEdward Tomasz Napierala connection_new(int iscsi_fd, const struct iscsi_daemon_request *request) 158009ea47eSEdward Tomasz Napierala { 159009ea47eSEdward Tomasz Napierala struct connection *conn; 16097b84d34SNavdeep Parhar struct iscsi_session_limits *isl; 161009ea47eSEdward Tomasz Napierala struct addrinfo *from_ai, *to_ai; 162009ea47eSEdward Tomasz Napierala const char *from_addr, *to_addr; 163009ea47eSEdward Tomasz Napierala #ifdef ICL_KERNEL_PROXY 1647843bd03SEdward Tomasz Napierala struct iscsi_daemon_connect idc; 165009ea47eSEdward Tomasz Napierala #endif 1668b94b583SAlexander Motin int error, sockbuf; 167009ea47eSEdward Tomasz Napierala 168009ea47eSEdward Tomasz Napierala conn = calloc(1, sizeof(*conn)); 169009ea47eSEdward Tomasz Napierala if (conn == NULL) 170009ea47eSEdward Tomasz Napierala log_err(1, "calloc"); 171009ea47eSEdward Tomasz Napierala 172009ea47eSEdward Tomasz Napierala /* 173009ea47eSEdward Tomasz Napierala * Default values, from RFC 3720, section 12. 174009ea47eSEdward Tomasz Napierala */ 175009ea47eSEdward Tomasz Napierala conn->conn_header_digest = CONN_DIGEST_NONE; 176009ea47eSEdward Tomasz Napierala conn->conn_data_digest = CONN_DIGEST_NONE; 177009ea47eSEdward Tomasz Napierala conn->conn_initial_r2t = true; 178009ea47eSEdward Tomasz Napierala conn->conn_immediate_data = true; 179a15fbc90SAlexander Motin conn->conn_max_recv_data_segment_length = 8192; 180a15fbc90SAlexander Motin conn->conn_max_send_data_segment_length = 8192; 181a15fbc90SAlexander Motin conn->conn_max_burst_length = 262144; 182a15fbc90SAlexander Motin conn->conn_first_burst_length = 65536; 1831f90f282SEdward Tomasz Napierala conn->conn_iscsi_fd = iscsi_fd; 1841f90f282SEdward Tomasz Napierala 18583f37561SEdward Tomasz Napierala conn->conn_session_id = request->idr_session_id; 18683f37561SEdward Tomasz Napierala memcpy(&conn->conn_conf, &request->idr_conf, sizeof(conn->conn_conf)); 18783f37561SEdward Tomasz Napierala memcpy(&conn->conn_isid, &request->idr_isid, sizeof(conn->conn_isid)); 18883f37561SEdward Tomasz Napierala conn->conn_tsih = request->idr_tsih; 18997b84d34SNavdeep Parhar 19097b84d34SNavdeep Parhar /* 19197b84d34SNavdeep Parhar * Read the driver limits and provide reasonable defaults for the ones 19297b84d34SNavdeep Parhar * the driver doesn't care about. If a max_snd_dsl is not explicitly 19397b84d34SNavdeep Parhar * provided by the driver then we'll make sure both conn->max_snd_dsl 19497b84d34SNavdeep Parhar * and isl->max_snd_dsl are set to the rcv_dsl. This preserves historic 19597b84d34SNavdeep Parhar * behavior. 19697b84d34SNavdeep Parhar */ 19797b84d34SNavdeep Parhar isl = &conn->conn_limits; 19897b84d34SNavdeep Parhar memcpy(isl, &request->idr_limits, sizeof(*isl)); 199a15fbc90SAlexander Motin if (isl->isl_max_recv_data_segment_length == 0) 200a15fbc90SAlexander Motin isl->isl_max_recv_data_segment_length = (1 << 24) - 1; 201a15fbc90SAlexander Motin if (isl->isl_max_send_data_segment_length == 0) 20297b84d34SNavdeep Parhar isl->isl_max_send_data_segment_length = 20397b84d34SNavdeep Parhar isl->isl_max_recv_data_segment_length; 204a15fbc90SAlexander Motin if (isl->isl_max_burst_length == 0) 205a15fbc90SAlexander Motin isl->isl_max_burst_length = (1 << 24) - 1; 206a15fbc90SAlexander Motin if (isl->isl_first_burst_length == 0) 207a15fbc90SAlexander Motin isl->isl_first_burst_length = (1 << 24) - 1; 208a15fbc90SAlexander Motin if (isl->isl_first_burst_length > isl->isl_max_burst_length) 209a15fbc90SAlexander Motin isl->isl_first_burst_length = isl->isl_max_burst_length; 210a15fbc90SAlexander Motin 211a15fbc90SAlexander Motin /* 212a15fbc90SAlexander Motin * Limit default send length in case it won't be negotiated. 213a15fbc90SAlexander Motin * We can't do it for other limits, since they may affect both 214a15fbc90SAlexander Motin * sender and receiver operation, and we must obey defaults. 215a15fbc90SAlexander Motin */ 216a15fbc90SAlexander Motin if (conn->conn_max_send_data_segment_length > 217a15fbc90SAlexander Motin isl->isl_max_send_data_segment_length) { 21897b84d34SNavdeep Parhar conn->conn_max_send_data_segment_length = 21997b84d34SNavdeep Parhar isl->isl_max_send_data_segment_length; 22097b84d34SNavdeep Parhar } 221009ea47eSEdward Tomasz Napierala 222009ea47eSEdward Tomasz Napierala from_addr = conn->conn_conf.isc_initiator_addr; 223009ea47eSEdward Tomasz Napierala to_addr = conn->conn_conf.isc_target_addr; 224009ea47eSEdward Tomasz Napierala 2251f90f282SEdward Tomasz Napierala if (from_addr[0] != '\0') 2261f90f282SEdward Tomasz Napierala resolve_addr(conn, from_addr, &from_ai, true); 2271f90f282SEdward Tomasz Napierala else 228009ea47eSEdward Tomasz Napierala from_ai = NULL; 229009ea47eSEdward Tomasz Napierala 2301f90f282SEdward Tomasz Napierala resolve_addr(conn, to_addr, &to_ai, false); 231009ea47eSEdward Tomasz Napierala 232009ea47eSEdward Tomasz Napierala #ifdef ICL_KERNEL_PROXY 23357a4f20bSEdward Tomasz Napierala if (conn->conn_conf.isc_iser) { 2347843bd03SEdward Tomasz Napierala memset(&idc, 0, sizeof(idc)); 2357843bd03SEdward Tomasz Napierala idc.idc_session_id = conn->conn_session_id; 236009ea47eSEdward Tomasz Napierala if (conn->conn_conf.isc_iser) 2377843bd03SEdward Tomasz Napierala idc.idc_iser = 1; 2387843bd03SEdward Tomasz Napierala idc.idc_domain = to_ai->ai_family; 2397843bd03SEdward Tomasz Napierala idc.idc_socktype = to_ai->ai_socktype; 2407843bd03SEdward Tomasz Napierala idc.idc_protocol = to_ai->ai_protocol; 241009ea47eSEdward Tomasz Napierala if (from_ai != NULL) { 2427843bd03SEdward Tomasz Napierala idc.idc_from_addr = from_ai->ai_addr; 2437843bd03SEdward Tomasz Napierala idc.idc_from_addrlen = from_ai->ai_addrlen; 244009ea47eSEdward Tomasz Napierala } 2457843bd03SEdward Tomasz Napierala idc.idc_to_addr = to_ai->ai_addr; 2467843bd03SEdward Tomasz Napierala idc.idc_to_addrlen = to_ai->ai_addrlen; 247009ea47eSEdward Tomasz Napierala 248009ea47eSEdward Tomasz Napierala log_debugx("connecting to %s using ICL kernel proxy", to_addr); 2497843bd03SEdward Tomasz Napierala error = ioctl(iscsi_fd, ISCSIDCONNECT, &idc); 250009ea47eSEdward Tomasz Napierala if (error != 0) { 251009ea47eSEdward Tomasz Napierala fail(conn, strerror(errno)); 25257a4f20bSEdward Tomasz Napierala log_err(1, "failed to connect to %s " 25357a4f20bSEdward Tomasz Napierala "using ICL kernel proxy: ISCSIDCONNECT", to_addr); 254009ea47eSEdward Tomasz Napierala } 255009ea47eSEdward Tomasz Napierala 25657a4f20bSEdward Tomasz Napierala return (conn); 25757a4f20bSEdward Tomasz Napierala } 25857a4f20bSEdward Tomasz Napierala #endif /* ICL_KERNEL_PROXY */ 259009ea47eSEdward Tomasz Napierala 2601f90f282SEdward Tomasz Napierala if (conn->conn_conf.isc_iser) { 2611f90f282SEdward Tomasz Napierala fail(conn, "iSER not supported"); 262009ea47eSEdward Tomasz Napierala log_errx(1, "iscsid(8) compiled without ICL_KERNEL_PROXY " 263009ea47eSEdward Tomasz Napierala "does not support iSER"); 2641f90f282SEdward Tomasz Napierala } 265009ea47eSEdward Tomasz Napierala 266009ea47eSEdward Tomasz Napierala conn->conn_socket = socket(to_ai->ai_family, to_ai->ai_socktype, 267009ea47eSEdward Tomasz Napierala to_ai->ai_protocol); 2681f90f282SEdward Tomasz Napierala if (conn->conn_socket < 0) { 2691f90f282SEdward Tomasz Napierala fail(conn, strerror(errno)); 270009ea47eSEdward Tomasz Napierala log_err(1, "failed to create socket for %s", from_addr); 2711f90f282SEdward Tomasz Napierala } 2728b94b583SAlexander Motin sockbuf = SOCKBUF_SIZE; 2738b94b583SAlexander Motin if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_RCVBUF, 2748b94b583SAlexander Motin &sockbuf, sizeof(sockbuf)) == -1) 2758b94b583SAlexander Motin log_warn("setsockopt(SO_RCVBUF) failed"); 2768b94b583SAlexander Motin sockbuf = SOCKBUF_SIZE; 2778b94b583SAlexander Motin if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_SNDBUF, 2788b94b583SAlexander Motin &sockbuf, sizeof(sockbuf)) == -1) 2798b94b583SAlexander Motin log_warn("setsockopt(SO_SNDBUF) failed"); 280*bfabdadeSRichard Scheffenegger if (conn->conn_conf.isc_dscp != -1) { 281*bfabdadeSRichard Scheffenegger int tos = conn->conn_conf.isc_dscp << 2; 282*bfabdadeSRichard Scheffenegger if (to_ai->ai_family == AF_INET) { 283*bfabdadeSRichard Scheffenegger if (setsockopt(conn->conn_socket, 284*bfabdadeSRichard Scheffenegger IPPROTO_IP, IP_TOS, 285*bfabdadeSRichard Scheffenegger &tos, sizeof(tos)) == -1) 286*bfabdadeSRichard Scheffenegger log_warn("setsockopt(IP_TOS) " 287*bfabdadeSRichard Scheffenegger "failed for %s", 288*bfabdadeSRichard Scheffenegger from_addr); 289*bfabdadeSRichard Scheffenegger } else 290*bfabdadeSRichard Scheffenegger if (to_ai->ai_family == AF_INET6) { 291*bfabdadeSRichard Scheffenegger if (setsockopt(conn->conn_socket, 292*bfabdadeSRichard Scheffenegger IPPROTO_IPV6, IPV6_TCLASS, 293*bfabdadeSRichard Scheffenegger &tos, sizeof(tos)) == -1) 294*bfabdadeSRichard Scheffenegger log_warn("setsockopt(IPV6_TCLASS) " 295*bfabdadeSRichard Scheffenegger "failed for %s", 296*bfabdadeSRichard Scheffenegger from_addr); 297*bfabdadeSRichard Scheffenegger } 298*bfabdadeSRichard Scheffenegger } 299009ea47eSEdward Tomasz Napierala if (from_ai != NULL) { 300009ea47eSEdward Tomasz Napierala error = bind(conn->conn_socket, from_ai->ai_addr, 301009ea47eSEdward Tomasz Napierala from_ai->ai_addrlen); 3021f90f282SEdward Tomasz Napierala if (error != 0) { 3031f90f282SEdward Tomasz Napierala fail(conn, strerror(errno)); 304009ea47eSEdward Tomasz Napierala log_err(1, "failed to bind to %s", from_addr); 305009ea47eSEdward Tomasz Napierala } 3061f90f282SEdward Tomasz Napierala } 307009ea47eSEdward Tomasz Napierala log_debugx("connecting to %s", to_addr); 308009ea47eSEdward Tomasz Napierala error = connect(conn->conn_socket, to_ai->ai_addr, to_ai->ai_addrlen); 309009ea47eSEdward Tomasz Napierala if (error != 0) { 310009ea47eSEdward Tomasz Napierala fail(conn, strerror(errno)); 311009ea47eSEdward Tomasz Napierala log_err(1, "failed to connect to %s", to_addr); 312009ea47eSEdward Tomasz Napierala } 313009ea47eSEdward Tomasz Napierala 314009ea47eSEdward Tomasz Napierala return (conn); 315009ea47eSEdward Tomasz Napierala } 316009ea47eSEdward Tomasz Napierala 317009ea47eSEdward Tomasz Napierala static void 318009ea47eSEdward Tomasz Napierala handoff(struct connection *conn) 319009ea47eSEdward Tomasz Napierala { 3207843bd03SEdward Tomasz Napierala struct iscsi_daemon_handoff idh; 321009ea47eSEdward Tomasz Napierala int error; 322009ea47eSEdward Tomasz Napierala 323009ea47eSEdward Tomasz Napierala log_debugx("handing off connection to the kernel"); 324009ea47eSEdward Tomasz Napierala 3257843bd03SEdward Tomasz Napierala memset(&idh, 0, sizeof(idh)); 3267843bd03SEdward Tomasz Napierala idh.idh_session_id = conn->conn_session_id; 3277843bd03SEdward Tomasz Napierala idh.idh_socket = conn->conn_socket; 3287843bd03SEdward Tomasz Napierala strlcpy(idh.idh_target_alias, conn->conn_target_alias, 3297843bd03SEdward Tomasz Napierala sizeof(idh.idh_target_alias)); 330ffe82e05SAlexander Motin idh.idh_tsih = conn->conn_tsih; 3317843bd03SEdward Tomasz Napierala idh.idh_statsn = conn->conn_statsn; 3327843bd03SEdward Tomasz Napierala idh.idh_header_digest = conn->conn_header_digest; 3337843bd03SEdward Tomasz Napierala idh.idh_data_digest = conn->conn_data_digest; 3347843bd03SEdward Tomasz Napierala idh.idh_initial_r2t = conn->conn_initial_r2t; 3357843bd03SEdward Tomasz Napierala idh.idh_immediate_data = conn->conn_immediate_data; 33697b84d34SNavdeep Parhar idh.idh_max_recv_data_segment_length = 33797b84d34SNavdeep Parhar conn->conn_max_recv_data_segment_length; 33897b84d34SNavdeep Parhar idh.idh_max_send_data_segment_length = 33997b84d34SNavdeep Parhar conn->conn_max_send_data_segment_length; 3407843bd03SEdward Tomasz Napierala idh.idh_max_burst_length = conn->conn_max_burst_length; 3417843bd03SEdward Tomasz Napierala idh.idh_first_burst_length = conn->conn_first_burst_length; 342009ea47eSEdward Tomasz Napierala 3437843bd03SEdward Tomasz Napierala error = ioctl(conn->conn_iscsi_fd, ISCSIDHANDOFF, &idh); 344009ea47eSEdward Tomasz Napierala if (error != 0) 345009ea47eSEdward Tomasz Napierala log_err(1, "ISCSIDHANDOFF"); 346009ea47eSEdward Tomasz Napierala } 347009ea47eSEdward Tomasz Napierala 348009ea47eSEdward Tomasz Napierala void 349009ea47eSEdward Tomasz Napierala fail(const struct connection *conn, const char *reason) 350009ea47eSEdward Tomasz Napierala { 3517843bd03SEdward Tomasz Napierala struct iscsi_daemon_fail idf; 352535bd9beSEdward Tomasz Napierala int error, saved_errno; 353535bd9beSEdward Tomasz Napierala 354535bd9beSEdward Tomasz Napierala saved_errno = errno; 355009ea47eSEdward Tomasz Napierala 3567843bd03SEdward Tomasz Napierala memset(&idf, 0, sizeof(idf)); 3577843bd03SEdward Tomasz Napierala idf.idf_session_id = conn->conn_session_id; 3587843bd03SEdward Tomasz Napierala strlcpy(idf.idf_reason, reason, sizeof(idf.idf_reason)); 359009ea47eSEdward Tomasz Napierala 3607843bd03SEdward Tomasz Napierala error = ioctl(conn->conn_iscsi_fd, ISCSIDFAIL, &idf); 361009ea47eSEdward Tomasz Napierala if (error != 0) 362009ea47eSEdward Tomasz Napierala log_err(1, "ISCSIDFAIL"); 363535bd9beSEdward Tomasz Napierala 364535bd9beSEdward Tomasz Napierala errno = saved_errno; 365009ea47eSEdward Tomasz Napierala } 366009ea47eSEdward Tomasz Napierala 367009ea47eSEdward Tomasz Napierala /* 368009ea47eSEdward Tomasz Napierala * XXX: I CANT INTO LATIN 369009ea47eSEdward Tomasz Napierala */ 370009ea47eSEdward Tomasz Napierala static void 371009ea47eSEdward Tomasz Napierala capsicate(struct connection *conn) 372009ea47eSEdward Tomasz Napierala { 373009ea47eSEdward Tomasz Napierala cap_rights_t rights; 374009ea47eSEdward Tomasz Napierala #ifdef ICL_KERNEL_PROXY 375009ea47eSEdward Tomasz Napierala const unsigned long cmds[] = { ISCSIDCONNECT, ISCSIDSEND, ISCSIDRECEIVE, 37651be90b5SEdward Tomasz Napierala ISCSIDHANDOFF, ISCSIDFAIL, ISCSISADD, ISCSISREMOVE, ISCSISMODIFY }; 377009ea47eSEdward Tomasz Napierala #else 378009ea47eSEdward Tomasz Napierala const unsigned long cmds[] = { ISCSIDHANDOFF, ISCSIDFAIL, ISCSISADD, 37951be90b5SEdward Tomasz Napierala ISCSISREMOVE, ISCSISMODIFY }; 380009ea47eSEdward Tomasz Napierala #endif 381009ea47eSEdward Tomasz Napierala 382009ea47eSEdward Tomasz Napierala cap_rights_init(&rights, CAP_IOCTL); 3831489776dSMariusz Zaborski if (caph_rights_limit(conn->conn_iscsi_fd, &rights) < 0) 384009ea47eSEdward Tomasz Napierala log_err(1, "cap_rights_limit"); 385009ea47eSEdward Tomasz Napierala 3861489776dSMariusz Zaborski if (caph_ioctls_limit(conn->conn_iscsi_fd, cmds, nitems(cmds)) < 0) 387009ea47eSEdward Tomasz Napierala log_err(1, "cap_ioctls_limit"); 388009ea47eSEdward Tomasz Napierala 3891489776dSMariusz Zaborski if (caph_enter() != 0) 390009ea47eSEdward Tomasz Napierala log_err(1, "cap_enter"); 391009ea47eSEdward Tomasz Napierala 392009ea47eSEdward Tomasz Napierala if (cap_sandboxed()) 393009ea47eSEdward Tomasz Napierala log_debugx("Capsicum capability mode enabled"); 394009ea47eSEdward Tomasz Napierala else 395009ea47eSEdward Tomasz Napierala log_warnx("Capsicum capability mode not supported"); 396009ea47eSEdward Tomasz Napierala } 397009ea47eSEdward Tomasz Napierala 398009ea47eSEdward Tomasz Napierala bool 399009ea47eSEdward Tomasz Napierala timed_out(void) 400009ea47eSEdward Tomasz Napierala { 401009ea47eSEdward Tomasz Napierala 402009ea47eSEdward Tomasz Napierala return (sigalrm_received); 403009ea47eSEdward Tomasz Napierala } 404009ea47eSEdward Tomasz Napierala 405009ea47eSEdward Tomasz Napierala static void 406009ea47eSEdward Tomasz Napierala sigalrm_handler(int dummy __unused) 407009ea47eSEdward Tomasz Napierala { 408009ea47eSEdward Tomasz Napierala /* 409009ea47eSEdward Tomasz Napierala * It would be easiest to just log an error and exit. We can't 410009ea47eSEdward Tomasz Napierala * do this, though, because log_errx() is not signal safe, since 411009ea47eSEdward Tomasz Napierala * it calls syslog(3). Instead, set a flag checked by pdu_send() 412009ea47eSEdward Tomasz Napierala * and pdu_receive(), to call log_errx() there. Should they fail 413009ea47eSEdward Tomasz Napierala * to notice, we'll exit here one second later. 414009ea47eSEdward Tomasz Napierala */ 415009ea47eSEdward Tomasz Napierala if (sigalrm_received) { 416009ea47eSEdward Tomasz Napierala /* 417009ea47eSEdward Tomasz Napierala * Oh well. Just give up and quit. 418009ea47eSEdward Tomasz Napierala */ 419009ea47eSEdward Tomasz Napierala _exit(2); 420009ea47eSEdward Tomasz Napierala } 421009ea47eSEdward Tomasz Napierala 422009ea47eSEdward Tomasz Napierala sigalrm_received = true; 423009ea47eSEdward Tomasz Napierala } 424009ea47eSEdward Tomasz Napierala 425009ea47eSEdward Tomasz Napierala static void 426009ea47eSEdward Tomasz Napierala set_timeout(int timeout) 427009ea47eSEdward Tomasz Napierala { 428009ea47eSEdward Tomasz Napierala struct sigaction sa; 429009ea47eSEdward Tomasz Napierala struct itimerval itv; 430009ea47eSEdward Tomasz Napierala int error; 431009ea47eSEdward Tomasz Napierala 432009ea47eSEdward Tomasz Napierala if (timeout <= 0) { 433009ea47eSEdward Tomasz Napierala log_debugx("session timeout disabled"); 434009ea47eSEdward Tomasz Napierala return; 435009ea47eSEdward Tomasz Napierala } 436009ea47eSEdward Tomasz Napierala 437009ea47eSEdward Tomasz Napierala bzero(&sa, sizeof(sa)); 438009ea47eSEdward Tomasz Napierala sa.sa_handler = sigalrm_handler; 439009ea47eSEdward Tomasz Napierala sigfillset(&sa.sa_mask); 440009ea47eSEdward Tomasz Napierala error = sigaction(SIGALRM, &sa, NULL); 441009ea47eSEdward Tomasz Napierala if (error != 0) 442009ea47eSEdward Tomasz Napierala log_err(1, "sigaction"); 443009ea47eSEdward Tomasz Napierala 444009ea47eSEdward Tomasz Napierala /* 445009ea47eSEdward Tomasz Napierala * First SIGALRM will arive after conf_timeout seconds. 446009ea47eSEdward Tomasz Napierala * If we do nothing, another one will arrive a second later. 447009ea47eSEdward Tomasz Napierala */ 448009ea47eSEdward Tomasz Napierala bzero(&itv, sizeof(itv)); 449009ea47eSEdward Tomasz Napierala itv.it_interval.tv_sec = 1; 450009ea47eSEdward Tomasz Napierala itv.it_value.tv_sec = timeout; 451009ea47eSEdward Tomasz Napierala 452009ea47eSEdward Tomasz Napierala log_debugx("setting session timeout to %d seconds", 453009ea47eSEdward Tomasz Napierala timeout); 454009ea47eSEdward Tomasz Napierala error = setitimer(ITIMER_REAL, &itv, NULL); 455009ea47eSEdward Tomasz Napierala if (error != 0) 456009ea47eSEdward Tomasz Napierala log_err(1, "setitimer"); 457009ea47eSEdward Tomasz Napierala } 458009ea47eSEdward Tomasz Napierala 459009ea47eSEdward Tomasz Napierala static void 4601ecb3c58SEdward Tomasz Napierala sigchld_handler(int dummy __unused) 4611ecb3c58SEdward Tomasz Napierala { 4621ecb3c58SEdward Tomasz Napierala 4631ecb3c58SEdward Tomasz Napierala /* 4641ecb3c58SEdward Tomasz Napierala * The only purpose of this handler is to make SIGCHLD 4651ecb3c58SEdward Tomasz Napierala * interrupt the ISCSIDWAIT ioctl(2), so we can call 4661ecb3c58SEdward Tomasz Napierala * wait_for_children(). 4671ecb3c58SEdward Tomasz Napierala */ 4681ecb3c58SEdward Tomasz Napierala } 4691ecb3c58SEdward Tomasz Napierala 4701ecb3c58SEdward Tomasz Napierala static void 4711ecb3c58SEdward Tomasz Napierala register_sigchld(void) 4721ecb3c58SEdward Tomasz Napierala { 4731ecb3c58SEdward Tomasz Napierala struct sigaction sa; 4741ecb3c58SEdward Tomasz Napierala int error; 4751ecb3c58SEdward Tomasz Napierala 4761ecb3c58SEdward Tomasz Napierala bzero(&sa, sizeof(sa)); 4771ecb3c58SEdward Tomasz Napierala sa.sa_handler = sigchld_handler; 4781ecb3c58SEdward Tomasz Napierala sigfillset(&sa.sa_mask); 4791ecb3c58SEdward Tomasz Napierala error = sigaction(SIGCHLD, &sa, NULL); 4801ecb3c58SEdward Tomasz Napierala if (error != 0) 4811ecb3c58SEdward Tomasz Napierala log_err(1, "sigaction"); 4821ecb3c58SEdward Tomasz Napierala 4831ecb3c58SEdward Tomasz Napierala } 4841ecb3c58SEdward Tomasz Napierala 4851ecb3c58SEdward Tomasz Napierala static void 4867843bd03SEdward Tomasz Napierala handle_request(int iscsi_fd, const struct iscsi_daemon_request *request, int timeout) 487009ea47eSEdward Tomasz Napierala { 488009ea47eSEdward Tomasz Napierala struct connection *conn; 489009ea47eSEdward Tomasz Napierala 490009ea47eSEdward Tomasz Napierala log_set_peer_addr(request->idr_conf.isc_target_addr); 491009ea47eSEdward Tomasz Napierala if (request->idr_conf.isc_target[0] != '\0') { 492009ea47eSEdward Tomasz Napierala log_set_peer_name(request->idr_conf.isc_target); 493009ea47eSEdward Tomasz Napierala setproctitle("%s (%s)", request->idr_conf.isc_target_addr, request->idr_conf.isc_target); 494009ea47eSEdward Tomasz Napierala } else { 495009ea47eSEdward Tomasz Napierala setproctitle("%s", request->idr_conf.isc_target_addr); 496009ea47eSEdward Tomasz Napierala } 497009ea47eSEdward Tomasz Napierala 49883f37561SEdward Tomasz Napierala conn = connection_new(iscsi_fd, request); 499009ea47eSEdward Tomasz Napierala set_timeout(timeout); 500009ea47eSEdward Tomasz Napierala capsicate(conn); 501009ea47eSEdward Tomasz Napierala login(conn); 502009ea47eSEdward Tomasz Napierala if (conn->conn_conf.isc_discovery != 0) 503009ea47eSEdward Tomasz Napierala discovery(conn); 504009ea47eSEdward Tomasz Napierala else 505009ea47eSEdward Tomasz Napierala handoff(conn); 506009ea47eSEdward Tomasz Napierala 507009ea47eSEdward Tomasz Napierala log_debugx("nothing more to do; exiting"); 508009ea47eSEdward Tomasz Napierala exit (0); 509009ea47eSEdward Tomasz Napierala } 510009ea47eSEdward Tomasz Napierala 511009ea47eSEdward Tomasz Napierala static int 512009ea47eSEdward Tomasz Napierala wait_for_children(bool block) 513009ea47eSEdward Tomasz Napierala { 514009ea47eSEdward Tomasz Napierala pid_t pid; 515009ea47eSEdward Tomasz Napierala int status; 516009ea47eSEdward Tomasz Napierala int num = 0; 517009ea47eSEdward Tomasz Napierala 518009ea47eSEdward Tomasz Napierala for (;;) { 519009ea47eSEdward Tomasz Napierala /* 520009ea47eSEdward Tomasz Napierala * If "block" is true, wait for at least one process. 521009ea47eSEdward Tomasz Napierala */ 522009ea47eSEdward Tomasz Napierala if (block && num == 0) 523009ea47eSEdward Tomasz Napierala pid = wait4(-1, &status, 0, NULL); 524009ea47eSEdward Tomasz Napierala else 525009ea47eSEdward Tomasz Napierala pid = wait4(-1, &status, WNOHANG, NULL); 526009ea47eSEdward Tomasz Napierala if (pid <= 0) 527009ea47eSEdward Tomasz Napierala break; 528009ea47eSEdward Tomasz Napierala if (WIFSIGNALED(status)) { 529009ea47eSEdward Tomasz Napierala log_warnx("child process %d terminated with signal %d", 530009ea47eSEdward Tomasz Napierala pid, WTERMSIG(status)); 531009ea47eSEdward Tomasz Napierala } else if (WEXITSTATUS(status) != 0) { 532009ea47eSEdward Tomasz Napierala log_warnx("child process %d terminated with exit status %d", 533009ea47eSEdward Tomasz Napierala pid, WEXITSTATUS(status)); 534009ea47eSEdward Tomasz Napierala } else { 535009ea47eSEdward Tomasz Napierala log_debugx("child process %d terminated gracefully", pid); 536009ea47eSEdward Tomasz Napierala } 537009ea47eSEdward Tomasz Napierala num++; 538009ea47eSEdward Tomasz Napierala } 539009ea47eSEdward Tomasz Napierala 540009ea47eSEdward Tomasz Napierala return (num); 541009ea47eSEdward Tomasz Napierala } 542009ea47eSEdward Tomasz Napierala 543009ea47eSEdward Tomasz Napierala int 544009ea47eSEdward Tomasz Napierala main(int argc, char **argv) 545009ea47eSEdward Tomasz Napierala { 546009ea47eSEdward Tomasz Napierala int ch, debug = 0, error, iscsi_fd, maxproc = 30, retval, saved_errno, 547009ea47eSEdward Tomasz Napierala timeout = 60; 548009ea47eSEdward Tomasz Napierala bool dont_daemonize = false; 549009ea47eSEdward Tomasz Napierala struct pidfh *pidfh; 550009ea47eSEdward Tomasz Napierala pid_t pid, otherpid; 551009ea47eSEdward Tomasz Napierala const char *pidfile_path = DEFAULT_PIDFILE; 5527843bd03SEdward Tomasz Napierala struct iscsi_daemon_request request; 553009ea47eSEdward Tomasz Napierala 554009ea47eSEdward Tomasz Napierala while ((ch = getopt(argc, argv, "P:dl:m:t:")) != -1) { 555009ea47eSEdward Tomasz Napierala switch (ch) { 556009ea47eSEdward Tomasz Napierala case 'P': 557009ea47eSEdward Tomasz Napierala pidfile_path = optarg; 558009ea47eSEdward Tomasz Napierala break; 559009ea47eSEdward Tomasz Napierala case 'd': 560009ea47eSEdward Tomasz Napierala dont_daemonize = true; 561009ea47eSEdward Tomasz Napierala debug++; 562009ea47eSEdward Tomasz Napierala break; 563009ea47eSEdward Tomasz Napierala case 'l': 564009ea47eSEdward Tomasz Napierala debug = atoi(optarg); 565009ea47eSEdward Tomasz Napierala break; 566009ea47eSEdward Tomasz Napierala case 'm': 567009ea47eSEdward Tomasz Napierala maxproc = atoi(optarg); 568009ea47eSEdward Tomasz Napierala break; 569009ea47eSEdward Tomasz Napierala case 't': 570009ea47eSEdward Tomasz Napierala timeout = atoi(optarg); 571009ea47eSEdward Tomasz Napierala break; 572009ea47eSEdward Tomasz Napierala case '?': 573009ea47eSEdward Tomasz Napierala default: 574009ea47eSEdward Tomasz Napierala usage(); 575009ea47eSEdward Tomasz Napierala } 576009ea47eSEdward Tomasz Napierala } 577009ea47eSEdward Tomasz Napierala argc -= optind; 578009ea47eSEdward Tomasz Napierala if (argc != 0) 579009ea47eSEdward Tomasz Napierala usage(); 580009ea47eSEdward Tomasz Napierala 581009ea47eSEdward Tomasz Napierala log_init(debug); 582009ea47eSEdward Tomasz Napierala 583009ea47eSEdward Tomasz Napierala pidfh = pidfile_open(pidfile_path, 0600, &otherpid); 584009ea47eSEdward Tomasz Napierala if (pidfh == NULL) { 585009ea47eSEdward Tomasz Napierala if (errno == EEXIST) 586009ea47eSEdward Tomasz Napierala log_errx(1, "daemon already running, pid: %jd.", 587009ea47eSEdward Tomasz Napierala (intmax_t)otherpid); 588009ea47eSEdward Tomasz Napierala log_err(1, "cannot open or create pidfile \"%s\"", 589009ea47eSEdward Tomasz Napierala pidfile_path); 590009ea47eSEdward Tomasz Napierala } 591009ea47eSEdward Tomasz Napierala 592009ea47eSEdward Tomasz Napierala iscsi_fd = open(ISCSI_PATH, O_RDWR); 593c76e8a9aSEdward Tomasz Napierala if (iscsi_fd < 0 && errno == ENOENT) { 594009ea47eSEdward Tomasz Napierala saved_errno = errno; 595009ea47eSEdward Tomasz Napierala retval = kldload("iscsi"); 596009ea47eSEdward Tomasz Napierala if (retval != -1) 597009ea47eSEdward Tomasz Napierala iscsi_fd = open(ISCSI_PATH, O_RDWR); 598009ea47eSEdward Tomasz Napierala else 599009ea47eSEdward Tomasz Napierala errno = saved_errno; 600009ea47eSEdward Tomasz Napierala } 601009ea47eSEdward Tomasz Napierala if (iscsi_fd < 0) 602009ea47eSEdward Tomasz Napierala log_err(1, "failed to open %s", ISCSI_PATH); 603009ea47eSEdward Tomasz Napierala 604009ea47eSEdward Tomasz Napierala if (dont_daemonize == false) { 605009ea47eSEdward Tomasz Napierala if (daemon(0, 0) == -1) { 606009ea47eSEdward Tomasz Napierala log_warn("cannot daemonize"); 607009ea47eSEdward Tomasz Napierala pidfile_remove(pidfh); 608009ea47eSEdward Tomasz Napierala exit(1); 609009ea47eSEdward Tomasz Napierala } 610009ea47eSEdward Tomasz Napierala } 611009ea47eSEdward Tomasz Napierala 612009ea47eSEdward Tomasz Napierala pidfile_write(pidfh); 613009ea47eSEdward Tomasz Napierala 6141ecb3c58SEdward Tomasz Napierala register_sigchld(); 6151ecb3c58SEdward Tomasz Napierala 616009ea47eSEdward Tomasz Napierala for (;;) { 617009ea47eSEdward Tomasz Napierala log_debugx("waiting for request from the kernel"); 618009ea47eSEdward Tomasz Napierala 6197843bd03SEdward Tomasz Napierala memset(&request, 0, sizeof(request)); 6207843bd03SEdward Tomasz Napierala error = ioctl(iscsi_fd, ISCSIDWAIT, &request); 621009ea47eSEdward Tomasz Napierala if (error != 0) { 622009ea47eSEdward Tomasz Napierala if (errno == EINTR) { 623009ea47eSEdward Tomasz Napierala nchildren -= wait_for_children(false); 624009ea47eSEdward Tomasz Napierala assert(nchildren >= 0); 625009ea47eSEdward Tomasz Napierala continue; 626009ea47eSEdward Tomasz Napierala } 627009ea47eSEdward Tomasz Napierala 628009ea47eSEdward Tomasz Napierala log_err(1, "ISCSIDWAIT"); 629009ea47eSEdward Tomasz Napierala } 630009ea47eSEdward Tomasz Napierala 631009ea47eSEdward Tomasz Napierala if (dont_daemonize) { 632009ea47eSEdward Tomasz Napierala log_debugx("not forking due to -d flag; " 633009ea47eSEdward Tomasz Napierala "will exit after servicing a single request"); 634009ea47eSEdward Tomasz Napierala } else { 635009ea47eSEdward Tomasz Napierala nchildren -= wait_for_children(false); 636009ea47eSEdward Tomasz Napierala assert(nchildren >= 0); 637009ea47eSEdward Tomasz Napierala 638009ea47eSEdward Tomasz Napierala while (maxproc > 0 && nchildren >= maxproc) { 639009ea47eSEdward Tomasz Napierala log_debugx("maxproc limit of %d child processes hit; " 640009ea47eSEdward Tomasz Napierala "waiting for child process to exit", maxproc); 641009ea47eSEdward Tomasz Napierala nchildren -= wait_for_children(true); 642009ea47eSEdward Tomasz Napierala assert(nchildren >= 0); 643009ea47eSEdward Tomasz Napierala } 644009ea47eSEdward Tomasz Napierala log_debugx("incoming connection; forking child process #%d", 645009ea47eSEdward Tomasz Napierala nchildren); 646009ea47eSEdward Tomasz Napierala nchildren++; 647009ea47eSEdward Tomasz Napierala 648009ea47eSEdward Tomasz Napierala pid = fork(); 649009ea47eSEdward Tomasz Napierala if (pid < 0) 650009ea47eSEdward Tomasz Napierala log_err(1, "fork"); 651009ea47eSEdward Tomasz Napierala if (pid > 0) 652009ea47eSEdward Tomasz Napierala continue; 653009ea47eSEdward Tomasz Napierala } 654009ea47eSEdward Tomasz Napierala 655009ea47eSEdward Tomasz Napierala pidfile_close(pidfh); 6567843bd03SEdward Tomasz Napierala handle_request(iscsi_fd, &request, timeout); 657009ea47eSEdward Tomasz Napierala } 658009ea47eSEdward Tomasz Napierala 659009ea47eSEdward Tomasz Napierala return (0); 660009ea47eSEdward Tomasz Napierala } 661