1 /*
2  * Copyright (C) 2008-2015 Daisuke Aoyama <aoyama@peach.ne.jp>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <inttypes.h>
33 #include <stdint.h>
34 
35 #include <errno.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <poll.h>
41 #include <pthread.h>
42 #ifdef HAVE_PTHREAD_NP_H
43 #include <pthread_np.h>
44 #endif
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <signal.h>
48 
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 
53 #include "istgt.h"
54 #include "istgt_ver.h"
55 #include "istgt_log.h"
56 #include "istgt_conf.h"
57 #include "istgt_sock.h"
58 #include "istgt_misc.h"
59 #include "istgt_crc32c.h"
60 #include "istgt_iscsi.h"
61 #include "istgt_lu.h"
62 #include "istgt_proto.h"
63 
64 #ifdef ISTGT_USE_KQUEUE
65 #include <sys/types.h>
66 #include <sys/event.h>
67 #include <sys/time.h>
68 #endif
69 
70 #if !defined(__GNUC__)
71 #undef __attribute__
72 #define __attribute__(x)
73 #endif
74 
75 #define POLLWAIT 5000
76 #define PORTNUMLEN 32
77 
78 ISTGT g_istgt;
79 
80 static int
istgt_parse_portal(const char * portal,char ** host,char ** port)81 istgt_parse_portal(const char *portal, char **host, char **port)
82 {
83 	const char *p;
84 	int n;
85 
86 	if (portal == NULL) {
87 		ISTGT_ERRLOG("portal error\n");
88 		return -1;
89 	}
90 
91 	if (portal[0] == '[') {
92 		/* IPv6 */
93 		p = strchr(portal + 1, ']');
94 		if (p == NULL) {
95 			ISTGT_ERRLOG("portal error\n");
96 			return -1;
97 		}
98 		p++;
99 		n = p - portal;
100 		if (host != NULL) {
101 			*host = xmalloc(n + 1);
102 			memcpy(*host, portal, n);
103 			(*host)[n] = '\0';
104 		}
105 		if (p[0] == '\0') {
106 			if (port != NULL) {
107 				*port = xmalloc(PORTNUMLEN);
108 				snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT);
109 			}
110 		} else {
111 			if (p[0] != ':') {
112 				ISTGT_ERRLOG("portal error\n");
113 				if (host != NULL)
114 					xfree(*host);
115 				return -1;
116 			}
117 			if (port != NULL)
118 				*port = xstrdup(p + 1);
119 		}
120 	} else {
121 		/* IPv4 */
122 		p = strchr(portal, ':');
123 		if (p == NULL) {
124 			p = portal + strlen(portal);
125 		}
126 		n = p - portal;
127 		if (host != NULL) {
128 			*host = xmalloc(n + 1);
129 			memcpy(*host, portal, n);
130 			(*host)[n] = '\0';
131 		}
132 		if (p[0] == '\0') {
133 			if (port != NULL) {
134 				*port = xmalloc(PORTNUMLEN);
135 				snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT);
136 			}
137 		} else {
138 			if (p[0] != ':') {
139 				ISTGT_ERRLOG("portal error\n");
140 				if (host != NULL)
141 					xfree(*host);
142 				return -1;
143 			}
144 			if (port != NULL)
145 				*port = xstrdup(p + 1);
146 		}
147 	}
148 	return 0;
149 }
150 
151 static int
istgt_add_portal_group(ISTGT_Ptr istgt,CF_SECTION * sp,int * pgp_idx)152 istgt_add_portal_group(ISTGT_Ptr istgt, CF_SECTION *sp, int *pgp_idx)
153 {
154 	const char *val;
155 	char *label, *portal, *host, *port;
156 	int alloc_len;
157 	int idx, free_idx;
158 	int portals;
159 	int rc;
160 	int i;
161 
162 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add portal group %d\n", sp->num);
163 
164 	val = istgt_get_val(sp, "Comment");
165 	if (val != NULL) {
166 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
167 	}
168 
169 	/* counts number of definition */
170 	for (i = 0; ; i++) {
171 		label = istgt_get_nmval(sp, "Portal", i, 0);
172 		portal = istgt_get_nmval(sp, "Portal", i, 1);
173 		if (label == NULL || portal == NULL)
174 			break;
175 		rc = istgt_parse_portal(portal, NULL, NULL);
176 		if (rc < 0) {
177 			ISTGT_ERRLOG("parse portal error (%s)\n", portal);
178 			return -1;
179 		}
180 	}
181 	portals = i;
182 	if (portals > MAX_PORTAL) {
183 		ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals);
184 		return -1;
185 	}
186 
187 	MTX_LOCK(&istgt->mutex);
188 	idx = istgt->nportal_group;
189 	free_idx = -1;
190 	for (i = 0; i < istgt->nportal_group; i++) {
191 		if (istgt->portal_group[i].tag != 0)
192 			continue;
193 		if (istgt->portal_group[i].nportals == portals) {
194 			free_idx = i;
195 			break;
196 		}
197 	}
198 	if (free_idx >= 0)
199 		idx = free_idx;
200 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
201 	    "Index=%d, Tag=%d, Portals=%d\n",
202 	    idx, sp->num, portals);
203 	if (idx < MAX_PORTAL_GROUP) {
204 		if (free_idx < 0) {
205 			istgt->portal_group[idx].nportals = portals;
206 			alloc_len = sizeof (PORTAL *) * portals;
207 			istgt->portal_group[idx].portals = xmalloc(alloc_len);
208 		}
209 		istgt->portal_group[idx].ref = 0;
210 		istgt->portal_group[idx].idx = idx;
211 		istgt->portal_group[idx].tag = sp->num;
212 
213 		for (i = 0; i < portals; i++) {
214 			label = istgt_get_nmval(sp, "Portal", i, 0);
215 			portal = istgt_get_nmval(sp, "Portal", i, 1);
216 			if (label == NULL || portal == NULL) {
217 				if (free_idx < 0) {
218 					xfree(istgt->portal_group[idx].portals);
219 					istgt->portal_group[idx].nportals = 0;
220 				}
221 				istgt->portal_group[idx].tag = 0;
222 				MTX_UNLOCK(&istgt->mutex);
223 				ISTGT_ERRLOG("portal error\n");
224 				return -1;
225 			}
226 			rc = istgt_parse_portal(portal, &host, &port);
227 			if (rc < 0) {
228 				if (free_idx < 0) {
229 					xfree(istgt->portal_group[idx].portals);
230 					istgt->portal_group[idx].nportals = 0;
231 				}
232 				istgt->portal_group[idx].tag = 0;
233 				MTX_UNLOCK(&istgt->mutex);
234 				ISTGT_ERRLOG("parse portal error (%s)\n", portal);
235 				return -1;
236 			}
237 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
238 			    "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
239 			    i, host, port, sp->num);
240 
241 			if (free_idx < 0) {
242 				istgt->portal_group[idx].portals[i] = xmalloc(sizeof (PORTAL));
243 			} else {
244 				xfree(istgt->portal_group[idx].portals[i]->label);
245 				xfree(istgt->portal_group[idx].portals[i]->host);
246 				xfree(istgt->portal_group[idx].portals[i]->port);
247 			}
248 			istgt->portal_group[idx].portals[i]->label = xstrdup(label);
249 			istgt->portal_group[idx].portals[i]->host = host;
250 			istgt->portal_group[idx].portals[i]->port = port;
251 			istgt->portal_group[idx].portals[i]->ref = 0;
252 			istgt->portal_group[idx].portals[i]->idx = i;
253 			istgt->portal_group[idx].portals[i]->tag = sp->num;
254 			istgt->portal_group[idx].portals[i]->sock = -1;
255                 }
256 
257 		if (pgp_idx != NULL)
258 			*pgp_idx = idx;
259 		if (free_idx < 0) {
260 			idx++;
261 			istgt->nportal_group = idx;
262 		}
263 	} else {
264 		MTX_UNLOCK(&istgt->mutex);
265 		ISTGT_ERRLOG("nportal_group(%d) >= MAX_PORTAL_GROUP\n", idx);
266 		return -1;
267 	}
268 	MTX_UNLOCK(&istgt->mutex);
269 	return 0;
270 }
271 
272 static int
istgt_pg_match_all(PORTAL_GROUP * pgp,CF_SECTION * sp)273 istgt_pg_match_all(PORTAL_GROUP *pgp, CF_SECTION *sp)
274 {
275 	char *label, *portal, *host, *port;
276 	int rc;
277 	int i;
278 
279 	for (i = 0; i < pgp->nportals; i++) {
280 		label = istgt_get_nmval(sp, "Portal", i, 0);
281 		portal = istgt_get_nmval(sp, "Portal", i, 1);
282 		if (label == NULL || portal == NULL)
283 			return 0;
284 		rc = istgt_parse_portal(portal, &host, &port);
285 		if (rc < 0)
286 			return 0;
287 		if (strcmp(pgp->portals[i]->label, label) != 0)
288 			return 0;
289 		if (strcmp(pgp->portals[i]->host, host) != 0)
290 			return 0;
291 		if (strcmp(pgp->portals[i]->port, port) != 0)
292 			return 0;
293 	}
294 	label = istgt_get_nmval(sp, "Portal", i, 0);
295 	portal = istgt_get_nmval(sp, "Portal", i, 1);
296 	if (label != NULL || portal != NULL)
297 		return 0;
298 	return 1;
299 }
300 
301 static int
istgt_update_portal_group(ISTGT_Ptr istgt,CF_SECTION * sp,int * pgp_idx)302 istgt_update_portal_group(ISTGT_Ptr istgt, CF_SECTION *sp, int *pgp_idx)
303 {
304 	const char *val;
305 	char *label, *portal, *host, *port;
306 	int alloc_len;
307 	int idx, free_idx;
308 	int portals;
309 	int rc;
310 	int i;
311 
312 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "update portal group %d\n", sp->num);
313 
314 	val = istgt_get_val(sp, "Comment");
315 	if (val != NULL) {
316 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
317 	}
318 
319 	/* counts number of definition */
320 	for (i = 0; ; i++) {
321 		label = istgt_get_nmval(sp, "Portal", i, 0);
322 		portal = istgt_get_nmval(sp, "Portal", i, 1);
323 		if (label == NULL || portal == NULL)
324 			break;
325 		rc = istgt_parse_portal(portal, NULL, NULL);
326 		if (rc < 0) {
327 			ISTGT_ERRLOG("parse portal error (%s)\n", portal);
328 			return -1;
329 		}
330 	}
331 	portals = i;
332 	if (portals > MAX_PORTAL) {
333 		ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals);
334 		return -1;
335 	}
336 
337 	MTX_LOCK(&istgt->mutex);
338 	idx = -1;
339 	for (i = 0; i < istgt->nportal_group; i++) {
340 		if (istgt->portal_group[i].tag == sp->num) {
341 			idx = i;
342 			break;
343 		}
344 	}
345 	if (idx < 0) {
346 		MTX_UNLOCK(&istgt->mutex);
347 		ISTGT_ERRLOG("can't find PG%d\n", sp->num);
348 		return -1;
349 	}
350 	if (istgt_pg_match_all(&istgt->portal_group[i], sp)) {
351 		MTX_UNLOCK(&istgt->mutex);
352 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip for PG%d\n", sp->num);
353 		return 0;
354 	}
355 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
356 	    "Index=%d, Tag=%d, Portals=%d\n",
357 	    idx, sp->num, portals);
358 	if (istgt->portal_group[idx].nportals == portals) {
359 		/* udpate PG */
360 		for (i = 0; i < portals; i++) {
361 			label = istgt_get_nmval(sp, "Portal", i, 0);
362 			portal = istgt_get_nmval(sp, "Portal", i, 1);
363 			if (label == NULL || portal == NULL) {
364 				xfree(istgt->portal_group[idx].portals);
365 				istgt->portal_group[idx].nportals = 0;
366 				istgt->portal_group[idx].tag = 0;
367 				MTX_UNLOCK(&istgt->mutex);
368 				ISTGT_ERRLOG("portal error\n");
369 				return -1;
370 			}
371 			rc = istgt_parse_portal(portal, &host, &port);
372 			if (rc < 0) {
373 				xfree(istgt->portal_group[idx].portals);
374 				istgt->portal_group[idx].nportals = 0;
375 				istgt->portal_group[idx].tag = 0;
376 				MTX_UNLOCK(&istgt->mutex);
377 				ISTGT_ERRLOG("parse portal error (%s)\n", portal);
378 				return -1;
379 			}
380 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
381 			    "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
382 			    i, host, port, sp->num);
383 
384 			/* free old PG */
385 			xfree(istgt->portal_group[idx].portals[i]->label);
386 			xfree(istgt->portal_group[idx].portals[i]->host);
387 			xfree(istgt->portal_group[idx].portals[i]->port);
388 
389 			/* allocate new PG */
390 			istgt->portal_group[idx].portals[i]->label = xstrdup(label);
391 			istgt->portal_group[idx].portals[i]->host = host;
392 			istgt->portal_group[idx].portals[i]->port = port;
393 			//istgt->portal_group[idx].portals[i]->ref = 0;
394 			//istgt->portal_group[idx].portals[i]->idx = i;
395 			//istgt->portal_group[idx].portals[i]->tag = sp->num;
396 			//istgt->portal_group[idx].portals[i]->sock = -1;
397                 }
398 		if (pgp_idx != NULL)
399 			*pgp_idx = idx;
400 	} else {
401 		/* mark as free */
402 		istgt->portal_group[*pgp_idx].tag = 0;
403 
404 		/* allocate new PG */
405 		idx = istgt->nportal_group;
406 		free_idx = -1;
407 		for (i = 0; i < istgt->nportal_group; i++) {
408 			if (istgt->portal_group[i].tag != 0)
409 				continue;
410 			if (istgt->portal_group[i].nportals == portals) {
411 				free_idx = i;
412 				break;
413 			}
414 		}
415 		if (free_idx >= 0)
416 			idx = free_idx;
417 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
418 		    "Index=%d, Tag=%d, Portals=%d -> %d\n",
419 		    idx, sp->num, istgt->portal_group[*pgp_idx].nportals, portals);
420 		if (idx < MAX_PORTAL_GROUP) {
421 			if (free_idx < 0) {
422 				istgt->portal_group[idx].nportals = portals;
423 				alloc_len = sizeof (PORTAL *) * portals;
424 				istgt->portal_group[idx].portals = xmalloc(alloc_len);
425 			}
426 			istgt->portal_group[idx].ref = istgt->portal_group[*pgp_idx].ref;
427 			istgt->portal_group[idx].idx = idx;
428 			istgt->portal_group[idx].tag = sp->num;
429 
430 			for (i = 0; i < portals; i++) {
431 				label = istgt_get_nmval(sp, "Portal", i, 0);
432 				portal = istgt_get_nmval(sp, "Portal", i, 1);
433 				if (label == NULL || portal == NULL) {
434 					if (free_idx < 0) {
435 						xfree(istgt->portal_group[idx].portals);
436 						istgt->portal_group[idx].nportals = 0;
437 					}
438 					istgt->portal_group[idx].tag = 0;
439 					MTX_UNLOCK(&istgt->mutex);
440 					ISTGT_ERRLOG("portal error\n");
441 					return -1;
442 				}
443 				rc = istgt_parse_portal(portal, &host, &port);
444 				if (rc < 0) {
445 					if (free_idx < 0) {
446 						xfree(istgt->portal_group[idx].portals);
447 						istgt->portal_group[idx].nportals = 0;
448 					}
449 					istgt->portal_group[idx].tag = 0;
450 					MTX_UNLOCK(&istgt->mutex);
451 					ISTGT_ERRLOG("parse portal error (%s)\n", portal);
452 					return -1;
453 				}
454 				ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
455 				    "RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
456 				    i, host, port, sp->num);
457 
458 				if (free_idx < 0) {
459 					istgt->portal_group[idx].portals[i] = xmalloc(sizeof (PORTAL));
460 				} else {
461 					xfree(istgt->portal_group[idx].portals[i]->label);
462 					xfree(istgt->portal_group[idx].portals[i]->host);
463 					xfree(istgt->portal_group[idx].portals[i]->port);
464 				}
465 				istgt->portal_group[idx].portals[i]->label = xstrdup(label);
466 				istgt->portal_group[idx].portals[i]->host = host;
467 				istgt->portal_group[idx].portals[i]->port = port;
468 				istgt->portal_group[idx].portals[i]->ref = 0;
469 				istgt->portal_group[idx].portals[i]->idx = i;
470 				istgt->portal_group[idx].portals[i]->tag = sp->num;
471 				istgt->portal_group[idx].portals[i]->sock = -1;
472 			}
473 
474 			if (pgp_idx != NULL)
475 				*pgp_idx = idx;
476 			if (free_idx < 0) {
477 				idx++;
478 				istgt->nportal_group = idx;
479 			}
480 		} else {
481 			MTX_UNLOCK(&istgt->mutex);
482 			ISTGT_ERRLOG("nportal_group(%d) >= MAX_PORTAL_GROUP\n", idx);
483 			return -1;
484 		}
485 	}
486 	MTX_UNLOCK(&istgt->mutex);
487 	return 1;
488 }
489 
490 static int
istgt_build_portal_group_array(ISTGT_Ptr istgt)491 istgt_build_portal_group_array(ISTGT_Ptr istgt)
492 {
493 	CF_SECTION *sp;
494 	int rc;
495 
496 	sp = istgt->config->section;
497 	while (sp != NULL) {
498 		if (sp->type == ST_PORTALGROUP) {
499 			if (sp->num == 0) {
500 				ISTGT_ERRLOG("Group 0 is invalid\n");
501 				return -1;
502 			}
503 			rc = istgt_add_portal_group(istgt, sp, NULL);
504 			if (rc < 0) {
505 				ISTGT_ERRLOG("add_portal_group() failed\n");
506 				return -1;
507 			}
508 		}
509 		sp = sp->next;
510 	}
511 	return 0;
512 }
513 
514 static void
istgt_destroy_portal_group_array(ISTGT_Ptr istgt)515 istgt_destroy_portal_group_array(ISTGT_Ptr istgt)
516 {
517 	int i, j;
518 
519 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destory_portal_group_array\n");
520 	MTX_LOCK(&istgt->mutex);
521 	for (i = 0; i < istgt->nportal_group; i++) {
522 		for (j = 0; j < istgt->portal_group[i].nportals; j++) {
523 			xfree(istgt->portal_group[i].portals[j]->label);
524 			xfree(istgt->portal_group[i].portals[j]->host);
525 			xfree(istgt->portal_group[i].portals[j]->port);
526 			xfree(istgt->portal_group[i].portals[j]);
527 		}
528 		xfree(istgt->portal_group[i].portals);
529 
530 		istgt->portal_group[i].nportals = 0;
531 		istgt->portal_group[i].portals = NULL;
532 		istgt->portal_group[i].ref = 0;
533 		istgt->portal_group[i].idx = i;
534 		istgt->portal_group[i].tag = 0;
535 	}
536 	istgt->nportal_group = 0;
537 	MTX_UNLOCK(&istgt->mutex);
538 }
539 
540 static int
istgt_open_portal_group(PORTAL_GROUP * pgp)541 istgt_open_portal_group(PORTAL_GROUP *pgp)
542 {
543 	int port;
544 	int sock;
545 	int i;
546 
547 	for (i = 0; i < pgp->nportals; i++) {
548 		if (pgp->portals[i]->sock < 0) {
549 			ISTGT_TRACELOG(ISTGT_TRACE_NET, "open host %s, port %s, tag %d\n",
550 			    pgp->portals[i]->host, pgp->portals[i]->port,
551 			    pgp->portals[i]->tag);
552 			port = (int)strtol(pgp->portals[i]->port, NULL, 0);
553 			sock = istgt_listen(pgp->portals[i]->host, port);
554 			if (sock < 0) {
555 				ISTGT_ERRLOG("listen error %.64s:%d\n",
556 				    pgp->portals[i]->host, port);
557 				return -1;
558 			}
559 			pgp->portals[i]->sock = sock;
560 		}
561 	}
562 	return 0;
563 }
564 
565 static int
istgt_open_all_portals(ISTGT_Ptr istgt)566 istgt_open_all_portals(ISTGT_Ptr istgt)
567 {
568 	int rc;
569 	int i;
570 
571 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_portal\n");
572 	MTX_LOCK(&istgt->mutex);
573 	for (i = 0; i < istgt->nportal_group; i++) {
574 		rc = istgt_open_portal_group(&istgt->portal_group[i]);
575 		if (rc < 0) {
576 			MTX_UNLOCK(&istgt->mutex);
577 			return -1;
578 		}
579 	}
580 	MTX_UNLOCK(&istgt->mutex);
581 	return 0;
582 }
583 
584 static int
istgt_close_portal_group(PORTAL_GROUP * pgp)585 istgt_close_portal_group(PORTAL_GROUP *pgp)
586 {
587 	int i;
588 
589 	for (i = 0; i < pgp->nportals; i++) {
590 		if (pgp->portals[i]->sock >= 0) {
591 			ISTGT_TRACELOG(ISTGT_TRACE_NET, "close host %s, port %s, tag %d\n",
592 			    pgp->portals[i]->host, pgp->portals[i]->port,
593 			    pgp->portals[i]->tag);
594 			close(pgp->portals[i]->sock);
595 			pgp->portals[i]->sock = -1;
596 		}
597 	}
598 	return 0;
599 }
600 
601 static int
istgt_close_all_portals(ISTGT_Ptr istgt)602 istgt_close_all_portals(ISTGT_Ptr istgt)
603 {
604 	int rc;
605 	int i;
606 
607 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_portal\n");
608 	MTX_LOCK(&istgt->mutex);
609 	for (i = 0; i < istgt->nportal_group; i++) {
610 		rc = istgt_close_portal_group(&istgt->portal_group[i]);
611 		if (rc < 0) {
612 			MTX_UNLOCK(&istgt->mutex);
613 			return -1;
614 		}
615 	}
616 	MTX_UNLOCK(&istgt->mutex);
617 	return 0;
618 }
619 
620 static int
istgt_add_initiator_group(ISTGT_Ptr istgt,CF_SECTION * sp)621 istgt_add_initiator_group(ISTGT_Ptr istgt, CF_SECTION *sp)
622 {
623 	const char *val;
624 	int alloc_len;
625 	int idx;
626 	int names;
627 	int masks;
628 	int i;
629 
630 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add initiator group %d\n", sp->num);
631 
632 	val = istgt_get_val(sp, "Comment");
633 	if (val != NULL) {
634 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
635 	}
636 
637 	/* counts number of definition */
638 	for (i = 0; ; i++) {
639 		val = istgt_get_nval(sp, "InitiatorName", i);
640 		if (val == NULL)
641 			break;
642 	}
643 	names = i;
644 	if (names > MAX_INITIATOR) {
645 		ISTGT_ERRLOG("%d > MAX_INITIATOR\n", names);
646 		return -1;
647 	}
648 	for (i = 0; ; i++) {
649 		val = istgt_get_nval(sp, "Netmask", i);
650 		if (val == NULL)
651 			break;
652 	}
653 	masks = i;
654 	if (masks > MAX_NETMASK) {
655 		ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks);
656 		return -1;
657 	}
658 
659 	MTX_LOCK(&istgt->mutex);
660 	idx = istgt->ninitiator_group;
661 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
662 	    "Index=%d, Tag=%d, Names=%d, Masks=%d\n",
663 	    idx, sp->num, names, masks);
664 	if (idx < MAX_INITIATOR_GROUP) {
665 		istgt->initiator_group[idx].ninitiators = names;
666 		alloc_len = sizeof (char *) * names;
667 		istgt->initiator_group[idx].initiators = xmalloc(alloc_len);
668 		istgt->initiator_group[idx].nnetmasks = masks;
669 		alloc_len = sizeof (char *) * masks;
670 		istgt->initiator_group[idx].netmasks = xmalloc(alloc_len);
671 		istgt->initiator_group[idx].ref = 0;
672 		istgt->initiator_group[idx].idx = idx;
673 		istgt->initiator_group[idx].tag = sp->num;
674 
675 		for (i = 0; i < names; i++) {
676 			val = istgt_get_nval(sp, "InitiatorName", i);
677 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
678 			    "InitiatorName %s\n", val);
679 			istgt->initiator_group[idx].initiators[i] = xstrdup(val);
680 		}
681 		for (i = 0; i < masks; i++) {
682 			val = istgt_get_nval(sp, "Netmask", i);
683 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val);
684 			istgt->initiator_group[idx].netmasks[i] = xstrdup(val);
685 		}
686 
687 		idx++;
688 		istgt->ninitiator_group = idx;
689 	} else {
690 		MTX_UNLOCK(&istgt->mutex);
691 		ISTGT_ERRLOG("ninitiator_group(%d) >= MAX_INITIATOR_GROUP\n", idx);
692 		return -1;
693 	}
694 	MTX_UNLOCK(&istgt->mutex);
695 	return 0;
696 }
697 
698 static int
istgt_ig_match_all(INITIATOR_GROUP * igp,CF_SECTION * sp)699 istgt_ig_match_all(INITIATOR_GROUP *igp, CF_SECTION *sp)
700 {
701 	const char *val;
702 	int i;
703 
704 	for (i = 0; i < igp->ninitiators; i++) {
705 		val = istgt_get_nval(sp, "InitiatorName", i);
706 		if (val == NULL)
707 			return 0;
708 		if (strcmp(igp->initiators[i], val) != 0)
709 			return 0;
710 	}
711 	val = istgt_get_nval(sp, "InitiatorName", i);
712 	if (val != NULL)
713 		return 0;
714 	for (i = 0; i < igp->nnetmasks; i++) {
715 		val = istgt_get_nval(sp, "Netmask", i);
716 		if (val == NULL)
717 			return 0;
718 		if (strcmp(igp->netmasks[i], val) != 0)
719 			return 0;
720 	}
721 	val = istgt_get_nval(sp, "Netmask", i);
722 	if (val != NULL)
723 		return 0;
724 	return 1;
725 }
726 
727 static int
istgt_update_initiator_group(ISTGT_Ptr istgt,CF_SECTION * sp)728 istgt_update_initiator_group(ISTGT_Ptr istgt, CF_SECTION *sp)
729 {
730 	const char *val;
731 	int alloc_len;
732 	int idx;
733 	int names;
734 	int masks;
735 	int i;
736 
737 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "update initiator group %d\n", sp->num);
738 
739 	val = istgt_get_val(sp, "Comment");
740 	if (val != NULL) {
741 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
742 	}
743 
744 	/* counts number of definition */
745 	for (i = 0; ; i++) {
746 		val = istgt_get_nval(sp, "InitiatorName", i);
747 		if (val == NULL)
748 			break;
749 	}
750 	names = i;
751 	if (names > MAX_INITIATOR) {
752 		ISTGT_ERRLOG("%d > MAX_INITIATOR\n", names);
753 		return -1;
754 	}
755 	for (i = 0; ; i++) {
756 		val = istgt_get_nval(sp, "Netmask", i);
757 		if (val == NULL)
758 			break;
759 	}
760 	masks = i;
761 	if (masks > MAX_NETMASK) {
762 		ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks);
763 		return -1;
764 	}
765 
766 	MTX_LOCK(&istgt->mutex);
767 	idx = -1;
768 	for (i = 0; i < istgt->ninitiator_group; i++) {
769 		if (istgt->initiator_group[i].tag == sp->num) {
770 			idx = i;
771 			break;
772 		}
773 	}
774 	if (idx < 0) {
775 		MTX_UNLOCK(&istgt->mutex);
776 		ISTGT_ERRLOG("can't find IG%d\n", sp->num);
777 		return -1;
778 	}
779 	if (istgt_ig_match_all(&istgt->initiator_group[i], sp)) {
780 		MTX_UNLOCK(&istgt->mutex);
781 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip for IG%d\n", sp->num);
782 		return 0;
783 	}
784 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
785 	    "Index=%d, Tag=%d, Names=%d, Masks=%d\n",
786 	    idx, sp->num, names, masks);
787 
788 	/* free old IG */
789 	for (i = 0; i < istgt->initiator_group[idx].ninitiators; i++) {
790 		xfree(istgt->initiator_group[idx].initiators[i]);
791 	}
792 	xfree(istgt->initiator_group[idx].initiators);
793 	for (i = 0; i < istgt->initiator_group[idx].nnetmasks; i++) {
794 		xfree(istgt->initiator_group[idx].netmasks[i]);
795 	}
796 	xfree(istgt->initiator_group[idx].netmasks);
797 
798 	/* allocate new IG */
799 	istgt->initiator_group[idx].ninitiators = names;
800 	alloc_len = sizeof (char *) * names;
801 	istgt->initiator_group[idx].initiators = xmalloc(alloc_len);
802 	istgt->initiator_group[idx].nnetmasks = masks;
803 	alloc_len = sizeof (char *) * masks;
804 	istgt->initiator_group[idx].netmasks = xmalloc(alloc_len);
805 	//istgt->initiator_group[idx].ref = 0;
806 	//istgt->initiator_group[idx].idx = idx;
807 	//istgt->initiator_group[idx].tag = sp->num;
808 
809 	/* copy new strings */
810 	for (i = 0; i < names; i++) {
811 		val = istgt_get_nval(sp, "InitiatorName", i);
812 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
813 		    "InitiatorName %s\n", val);
814 		istgt->initiator_group[idx].initiators[i] = xstrdup(val);
815 	}
816 	for (i = 0; i < masks; i++) {
817 		val = istgt_get_nval(sp, "Netmask", i);
818 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val);
819 		istgt->initiator_group[idx].netmasks[i] = xstrdup(val);
820 	}
821 	MTX_UNLOCK(&istgt->mutex);
822 	return 1;
823 }
824 
825 static int
istgt_build_initiator_group_array(ISTGT_Ptr istgt)826 istgt_build_initiator_group_array(ISTGT_Ptr istgt)
827 {
828 	CF_SECTION *sp;
829 	int rc;
830 
831 	sp = istgt->config->section;
832 	while (sp != NULL) {
833 		if (sp->type == ST_INITIATORGROUP) {
834 			if (sp->num == 0) {
835 				ISTGT_ERRLOG("Group 0 is invalid\n");
836 				return -1;
837 			}
838 			rc = istgt_add_initiator_group(istgt, sp);
839 			if (rc < 0) {
840 				ISTGT_ERRLOG("add_initiator_group() failed\n");
841 				return -1;
842 			}
843 		}
844 		sp = sp->next;
845 	}
846 	return 0;
847 }
848 
849 static void
istgt_destory_initiator_group_array(ISTGT_Ptr istgt)850 istgt_destory_initiator_group_array(ISTGT_Ptr istgt)
851 {
852 	int i, j;
853 
854 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destory_initiator_group_array\n");
855 	MTX_LOCK(&istgt->mutex);
856 	for (i = 0; i < istgt->ninitiator_group; i++) {
857 		for (j = 0; j < istgt->initiator_group[i].ninitiators; j++) {
858 			xfree(istgt->initiator_group[i].initiators[j]);
859 		}
860 		xfree(istgt->initiator_group[i].initiators);
861 		for (j = 0; j < istgt->initiator_group[i].nnetmasks; j++) {
862 			xfree(istgt->initiator_group[i].netmasks[j]);
863 		}
864 		xfree(istgt->initiator_group[i].netmasks);
865 
866 		istgt->initiator_group[i].ninitiators = 0;
867 		istgt->initiator_group[i].initiators = NULL;
868 		istgt->initiator_group[i].nnetmasks = 0;
869 		istgt->initiator_group[i].netmasks = NULL;
870 		istgt->initiator_group[i].ref = 0;
871 		istgt->initiator_group[i].idx = i;
872 		istgt->initiator_group[i].tag = 0;
873 	}
874 	istgt->ninitiator_group = 0;
875 	MTX_UNLOCK(&istgt->mutex);
876 }
877 
878 static int
istgt_build_uctl_portal(ISTGT_Ptr istgt)879 istgt_build_uctl_portal(ISTGT_Ptr istgt)
880 {
881 	CF_SECTION *sp;
882 	const char *val;
883 	char *label, *portal, *host, *port;
884 	int tag;
885 	int idx;
886 	int rc;
887 	int i;
888 
889 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_build_uctl_portal\n");
890 
891 	sp = istgt_find_cf_section(istgt->config, "UnitControl");
892 	if (sp == NULL) {
893 		ISTGT_ERRLOG("find_cf_section failed()\n");
894 		return -1;
895 	}
896 
897 	for (i = 0; ; i++) {
898 		val = istgt_get_nval(sp, "Portal", i);
899 		if (val == NULL)
900 			break;
901 
902 		label = istgt_get_nmval(sp, "Portal", i, 0);
903 		portal = istgt_get_nmval(sp, "Portal", i, 1);
904 		if (label == NULL || portal == NULL) {
905 			ISTGT_ERRLOG("uctl portal error\n");
906 			return -1;
907 		}
908 
909 		rc = istgt_parse_portal(portal, &host, &port);
910 		if (rc < 0) {
911 			ISTGT_ERRLOG("parse uctl portal error\n");
912 			return -1;
913 		}
914 
915 		idx = istgt->nuctl_portal;
916 		tag = ISTGT_UC_TAG;
917 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
918 		    "Index=%d, Host=%s, Port=%s, Tag=%d\n",
919 		    idx, host, port, tag);
920 		if (idx < MAX_UCPORTAL) {
921 			istgt->uctl_portal[idx].label = xstrdup(label);
922 			istgt->uctl_portal[idx].host = host;
923 			istgt->uctl_portal[idx].port = port;
924 			istgt->uctl_portal[idx].ref = 0;
925 			istgt->uctl_portal[idx].idx = idx;
926 			istgt->uctl_portal[idx].tag = tag;
927 			istgt->uctl_portal[idx].sock = -1;
928 			idx++;
929 			istgt->nuctl_portal = idx;
930 		} else {
931 			ISTGT_ERRLOG("nportal(%d) >= MAX_UCPORTAL\n", idx);
932 			xfree(host);
933 			xfree(port);
934 			return -1;
935 		}
936 	}
937 
938 	return 0;
939 }
940 
941 static void
istgt_destroy_uctl_portal(ISTGT_Ptr istgt)942 istgt_destroy_uctl_portal(ISTGT_Ptr istgt)
943 {
944 	int i;
945 
946 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destroy_uctl_portal\n");
947 	for (i = 0; i < istgt->nuctl_portal; i++) {
948 		xfree(istgt->uctl_portal[i].label);
949 		xfree(istgt->uctl_portal[i].host);
950 		xfree(istgt->uctl_portal[i].port);
951 
952 		istgt->uctl_portal[i].label = NULL;
953 		istgt->uctl_portal[i].host = NULL;
954 		istgt->uctl_portal[i].port = NULL;
955 		istgt->uctl_portal[i].ref = 0;
956 		istgt->uctl_portal[i].idx = i;
957 		istgt->uctl_portal[i].tag = 0;
958 	}
959 	istgt->nuctl_portal = 0;
960 }
961 
962 static int
istgt_open_uctl_portal(ISTGT_Ptr istgt)963 istgt_open_uctl_portal(ISTGT_Ptr istgt)
964 {
965 	int port;
966 	int sock;
967 	int i;
968 
969 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_uctl_portal\n");
970 	for (i = 0; i < istgt->nuctl_portal; i++) {
971 		if (istgt->uctl_portal[i].sock < 0) {
972 			ISTGT_TRACELOG(ISTGT_TRACE_NET,
973 			    "open host %s, port %s, tag %d\n",
974 			    istgt->uctl_portal[i].host,
975 			    istgt->uctl_portal[i].port,
976 			    istgt->uctl_portal[i].tag);
977 			port = (int)strtol(istgt->uctl_portal[i].port, NULL, 0);
978 			sock = istgt_listen(istgt->uctl_portal[i].host, port);
979 			if (sock < 0) {
980 				ISTGT_ERRLOG("listen error %.64s:%d\n",
981 				    istgt->uctl_portal[i].host, port);
982 				return -1;
983 			}
984 			istgt->uctl_portal[i].sock = sock;
985 		}
986 	}
987 	return 0;
988 }
989 
990 static int
istgt_close_uctl_portal(ISTGT_Ptr istgt)991 istgt_close_uctl_portal(ISTGT_Ptr istgt)
992 {
993 	int i;
994 
995 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_uctl_portal\n");
996 	for (i = 0; i < istgt->nuctl_portal; i++) {
997 		if (istgt->uctl_portal[i].sock >= 0) {
998 			ISTGT_TRACELOG(ISTGT_TRACE_NET,
999 			    "close host %s, port %s, tag %d\n",
1000 			    istgt->uctl_portal[i].host,
1001 			    istgt->uctl_portal[i].port,
1002 			    istgt->uctl_portal[i].tag);
1003 			close(istgt->uctl_portal[i].sock);
1004 			istgt->uctl_portal[i].sock = -1;
1005 		}
1006 	}
1007 	return 0;
1008 }
1009 
1010 static int
istgt_write_pidfile(ISTGT_Ptr istgt)1011 istgt_write_pidfile(ISTGT_Ptr istgt)
1012 {
1013 	FILE *fp;
1014 	pid_t pid;
1015 	int rc;
1016 
1017 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_write_pidfile\n");
1018 	rc = remove(istgt->pidfile);
1019 	if (rc != 0) {
1020 		if (errno != ENOENT) {
1021 			ISTGT_ERRLOG("pidfile remove error %d\n", errno);
1022 			return -1;
1023 		}
1024 	}
1025 	fp = fopen(istgt->pidfile, "w");
1026 	if (fp == NULL) {
1027 		ISTGT_ERRLOG("pidfile open error %d\n", errno);
1028 		return -1;
1029 	}
1030 	pid = getpid();
1031 	fprintf(fp, "%d\n", (int)pid);
1032 	fclose(fp);
1033 	return 0;
1034 }
1035 
1036 static void
istgt_remove_pidfile(ISTGT_Ptr istgt)1037 istgt_remove_pidfile(ISTGT_Ptr istgt)
1038 {
1039 	int rc;
1040 
1041 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_remove_pidfile\n");
1042 	rc = remove(istgt->pidfile);
1043 	if (rc != 0) {
1044 		ISTGT_ERRLOG("pidfile remove error %d\n", errno);
1045 		/* ignore error */
1046 	}
1047 }
1048 
1049 char *
istgt_get_nmval(CF_SECTION * sp,const char * key,int idx1,int idx2)1050 istgt_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2)
1051 {
1052 	CF_ITEM *ip;
1053 	CF_VALUE *vp;
1054 	int i;
1055 
1056 	ip = istgt_find_cf_nitem(sp, key, idx1);
1057 	if (ip == NULL)
1058 		return NULL;
1059 	vp = ip->val;
1060 	if (vp == NULL)
1061 		return NULL;
1062 	for (i = 0; vp != NULL; vp = vp->next) {
1063 		if (i == idx2)
1064 			return vp->value;
1065 		i++;
1066 	}
1067 	return NULL;
1068 }
1069 
1070 char *
istgt_get_nval(CF_SECTION * sp,const char * key,int idx)1071 istgt_get_nval(CF_SECTION *sp, const char *key, int idx)
1072 {
1073 	CF_ITEM *ip;
1074 	CF_VALUE *vp;
1075 
1076 	ip = istgt_find_cf_nitem(sp, key, idx);
1077 	if (ip == NULL)
1078 		return NULL;
1079 	vp = ip->val;
1080 	if (vp == NULL)
1081 		return NULL;
1082 	return vp->value;
1083 }
1084 
1085 char *
istgt_get_val(CF_SECTION * sp,const char * key)1086 istgt_get_val(CF_SECTION *sp, const char *key)
1087 {
1088 	return istgt_get_nval(sp, key, 0);
1089 }
1090 
1091 int
istgt_get_nintval(CF_SECTION * sp,const char * key,int idx)1092 istgt_get_nintval(CF_SECTION *sp, const char *key, int idx)
1093 {
1094 	const char *v;
1095 	int value;
1096 
1097 	v = istgt_get_nval(sp, key, idx);
1098 	if (v == NULL)
1099 		return -1;
1100 	value = (int)strtol(v, NULL, 10);
1101 	return value;
1102 }
1103 
1104 int
istgt_get_intval(CF_SECTION * sp,const char * key)1105 istgt_get_intval(CF_SECTION *sp, const char *key)
1106 {
1107 	return istgt_get_nintval(sp, key, 0);
1108 }
1109 
1110 static const char *
istgt_get_log_facility(CONFIG * config)1111 istgt_get_log_facility(CONFIG *config)
1112 {
1113 	CF_SECTION *sp;
1114 	const char *logfacility;
1115 
1116 	sp = istgt_find_cf_section(config, "Global");
1117 	if (sp == NULL) {
1118 		return NULL;
1119 	}
1120 	logfacility = istgt_get_val(sp, "LogFacility");
1121 	if (logfacility == NULL) {
1122 		logfacility = DEFAULT_LOG_FACILITY;
1123 	}
1124 #if 0
1125 	if (g_trace_flag & ISTGT_TRACE_DEBUG) {
1126 		fprintf(stderr, "LogFacility %s\n", logfacility);
1127 	}
1128 #endif
1129 
1130 	return logfacility;
1131 }
1132 
1133 static int
istgt_init(ISTGT_Ptr istgt)1134 istgt_init(ISTGT_Ptr istgt)
1135 {
1136 	CF_SECTION *sp;
1137 	const char *ag_tag;
1138 	const char *val;
1139 	size_t stacksize;
1140 	int ag_tag_i;
1141 	int MaxSessions;
1142 	int MaxConnections;
1143 	int MaxOutstandingR2T;
1144 	int DefaultTime2Wait;
1145 	int DefaultTime2Retain;
1146 	int FirstBurstLength;
1147 	int MaxBurstLength;
1148 	int MaxRecvDataSegmentLength;
1149 	int InitialR2T;
1150 	int ImmediateData;
1151 	int DataPDUInOrder;
1152 	int DataSequenceInOrder;
1153 	int ErrorRecoveryLevel;
1154 	int timeout;
1155 	int nopininterval;
1156 	int maxr2t;
1157 	int rc;
1158 	int i;
1159 
1160 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_init\n");
1161 	sp = istgt_find_cf_section(istgt->config, "Global");
1162 	if (sp == NULL) {
1163 		ISTGT_ERRLOG("find_cf_section failed()\n");
1164 		return -1;
1165 	}
1166 
1167 	val = istgt_get_val(sp, "Comment");
1168 	if (val != NULL) {
1169 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
1170 	}
1171 
1172 	val = istgt_get_val(sp, "PidFile");
1173 	if (val == NULL) {
1174 		val = DEFAULT_PIDFILE;
1175 	}
1176 	istgt->pidfile = xstrdup(val);
1177 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PidFile %s\n",
1178 	    istgt->pidfile);
1179 
1180 	val = istgt_get_val(sp, "AuthFile");
1181 	if (val == NULL) {
1182 		val = DEFAULT_AUTHFILE;
1183 	}
1184 	istgt->authfile = xstrdup(val);
1185 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthFile %s\n",
1186 	    istgt->authfile);
1187 
1188 #if 0
1189 	val = istgt_get_val(sp, "MediaFile");
1190 	if (val == NULL) {
1191 		val = DEFAULT_MEDIAFILE;
1192 	}
1193 	istgt->mediafile = xstrdup(val);
1194 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaFile %s\n",
1195 	    istgt->mediafile);
1196 #endif
1197 
1198 #if 0
1199 	val = istgt_get_val(sp, "LiveFile");
1200 	if (val == NULL) {
1201 		val = DEFAULT_LIVEFILE;
1202 	}
1203 	istgt->livefile = xstrdup(val);
1204 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LiveFile %s\n",
1205 	    istgt->livefile);
1206 #endif
1207 
1208 	val = istgt_get_val(sp, "MediaDirectory");
1209 	if (val == NULL) {
1210 		val = DEFAULT_MEDIADIRECTORY;
1211 	}
1212 	istgt->mediadirectory = xstrdup(val);
1213 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaDirectory %s\n",
1214 	    istgt->mediadirectory);
1215 
1216 	val = istgt_get_val(sp, "NodeBase");
1217 	if (val == NULL) {
1218 		val = DEFAULT_NODEBASE;
1219 	}
1220 	istgt->nodebase = xstrdup(val);
1221 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NodeBase %s\n",
1222 	    istgt->nodebase);
1223 
1224 	MaxSessions = istgt_get_intval(sp, "MaxSessions");
1225 	if (MaxSessions < 1) {
1226 		MaxSessions = DEFAULT_MAX_SESSIONS;
1227 	}
1228 	istgt->MaxSessions = MaxSessions;
1229 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxSessions %d\n",
1230 	    istgt->MaxSessions);
1231 
1232 	MaxConnections = istgt_get_intval(sp, "MaxConnections");
1233 	if (MaxConnections < 1) {
1234 		MaxConnections = DEFAULT_MAX_CONNECTIONS;
1235 	}
1236 	istgt->MaxConnections = MaxConnections;
1237 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxConnections %d\n",
1238 	    istgt->MaxConnections);
1239 
1240 	/* limited to 16bits - RFC3720(12.2) */
1241 	if (MaxSessions > 0xffff) {
1242 		ISTGT_ERRLOG("over 65535 sessions are not supported\n");
1243 		return -1;
1244 	}
1245 	if (MaxConnections > 0xffff) {
1246 		ISTGT_ERRLOG("over 65535 connections are not supported\n");
1247 		return -1;
1248 	}
1249 
1250 	MaxOutstandingR2T = istgt_get_intval(sp, "MaxOutstandingR2T");
1251 	if (MaxOutstandingR2T < 1) {
1252 		MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T;
1253 	}
1254 	istgt->MaxOutstandingR2T = MaxOutstandingR2T;
1255 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxOutstandingR2T %d\n",
1256 	    istgt->MaxOutstandingR2T);
1257 
1258 	DefaultTime2Wait = istgt_get_intval(sp, "DefaultTime2Wait");
1259 	if (DefaultTime2Wait < 0) {
1260 		DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
1261 	}
1262 	istgt->DefaultTime2Wait = DefaultTime2Wait;
1263 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Wait %d\n",
1264 	    istgt->DefaultTime2Wait);
1265 
1266 	DefaultTime2Retain = istgt_get_intval(sp, "DefaultTime2Retain");
1267 	if (DefaultTime2Retain < 0) {
1268 		DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
1269 	}
1270 	istgt->DefaultTime2Retain = DefaultTime2Retain;
1271 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Retain %d\n",
1272 	    istgt->DefaultTime2Retain);
1273 
1274 	/* check size limit - RFC3720(12.15, 12.16, 12.17) */
1275 	if (istgt->MaxOutstandingR2T > 65535) {
1276 		ISTGT_ERRLOG("MaxOutstandingR2T(%d) > 65535\n",
1277 		    istgt->MaxOutstandingR2T);
1278 		return -1;
1279 	}
1280 	if (istgt->DefaultTime2Wait > 3600) {
1281 		ISTGT_ERRLOG("DefaultTime2Wait(%d) > 3600\n",
1282 		    istgt->DefaultTime2Wait);
1283 		return -1;
1284 	}
1285 	if (istgt->DefaultTime2Retain > 3600) {
1286 		ISTGT_ERRLOG("DefaultTime2Retain(%d) > 3600\n",
1287 		    istgt->DefaultTime2Retain);
1288 		return -1;
1289 	}
1290 
1291 	FirstBurstLength = istgt_get_intval(sp, "FirstBurstLength");
1292 	if (FirstBurstLength < 0) {
1293 		FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH;
1294 	}
1295 	istgt->FirstBurstLength = FirstBurstLength;
1296 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "FirstBurstLength %d\n",
1297 	    istgt->FirstBurstLength);
1298 
1299 	MaxBurstLength = istgt_get_intval(sp, "MaxBurstLength");
1300 	if (MaxBurstLength < 0) {
1301 		MaxBurstLength = DEFAULT_MAXBURSTLENGTH;
1302 	}
1303 	istgt->MaxBurstLength = MaxBurstLength;
1304 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxBurstLength %d\n",
1305 	    istgt->MaxBurstLength);
1306 
1307 	MaxRecvDataSegmentLength
1308 		= istgt_get_intval(sp, "MaxRecvDataSegmentLength");
1309 	if (MaxRecvDataSegmentLength < 0) {
1310 		MaxRecvDataSegmentLength = DEFAULT_MAXRECVDATASEGMENTLENGTH;
1311 	}
1312 	istgt->MaxRecvDataSegmentLength = MaxRecvDataSegmentLength;
1313 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n",
1314 	    istgt->MaxRecvDataSegmentLength);
1315 
1316 	/* check size limit (up to 24bits - RFC3720(12.12)) */
1317 	if (istgt->MaxBurstLength < 512) {
1318 		ISTGT_ERRLOG("MaxBurstLength(%d) < 512\n",
1319 		    istgt->MaxBurstLength);
1320 		return -1;
1321 	}
1322 	if (istgt->FirstBurstLength < 512) {
1323 		ISTGT_ERRLOG("FirstBurstLength(%d) < 512\n",
1324 		    istgt->FirstBurstLength);
1325 		return -1;
1326 	}
1327 	if (istgt->FirstBurstLength > istgt->MaxBurstLength) {
1328 		ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
1329 		    istgt->FirstBurstLength, istgt->MaxBurstLength);
1330 		return -1;
1331 	}
1332 	if (istgt->MaxBurstLength > 0x00ffffff) {
1333 		ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
1334 		    istgt->MaxBurstLength);
1335 		return -1;
1336 	}
1337 	if (istgt->MaxRecvDataSegmentLength < 512) {
1338 		ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
1339 		    istgt->MaxRecvDataSegmentLength);
1340 		return -1;
1341 	}
1342 	if (istgt->MaxRecvDataSegmentLength > 0x00ffffff) {
1343 		ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
1344 		    istgt->MaxRecvDataSegmentLength);
1345 		return -1;
1346 	}
1347 
1348 	val = istgt_get_val(sp, "InitialR2T");
1349 	if (val == NULL) {
1350 		InitialR2T = DEFAULT_INITIALR2T;
1351 	} else if (strcasecmp(val, "Yes") == 0) {
1352 		InitialR2T = 1;
1353 	} else if (strcasecmp(val, "No") == 0) {
1354 #if 0
1355 		InitialR2T = 0;
1356 #else
1357 		ISTGT_ERRLOG("not supported value %s\n", val);
1358 		return -1;
1359 #endif
1360 	} else {
1361 		ISTGT_ERRLOG("unknown value %s\n", val);
1362 		return -1;
1363 	}
1364 	istgt->InitialR2T = InitialR2T;
1365 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "InitialR2T %s\n",
1366 	    istgt->InitialR2T ? "Yes" : "No");
1367 
1368 	val = istgt_get_val(sp, "ImmediateData");
1369 	if (val == NULL) {
1370 		ImmediateData = DEFAULT_IMMEDIATEDATA;
1371 	} else if (strcasecmp(val, "Yes") == 0) {
1372 		ImmediateData = 1;
1373 	} else if (strcasecmp(val, "No") == 0) {
1374 		ImmediateData = 0;
1375 	} else {
1376 		ISTGT_ERRLOG("unknown value %s\n", val);
1377 		return -1;
1378 	}
1379 	istgt->ImmediateData = ImmediateData;
1380 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ImmediateData %s\n",
1381 	    istgt->ImmediateData ? "Yes" : "No");
1382 
1383 	val = istgt_get_val(sp, "DataPDUInOrder");
1384 	if (val == NULL) {
1385 		DataPDUInOrder = DEFAULT_DATAPDUINORDER;
1386 	} else if (strcasecmp(val, "Yes") == 0) {
1387 		DataPDUInOrder = 1;
1388 	} else if (strcasecmp(val, "No") == 0) {
1389 #if 0
1390 		DataPDUInOrder = 0;
1391 #else
1392 		ISTGT_ERRLOG("not supported value %s\n", val);
1393 		return -1;
1394 #endif
1395 	} else {
1396 		ISTGT_ERRLOG("unknown value %s\n", val);
1397 		return -1;
1398 	}
1399 	istgt->DataPDUInOrder = DataPDUInOrder;
1400 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataPDUInOrder %s\n",
1401 	    istgt->DataPDUInOrder ? "Yes" : "No");
1402 
1403 	val = istgt_get_val(sp, "DataSequenceInOrder");
1404 	if (val == NULL) {
1405 		DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
1406 	} else if (strcasecmp(val, "Yes") == 0) {
1407 		DataSequenceInOrder = 1;
1408 	} else if (strcasecmp(val, "No") == 0) {
1409 #if 0
1410 		DataSequenceInOrder = 0;
1411 #else
1412 		ISTGT_ERRLOG("not supported value %s\n", val);
1413 		return -1;
1414 #endif
1415 	} else {
1416 		ISTGT_ERRLOG("unknown value %s\n", val);
1417 		return -1;
1418 	}
1419 	istgt->DataSequenceInOrder = DataSequenceInOrder;
1420 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataSequenceInOrder %s\n",
1421 	    istgt->DataSequenceInOrder ? "Yes" : "No");
1422 
1423 	ErrorRecoveryLevel = istgt_get_intval(sp, "ErrorRecoveryLevel");
1424 	if (ErrorRecoveryLevel < 0) {
1425 		ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
1426 	} else if (ErrorRecoveryLevel == 0) {
1427 		ErrorRecoveryLevel = 0;
1428 	} else if (ErrorRecoveryLevel == 1) {
1429 #if 0
1430 		ErrorRecoveryLevel = 1;
1431 #else
1432 		ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
1433 		return -1;
1434 #endif
1435 	} else if (ErrorRecoveryLevel == 2) {
1436 #if 0
1437 		ErrorRecoveryLevel = 2;
1438 #else
1439 		ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
1440 		return -1;
1441 #endif
1442 	} else {
1443 		ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
1444 		return -1;
1445 	}
1446 	istgt->ErrorRecoveryLevel = ErrorRecoveryLevel;
1447 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
1448 	    istgt->ErrorRecoveryLevel);
1449 
1450 	timeout = istgt_get_intval(sp, "Timeout");
1451 	if (timeout < 0) {
1452 		timeout = DEFAULT_TIMEOUT;
1453 	}
1454 	istgt->timeout = timeout;
1455 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Timeout %d\n",
1456 	    istgt->timeout);
1457 
1458 	nopininterval = istgt_get_intval(sp, "NopInInterval");
1459 	if (nopininterval < 0) {
1460 		nopininterval = DEFAULT_NOPININTERVAL;
1461 	}
1462 	istgt->nopininterval = nopininterval;
1463 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NopInInterval %d\n",
1464 	    istgt->nopininterval);
1465 
1466 	maxr2t = istgt_get_intval(sp, "MaxR2T");
1467 	if (maxr2t < 0) {
1468 		maxr2t = DEFAULT_MAXR2T;
1469 	}
1470 	if (maxr2t > MAX_R2T) {
1471 		ISTGT_ERRLOG("MaxR2T(%d) > %d\n",
1472 		    maxr2t, MAX_R2T);
1473 		return -1;
1474 	}
1475 	istgt->maxr2t = maxr2t;
1476 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxR2T %d\n",
1477 	    istgt->maxr2t);
1478 
1479 	val = istgt_get_val(sp, "DiscoveryAuthMethod");
1480 	if (val == NULL) {
1481 		istgt->no_discovery_auth = 0;
1482 		istgt->req_discovery_auth = 0;
1483 		istgt->req_discovery_auth_mutual = 0;
1484 	} else {
1485 		istgt->no_discovery_auth = 0;
1486 		for (i = 0; ; i++) {
1487 			val = istgt_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
1488 			if (val == NULL)
1489 				break;
1490 			if (strcasecmp(val, "CHAP") == 0) {
1491 				istgt->req_discovery_auth = 1;
1492 			} else if (strcasecmp(val, "Mutual") == 0) {
1493 				istgt->req_discovery_auth_mutual = 1;
1494 			} else if (strcasecmp(val, "Auto") == 0) {
1495 				istgt->req_discovery_auth = 0;
1496 				istgt->req_discovery_auth_mutual = 0;
1497 			} else if (strcasecmp(val, "None") == 0) {
1498 				istgt->no_discovery_auth = 1;
1499 				istgt->req_discovery_auth = 0;
1500 				istgt->req_discovery_auth_mutual = 0;
1501 			} else {
1502 				ISTGT_ERRLOG("unknown auth\n");
1503 				return -1;
1504 			}
1505 		}
1506 		if (istgt->req_discovery_auth_mutual && !istgt->req_discovery_auth) {
1507 			ISTGT_ERRLOG("Mutual but not CHAP\n");
1508 			return -1;
1509 		}
1510 	}
1511 	if (istgt->no_discovery_auth != 0) {
1512 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1513 		    "DiscoveryAuthMethod None\n");
1514 	} else if (istgt->req_discovery_auth == 0) {
1515 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1516 		    "DiscoveryAuthMethod Auto\n");
1517 	} else {
1518 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1519 		    "DiscoveryAuthMethod %s %s\n",
1520 		    istgt->req_discovery_auth ? "CHAP" : "",
1521 		    istgt->req_discovery_auth_mutual ? "Mutual" : "");
1522 	}
1523 
1524 	val = istgt_get_val(sp, "DiscoveryAuthGroup");
1525 	if (val == NULL) {
1526 		istgt->discovery_auth_group = 0;
1527 	} else {
1528 		ag_tag = val;
1529 		if (strcasecmp(ag_tag, "None") == 0) {
1530 			ag_tag_i = 0;
1531 		} else {
1532 			if (strncasecmp(ag_tag, "AuthGroup",
1533 				strlen("AuthGroup")) != 0
1534 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
1535 				ISTGT_ERRLOG("auth group error\n");
1536 				return -1;
1537 			}
1538 			if (ag_tag_i == 0) {
1539 				ISTGT_ERRLOG("invalid auth group %d\n",
1540 				    ag_tag_i);
1541 				return -1;
1542 			}
1543 		}
1544 		istgt->discovery_auth_group = ag_tag_i;
1545 	}
1546 	if (istgt->discovery_auth_group == 0) {
1547 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1548 		    "DiscoveryAuthGroup None\n");
1549 	} else {
1550 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
1551 		    "DiscoveryAuthGroup AuthGroup%d\n",
1552 		    istgt->discovery_auth_group);
1553 	}
1554 
1555 	/* global mutex */
1556 	rc = pthread_mutex_init(&istgt->mutex, NULL);
1557 	if (rc != 0) {
1558 		ISTGT_ERRLOG("mutex_init() failed\n");
1559 		return -1;
1560 	}
1561 
1562 	rc = istgt_uctl_init(istgt);
1563 	if (rc < 0) {
1564 		ISTGT_ERRLOG("istgt_uctl_init() failed\n");
1565 		return -1;
1566 	}
1567 	rc = istgt_build_uctl_portal(istgt);
1568 	if (rc < 0) {
1569 		ISTGT_ERRLOG("istgt_build_uctl_portal() failed\n");
1570 		return -1;
1571 	}
1572 	rc = istgt_build_portal_group_array(istgt);
1573 	if (rc < 0) {
1574 		ISTGT_ERRLOG("istgt_build_portal_array() failed\n");
1575 		return -1;
1576 	}
1577 	rc = istgt_build_initiator_group_array(istgt);
1578 	if (rc < 0) {
1579 		ISTGT_ERRLOG("build_initiator_group_array() failed\n");
1580 		return -1;
1581 	}
1582 
1583 	rc = pthread_attr_init(&istgt->attr);
1584 	if (rc != 0) {
1585 		ISTGT_ERRLOG("pthread_attr_init() failed\n");
1586 		return -1;
1587 	}
1588 	rc = pthread_attr_getstacksize(&istgt->attr, &stacksize);
1589 	if (rc != 0) {
1590 		ISTGT_ERRLOG("pthread_attr_getstacksize() failed\n");
1591 		return -1;
1592 	}
1593 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "current thread stack = %zd\n", stacksize);
1594 	if (stacksize < ISTGT_STACKSIZE) {
1595 		stacksize = ISTGT_STACKSIZE;
1596 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "new thread stack = %zd\n", stacksize);
1597 		rc = pthread_attr_setstacksize(&istgt->attr, stacksize);
1598 		if (rc != 0) {
1599 			ISTGT_ERRLOG("pthread_attr_setstacksize() failed\n");
1600 			return -1;
1601 		}
1602 	}
1603 
1604 	rc = pthread_mutexattr_init(&istgt->mutex_attr);
1605 	if (rc != 0) {
1606 		ISTGT_ERRLOG("mutexattr_init() failed\n");
1607 		return -1;
1608 	}
1609 #ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
1610 	rc = pthread_mutexattr_settype(&istgt->mutex_attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1611 #else
1612 	rc = pthread_mutexattr_settype(&istgt->mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
1613 #endif
1614 	if (rc != 0) {
1615 		ISTGT_ERRLOG("mutexattr_settype() failed\n");
1616 		return -1;
1617 	}
1618 	rc = pthread_mutex_init(&istgt->state_mutex, &istgt->mutex_attr);
1619 	if (rc != 0) {
1620 		ISTGT_ERRLOG("mutex_init() failed\n");
1621 		return -1;
1622 	}
1623 	rc = pthread_mutex_init(&istgt->reload_mutex, &istgt->mutex_attr);
1624 	if (rc != 0) {
1625 		ISTGT_ERRLOG("mutex_init() failed\n");
1626 		return -1;
1627 	}
1628 	rc = pthread_cond_init(&istgt->reload_cond, NULL);
1629 	if (rc != 0) {
1630 		ISTGT_ERRLOG("cond_init() failed\n");
1631 		return -1;
1632 	}
1633 
1634 	rc = pipe(istgt->sig_pipe);
1635 	if (rc != 0) {
1636 		ISTGT_ERRLOG("pipe() failed\n");
1637 		istgt->sig_pipe[0] = -1;
1638 		istgt->sig_pipe[1] = -1;
1639 		return -1;
1640 	}
1641 
1642 	/* XXX TODO: add initializer */
1643 
1644 	istgt_set_state(istgt, ISTGT_STATE_INITIALIZED);
1645 
1646 	return 0;
1647 }
1648 
1649 static void
istgt_shutdown(ISTGT_Ptr istgt)1650 istgt_shutdown(ISTGT_Ptr istgt)
1651 {
1652 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_shutdown\n");
1653 
1654 	istgt_destory_initiator_group_array(istgt);
1655 	istgt_destroy_portal_group_array(istgt);
1656 	istgt_destroy_uctl_portal(istgt);
1657 	istgt_uctl_shutdown(istgt);
1658 	istgt_remove_pidfile(istgt);
1659 	xfree(istgt->pidfile);
1660 	xfree(istgt->authfile);
1661 #if 0
1662 	xfree(istgt->mediafile);
1663 	xfree(istgt->livefile);
1664 #endif
1665 	xfree(istgt->mediadirectory);
1666 	xfree(istgt->nodebase);
1667 
1668 	if (istgt->sig_pipe[0] != -1)
1669 	    close(istgt->sig_pipe[0]);
1670 	if (istgt->sig_pipe[1] != -1)
1671 	    close(istgt->sig_pipe[1]);
1672 
1673 	(void) pthread_cond_destroy(&istgt->reload_cond);
1674 	(void) pthread_mutex_destroy(&istgt->reload_mutex);
1675 	(void) pthread_mutex_destroy(&istgt->state_mutex);
1676 	(void) pthread_mutex_destroy(&istgt->mutex);
1677 	(void) pthread_attr_destroy(&istgt->attr);
1678 }
1679 
1680 static int
istgt_pg_exist_num(CONFIG * config,int num)1681 istgt_pg_exist_num(CONFIG *config, int num)
1682 {
1683 	CF_SECTION *sp;
1684 
1685 	sp = config->section;
1686 	while (sp != NULL) {
1687 		if (sp->type == ST_PORTALGROUP) {
1688 			if (sp->num == num) {
1689 				return 1;
1690 			}
1691 		}
1692 		sp = sp->next;
1693 	}
1694 	return -1;
1695 }
1696 
1697 static PORTAL_GROUP *
istgt_get_tag_portal(ISTGT_Ptr istgt,int tag)1698 istgt_get_tag_portal(ISTGT_Ptr istgt, int tag)
1699 {
1700 	int i;
1701 
1702 	if (tag == 0)
1703 		return NULL;
1704 	MTX_LOCK(&istgt->mutex);
1705 	for (i = 0; i < istgt->nportal_group; i++) {
1706 		if (istgt->portal_group[i].tag == tag) {
1707 			MTX_UNLOCK(&istgt->mutex);
1708 			return &istgt->portal_group[i];
1709 		}
1710 	}
1711 	MTX_UNLOCK(&istgt->mutex);
1712 	return NULL;
1713 }
1714 
1715 #if 0
1716 static int
1717 istgt_get_num_of_portals(CF_SECTION *sp)
1718 {
1719 	char *label, *portal;
1720 	int portals;
1721 	int rc;
1722 	int i;
1723 
1724 	for (i = 0; ; i++) {
1725 		label = istgt_get_nmval(sp, "Portal", i, 0);
1726 		portal = istgt_get_nmval(sp, "Portal", i, 1);
1727 		if (label == NULL || portal == NULL)
1728 			break;
1729 		rc = istgt_parse_portal(portal, NULL, NULL);
1730 		if (rc < 0) {
1731 			ISTGT_ERRLOG("parse portal error (%s)\n", portal);
1732 			return -1;
1733 		}
1734 	}
1735 	portals = i;
1736 	if (portals > MAX_PORTAL) {
1737 		ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals);
1738 		return -1;
1739 	}
1740 	return portals;
1741 }
1742 #endif
1743 
1744 #define RELOAD_CMD_LENGTH 5
1745 static int
istgt_pg_reload_delete(ISTGT_Ptr istgt)1746 istgt_pg_reload_delete(ISTGT_Ptr istgt)
1747 {
1748 	char tmp[RELOAD_CMD_LENGTH];
1749 	int rc;
1750 
1751 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_pg_reload_delete\n");
1752 
1753 	istgt->pg_reload = 0;
1754 	/* request delete */
1755 	tmp[0] = 'D';
1756 	DSET32(&tmp[1], 0);
1757 	rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH);
1758 	if (rc < 0 || rc != RELOAD_CMD_LENGTH) {
1759 		ISTGT_ERRLOG("write() failed\n");
1760 		return -1;
1761 	}
1762 	/* wait for completion */
1763 	MTX_LOCK(&istgt->reload_mutex);
1764 	while (istgt->pg_reload == 0) {
1765 		pthread_cond_wait(&istgt->reload_cond, &istgt->reload_mutex);
1766 	}
1767 	rc = istgt->pg_reload;
1768 	MTX_UNLOCK(&istgt->reload_mutex);
1769 	if (rc < 0) {
1770 		if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) {
1771 			ISTGT_WARNLOG("pg_reload abort\n");
1772 			return -1;
1773 		}
1774 	}
1775 	return 0;
1776 }
1777 
1778 static int
istgt_pg_reload_update(ISTGT_Ptr istgt)1779 istgt_pg_reload_update(ISTGT_Ptr istgt)
1780 {
1781 	char tmp[RELOAD_CMD_LENGTH];
1782 	int rc;
1783 
1784 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_pg_reload_update\n");
1785 
1786 	istgt->pg_reload = 0;
1787 	/* request update */
1788 	tmp[0] = 'U';
1789 	DSET32(&tmp[1], 0);
1790 	rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH);
1791 	if (rc < 0 || rc != RELOAD_CMD_LENGTH) {
1792 		ISTGT_ERRLOG("write() failed\n");
1793 		return -1;
1794 	}
1795 	/* wait for completion */
1796 	MTX_LOCK(&istgt->reload_mutex);
1797 	while (istgt->pg_reload == 0) {
1798 		pthread_cond_wait(&istgt->reload_cond, &istgt->reload_mutex);
1799 	}
1800 	rc = istgt->pg_reload;
1801 	MTX_UNLOCK(&istgt->reload_mutex);
1802 	if (rc < 0) {
1803 		if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) {
1804 			ISTGT_WARNLOG("pg_reload abort\n");
1805 			return -1;
1806 		}
1807 	}
1808 	return 0;
1809 }
1810 
1811 static int
istgt_ig_exist_num(CONFIG * config,int num)1812 istgt_ig_exist_num(CONFIG *config, int num)
1813 {
1814 	CF_SECTION *sp;
1815 
1816 	sp = config->section;
1817 	while (sp != NULL) {
1818 		if (sp->type == ST_INITIATORGROUP) {
1819 			if (sp->num == num) {
1820 				return 1;
1821 			}
1822 		}
1823 		sp = sp->next;
1824 	}
1825 	return -1;
1826 }
1827 
1828 static int
istgt_ig_reload_delete(ISTGT_Ptr istgt)1829 istgt_ig_reload_delete(ISTGT_Ptr istgt)
1830 {
1831 	INITIATOR_GROUP *igp;
1832 	int rc;
1833 	int i, j;
1834 
1835 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_ig_reload_delete\n");
1836 	MTX_LOCK(&istgt->mutex);
1837 	for (i = 0; i < istgt->ninitiator_group; i++) {
1838 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "IG reload idx=%d, (%d)\n",
1839 		    i, istgt->ninitiator_group);
1840 		igp = &istgt->initiator_group[i];
1841 		rc = istgt_ig_exist_num(istgt->config, igp->tag);
1842 		if (rc < 0) {
1843 			if (igp->ref != 0) {
1844 				ISTGT_ERRLOG("delete request for referenced IG%d\n",
1845 				    igp->tag);
1846 			} else {
1847 				ISTGT_NOTICELOG("delete IG%d\n", igp->tag);
1848 				/* free old IG */
1849 				for (j = 0; j < istgt->initiator_group[i].ninitiators; j++) {
1850 					xfree(istgt->initiator_group[i].initiators[j]);
1851 				}
1852 				xfree(istgt->initiator_group[i].initiators);
1853 				for (j = 0; j < istgt->initiator_group[i].nnetmasks; j++) {
1854 					xfree(istgt->initiator_group[i].netmasks[j]);
1855 				}
1856 				xfree(istgt->initiator_group[i].netmasks);
1857 
1858 				/* move from beyond the IG */
1859 				for (j = i; j < istgt->ninitiator_group - 1; j++) {
1860 					istgt->initiator_group[j].ninitiators
1861 						= istgt->initiator_group[j+1].ninitiators;
1862 					istgt->initiator_group[j].initiators
1863 						= istgt->initiator_group[j+1].initiators;
1864 					istgt->initiator_group[j].nnetmasks
1865 						= istgt->initiator_group[j+1].nnetmasks;
1866 					istgt->initiator_group[j].netmasks
1867 						= istgt->initiator_group[j+1].netmasks;
1868 					istgt->initiator_group[j].ref
1869 						= istgt->initiator_group[j+1].ref;
1870 					istgt->initiator_group[j].idx
1871 						= istgt->initiator_group[j+1].idx;
1872 					istgt->initiator_group[j].tag
1873 						= istgt->initiator_group[j+1].tag;
1874 				}
1875 				istgt->ninitiator_group--;
1876 			}
1877 		}
1878 	}
1879 	MTX_UNLOCK(&istgt->mutex);
1880 	return 0;
1881 }
1882 
1883 static int
istgt_ig_reload_update(ISTGT_Ptr istgt)1884 istgt_ig_reload_update(ISTGT_Ptr istgt)
1885 {
1886 	CF_SECTION *sp;
1887 	int rc;
1888 	int i;
1889 
1890 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_ig_reload_update\n");
1891 	sp = istgt->config->section;
1892 	while (sp != NULL) {
1893 		if (sp->type == ST_INITIATORGROUP) {
1894 			if (sp->num == 0) {
1895 				ISTGT_ERRLOG("Group 0 is invalid\n");
1896 				goto skip_ig;
1897 			}
1898 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "IG reload tag=%d\n", sp->num);
1899 #if 0
1900 			rc = istgt_ig_exist_num(istgt->config_old, sp->num);
1901 #else
1902 			rc = -1;
1903 			MTX_LOCK(&istgt->mutex);
1904 			for (i = 0; i < istgt->ninitiator_group; i++) {
1905 				if (istgt->initiator_group[i].tag == sp->num) {
1906 					rc = 1;
1907 					break;
1908 				}
1909 			}
1910 			MTX_UNLOCK(&istgt->mutex);
1911 #endif
1912 			if (rc < 0) {
1913 				rc = istgt_add_initiator_group(istgt, sp);
1914 				if (rc < 0) {
1915 					ISTGT_ERRLOG("add_initiator_group() failed\n");
1916 					goto skip_ig;
1917 				}
1918 				ISTGT_NOTICELOG("add IG%d\n", sp->num);
1919 			} else {
1920 				rc = istgt_update_initiator_group(istgt, sp);
1921 				if (rc < 0) {
1922 					ISTGT_ERRLOG("update_initiator_group() failed\n");
1923 					goto skip_ig;
1924 				} else if (rc == 0) {
1925 					// not modified
1926 				} else if (rc > 0) {
1927 					ISTGT_NOTICELOG("update IG%d\n", sp->num);
1928 				}
1929 			}
1930 		}
1931 	skip_ig:
1932 		sp = sp->next;
1933 	}
1934 	return 0;
1935 }
1936 
1937 static int
istgt_reload(ISTGT_Ptr istgt)1938 istgt_reload(ISTGT_Ptr istgt)
1939 {
1940 	CONFIG *config_new, *config_old;
1941 	char *config_file;
1942 	int rc;
1943 
1944 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_reload\n");
1945 	/* prepare config structure */
1946 	config_new = istgt_allocate_config();
1947 	config_old = istgt->config;
1948 	config_file = config_old->file;
1949 	rc = istgt_read_config(config_new, config_file);
1950 	if (rc < 0) {
1951 		ISTGT_ERRLOG("config error\n");
1952 		return -1;
1953 	}
1954 	if (config_new->section == NULL) {
1955 		ISTGT_ERRLOG("empty config\n");
1956 		istgt_free_config(config_new);
1957 		return -1;
1958 	}
1959 	istgt->config = config_new;
1960 	istgt->config_old = config_old;
1961 	istgt->generation++;
1962 
1963 	/* reload sub groups */
1964 	ISTGT_NOTICELOG("reload configuration #%"PRIu32"\n", istgt->generation);
1965 	rc = istgt_lu_reload_delete(istgt);
1966 	if (rc < 0) {
1967 		ISTGT_ERRLOG("LU reload del error\n");
1968 		return -1;
1969 	}
1970 	rc = istgt_ig_reload_delete(istgt);
1971 	if (rc < 0) {
1972 		ISTGT_ERRLOG("IG reload del error\n");
1973 		return -1;
1974 	}
1975 	rc = istgt_pg_reload_delete(istgt);
1976 	if (rc < 0) {
1977 		ISTGT_ERRLOG("PG reload del error\n");
1978 		return -1;
1979 	}
1980 
1981 	rc = istgt_pg_reload_update(istgt);
1982 	if (rc < 0) {
1983 		ISTGT_ERRLOG("PG reload add error\n");
1984 		return -1;
1985 	}
1986 	rc = istgt_ig_reload_update(istgt);
1987 	if (rc < 0) {
1988 		ISTGT_ERRLOG("IG reload add error\n");
1989 		return -1;
1990 	}
1991 	rc = istgt_lu_reload_update(istgt);
1992 	if (rc < 0) {
1993 		ISTGT_ERRLOG("LU reload add error\n");
1994 		return -1;
1995 	}
1996 
1997 	istgt->config_old = NULL;
1998 	istgt_free_config(config_old);
1999 	return 0;
2000 }
2001 
2002 static int
istgt_stop_loop(ISTGT_Ptr istgt)2003 istgt_stop_loop(ISTGT_Ptr istgt)
2004 {
2005 	char tmp[RELOAD_CMD_LENGTH];
2006 	int rc;
2007 
2008 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_stop_loop\n");
2009 	tmp[0] = 'E';
2010 	DSET32(&tmp[1], 0);
2011 	rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH);
2012 	if (rc < 0 || rc != RELOAD_CMD_LENGTH) {
2013 		ISTGT_ERRLOG("write() failed\n");
2014 		/* ignore error */
2015 	}
2016 	return 0;
2017 }
2018 
2019 
2020 static void
istgt_sigint(int signo)2021 istgt_sigint(int signo __attribute__((__unused__)))
2022 {
2023 }
2024 
2025 static void
istgt_sigterm(int signo)2026 istgt_sigterm(int signo __attribute__((__unused__)))
2027 {
2028 }
2029 
2030 static void
istgt_sighup(int signo)2031 istgt_sighup(int signo __attribute__((__unused__)))
2032 {
2033 }
2034 
2035 #ifdef SIGINFO
2036 static void
istgt_siginfo(int signo)2037 istgt_siginfo(int signo __attribute__((__unused__)))
2038 {
2039 	/* nothing */
2040 }
2041 #endif
2042 
2043 static void
istgt_sigwakeup(int signo)2044 istgt_sigwakeup(int signo __attribute__((__unused__)))
2045 {
2046 }
2047 
2048 #ifdef SIGIO
2049 static void
istgt_sigio(int signo)2050 istgt_sigio(int signo __attribute__((__unused__)))
2051 {
2052 }
2053 #endif
2054 
2055 static void *
istgt_sighandler(void * arg)2056 istgt_sighandler(void *arg)
2057 {
2058 	ISTGT_Ptr istgt = (ISTGT_Ptr) arg;
2059 	sigset_t signew;
2060 	int signo;
2061 
2062 	sigemptyset(&signew);
2063 	sigaddset(&signew, SIGINT);
2064 	sigaddset(&signew, SIGTERM);
2065 	sigaddset(&signew, SIGQUIT);
2066 	sigaddset(&signew, SIGHUP);
2067 #ifdef SIGINFO
2068 	sigaddset(&signew, SIGINFO);
2069 #endif
2070 	sigaddset(&signew, SIGUSR1);
2071 	sigaddset(&signew, SIGUSR2);
2072 #ifdef SIGIO
2073 	sigaddset(&signew, SIGIO);
2074 #endif
2075 
2076 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start\n");
2077 	while (1) {
2078 		if (istgt_get_state(istgt) == ISTGT_STATE_EXITING
2079 		    || istgt_get_state(istgt) == ISTGT_STATE_SHUTDOWN) {
2080 			break;
2081 		}
2082 		sigwait(&signew, &signo);
2083 		switch (signo) {
2084 		case SIGINT:
2085 			printf("SIGINT catch\n");
2086 			istgt_stop_loop(istgt);
2087 			istgt_set_state(istgt, ISTGT_STATE_EXITING);
2088 			istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
2089 			break;
2090 		case SIGTERM:
2091 			printf("SIGTERM catch\n");
2092 			istgt_stop_loop(istgt);
2093 			istgt_set_state(istgt, ISTGT_STATE_EXITING);
2094 			istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
2095 			break;
2096 		case SIGQUIT:
2097 			printf("SIGQUIT catch\n");
2098 			exit(EXIT_SUCCESS);
2099 			break;
2100 		case SIGHUP:
2101 			printf("SIGHUP catch\n");
2102 			istgt_reload(istgt);
2103 			break;
2104 #ifdef SIGINFO
2105 		case SIGINFO:
2106 			printf("SIGINFO catch\n");
2107 			istgt_set_trace_flag(ISTGT_TRACE_ISCSI);
2108 			break;
2109 #endif
2110 		case SIGUSR1:
2111 			printf("SIGUSR1 catch\n");
2112 			istgt_set_trace_flag(ISTGT_TRACE_NONE);
2113 			break;
2114 		case SIGUSR2:
2115 			printf("SIGUSR2 catch\n");
2116 			//istgt_set_trace_flag(ISTGT_TRACE_SCSI);
2117 			istgt_set_trace_flag(ISTGT_TRACE_ALL);
2118 			break;
2119 #ifdef SIGIO
2120 		case SIGIO:
2121 			//printf("SIGIO catch\n");
2122 			break;
2123 #endif
2124 		default:
2125 			break;
2126 		}
2127 	}
2128 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended\n");
2129 
2130 	return NULL;
2131 }
2132 
2133 static PORTAL *
istgt_get_sock_portal(ISTGT_Ptr istgt,int sock)2134 istgt_get_sock_portal(ISTGT_Ptr istgt, int sock)
2135 {
2136 	int i, j;
2137 
2138 	if (sock < 0)
2139 		return NULL;
2140 	MTX_LOCK(&istgt->mutex);
2141 	for (i = 0; i < istgt->nportal_group; i++) {
2142 		for (j = 0; j < istgt->portal_group[i].nportals; j++) {
2143 			if (istgt->portal_group[i].portals[j]->sock == sock) {
2144 				MTX_UNLOCK(&istgt->mutex);
2145 				return istgt->portal_group[i].portals[j];
2146 			}
2147 		}
2148 	}
2149 	MTX_UNLOCK(&istgt->mutex);
2150 	return NULL;
2151 }
2152 
2153 static int
istgt_pg_delete(ISTGT_Ptr istgt)2154 istgt_pg_delete(ISTGT_Ptr istgt)
2155 {
2156 	PORTAL_GROUP *pgp;
2157 	int rc;
2158 	int i;
2159 
2160 	MTX_LOCK(&istgt->mutex);
2161 	for (i = 0; i < istgt->nportal_group; i++) {
2162 		pgp = &istgt->portal_group[i];
2163 		if (pgp->tag == 0)
2164 			continue;
2165 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PG reload idx=%d, tag=%d, (%d)\n",
2166 		    i, pgp->tag, istgt->nportal_group);
2167 		rc = istgt_pg_exist_num(istgt->config, pgp->tag);
2168 		if (rc < 0) {
2169 			if (pgp->ref != 0) {
2170 				ISTGT_ERRLOG("delete request for referenced PG%d\n",
2171 				    pgp->tag);
2172 			} else {
2173 				ISTGT_NOTICELOG("delete PG%d\n", pgp->tag);
2174 				pgp->tag = 0;
2175 				(void) istgt_close_portal_group(pgp);
2176 			}
2177 		}
2178 	}
2179 	MTX_UNLOCK(&istgt->mutex);
2180 	return 0;
2181 }
2182 
2183 static int
istgt_pg_update(ISTGT_Ptr istgt)2184 istgt_pg_update(ISTGT_Ptr istgt)
2185 {
2186 	PORTAL_GROUP *pgp;
2187 	CF_SECTION *sp;
2188 	int pgp_idx;
2189 	int rc;
2190 	int i;
2191 
2192 	sp = istgt->config->section;
2193 	while (sp != NULL) {
2194 		if (sp->type == ST_PORTALGROUP) {
2195 			if (sp->num == 0) {
2196 				ISTGT_ERRLOG("Group 0 is invalid\n");
2197 				goto skip_pg;
2198 			}
2199 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PG reload tag=%d\n", sp->num);
2200 #if 0
2201 			rc = istgt_pg_exist_num(istgt->config_old, sp->num);
2202 #else
2203 			rc = -1;
2204 			MTX_LOCK(&istgt->mutex);
2205 			for (i = 0; i < istgt->nportal_group; i++) {
2206 				if (istgt->portal_group[i].tag == sp->num) {
2207 					rc = 1;
2208 					break;
2209 				}
2210 			}
2211 			MTX_UNLOCK(&istgt->mutex);
2212 #endif
2213 			if (rc < 0) {
2214 				rc = istgt_add_portal_group(istgt, sp, &pgp_idx);
2215 				if (rc < 0) {
2216 					ISTGT_ERRLOG("add_portal_group() failed\n");
2217 					goto skip_pg;
2218 				}
2219 				MTX_LOCK(&istgt->mutex);
2220 				pgp = &istgt->portal_group[pgp_idx];
2221 				(void) istgt_open_portal_group(pgp);
2222 				MTX_UNLOCK(&istgt->mutex);
2223 				ISTGT_NOTICELOG("add PG%d\n", sp->num);
2224 			} else {
2225 				//portals = istgt_get_num_of_portals(sp);
2226 				pgp = istgt_get_tag_portal(istgt, sp->num);
2227 				if (istgt_pg_match_all(pgp, sp)) {
2228 					ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2229 					    "skip for PG%d\n", sp->num);
2230 				} else if (pgp->ref != 0) {
2231 					ISTGT_ERRLOG("update request for referenced PG%d\n",
2232 					    pgp->tag);
2233 				} else {
2234 					/* delete old sock */
2235 					MTX_LOCK(&istgt->mutex);
2236 					pgp_idx = pgp->idx;
2237 					(void) istgt_close_portal_group(pgp);
2238 					MTX_UNLOCK(&istgt->mutex);
2239 					rc = istgt_update_portal_group(istgt, sp, &pgp_idx);
2240 					if (rc < 0) {
2241 						ISTGT_ERRLOG("update_portal_group() failed\n");
2242 						goto skip_pg;
2243 					} else if (rc == 0) {
2244 						// not modified
2245 					} else if (rc > 0) {
2246 						/* add new sock */
2247 						MTX_LOCK(&istgt->mutex);
2248 						pgp = &istgt->portal_group[pgp_idx];
2249 						(void) istgt_open_portal_group(pgp);
2250 						MTX_UNLOCK(&istgt->mutex);
2251 						ISTGT_NOTICELOG("update PG%d\n", sp->num);
2252 					}
2253 				}
2254 			}
2255 		}
2256 	skip_pg:
2257 		sp = sp->next;
2258 	}
2259 	return 0;
2260 }
2261 
2262 static int
istgt_acceptor(ISTGT_Ptr istgt)2263 istgt_acceptor(ISTGT_Ptr istgt)
2264 {
2265 	PORTAL *pp;
2266 #ifdef ISTGT_USE_KQUEUE
2267 	int kq;
2268 	struct kevent kev;
2269 	struct timespec kev_timeout;
2270 	int kqsocks[MAX_PORTAL_GROUP + MAX_UCPORTAL];
2271 #else
2272 	struct pollfd fds[MAX_PORTAL_GROUP + MAX_UCPORTAL];
2273 #endif /* ISTGT_USE_KQUEUE */
2274 	struct sockaddr_storage sa;
2275 	socklen_t salen;
2276 	int sock;
2277 	int rc, n;
2278 	int ucidx;
2279 	int nidx;
2280 	int i, j;
2281 
2282 	if (istgt_get_state(istgt) != ISTGT_STATE_INITIALIZED) {
2283 		ISTGT_ERRLOG("not initialized\n");
2284 		return -1;
2285 	}
2286 	/* now running main thread */
2287 	istgt_set_state(istgt, ISTGT_STATE_RUNNING);
2288 
2289 reload:
2290 	nidx = 0;
2291 #ifdef ISTGT_USE_KQUEUE
2292 	kq = kqueue();
2293 	if (kq == -1) {
2294 		ISTGT_ERRLOG("kqueue() failed\n");
2295 		return -1;
2296 	}
2297 	for (i = 0; i < (int)(sizeof kqsocks / sizeof *kqsocks); i++) {
2298 		kqsocks[i] = -1;
2299 	}
2300 	MTX_LOCK(&istgt->mutex);
2301 	for (i = 0; i < istgt->nportal_group; i++) {
2302 		for (j = 0; j < istgt->portal_group[i].nportals; j++) {
2303 			if (istgt->portal_group[i].portals[j]->sock >= 0) {
2304 				ISTGT_EV_SET(&kev, istgt->portal_group[i].portals[j]->sock,
2305 				    EVFILT_READ, EV_ADD, 0, 0, NULL);
2306 				rc = kevent(kq, &kev, 1, NULL, 0, NULL);
2307 				if (rc == -1) {
2308 					MTX_UNLOCK(&istgt->mutex);
2309 					ISTGT_ERRLOG("kevent() failed\n");
2310 					close(kq);
2311 					return -1;
2312 				}
2313 				kqsocks[nidx] = istgt->portal_group[i].portals[j]->sock;
2314 				nidx++;
2315 			}
2316 		}
2317 	}
2318 	MTX_UNLOCK(&istgt->mutex);
2319 	ucidx = nidx;
2320 	for (i = 0; i < istgt->nuctl_portal; i++) {
2321 		ISTGT_EV_SET(&kev, istgt->uctl_portal[i].sock,
2322 		    EVFILT_READ, EV_ADD, 0, 0, NULL);
2323 		rc = kevent(kq, &kev, 1, NULL, 0, NULL);
2324 		if (rc == -1) {
2325 			ISTGT_ERRLOG("kevent() failed\n");
2326 			close(kq);
2327 			return -1;
2328 		}
2329 		kqsocks[nidx] = istgt->uctl_portal[i].sock;
2330 		nidx++;
2331 	}
2332 	ISTGT_EV_SET(&kev, istgt->sig_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
2333 	rc = kevent(kq, &kev, 1, NULL, 0, NULL);
2334 	if (rc == -1) {
2335 		ISTGT_ERRLOG("kevent() failed\n");
2336 		close(kq);
2337 		return -1;
2338 	}
2339 	kqsocks[nidx] = istgt->sig_pipe[0];
2340 	nidx++;
2341 
2342 	if (!istgt->daemon) {
2343 		ISTGT_EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
2344 		rc = kevent(kq, &kev, 1, NULL, 0, NULL);
2345 		if (rc == -1) {
2346 			ISTGT_ERRLOG("kevent() failed\n");
2347 			close(kq);
2348 			return -1;
2349 		}
2350 		ISTGT_EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
2351 		rc = kevent(kq, &kev, 1, NULL, 0, NULL);
2352 		if (rc == -1) {
2353 			ISTGT_ERRLOG("kevent() failed\n");
2354 			close(kq);
2355 			return -1;
2356 		}
2357 	}
2358 #else
2359 	memset(&fds, 0, sizeof fds);
2360 	MTX_LOCK(&istgt->mutex);
2361 	for (i = 0; i < istgt->nportal_group; i++) {
2362 		for (j = 0; j < istgt->portal_group[i].nportals; j++) {
2363 			if (istgt->portal_group[i].portals[j]->sock >= 0) {
2364 				fds[i].fd = istgt->portal_group[i].portals[j]->sock;
2365 				fds[i].events = POLLIN;
2366 				nidx++;
2367 			}
2368 		}
2369 	}
2370 	MTX_UNLOCK(&istgt->mutex);
2371 	ucidx = nidx;
2372 	for (i = 0; i < istgt->nuctl_portal; i++) {
2373 		fds[ucidx + i].fd = istgt->uctl_portal[i].sock;
2374 		fds[ucidx + i].events = POLLIN;
2375 		nidx++;
2376 	}
2377 	fds[nidx].fd = istgt->sig_pipe[0];
2378 	fds[nidx].events = POLLIN;
2379 	nidx++;
2380 #endif /* ISTGT_USE_KQUEUE */
2381 
2382 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start\n");
2383 	while (1) {
2384 		if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) {
2385 			break;
2386 		}
2387 #ifdef ISTGT_USE_KQUEUE
2388 		//ISTGT_TRACELOG(ISTGT_TRACE_NET, "kevent %d\n", nidx);
2389 		kev_timeout.tv_sec = 10;
2390 		kev_timeout.tv_nsec = 0;
2391 		rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout);
2392 		if (rc == -1 && errno == EINTR) {
2393 			continue;
2394 		}
2395 		if (rc == -1) {
2396 			ISTGT_ERRLOG("kevent() failed\n");
2397 			break;
2398 		}
2399 		if (rc == 0) {
2400 			/* idle timeout */
2401 			//ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent TIMEOUT\n");
2402 			continue;
2403 		}
2404 		if (kev.filter == EVFILT_SIGNAL) {
2405 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent SIGNAL\n");
2406 			if (kev.ident == SIGINT || kev.ident == SIGTERM) {
2407 				ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2408 				    "kevent SIGNAL SIGINT/SIGTERM\n");
2409 				break;
2410 			}
2411 			continue;
2412 		}
2413 #else
2414 		//ISTGT_TRACELOG(ISTGT_TRACE_NET, "poll %d\n", nidx);
2415 		rc = poll(fds, nidx, POLLWAIT);
2416 		if (rc == -1 && errno == EINTR) {
2417 			continue;
2418 		}
2419 		if (rc == -1) {
2420 			ISTGT_ERRLOG("poll() failed\n");
2421 			break;
2422 		}
2423 		if (rc == 0) {
2424 			/* no fds */
2425 			//ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "poll TIMEOUT\n");
2426 			continue;
2427 		}
2428 #endif /* ISTGT_USE_KQUEUE */
2429 
2430 		n = rc;
2431 		for (i = 0; n != 0 && i < ucidx; i++) {
2432 #ifdef ISTGT_USE_KQUEUE
2433 			if (kev.ident == (uintptr_t)kqsocks[i]) {
2434 				if (kev.flags) {
2435 					ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2436 					    "flags %x\n",
2437 					    kev.flags);
2438 				}
2439 #else
2440 			if (fds[i].revents) {
2441 				ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2442 				    "events %x\n",
2443 				    fds[i].revents);
2444 			}
2445 			if (fds[i].revents & POLLIN) {
2446 #endif /* ISTGT_USE_KQUEUE */
2447 				n--;
2448 				memset(&sa, 0, sizeof(sa));
2449 				salen = sizeof(sa);
2450 #ifdef ISTGT_USE_KQUEUE
2451 				ISTGT_TRACELOG(ISTGT_TRACE_NET, "accept %ld\n",
2452 				    (unsigned long)kev.ident);
2453 				pp = istgt_get_sock_portal(istgt, kev.ident);
2454 				rc = accept(kev.ident, (struct sockaddr *) &sa, &salen);
2455 #else
2456 				ISTGT_TRACELOG(ISTGT_TRACE_NET, "accept %d\n",
2457 				    fds[i].fd);
2458 				pp = istgt_get_sock_portal(istgt, fds[i].fd);
2459 				rc = accept(fds[i].fd, (struct sockaddr *) &sa, &salen);
2460 #endif /* ISTGT_USE_KQUEUE */
2461 				if (rc < 0) {
2462 					if (errno == ECONNABORTED || errno == ECONNRESET) {
2463 						continue;
2464 					}
2465 					ISTGT_ERRLOG("accept error: %d(errno=%d)\n",
2466 					    rc, errno);
2467 					continue;
2468 				}
2469 				sock = rc;
2470 #if 0
2471 				rc = fcntl(sock, F_GETFL, 0);
2472 				if (rc == -1) {
2473 					ISTGT_ERRLOG("fcntl() failed\n");
2474 					continue;
2475 				}
2476 				rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
2477 				if (rc == -1) {
2478 					ISTGT_ERRLOG("fcntl() failed\n");
2479 					continue;
2480 				}
2481 #endif
2482 				rc = istgt_create_conn(istgt, pp, sock,
2483 				    (struct sockaddr *) &sa, salen);
2484 				if (rc < 0) {
2485 					close(sock);
2486 					ISTGT_ERRLOG("istgt_create_conn() failed\n");
2487 					continue;
2488 				}
2489 			}
2490 		}
2491 
2492 		/* check for control */
2493 		for (i = 0; n != 0 && i < istgt->nuctl_portal; i++) {
2494 #ifdef ISTGT_USE_KQUEUE
2495 			if (kev.ident == (uintptr_t)istgt->uctl_portal[i].sock) {
2496 				if (kev.flags) {
2497 					ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2498 					    "flags %x\n",
2499 					    kev.flags);
2500 				}
2501 #else
2502 			if (fds[ucidx + i].revents) {
2503 				ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2504 				    "events %x\n",
2505 				    fds[ucidx + i].revents);
2506 			}
2507 			if (fds[ucidx + i].revents & POLLIN) {
2508 #endif /* ISTGT_USE_KQUEUE */
2509 				n--;
2510 				memset(&sa, 0, sizeof(sa));
2511 				salen = sizeof(sa);
2512 #ifdef ISTGT_USE_KQUEUE
2513 				ISTGT_TRACELOG(ISTGT_TRACE_NET,
2514 				    "accept %ld\n", (unsigned long)kev.ident);
2515 				rc = accept(kev.ident,
2516 				    (struct sockaddr *) &sa, &salen);
2517 #else
2518 				ISTGT_TRACELOG(ISTGT_TRACE_NET,
2519 				    "accept %d\n", fds[ucidx + i].fd);
2520 				rc = accept(fds[ucidx + i].fd,
2521 				    (struct sockaddr *) &sa, &salen);
2522 #endif /* ISTGT_USE_KQUEUE */
2523 				if (rc < 0) {
2524 					ISTGT_ERRLOG("accept error: %d\n", rc);
2525 					continue;
2526 				}
2527 				sock = rc;
2528 				rc = istgt_create_uctl(istgt,
2529 				    &istgt->uctl_portal[i], sock,
2530 				    (struct sockaddr *) &sa, salen);
2531 				if (rc < 0) {
2532 					close(sock);
2533 					ISTGT_ERRLOG("istgt_create_uctl() failed\n");
2534 					continue;
2535 				}
2536 			}
2537 		}
2538 
2539 		/* check for signal thread */
2540 #ifdef ISTGT_USE_KQUEUE
2541 		if (kev.ident == (uintptr_t)istgt->sig_pipe[0]) {
2542 			if (kev.flags & (EV_EOF|EV_ERROR)) {
2543 				ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2544 				    "kevent EOF/ERROR\n");
2545 				break;
2546 			}
2547 #else
2548 		if (fds[nidx - 1].revents & POLLHUP) {
2549 			break;
2550 		}
2551 		if (fds[nidx - 1].revents & POLLIN) {
2552 #endif /* ISTGT_USE_KQUEUE */
2553 			char tmp[RELOAD_CMD_LENGTH];
2554 			//int pgp_idx;
2555 			int rc2;
2556 
2557 			rc = read(istgt->sig_pipe[0], tmp, RELOAD_CMD_LENGTH);
2558 			if (rc < 0 || rc == 0 || rc != RELOAD_CMD_LENGTH) {
2559 				ISTGT_ERRLOG("read() failed\n");
2560 				break;
2561 			}
2562 			//pgp_idx = (int)DGET32(&tmp[1]);
2563 
2564 			if (tmp[0] == 'E') {
2565 				ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
2566 				    "exit request (main loop)\n");
2567 				break;
2568 			}
2569 			if (tmp[0] == 'D') {
2570 				rc = istgt_pg_delete(istgt);
2571 				MTX_LOCK(&istgt->reload_mutex);
2572 				istgt->pg_reload = rc < 0 ? -1 : 1;
2573 				rc2 = pthread_cond_broadcast(&istgt->reload_cond);
2574 				if (rc2 != 0) {
2575 					ISTGT_ERRLOG("cond_broadcast() failed\n");
2576 				}
2577 				MTX_UNLOCK(&istgt->reload_mutex);
2578 				if (rc < 0) {
2579 					ISTGT_ERRLOG("pg_delete() failed\n");
2580 					//break;
2581 				}
2582 			}
2583 			if (tmp[0] == 'U') {
2584 				rc = istgt_pg_update(istgt);
2585 				MTX_LOCK(&istgt->reload_mutex);
2586 				istgt->pg_reload = rc < 0 ? -1 : 1;
2587 				rc2 = pthread_cond_broadcast(&istgt->reload_cond);
2588 				if (rc2 != 0) {
2589 					ISTGT_ERRLOG("cond_broadcast() failed\n");
2590 				}
2591 				MTX_UNLOCK(&istgt->reload_mutex);
2592 				if (rc < 0) {
2593 					ISTGT_ERRLOG("pg_update() failed\n");
2594 					//break;
2595 				}
2596 			}
2597 #ifdef ISTGT_USE_KQUEUE
2598 			close(kq);
2599 #endif /* ISTGT_USE_KQUEUE */
2600 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "reload accept loop\n");
2601 			goto reload;
2602 		}
2603 	}
2604 #ifdef ISTGT_USE_KQUEUE
2605 	close(kq);
2606 #endif /* ISTGT_USE_KQUEUE */
2607 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended\n");
2608 	istgt_set_state(istgt, ISTGT_STATE_EXITING);
2609 	istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
2610 
2611 	return 0;
2612 }
2613 
2614 static void
2615 usage(void)
2616 {
2617 	printf("istgt [options]\n");
2618 	printf("options:\n");
2619 	printf(" -c config  config file (default %s)\n", DEFAULT_CONFIG);
2620 	printf(" -p pidfile use specific file\n");
2621 	printf(" -l facility use specific syslog facility (default %s)\n",
2622 	    DEFAULT_LOG_FACILITY);
2623 	printf(" -m mode    operational mode (default %d, 0=traditional, "
2624 	    "1=normal, 2=experimental)\n", DEFAULT_ISTGT_SWMODE);
2625 	printf(" -t flag    trace flag (all, net, iscsi, scsi, lu)\n");
2626 	printf(" -q         quiet warnings\n");
2627 	printf(" -D         don't detach from tty\n");
2628 	printf(" -H         show this usage\n");
2629 	printf(" -V         show version\n");
2630 }
2631 
2632 int
2633 main(int argc, char **argv)
2634 {
2635 	ISTGT_Ptr istgt;
2636 	const char *config_file = DEFAULT_CONFIG;
2637 	const char *pidfile = NULL;
2638 	const char *logfacility = NULL;
2639 	const char *logpriority = NULL;
2640 	CONFIG *config;
2641 	pthread_t sigthread;
2642 	struct sigaction sigact, sigoldact_pipe, sigoldact_int, sigoldact_term;
2643 	struct sigaction sigoldact_hup, sigoldact_info;
2644 	struct sigaction sigoldact_wakeup, sigoldact_io;
2645 	sigset_t signew, sigold;
2646 	int retry = 10;
2647 	int detach = 1;
2648 	int swmode;
2649 	int ch;
2650 	int rc;
2651 
2652 	if (sizeof (ISCSI_BHS) != ISCSI_BHS_LEN) {
2653 		fprintf(stderr, "Internal Error\n");
2654 		exit(EXIT_FAILURE);
2655 	}
2656 
2657 	memset(&g_istgt, 0, sizeof g_istgt);
2658 	istgt = &g_istgt;
2659 	istgt->state = ISTGT_STATE_INVALID;
2660 	istgt->swmode = DEFAULT_ISTGT_SWMODE;
2661 	istgt->sig_pipe[0] = istgt->sig_pipe[1] = -1;
2662 	istgt->daemon = 0;
2663 	istgt->generation = 0;
2664 
2665 	while ((ch = getopt(argc, argv, "c:p:l:m:t:qDHV")) != -1) {
2666 		switch (ch) {
2667 		case 'c':
2668 			config_file = optarg;
2669 			break;
2670 		case 'p':
2671 			pidfile = optarg;
2672 			break;
2673 		case 'l':
2674 			logfacility = optarg;
2675 			break;
2676 		case 'm':
2677 			swmode = strtol(optarg, NULL, 10);
2678 			if (swmode == ISTGT_SWMODE_TRADITIONAL
2679 			    || swmode == ISTGT_SWMODE_NORMAL
2680 			    || swmode == ISTGT_SWMODE_EXPERIMENTAL) {
2681 				istgt->swmode = swmode;
2682 			} else {
2683 				fprintf(stderr, "unknown mode %x\n", swmode);
2684 				usage();
2685 				exit(EXIT_FAILURE);
2686 			}
2687 			break;
2688 		case 't':
2689 			if (strcasecmp(optarg, "NET") == 0) {
2690 				istgt_set_trace_flag(ISTGT_TRACE_NET);
2691 			} else if (strcasecmp(optarg, "ISCSI") == 0) {
2692 				istgt_set_trace_flag(ISTGT_TRACE_ISCSI);
2693 			} else if (strcasecmp(optarg, "SCSI") == 0) {
2694 				istgt_set_trace_flag(ISTGT_TRACE_SCSI);
2695 			} else if (strcasecmp(optarg, "LU") == 0) {
2696 				istgt_set_trace_flag(ISTGT_TRACE_LU);
2697 			} else if (strcasecmp(optarg, "ALL") == 0) {
2698 				istgt_set_trace_flag(ISTGT_TRACE_ALL);
2699 			} else if (strcasecmp(optarg, "NONE") == 0) {
2700 				istgt_set_trace_flag(ISTGT_TRACE_NONE);
2701 			} else {
2702 				fprintf(stderr, "unknown flag\n");
2703 				usage();
2704 				exit(EXIT_FAILURE);
2705 			}
2706 			break;
2707 		case 'q':
2708 			g_warn_flag = 0;
2709 			break;
2710 		case 'D':
2711 			detach = 0;
2712 			break;
2713 		case 'V':
2714 			printf("istgt version %s\n", ISTGT_VERSION);
2715 			printf("istgt extra version %s\n", ISTGT_EXTRA_VERSION);
2716 			exit(EXIT_SUCCESS);
2717 		case 'H':
2718 		default:
2719 			usage();
2720 			exit(EXIT_SUCCESS);
2721 		}
2722 	}
2723 
2724 	/* read config files */
2725 	config = istgt_allocate_config();
2726 	rc = istgt_read_config(config, config_file);
2727 	if (rc < 0) {
2728 		fprintf(stderr, "config error\n");
2729 		exit(EXIT_FAILURE);
2730 	}
2731 	if (config->section == NULL) {
2732 		fprintf(stderr, "empty config\n");
2733 		istgt_free_config(config);
2734 		exit(EXIT_FAILURE);
2735 	}
2736 	istgt->config = config;
2737 	istgt->config_old = NULL;
2738 	//istgt_print_config(config);
2739 
2740 	/* open log files */
2741 	if (logfacility == NULL) {
2742 		logfacility = istgt_get_log_facility(config);
2743 	}
2744 	rc = istgt_set_log_facility(logfacility);
2745 	if (rc < 0) {
2746 		fprintf(stderr, "log facility error\n");
2747 		istgt_free_config(config);
2748 		exit(EXIT_FAILURE);
2749 	}
2750 	if (logpriority == NULL) {
2751 		logpriority = DEFAULT_LOG_PRIORITY;
2752 	}
2753 	rc = istgt_set_log_priority(logpriority);
2754 	if (rc < 0) {
2755 		fprintf(stderr, "log priority error\n");
2756 		istgt_free_config(config);
2757 		exit(EXIT_FAILURE);
2758 	}
2759 	istgt_open_log();
2760 
2761 	ISTGT_NOTICELOG("istgt version %s (%s)\n", ISTGT_VERSION,
2762 	    ISTGT_EXTRA_VERSION);
2763 	switch (istgt->swmode) {
2764 	case ISTGT_SWMODE_TRADITIONAL:
2765 		ISTGT_NOTICELOG("traditional mode\n");
2766 		break;
2767 	case ISTGT_SWMODE_NORMAL:
2768 		ISTGT_NOTICELOG("normal mode\n");
2769 		break;
2770 	case ISTGT_SWMODE_EXPERIMENTAL:
2771 		ISTGT_NOTICELOG("experimental mode\n");
2772 		break;
2773 	default:
2774 		break;
2775 	}
2776 #ifdef ISTGT_USE_KQUEUE
2777 	ISTGT_NOTICELOG("using kqueue\n");
2778 #else
2779 	ISTGT_NOTICELOG("using poll\n");
2780 #endif /* ISTGT_USE_KQUEUE */
2781 #ifdef USE_ATOMIC
2782 	ISTGT_NOTICELOG("using host atomic\n");
2783 #elif defined (USE_GCC_ATOMIC)
2784 	ISTGT_NOTICELOG("using gcc atomic\n");
2785 #else
2786 	ISTGT_NOTICELOG("using generic atomic\n");
2787 #endif /* USE_ATOMIC */
2788 
2789 #ifdef ISTGT_USE_CRC32C_TABLE
2790 	/* build crc32c table */
2791 	istgt_init_crc32c_table();
2792 #endif /* ISTGT_USE_CRC32C_TABLE */
2793 
2794 	/* initialize sub modules */
2795 	rc = istgt_init(istgt);
2796 	if (rc < 0) {
2797 		ISTGT_ERRLOG("istgt_init() failed\n");
2798 	initialize_error:
2799 		istgt_close_log();
2800 		istgt_free_config(config);
2801 		exit(EXIT_FAILURE);
2802 	}
2803 	rc = istgt_lu_init(istgt);
2804 	if (rc < 0) {
2805 		ISTGT_ERRLOG("istgt_lu_init() failed\n");
2806 		goto initialize_error;
2807 	}
2808 	rc = istgt_iscsi_init(istgt);
2809 	if (rc < 0) {
2810 		ISTGT_ERRLOG("istgt_iscsi_init() failed\n");
2811 		goto initialize_error;
2812 	}
2813 
2814 	/* override by command line */
2815 	if (pidfile != NULL) {
2816 		xfree(istgt->pidfile);
2817 		istgt->pidfile = xstrdup(pidfile);
2818 	}
2819 
2820 	/* detach from tty and run background */
2821 	fflush(stdout);
2822 	if (detach) {
2823 		istgt->daemon = 1;
2824 		rc = daemon(0, 0);
2825 		if (rc < 0) {
2826 			ISTGT_ERRLOG("daemon() failed\n");
2827 			goto initialize_error;
2828 		}
2829 	}
2830 
2831 	/* setup signal handler thread */
2832 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "setup signal handler\n");
2833 	memset(&sigact, 0, sizeof sigact);
2834 	memset(&sigoldact_pipe, 0, sizeof sigoldact_pipe);
2835 	memset(&sigoldact_int, 0, sizeof sigoldact_int);
2836 	memset(&sigoldact_term, 0, sizeof sigoldact_term);
2837 	memset(&sigoldact_hup, 0, sizeof sigoldact_hup);
2838 	memset(&sigoldact_info, 0, sizeof sigoldact_info);
2839 	memset(&sigoldact_wakeup, 0, sizeof sigoldact_wakeup);
2840 	memset(&sigoldact_io, 0, sizeof sigoldact_io);
2841 	sigact.sa_handler = SIG_IGN;
2842 	sigemptyset(&sigact.sa_mask);
2843 	rc = sigaction(SIGPIPE, &sigact, &sigoldact_pipe);
2844 	if (rc < 0) {
2845 		ISTGT_ERRLOG("sigaction(SIGPIPE) failed\n");
2846 		goto initialize_error;
2847 	}
2848 	sigact.sa_handler = istgt_sigint;
2849 	sigemptyset(&sigact.sa_mask);
2850 	rc = sigaction(SIGINT, &sigact, &sigoldact_int);
2851 	if (rc < 0) {
2852 		ISTGT_ERRLOG("sigaction(SIGINT) failed\n");
2853 		goto initialize_error;
2854 	}
2855 	sigact.sa_handler = istgt_sigterm;
2856 	sigemptyset(&sigact.sa_mask);
2857 	rc = sigaction(SIGTERM, &sigact, &sigoldact_term);
2858 	if (rc < 0) {
2859 		ISTGT_ERRLOG("sigaction(SIGTERM) failed\n");
2860 		goto initialize_error;
2861 	}
2862 	sigact.sa_handler = istgt_sighup;
2863 	sigemptyset(&sigact.sa_mask);
2864 	rc = sigaction(SIGHUP, &sigact, &sigoldact_hup);
2865 	if (rc < 0) {
2866 		ISTGT_ERRLOG("sigaction(SIGHUP) failed\n");
2867 		goto initialize_error;
2868 	}
2869 #ifdef SIGINFO
2870 	sigact.sa_handler = istgt_siginfo;
2871 	sigemptyset(&sigact.sa_mask);
2872 	rc = sigaction(SIGINFO, &sigact, &sigoldact_info);
2873 	if (rc < 0) {
2874 		ISTGT_ERRLOG("sigaction(SIGINFO) failed\n");
2875 		goto initialize_error;
2876 	}
2877 #endif
2878 #ifdef ISTGT_USE_SIGRT
2879 	if (ISTGT_SIGWAKEUP < SIGRTMIN
2880 	    || ISTGT_SIGWAKEUP > SIGRTMAX) {
2881 		ISTGT_ERRLOG("SIGRT error\n");
2882 		goto initialize_error;
2883 	}
2884 #endif /* ISTGT_USE_SIGRT */
2885 	sigact.sa_handler = istgt_sigwakeup;
2886 	sigemptyset(&sigact.sa_mask);
2887 	rc = sigaction(ISTGT_SIGWAKEUP, &sigact, &sigoldact_wakeup);
2888 	if (rc < 0) {
2889 		ISTGT_ERRLOG("sigaction(ISTGT_SIGWAKEUP) failed\n");
2890 		goto initialize_error;
2891 	}
2892 #ifdef SIGIO
2893 	sigact.sa_handler = istgt_sigio;
2894 	sigemptyset(&sigact.sa_mask);
2895 	rc = sigaction(SIGIO, &sigact, &sigoldact_io);
2896 	if (rc < 0) {
2897 		ISTGT_ERRLOG("sigaction(SIGIO) failed\n");
2898 		goto initialize_error;
2899 	}
2900 #endif
2901 	pthread_sigmask(SIG_SETMASK, NULL, &signew);
2902 	sigaddset(&signew, SIGINT);
2903 	sigaddset(&signew, SIGTERM);
2904 	sigaddset(&signew, SIGQUIT);
2905 	sigaddset(&signew, SIGHUP);
2906 #ifdef SIGINFO
2907 	sigaddset(&signew, SIGINFO);
2908 #endif
2909 	sigaddset(&signew, SIGUSR1);
2910 	sigaddset(&signew, SIGUSR2);
2911 #ifdef SIGIO
2912 	sigaddset(&signew, SIGIO);
2913 #endif
2914 	sigaddset(&signew, ISTGT_SIGWAKEUP);
2915 	pthread_sigmask(SIG_SETMASK, &signew, &sigold);
2916 #ifdef ISTGT_STACKSIZE
2917 	rc = pthread_create(&sigthread, &istgt->attr, &istgt_sighandler,
2918 	    (void *) istgt);
2919 #else
2920 	rc = pthread_create(&sigthread, NULL, &istgt_sighandler,
2921 	    (void *) istgt);
2922 #endif
2923 	if (rc != 0) {
2924 		ISTGT_ERRLOG("pthread_create() failed\n");
2925 		goto initialize_error;
2926 	}
2927 #if 0
2928 	rc = pthread_detach(sigthread);
2929 	if (rc != 0) {
2930 		ISTGT_ERRLOG("pthread_detach() failed\n");
2931 		goto initialize_error;
2932 	}
2933 #endif
2934 #ifdef HAVE_PTHREAD_SET_NAME_NP
2935 	pthread_set_name_np(sigthread, "sigthread");
2936 	pthread_set_name_np(pthread_self(), "mainthread");
2937 #endif
2938 
2939 	/* create LUN threads for command queuing */
2940 	rc = istgt_lu_create_threads(istgt);
2941 	if (rc < 0) {
2942 		ISTGT_ERRLOG("lu_create_threads() failed\n");
2943 		goto initialize_error;
2944 	}
2945 	rc = istgt_lu_set_all_state(istgt, ISTGT_STATE_RUNNING);
2946 	if (rc < 0) {
2947 		ISTGT_ERRLOG("lu_set_all_state() failed\n");
2948 		goto initialize_error;
2949 	}
2950 
2951 	/* open portals */
2952 	rc = istgt_open_uctl_portal(istgt);
2953 	if (rc < 0) {
2954 		ISTGT_ERRLOG("istgt_open_uctl_portal() failed\n");
2955 		goto initialize_error;
2956 	}
2957 	rc = istgt_open_all_portals(istgt);
2958 	if (rc < 0) {
2959 		ISTGT_ERRLOG("istgt_open_all_portals() failed\n");
2960 		goto initialize_error;
2961 	}
2962 
2963 	/* write pid */
2964 	rc = istgt_write_pidfile(istgt);
2965 	if (rc < 0) {
2966 		ISTGT_ERRLOG("istgt_write_pid() failed\n");
2967 		goto initialize_error;
2968 	}
2969 
2970 	/* accept loop */
2971 	rc = istgt_acceptor(istgt);
2972 	if (rc < 0) {
2973 		ISTGT_ERRLOG("istgt_acceptor() failed\n");
2974 		istgt_close_all_portals(istgt);
2975 		istgt_close_uctl_portal(istgt);
2976 		istgt_iscsi_shutdown(istgt);
2977 		istgt_lu_shutdown(istgt);
2978 		istgt_shutdown(istgt);
2979 		istgt_close_log();
2980 		config = istgt->config;
2981 		istgt->config = NULL;
2982 		istgt_free_config(config);
2983 		exit(EXIT_FAILURE);
2984 	}
2985 
2986 	/* wait threads */
2987 	istgt_stop_conns();
2988 	while (retry > 0) {
2989 		if (istgt_get_active_conns() == 0) {
2990 			break;
2991 		}
2992 		sleep(1);
2993 		retry--;
2994 	}
2995 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "retry=%d\n", retry);
2996 
2997 	ISTGT_NOTICELOG("istgt version %s (%s) exiting\n", ISTGT_VERSION,
2998 	    ISTGT_EXTRA_VERSION);
2999 
3000 	/* stop signal thread */
3001 	rc = pthread_join(sigthread, NULL);
3002 	if (rc != 0) {
3003 		ISTGT_ERRLOG("pthread_join() failed\n");
3004 		exit (EXIT_FAILURE);
3005 	}
3006 
3007 	/* cleanup */
3008 	istgt_close_all_portals(istgt);
3009 	istgt_close_uctl_portal(istgt);
3010 	istgt_iscsi_shutdown(istgt);
3011 	istgt_lu_shutdown(istgt);
3012 	istgt_shutdown(istgt);
3013 	istgt_close_log();
3014 	config = istgt->config;
3015 	istgt->config = NULL;
3016 	istgt_free_config(config);
3017 	istgt->state = ISTGT_STATE_SHUTDOWN;
3018 
3019 	return 0;
3020 }
3021