ctld.c revision 263718
1255570Strasz/*- 2255570Strasz * Copyright (c) 2012 The FreeBSD Foundation 3255570Strasz * All rights reserved. 4255570Strasz * 5255570Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6255570Strasz * from the FreeBSD Foundation. 7255570Strasz * 8255570Strasz * Redistribution and use in source and binary forms, with or without 9255570Strasz * modification, are permitted provided that the following conditions 10255570Strasz * are met: 11255570Strasz * 1. Redistributions of source code must retain the above copyright 12255570Strasz * notice, this list of conditions and the following disclaimer. 13255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 14255570Strasz * notice, this list of conditions and the following disclaimer in the 15255570Strasz * documentation and/or other materials provided with the distribution. 16255570Strasz * 17255570Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20255570Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27255570Strasz * SUCH DAMAGE. 28255570Strasz * 29255570Strasz * $FreeBSD: stable/10/usr.sbin/ctld/ctld.c 263718 2014-03-25 11:58:24Z trasz $ 30255570Strasz */ 31255570Strasz 32255570Strasz#include <sys/types.h> 33255570Strasz#include <sys/time.h> 34255570Strasz#include <sys/socket.h> 35255570Strasz#include <sys/wait.h> 36255570Strasz#include <netinet/in.h> 37255570Strasz#include <assert.h> 38255570Strasz#include <ctype.h> 39255570Strasz#include <errno.h> 40255570Strasz#include <netdb.h> 41255570Strasz#include <signal.h> 42255570Strasz#include <stdbool.h> 43255570Strasz#include <stdio.h> 44255570Strasz#include <stdint.h> 45255570Strasz#include <stdlib.h> 46255570Strasz#include <string.h> 47255570Strasz#include <unistd.h> 48255570Strasz 49255570Strasz#include "ctld.h" 50255570Strasz 51255570Straszstatic volatile bool sighup_received = false; 52255570Straszstatic volatile bool sigterm_received = false; 53255570Straszstatic volatile bool sigalrm_received = false; 54255570Strasz 55255570Straszstatic int nchildren = 0; 56255570Strasz 57255570Straszstatic void 58255570Straszusage(void) 59255570Strasz{ 60255570Strasz 61255570Strasz fprintf(stderr, "usage: ctld [-d][-f config-file]\n"); 62255570Strasz exit(1); 63255570Strasz} 64255570Strasz 65255570Straszchar * 66255570Straszchecked_strdup(const char *s) 67255570Strasz{ 68255570Strasz char *c; 69255570Strasz 70255570Strasz c = strdup(s); 71255570Strasz if (c == NULL) 72255570Strasz log_err(1, "strdup"); 73255570Strasz return (c); 74255570Strasz} 75255570Strasz 76255570Straszstruct conf * 77255570Straszconf_new(void) 78255570Strasz{ 79255570Strasz struct conf *conf; 80255570Strasz 81255570Strasz conf = calloc(1, sizeof(*conf)); 82255570Strasz if (conf == NULL) 83255570Strasz log_err(1, "calloc"); 84255570Strasz TAILQ_INIT(&conf->conf_targets); 85255570Strasz TAILQ_INIT(&conf->conf_auth_groups); 86255570Strasz TAILQ_INIT(&conf->conf_portal_groups); 87255570Strasz 88255570Strasz conf->conf_debug = 0; 89255570Strasz conf->conf_timeout = 60; 90255570Strasz conf->conf_maxproc = 30; 91255570Strasz 92255570Strasz return (conf); 93255570Strasz} 94255570Strasz 95255570Straszvoid 96255570Straszconf_delete(struct conf *conf) 97255570Strasz{ 98255570Strasz struct target *targ, *tmp; 99255570Strasz struct auth_group *ag, *cagtmp; 100255570Strasz struct portal_group *pg, *cpgtmp; 101255570Strasz 102255570Strasz assert(conf->conf_pidfh == NULL); 103255570Strasz 104255570Strasz TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp) 105255570Strasz target_delete(targ); 106255570Strasz TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp) 107255570Strasz auth_group_delete(ag); 108255570Strasz TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) 109255570Strasz portal_group_delete(pg); 110255570Strasz free(conf->conf_pidfile_path); 111255570Strasz free(conf); 112255570Strasz} 113255570Strasz 114255570Straszstatic struct auth * 115255570Straszauth_new(struct auth_group *ag) 116255570Strasz{ 117255570Strasz struct auth *auth; 118255570Strasz 119255570Strasz auth = calloc(1, sizeof(*auth)); 120255570Strasz if (auth == NULL) 121255570Strasz log_err(1, "calloc"); 122255570Strasz auth->a_auth_group = ag; 123255570Strasz TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next); 124255570Strasz return (auth); 125255570Strasz} 126255570Strasz 127255570Straszstatic void 128255570Straszauth_delete(struct auth *auth) 129255570Strasz{ 130255570Strasz TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next); 131255570Strasz 132255570Strasz free(auth->a_user); 133255570Strasz free(auth->a_secret); 134255570Strasz free(auth->a_mutual_user); 135255570Strasz free(auth->a_mutual_secret); 136255570Strasz free(auth); 137255570Strasz} 138255570Strasz 139255570Straszconst struct auth * 140255570Straszauth_find(struct auth_group *ag, const char *user) 141255570Strasz{ 142255570Strasz const struct auth *auth; 143255570Strasz 144255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) { 145255570Strasz if (strcmp(auth->a_user, user) == 0) 146255570Strasz return (auth); 147255570Strasz } 148255570Strasz 149255570Strasz return (NULL); 150255570Strasz} 151255570Strasz 152255570Straszstruct auth_group * 153255570Straszauth_group_new(struct conf *conf, const char *name) 154255570Strasz{ 155255570Strasz struct auth_group *ag; 156255570Strasz 157255570Strasz if (name != NULL) { 158255570Strasz ag = auth_group_find(conf, name); 159255570Strasz if (ag != NULL) { 160255570Strasz log_warnx("duplicated auth-group \"%s\"", name); 161255570Strasz return (NULL); 162255570Strasz } 163255570Strasz } 164255570Strasz 165255570Strasz ag = calloc(1, sizeof(*ag)); 166255570Strasz if (ag == NULL) 167255570Strasz log_err(1, "calloc"); 168255570Strasz if (name != NULL) 169255570Strasz ag->ag_name = checked_strdup(name); 170255570Strasz TAILQ_INIT(&ag->ag_auths); 171255570Strasz ag->ag_conf = conf; 172255570Strasz TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); 173255570Strasz 174255570Strasz return (ag); 175255570Strasz} 176255570Strasz 177255570Straszvoid 178255570Straszauth_group_delete(struct auth_group *ag) 179255570Strasz{ 180255570Strasz struct auth *auth, *tmp; 181255570Strasz 182255570Strasz TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); 183255570Strasz 184255570Strasz TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, tmp) 185255570Strasz auth_delete(auth); 186255570Strasz free(ag->ag_name); 187255570Strasz free(ag); 188255570Strasz} 189255570Strasz 190255570Straszstruct auth_group * 191255570Straszauth_group_find(struct conf *conf, const char *name) 192255570Strasz{ 193255570Strasz struct auth_group *ag; 194255570Strasz 195255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 196255570Strasz if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) 197255570Strasz return (ag); 198255570Strasz } 199255570Strasz 200255570Strasz return (NULL); 201255570Strasz} 202255570Strasz 203255570Straszstatic void 204255570Straszauth_check_secret_length(struct auth *auth) 205255570Strasz{ 206255570Strasz size_t len; 207255570Strasz 208255570Strasz len = strlen(auth->a_secret); 209255570Strasz if (len > 16) { 210255570Strasz if (auth->a_auth_group->ag_name != NULL) 211255570Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 212255570Strasz "is too long; it should be at most 16 characters " 213255570Strasz "long", auth->a_user, auth->a_auth_group->ag_name); 214255570Strasz else 215255570Strasz log_warnx("secret for user \"%s\", target \"%s\", " 216255570Strasz "is too long; it should be at most 16 characters " 217255570Strasz "long", auth->a_user, 218255570Strasz auth->a_auth_group->ag_target->t_iqn); 219255570Strasz } 220255570Strasz if (len < 12) { 221255570Strasz if (auth->a_auth_group->ag_name != NULL) 222255570Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 223255570Strasz "is too short; it should be at least 12 characters " 224255570Strasz "long", auth->a_user, 225255570Strasz auth->a_auth_group->ag_name); 226255570Strasz else 227255570Strasz log_warnx("secret for user \"%s\", target \"%s\", " 228255570Strasz "is too short; it should be at least 16 characters " 229255570Strasz "long", auth->a_user, 230255570Strasz auth->a_auth_group->ag_target->t_iqn); 231255570Strasz } 232255570Strasz 233255570Strasz if (auth->a_mutual_secret != NULL) { 234255570Strasz len = strlen(auth->a_secret); 235255570Strasz if (len > 16) { 236255570Strasz if (auth->a_auth_group->ag_name != NULL) 237255570Strasz log_warnx("mutual secret for user \"%s\", " 238255570Strasz "auth-group \"%s\", is too long; it should " 239255570Strasz "be at most 16 characters long", 240255570Strasz auth->a_user, auth->a_auth_group->ag_name); 241255570Strasz else 242255570Strasz log_warnx("mutual secret for user \"%s\", " 243255570Strasz "target \"%s\", is too long; it should " 244255570Strasz "be at most 16 characters long", 245255570Strasz auth->a_user, 246255570Strasz auth->a_auth_group->ag_target->t_iqn); 247255570Strasz } 248255570Strasz if (len < 12) { 249255570Strasz if (auth->a_auth_group->ag_name != NULL) 250255570Strasz log_warnx("mutual secret for user \"%s\", " 251255570Strasz "auth-group \"%s\", is too short; it " 252255570Strasz "should be at least 12 characters long", 253255570Strasz auth->a_user, auth->a_auth_group->ag_name); 254255570Strasz else 255255570Strasz log_warnx("mutual secret for user \"%s\", " 256255570Strasz "target \"%s\", is too short; it should be " 257255570Strasz "at least 16 characters long", 258255570Strasz auth->a_user, 259255570Strasz auth->a_auth_group->ag_target->t_iqn); 260255570Strasz } 261255570Strasz } 262255570Strasz} 263255570Strasz 264255570Straszconst struct auth * 265255570Straszauth_new_chap(struct auth_group *ag, const char *user, 266255570Strasz const char *secret) 267255570Strasz{ 268255570Strasz struct auth *auth; 269255570Strasz 270255570Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 271255570Strasz ag->ag_type = AG_TYPE_CHAP; 272255570Strasz if (ag->ag_type != AG_TYPE_CHAP) { 273255570Strasz if (ag->ag_name != NULL) 274255570Strasz log_warnx("cannot mix \"chap\" authentication with " 275255570Strasz "other types for auth-group \"%s\"", ag->ag_name); 276255570Strasz else 277255570Strasz log_warnx("cannot mix \"chap\" authentication with " 278255570Strasz "other types for target \"%s\"", 279255570Strasz ag->ag_target->t_iqn); 280255570Strasz return (NULL); 281255570Strasz } 282255570Strasz 283255570Strasz auth = auth_new(ag); 284255570Strasz auth->a_user = checked_strdup(user); 285255570Strasz auth->a_secret = checked_strdup(secret); 286255570Strasz 287255570Strasz auth_check_secret_length(auth); 288255570Strasz 289255570Strasz return (auth); 290255570Strasz} 291255570Strasz 292255570Straszconst struct auth * 293255570Straszauth_new_chap_mutual(struct auth_group *ag, const char *user, 294255570Strasz const char *secret, const char *user2, const char *secret2) 295255570Strasz{ 296255570Strasz struct auth *auth; 297255570Strasz 298255570Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 299255570Strasz ag->ag_type = AG_TYPE_CHAP_MUTUAL; 300255570Strasz if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) { 301255570Strasz if (ag->ag_name != NULL) 302255570Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 303255570Strasz "with other types for auth-group \"%s\"", 304255570Strasz ag->ag_name); 305255570Strasz else 306255570Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 307255570Strasz "with other types for target \"%s\"", 308255570Strasz ag->ag_target->t_iqn); 309255570Strasz return (NULL); 310255570Strasz } 311255570Strasz 312255570Strasz auth = auth_new(ag); 313255570Strasz auth->a_user = checked_strdup(user); 314255570Strasz auth->a_secret = checked_strdup(secret); 315255570Strasz auth->a_mutual_user = checked_strdup(user2); 316255570Strasz auth->a_mutual_secret = checked_strdup(secret2); 317255570Strasz 318255570Strasz auth_check_secret_length(auth); 319255570Strasz 320255570Strasz return (auth); 321255570Strasz} 322255570Strasz 323255570Straszstatic struct portal * 324255570Straszportal_new(struct portal_group *pg) 325255570Strasz{ 326255570Strasz struct portal *portal; 327255570Strasz 328255570Strasz portal = calloc(1, sizeof(*portal)); 329255570Strasz if (portal == NULL) 330255570Strasz log_err(1, "calloc"); 331255570Strasz TAILQ_INIT(&portal->p_targets); 332255570Strasz portal->p_portal_group = pg; 333255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 334255570Strasz return (portal); 335255570Strasz} 336255570Strasz 337255570Straszstatic void 338255570Straszportal_delete(struct portal *portal) 339255570Strasz{ 340255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 341255570Strasz freeaddrinfo(portal->p_ai); 342255570Strasz free(portal->p_listen); 343255570Strasz free(portal); 344255570Strasz} 345255570Strasz 346255570Straszstruct portal_group * 347255570Straszportal_group_new(struct conf *conf, const char *name) 348255570Strasz{ 349255570Strasz struct portal_group *pg; 350255570Strasz 351255678Strasz pg = portal_group_find(conf, name); 352255678Strasz if (pg != NULL) { 353255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 354255678Strasz return (NULL); 355255570Strasz } 356255570Strasz 357255570Strasz pg = calloc(1, sizeof(*pg)); 358255570Strasz if (pg == NULL) 359255570Strasz log_err(1, "calloc"); 360255570Strasz pg->pg_name = checked_strdup(name); 361255570Strasz TAILQ_INIT(&pg->pg_portals); 362255570Strasz pg->pg_conf = conf; 363255570Strasz conf->conf_last_portal_group_tag++; 364255570Strasz pg->pg_tag = conf->conf_last_portal_group_tag; 365255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 366255570Strasz 367255570Strasz return (pg); 368255570Strasz} 369255570Strasz 370255570Straszvoid 371255570Straszportal_group_delete(struct portal_group *pg) 372255570Strasz{ 373255570Strasz struct portal *portal, *tmp; 374255570Strasz 375255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 376255570Strasz 377255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 378255570Strasz portal_delete(portal); 379255570Strasz free(pg->pg_name); 380255570Strasz free(pg); 381255570Strasz} 382255570Strasz 383255570Straszstruct portal_group * 384255570Straszportal_group_find(struct conf *conf, const char *name) 385255570Strasz{ 386255570Strasz struct portal_group *pg; 387255570Strasz 388255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 389255570Strasz if (strcmp(pg->pg_name, name) == 0) 390255570Strasz return (pg); 391255570Strasz } 392255570Strasz 393255570Strasz return (NULL); 394255570Strasz} 395255570Strasz 396255570Straszint 397255570Straszportal_group_add_listen(struct portal_group *pg, const char *value, bool iser) 398255570Strasz{ 399255570Strasz struct addrinfo hints; 400255570Strasz struct portal *portal; 401255570Strasz char *addr, *ch, *arg; 402255570Strasz const char *port; 403255570Strasz int error, colons = 0; 404255570Strasz 405255570Strasz#ifndef ICL_KERNEL_PROXY 406255570Strasz if (iser) { 407255570Strasz log_warnx("ctld(8) compiled without ICL_KERNEL_PROXY " 408255570Strasz "does not support iSER protocol"); 409255570Strasz return (-1); 410255570Strasz } 411255570Strasz#endif 412255570Strasz 413255570Strasz portal = portal_new(pg); 414255570Strasz portal->p_listen = checked_strdup(value); 415255570Strasz portal->p_iser = iser; 416255570Strasz 417255570Strasz arg = portal->p_listen; 418255570Strasz if (arg[0] == '\0') { 419255570Strasz log_warnx("empty listen address"); 420255570Strasz free(portal->p_listen); 421255570Strasz free(portal); 422255570Strasz return (1); 423255570Strasz } 424255570Strasz if (arg[0] == '[') { 425255570Strasz /* 426255570Strasz * IPv6 address in square brackets, perhaps with port. 427255570Strasz */ 428255570Strasz arg++; 429255570Strasz addr = strsep(&arg, "]"); 430255570Strasz if (arg == NULL) { 431255570Strasz log_warnx("invalid listen address %s", 432255570Strasz portal->p_listen); 433255570Strasz free(portal->p_listen); 434255570Strasz free(portal); 435255570Strasz return (1); 436255570Strasz } 437255570Strasz if (arg[0] == '\0') { 438255570Strasz port = "3260"; 439255570Strasz } else if (arg[0] == ':') { 440255570Strasz port = arg + 1; 441255570Strasz } else { 442255570Strasz log_warnx("invalid listen address %s", 443255570Strasz portal->p_listen); 444255570Strasz free(portal->p_listen); 445255570Strasz free(portal); 446255570Strasz return (1); 447255570Strasz } 448255570Strasz } else { 449255570Strasz /* 450255570Strasz * Either IPv6 address without brackets - and without 451255570Strasz * a port - or IPv4 address. Just count the colons. 452255570Strasz */ 453255570Strasz for (ch = arg; *ch != '\0'; ch++) { 454255570Strasz if (*ch == ':') 455255570Strasz colons++; 456255570Strasz } 457255570Strasz if (colons > 1) { 458255570Strasz addr = arg; 459255570Strasz port = "3260"; 460255570Strasz } else { 461255570Strasz addr = strsep(&arg, ":"); 462255570Strasz if (arg == NULL) 463255570Strasz port = "3260"; 464255570Strasz else 465255570Strasz port = arg; 466255570Strasz } 467255570Strasz } 468255570Strasz 469255570Strasz memset(&hints, 0, sizeof(hints)); 470255570Strasz hints.ai_family = PF_UNSPEC; 471255570Strasz hints.ai_socktype = SOCK_STREAM; 472255570Strasz hints.ai_flags = AI_PASSIVE; 473255570Strasz 474255570Strasz error = getaddrinfo(addr, port, &hints, &portal->p_ai); 475255570Strasz if (error != 0) { 476255570Strasz log_warnx("getaddrinfo for %s failed: %s", 477255570Strasz portal->p_listen, gai_strerror(error)); 478255570Strasz free(portal->p_listen); 479255570Strasz free(portal); 480255570Strasz return (1); 481255570Strasz } 482255570Strasz 483255570Strasz /* 484255570Strasz * XXX: getaddrinfo(3) may return multiple addresses; we should turn 485255570Strasz * those into multiple portals. 486255570Strasz */ 487255570Strasz 488255570Strasz return (0); 489255570Strasz} 490255570Strasz 491255570Straszstatic bool 492255570Straszvalid_hex(const char ch) 493255570Strasz{ 494255570Strasz switch (ch) { 495255570Strasz case '0': 496255570Strasz case '1': 497255570Strasz case '2': 498255570Strasz case '3': 499255570Strasz case '4': 500255570Strasz case '5': 501255570Strasz case '6': 502255570Strasz case '7': 503255570Strasz case '8': 504255570Strasz case '9': 505255570Strasz case 'a': 506255570Strasz case 'A': 507255570Strasz case 'b': 508255570Strasz case 'B': 509255570Strasz case 'c': 510255570Strasz case 'C': 511255570Strasz case 'd': 512255570Strasz case 'D': 513255570Strasz case 'e': 514255570Strasz case 'E': 515255570Strasz case 'f': 516255570Strasz case 'F': 517255570Strasz return (true); 518255570Strasz default: 519255570Strasz return (false); 520255570Strasz } 521255570Strasz} 522255570Strasz 523255570Straszbool 524255570Straszvalid_iscsi_name(const char *name) 525255570Strasz{ 526255570Strasz int i; 527255570Strasz 528255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 529255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 530255570Strasz "by iSCSI specification is %d characters", 531255570Strasz name, MAX_NAME_LEN); 532255570Strasz return (false); 533255570Strasz } 534255570Strasz 535255570Strasz /* 536255570Strasz * In the cases below, we don't return an error, just in case the admin 537255570Strasz * was right, and we're wrong. 538255570Strasz */ 539255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 540255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 541255570Strasz /* 542255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 543255570Strasz * by 3.2.6.2: iSCSI Name Encoding. 544255570Strasz */ 545255570Strasz if (isalnum(name[i])) 546255570Strasz continue; 547255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 548255570Strasz continue; 549255570Strasz log_warnx("invalid character \"%c\" in target name " 550255570Strasz "\"%s\"; allowed characters are letters, digits, " 551255570Strasz "'-', '.', and ':'", name[i], name); 552255570Strasz break; 553255570Strasz } 554255570Strasz /* 555255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 556255570Strasz */ 557255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 558255570Strasz if (strlen(name) != strlen("eui.") + 16) 559255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 560255570Strasz "should be followed by exactly 16 hexadecimal " 561255570Strasz "digits", name); 562255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 563255570Strasz if (!valid_hex(name[i])) { 564255570Strasz log_warnx("invalid character \"%c\" in target " 565255570Strasz "name \"%s\"; allowed characters are 1-9 " 566255570Strasz "and A-F", name[i], name); 567255570Strasz break; 568255570Strasz } 569255570Strasz } 570255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 571255570Strasz if (strlen(name) > strlen("naa.") + 32) 572255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 573255570Strasz "should be followed by at most 32 hexadecimal " 574255570Strasz "digits", name); 575255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 576255570Strasz if (!valid_hex(name[i])) { 577255570Strasz log_warnx("invalid character \"%c\" in target " 578255570Strasz "name \"%s\"; allowed characters are 1-9 " 579255570Strasz "and A-F", name[i], name); 580255570Strasz break; 581255570Strasz } 582255570Strasz } 583255570Strasz } else { 584255570Strasz log_warnx("invalid target name \"%s\"; should start with " 585255570Strasz "either \".iqn\", \"eui.\", or \"naa.\"", 586255570Strasz name); 587255570Strasz } 588255570Strasz return (true); 589255570Strasz} 590255570Strasz 591255570Straszstruct target * 592255570Strasztarget_new(struct conf *conf, const char *iqn) 593255570Strasz{ 594255570Strasz struct target *targ; 595255570Strasz int i, len; 596255570Strasz 597255570Strasz targ = target_find(conf, iqn); 598255570Strasz if (targ != NULL) { 599255570Strasz log_warnx("duplicated target \"%s\"", iqn); 600255570Strasz return (NULL); 601255570Strasz } 602255570Strasz if (valid_iscsi_name(iqn) == false) { 603255570Strasz log_warnx("target name \"%s\" is invalid", iqn); 604255570Strasz return (NULL); 605255570Strasz } 606255570Strasz targ = calloc(1, sizeof(*targ)); 607255570Strasz if (targ == NULL) 608255570Strasz log_err(1, "calloc"); 609255570Strasz targ->t_iqn = checked_strdup(iqn); 610255570Strasz 611255570Strasz /* 612255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 613255570Strasz */ 614255570Strasz len = strlen(iqn); 615255570Strasz for (i = 0; i < len; i++) 616255570Strasz targ->t_iqn[i] = tolower(targ->t_iqn[i]); 617255570Strasz 618255570Strasz TAILQ_INIT(&targ->t_luns); 619255570Strasz targ->t_conf = conf; 620255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 621255570Strasz 622255570Strasz return (targ); 623255570Strasz} 624255570Strasz 625255570Straszvoid 626255570Strasztarget_delete(struct target *targ) 627255570Strasz{ 628255570Strasz struct lun *lun, *tmp; 629255570Strasz 630255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 631255570Strasz 632255570Strasz TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp) 633255570Strasz lun_delete(lun); 634255570Strasz free(targ->t_iqn); 635255570Strasz free(targ); 636255570Strasz} 637255570Strasz 638255570Straszstruct target * 639255570Strasztarget_find(struct conf *conf, const char *iqn) 640255570Strasz{ 641255570Strasz struct target *targ; 642255570Strasz 643255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 644255570Strasz if (strcasecmp(targ->t_iqn, iqn) == 0) 645255570Strasz return (targ); 646255570Strasz } 647255570Strasz 648255570Strasz return (NULL); 649255570Strasz} 650255570Strasz 651255570Straszstruct lun * 652255570Straszlun_new(struct target *targ, int lun_id) 653255570Strasz{ 654255570Strasz struct lun *lun; 655255570Strasz 656255570Strasz lun = lun_find(targ, lun_id); 657255570Strasz if (lun != NULL) { 658255570Strasz log_warnx("duplicated lun %d for target \"%s\"", 659255570Strasz lun_id, targ->t_iqn); 660255570Strasz return (NULL); 661255570Strasz } 662255570Strasz 663255570Strasz lun = calloc(1, sizeof(*lun)); 664255570Strasz if (lun == NULL) 665255570Strasz log_err(1, "calloc"); 666255570Strasz lun->l_lun = lun_id; 667255570Strasz TAILQ_INIT(&lun->l_options); 668255570Strasz lun->l_target = targ; 669255570Strasz TAILQ_INSERT_TAIL(&targ->t_luns, lun, l_next); 670255570Strasz 671255570Strasz return (lun); 672255570Strasz} 673255570Strasz 674255570Straszvoid 675255570Straszlun_delete(struct lun *lun) 676255570Strasz{ 677255570Strasz struct lun_option *lo, *tmp; 678255570Strasz 679255570Strasz TAILQ_REMOVE(&lun->l_target->t_luns, lun, l_next); 680255570Strasz 681255570Strasz TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp) 682255570Strasz lun_option_delete(lo); 683255570Strasz free(lun->l_backend); 684255570Strasz free(lun->l_device_id); 685255570Strasz free(lun->l_path); 686255570Strasz free(lun->l_serial); 687255570Strasz free(lun); 688255570Strasz} 689255570Strasz 690255570Straszstruct lun * 691255570Straszlun_find(struct target *targ, int lun_id) 692255570Strasz{ 693255570Strasz struct lun *lun; 694255570Strasz 695255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 696255570Strasz if (lun->l_lun == lun_id) 697255570Strasz return (lun); 698255570Strasz } 699255570Strasz 700255570Strasz return (NULL); 701255570Strasz} 702255570Strasz 703255570Straszvoid 704255570Straszlun_set_backend(struct lun *lun, const char *value) 705255570Strasz{ 706255570Strasz free(lun->l_backend); 707255570Strasz lun->l_backend = checked_strdup(value); 708255570Strasz} 709255570Strasz 710255570Straszvoid 711255570Straszlun_set_blocksize(struct lun *lun, size_t value) 712255570Strasz{ 713255570Strasz 714255570Strasz lun->l_blocksize = value; 715255570Strasz} 716255570Strasz 717255570Straszvoid 718255570Straszlun_set_device_id(struct lun *lun, const char *value) 719255570Strasz{ 720255570Strasz free(lun->l_device_id); 721255570Strasz lun->l_device_id = checked_strdup(value); 722255570Strasz} 723255570Strasz 724255570Straszvoid 725255570Straszlun_set_path(struct lun *lun, const char *value) 726255570Strasz{ 727255570Strasz free(lun->l_path); 728255570Strasz lun->l_path = checked_strdup(value); 729255570Strasz} 730255570Strasz 731255570Straszvoid 732255570Straszlun_set_serial(struct lun *lun, const char *value) 733255570Strasz{ 734255570Strasz free(lun->l_serial); 735255570Strasz lun->l_serial = checked_strdup(value); 736255570Strasz} 737255570Strasz 738255570Straszvoid 739255570Straszlun_set_size(struct lun *lun, size_t value) 740255570Strasz{ 741255570Strasz 742255570Strasz lun->l_size = value; 743255570Strasz} 744255570Strasz 745255570Straszvoid 746255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 747255570Strasz{ 748255570Strasz 749255570Strasz lun->l_ctl_lun = value; 750255570Strasz} 751255570Strasz 752255570Straszstruct lun_option * 753255570Straszlun_option_new(struct lun *lun, const char *name, const char *value) 754255570Strasz{ 755255570Strasz struct lun_option *lo; 756255570Strasz 757255570Strasz lo = lun_option_find(lun, name); 758255570Strasz if (lo != NULL) { 759255570Strasz log_warnx("duplicated lun option %s for lun %d, target \"%s\"", 760255570Strasz name, lun->l_lun, lun->l_target->t_iqn); 761255570Strasz return (NULL); 762255570Strasz } 763255570Strasz 764255570Strasz lo = calloc(1, sizeof(*lo)); 765255570Strasz if (lo == NULL) 766255570Strasz log_err(1, "calloc"); 767255570Strasz lo->lo_name = checked_strdup(name); 768255570Strasz lo->lo_value = checked_strdup(value); 769255570Strasz lo->lo_lun = lun; 770255570Strasz TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next); 771255570Strasz 772255570Strasz return (lo); 773255570Strasz} 774255570Strasz 775255570Straszvoid 776255570Straszlun_option_delete(struct lun_option *lo) 777255570Strasz{ 778255570Strasz 779255570Strasz TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next); 780255570Strasz 781255570Strasz free(lo->lo_name); 782255570Strasz free(lo->lo_value); 783255570Strasz free(lo); 784255570Strasz} 785255570Strasz 786255570Straszstruct lun_option * 787255570Straszlun_option_find(struct lun *lun, const char *name) 788255570Strasz{ 789255570Strasz struct lun_option *lo; 790255570Strasz 791255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 792255570Strasz if (strcmp(lo->lo_name, name) == 0) 793255570Strasz return (lo); 794255570Strasz } 795255570Strasz 796255570Strasz return (NULL); 797255570Strasz} 798255570Strasz 799255570Straszvoid 800255570Straszlun_option_set(struct lun_option *lo, const char *value) 801255570Strasz{ 802255570Strasz 803255570Strasz free(lo->lo_value); 804255570Strasz lo->lo_value = checked_strdup(value); 805255570Strasz} 806255570Strasz 807255570Straszstatic struct connection * 808255570Straszconnection_new(struct portal *portal, int fd, const char *host) 809255570Strasz{ 810255570Strasz struct connection *conn; 811255570Strasz 812255570Strasz conn = calloc(1, sizeof(*conn)); 813255570Strasz if (conn == NULL) 814255570Strasz log_err(1, "calloc"); 815255570Strasz conn->conn_portal = portal; 816255570Strasz conn->conn_socket = fd; 817255570Strasz conn->conn_initiator_addr = checked_strdup(host); 818255570Strasz 819255570Strasz /* 820255570Strasz * Default values, from RFC 3720, section 12. 821255570Strasz */ 822255570Strasz conn->conn_max_data_segment_length = 8192; 823255570Strasz conn->conn_max_burst_length = 262144; 824255570Strasz conn->conn_immediate_data = true; 825255570Strasz 826255570Strasz return (conn); 827255570Strasz} 828255570Strasz 829255570Strasz#if 0 830255570Straszstatic void 831255570Straszconf_print(struct conf *conf) 832255570Strasz{ 833255570Strasz struct auth_group *ag; 834255570Strasz struct auth *auth; 835255570Strasz struct portal_group *pg; 836255570Strasz struct portal *portal; 837255570Strasz struct target *targ; 838255570Strasz struct lun *lun; 839255570Strasz struct lun_option *lo; 840255570Strasz 841255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 842255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 843255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 844255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 845255570Strasz auth->a_user, auth->a_secret, 846255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 847255570Strasz fprintf(stderr, "}\n"); 848255570Strasz } 849255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 850255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 851255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 852255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 853255570Strasz fprintf(stderr, "}\n"); 854255570Strasz } 855255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 856255570Strasz fprintf(stderr, "target %s {\n", targ->t_iqn); 857255570Strasz if (targ->t_alias != NULL) 858255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 859255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 860255570Strasz fprintf(stderr, "\tlun %d {\n", lun->l_lun); 861255570Strasz fprintf(stderr, "\t\tpath %s\n", lun->l_path); 862255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) 863255570Strasz fprintf(stderr, "\t\toption %s %s\n", 864255570Strasz lo->lo_name, lo->lo_value); 865255570Strasz fprintf(stderr, "\t}\n"); 866255570Strasz } 867255570Strasz fprintf(stderr, "}\n"); 868255570Strasz } 869255570Strasz} 870255570Strasz#endif 871255570Strasz 872263717Straszstatic int 873263717Straszconf_verify_lun(struct lun *lun) 874263717Strasz{ 875263717Strasz const struct lun *lun2; 876263718Strasz const struct target *targ2; 877263717Strasz 878263717Strasz if (lun->l_backend == NULL) 879263717Strasz lun_set_backend(lun, "block"); 880263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 881263717Strasz if (lun->l_path == NULL) { 882263717Strasz log_warnx("missing path for lun %d, target \"%s\"", 883263717Strasz lun->l_lun, lun->l_target->t_iqn); 884263717Strasz return (1); 885263717Strasz } 886263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 887263717Strasz if (lun->l_size == 0) { 888263717Strasz log_warnx("missing size for ramdisk-backed lun %d, " 889263717Strasz "target \"%s\"", lun->l_lun, lun->l_target->t_iqn); 890263717Strasz return (1); 891263717Strasz } 892263717Strasz if (lun->l_path != NULL) { 893263717Strasz log_warnx("path must not be specified " 894263717Strasz "for ramdisk-backed lun %d, target \"%s\"", 895263717Strasz lun->l_lun, lun->l_target->t_iqn); 896263717Strasz return (1); 897263717Strasz } 898263717Strasz } 899263717Strasz if (lun->l_lun < 0 || lun->l_lun > 255) { 900263717Strasz log_warnx("invalid lun number for lun %d, target \"%s\"; " 901263717Strasz "must be between 0 and 255", lun->l_lun, 902263717Strasz lun->l_target->t_iqn); 903263717Strasz return (1); 904263717Strasz } 905263717Strasz if (lun->l_blocksize == 0) { 906263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 907263717Strasz } else if (lun->l_blocksize < 0) { 908263717Strasz log_warnx("invalid blocksize for lun %d, target \"%s\"; " 909263717Strasz "must be larger than 0", lun->l_lun, lun->l_target->t_iqn); 910263717Strasz return (1); 911263717Strasz } 912263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 913263717Strasz log_warnx("invalid size for lun %d, target \"%s\"; " 914263717Strasz "must be multiple of blocksize", lun->l_lun, 915263717Strasz lun->l_target->t_iqn); 916263717Strasz return (1); 917263717Strasz } 918263718Strasz TAILQ_FOREACH(targ2, &lun->l_target->t_conf->conf_targets, t_next) { 919263718Strasz TAILQ_FOREACH(lun2, &targ2->t_luns, l_next) { 920263718Strasz if (lun == lun2) 921263718Strasz continue; 922263718Strasz if (lun->l_path != NULL && lun2->l_path != NULL && 923263718Strasz strcmp(lun->l_path, lun2->l_path) == 0) { 924263718Strasz log_debugx("WARNING: path \"%s\" duplicated " 925263718Strasz "between lun %d, target \"%s\", and " 926263718Strasz "lun %d, target \"%s\"", lun->l_path, 927263718Strasz lun->l_lun, lun->l_target->t_iqn, 928263718Strasz lun2->l_lun, lun2->l_target->t_iqn); 929263718Strasz } 930263718Strasz } 931263718Strasz } 932263717Strasz 933263717Strasz return (0); 934263717Strasz} 935263717Strasz 936255570Straszint 937255570Straszconf_verify(struct conf *conf) 938255570Strasz{ 939255570Strasz struct auth_group *ag; 940255570Strasz struct portal_group *pg; 941255570Strasz struct target *targ; 942263717Strasz struct lun *lun; 943255570Strasz bool found_lun0; 944263717Strasz int error; 945255570Strasz 946255570Strasz if (conf->conf_pidfile_path == NULL) 947255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 948255570Strasz 949255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 950255570Strasz if (targ->t_auth_group == NULL) { 951255570Strasz log_warnx("missing authentication for target \"%s\"; " 952255570Strasz "must specify either \"auth-group\", \"chap\", " 953255570Strasz "or \"chap-mutual\"", targ->t_iqn); 954255570Strasz return (1); 955255570Strasz } 956255570Strasz if (targ->t_portal_group == NULL) { 957255570Strasz targ->t_portal_group = portal_group_find(conf, 958255570Strasz "default"); 959255570Strasz assert(targ->t_portal_group != NULL); 960255570Strasz } 961255570Strasz found_lun0 = false; 962255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 963263717Strasz error = conf_verify_lun(lun); 964263717Strasz if (error != 0) 965263717Strasz return (error); 966255570Strasz if (lun->l_lun == 0) 967255570Strasz found_lun0 = true; 968255570Strasz } 969255570Strasz if (!found_lun0) { 970255570Strasz log_warnx("mandatory LUN 0 not configured " 971255570Strasz "for target \"%s\"", targ->t_iqn); 972255570Strasz return (1); 973255570Strasz } 974255570Strasz } 975255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 976255570Strasz assert(pg->pg_name != NULL); 977255570Strasz if (pg->pg_discovery_auth_group == NULL) { 978255570Strasz pg->pg_discovery_auth_group = 979255570Strasz auth_group_find(conf, "no-access"); 980255570Strasz assert(pg->pg_discovery_auth_group != NULL); 981255570Strasz } 982255570Strasz 983255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 984255570Strasz if (targ->t_portal_group == pg) 985255570Strasz break; 986255570Strasz } 987255570Strasz if (targ == NULL) { 988255570Strasz if (strcmp(pg->pg_name, "default") != 0) 989255570Strasz log_warnx("portal-group \"%s\" not assigned " 990255570Strasz "to any target", pg->pg_name); 991255570Strasz pg->pg_unassigned = true; 992255570Strasz } else 993255570Strasz pg->pg_unassigned = false; 994255570Strasz } 995255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 996255570Strasz if (ag->ag_name == NULL) 997255570Strasz assert(ag->ag_target != NULL); 998255570Strasz else 999255570Strasz assert(ag->ag_target == NULL); 1000255570Strasz 1001255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1002255570Strasz if (targ->t_auth_group == ag) 1003255570Strasz break; 1004255570Strasz } 1005255570Strasz if (targ == NULL && ag->ag_name != NULL && 1006255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1007255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1008255570Strasz log_warnx("auth-group \"%s\" not assigned " 1009255570Strasz "to any target", ag->ag_name); 1010255570Strasz } 1011255570Strasz } 1012255570Strasz 1013255570Strasz return (0); 1014255570Strasz} 1015255570Strasz 1016255570Straszstatic int 1017255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1018255570Strasz{ 1019255570Strasz struct target *oldtarg, *newtarg, *tmptarg; 1020255570Strasz struct lun *oldlun, *newlun, *tmplun; 1021255570Strasz struct portal_group *oldpg, *newpg; 1022255570Strasz struct portal *oldp, *newp; 1023255570Strasz pid_t otherpid; 1024255570Strasz int changed, cumulated_error = 0, error; 1025255570Strasz#ifndef ICL_KERNEL_PROXY 1026255570Strasz int one = 1; 1027255570Strasz#endif 1028255570Strasz 1029255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1030255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1031255570Strasz log_init(newconf->conf_debug); 1032255570Strasz } 1033255570Strasz 1034255570Strasz if (oldconf->conf_pidfh != NULL) { 1035255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1036255570Strasz if (newconf->conf_pidfile_path != NULL && 1037255570Strasz strcmp(oldconf->conf_pidfile_path, 1038255570Strasz newconf->conf_pidfile_path) == 0) { 1039255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1040255570Strasz oldconf->conf_pidfh = NULL; 1041255570Strasz } else { 1042255570Strasz log_debugx("removing pidfile %s", 1043255570Strasz oldconf->conf_pidfile_path); 1044255570Strasz pidfile_remove(oldconf->conf_pidfh); 1045255570Strasz oldconf->conf_pidfh = NULL; 1046255570Strasz } 1047255570Strasz } 1048255570Strasz 1049255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1050255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1051255570Strasz newconf->conf_pidfh = 1052255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1053255570Strasz if (newconf->conf_pidfh == NULL) { 1054255570Strasz if (errno == EEXIST) 1055255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1056255570Strasz (intmax_t)otherpid); 1057255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1058255570Strasz newconf->conf_pidfile_path); 1059255570Strasz } 1060255570Strasz } 1061255570Strasz 1062255570Strasz TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { 1063255570Strasz /* 1064255570Strasz * First, remove any targets present in the old configuration 1065255570Strasz * and missing in the new one. 1066255570Strasz */ 1067255570Strasz newtarg = target_find(newconf, oldtarg->t_iqn); 1068255570Strasz if (newtarg == NULL) { 1069255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, 1070255570Strasz tmplun) { 1071263716Strasz log_debugx("target %s not found in new " 1072263716Strasz "configuration; removing its lun %d, " 1073255570Strasz "backed by CTL lun %d", 1074255570Strasz oldtarg->t_iqn, oldlun->l_lun, 1075255570Strasz oldlun->l_ctl_lun); 1076255570Strasz error = kernel_lun_remove(oldlun); 1077255570Strasz if (error != 0) { 1078255570Strasz log_warnx("failed to remove lun %d, " 1079255570Strasz "target %s, CTL lun %d", 1080255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1081255570Strasz oldlun->l_ctl_lun); 1082255570Strasz cumulated_error++; 1083255570Strasz } 1084255570Strasz lun_delete(oldlun); 1085255570Strasz } 1086255570Strasz target_delete(oldtarg); 1087255570Strasz continue; 1088255570Strasz } 1089255570Strasz 1090255570Strasz /* 1091255570Strasz * Second, remove any LUNs present in the old target 1092255570Strasz * and missing in the new one. 1093255570Strasz */ 1094255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, tmplun) { 1095255570Strasz newlun = lun_find(newtarg, oldlun->l_lun); 1096255570Strasz if (newlun == NULL) { 1097255570Strasz log_debugx("lun %d, target %s, CTL lun %d " 1098263716Strasz "not found in new configuration; " 1099255570Strasz "removing", oldlun->l_lun, oldtarg->t_iqn, 1100255570Strasz oldlun->l_ctl_lun); 1101255570Strasz error = kernel_lun_remove(oldlun); 1102255570Strasz if (error != 0) { 1103255570Strasz log_warnx("failed to remove lun %d, " 1104255570Strasz "target %s, CTL lun %d", 1105255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1106255570Strasz oldlun->l_ctl_lun); 1107255570Strasz cumulated_error++; 1108255570Strasz } 1109255570Strasz lun_delete(oldlun); 1110255570Strasz continue; 1111255570Strasz } 1112255570Strasz 1113255570Strasz /* 1114255570Strasz * Also remove the LUNs changed by more than size. 1115255570Strasz */ 1116255570Strasz changed = 0; 1117255570Strasz assert(oldlun->l_backend != NULL); 1118255570Strasz assert(newlun->l_backend != NULL); 1119255570Strasz if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1120255570Strasz log_debugx("backend for lun %d, target %s, " 1121255570Strasz "CTL lun %d changed; removing", 1122255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1123255570Strasz oldlun->l_ctl_lun); 1124255570Strasz changed = 1; 1125255570Strasz } 1126255570Strasz if (oldlun->l_blocksize != newlun->l_blocksize) { 1127255570Strasz log_debugx("blocksize for lun %d, target %s, " 1128255570Strasz "CTL lun %d changed; removing", 1129255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1130255570Strasz oldlun->l_ctl_lun); 1131255570Strasz changed = 1; 1132255570Strasz } 1133255570Strasz if (newlun->l_device_id != NULL && 1134255570Strasz (oldlun->l_device_id == NULL || 1135255570Strasz strcmp(oldlun->l_device_id, newlun->l_device_id) != 1136255570Strasz 0)) { 1137255570Strasz log_debugx("device-id for lun %d, target %s, " 1138255570Strasz "CTL lun %d changed; removing", 1139255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1140255570Strasz oldlun->l_ctl_lun); 1141255570Strasz changed = 1; 1142255570Strasz } 1143255570Strasz if (newlun->l_path != NULL && 1144255570Strasz (oldlun->l_path == NULL || 1145255570Strasz strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1146255570Strasz log_debugx("path for lun %d, target %s, " 1147255570Strasz "CTL lun %d, changed; removing", 1148255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1149255570Strasz oldlun->l_ctl_lun); 1150255570Strasz changed = 1; 1151255570Strasz } 1152255570Strasz if (newlun->l_serial != NULL && 1153255570Strasz (oldlun->l_serial == NULL || 1154255570Strasz strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1155255570Strasz log_debugx("serial for lun %d, target %s, " 1156255570Strasz "CTL lun %d changed; removing", 1157255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1158255570Strasz oldlun->l_ctl_lun); 1159255570Strasz changed = 1; 1160255570Strasz } 1161255570Strasz if (changed) { 1162255570Strasz error = kernel_lun_remove(oldlun); 1163255570Strasz if (error != 0) { 1164255570Strasz log_warnx("failed to remove lun %d, " 1165255570Strasz "target %s, CTL lun %d", 1166255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1167255570Strasz oldlun->l_ctl_lun); 1168255570Strasz cumulated_error++; 1169255570Strasz } 1170255570Strasz lun_delete(oldlun); 1171255570Strasz continue; 1172255570Strasz } 1173255570Strasz 1174255570Strasz lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1175255570Strasz } 1176255570Strasz } 1177255570Strasz 1178255570Strasz /* 1179255570Strasz * Now add new targets or modify existing ones. 1180255570Strasz */ 1181255570Strasz TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { 1182255570Strasz oldtarg = target_find(oldconf, newtarg->t_iqn); 1183255570Strasz 1184255570Strasz TAILQ_FOREACH(newlun, &newtarg->t_luns, l_next) { 1185255570Strasz if (oldtarg != NULL) { 1186255570Strasz oldlun = lun_find(oldtarg, newlun->l_lun); 1187255570Strasz if (oldlun != NULL) { 1188255570Strasz if (newlun->l_size != oldlun->l_size) { 1189255570Strasz log_debugx("resizing lun %d, " 1190255570Strasz "target %s, CTL lun %d", 1191255570Strasz newlun->l_lun, 1192255570Strasz newtarg->t_iqn, 1193255570Strasz newlun->l_ctl_lun); 1194255570Strasz error = 1195255570Strasz kernel_lun_resize(newlun); 1196255570Strasz if (error != 0) { 1197255570Strasz log_warnx("failed to " 1198255570Strasz "resize lun %d, " 1199255570Strasz "target %s, " 1200255570Strasz "CTL lun %d", 1201255570Strasz newlun->l_lun, 1202255570Strasz newtarg->t_iqn, 1203255570Strasz newlun->l_lun); 1204255570Strasz cumulated_error++; 1205255570Strasz } 1206255570Strasz } 1207255570Strasz continue; 1208255570Strasz } 1209255570Strasz } 1210255570Strasz log_debugx("adding lun %d, target %s", 1211255570Strasz newlun->l_lun, newtarg->t_iqn); 1212255570Strasz error = kernel_lun_add(newlun); 1213255570Strasz if (error != 0) { 1214255570Strasz log_warnx("failed to add lun %d, target %s", 1215255570Strasz newlun->l_lun, newtarg->t_iqn); 1216255570Strasz cumulated_error++; 1217255570Strasz } 1218255570Strasz } 1219255570Strasz } 1220255570Strasz 1221255570Strasz /* 1222255570Strasz * Go through the new portals, opening the sockets as neccessary. 1223255570Strasz */ 1224255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1225255570Strasz if (newpg->pg_unassigned) { 1226255570Strasz log_debugx("not listening on portal-group \"%s\", " 1227255570Strasz "not assigned to any target", 1228255570Strasz newpg->pg_name); 1229255570Strasz continue; 1230255570Strasz } 1231255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1232255570Strasz /* 1233255570Strasz * Try to find already open portal and reuse 1234255570Strasz * the listening socket. We don't care about 1235255570Strasz * what portal or portal group that was, what 1236255570Strasz * matters is the listening address. 1237255570Strasz */ 1238255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1239255570Strasz pg_next) { 1240255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1241255570Strasz p_next) { 1242255570Strasz if (strcmp(newp->p_listen, 1243255570Strasz oldp->p_listen) == 0 && 1244255570Strasz oldp->p_socket > 0) { 1245255570Strasz newp->p_socket = 1246255570Strasz oldp->p_socket; 1247255570Strasz oldp->p_socket = 0; 1248255570Strasz break; 1249255570Strasz } 1250255570Strasz } 1251255570Strasz } 1252255570Strasz if (newp->p_socket > 0) { 1253255570Strasz /* 1254255570Strasz * We're done with this portal. 1255255570Strasz */ 1256255570Strasz continue; 1257255570Strasz } 1258255570Strasz 1259255570Strasz#ifdef ICL_KERNEL_PROXY 1260255570Strasz log_debugx("listening on %s, portal-group \"%s\" using ICL proxy", 1261255570Strasz newp->p_listen, newpg->pg_name); 1262255570Strasz kernel_listen(newp->p_ai, newp->p_iser); 1263255570Strasz#else 1264255570Strasz assert(newp->p_iser == false); 1265255570Strasz 1266255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1267255570Strasz newp->p_listen, newpg->pg_name); 1268255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1269255570Strasz newp->p_ai->ai_socktype, 1270255570Strasz newp->p_ai->ai_protocol); 1271255570Strasz if (newp->p_socket < 0) { 1272255570Strasz log_warn("socket(2) failed for %s", 1273255570Strasz newp->p_listen); 1274255570Strasz cumulated_error++; 1275255570Strasz continue; 1276255570Strasz } 1277255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1278255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1279255570Strasz if (error != 0) { 1280255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1281255570Strasz "for %s", newp->p_listen); 1282255570Strasz close(newp->p_socket); 1283255570Strasz newp->p_socket = 0; 1284255570Strasz cumulated_error++; 1285255570Strasz continue; 1286255570Strasz } 1287255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1288255570Strasz newp->p_ai->ai_addrlen); 1289255570Strasz if (error != 0) { 1290255570Strasz log_warn("bind(2) failed for %s", 1291255570Strasz newp->p_listen); 1292255570Strasz close(newp->p_socket); 1293255570Strasz newp->p_socket = 0; 1294255570Strasz cumulated_error++; 1295255570Strasz continue; 1296255570Strasz } 1297255570Strasz error = listen(newp->p_socket, -1); 1298255570Strasz if (error != 0) { 1299255570Strasz log_warn("listen(2) failed for %s", 1300255570Strasz newp->p_listen); 1301255570Strasz close(newp->p_socket); 1302255570Strasz newp->p_socket = 0; 1303255570Strasz cumulated_error++; 1304255570Strasz continue; 1305255570Strasz } 1306255570Strasz#endif /* !ICL_KERNEL_PROXY */ 1307255570Strasz } 1308255570Strasz } 1309255570Strasz 1310255570Strasz /* 1311255570Strasz * Go through the no longer used sockets, closing them. 1312255570Strasz */ 1313255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 1314255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 1315255570Strasz if (oldp->p_socket <= 0) 1316255570Strasz continue; 1317255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 1318255570Strasz oldp->p_listen, oldpg->pg_name); 1319255570Strasz close(oldp->p_socket); 1320255570Strasz oldp->p_socket = 0; 1321255570Strasz } 1322255570Strasz } 1323255570Strasz 1324255570Strasz return (cumulated_error); 1325255570Strasz} 1326255570Strasz 1327255570Straszbool 1328255570Strasztimed_out(void) 1329255570Strasz{ 1330255570Strasz 1331255570Strasz return (sigalrm_received); 1332255570Strasz} 1333255570Strasz 1334255570Straszstatic void 1335255570Straszsigalrm_handler(int dummy __unused) 1336255570Strasz{ 1337255570Strasz /* 1338255570Strasz * It would be easiest to just log an error and exit. We can't 1339255570Strasz * do this, though, because log_errx() is not signal safe, since 1340255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 1341255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 1342255570Strasz * to notice, we'll exit here one second later. 1343255570Strasz */ 1344255570Strasz if (sigalrm_received) { 1345255570Strasz /* 1346255570Strasz * Oh well. Just give up and quit. 1347255570Strasz */ 1348255570Strasz _exit(2); 1349255570Strasz } 1350255570Strasz 1351255570Strasz sigalrm_received = true; 1352255570Strasz} 1353255570Strasz 1354255570Straszstatic void 1355255570Straszset_timeout(const struct conf *conf) 1356255570Strasz{ 1357255570Strasz struct sigaction sa; 1358255570Strasz struct itimerval itv; 1359255570Strasz int error; 1360255570Strasz 1361255570Strasz if (conf->conf_timeout <= 0) { 1362255570Strasz log_debugx("session timeout disabled"); 1363255570Strasz return; 1364255570Strasz } 1365255570Strasz 1366255570Strasz bzero(&sa, sizeof(sa)); 1367255570Strasz sa.sa_handler = sigalrm_handler; 1368255570Strasz sigfillset(&sa.sa_mask); 1369255570Strasz error = sigaction(SIGALRM, &sa, NULL); 1370255570Strasz if (error != 0) 1371255570Strasz log_err(1, "sigaction"); 1372255570Strasz 1373255570Strasz /* 1374255570Strasz * First SIGALRM will arive after conf_timeout seconds. 1375255570Strasz * If we do nothing, another one will arrive a second later. 1376255570Strasz */ 1377255570Strasz bzero(&itv, sizeof(itv)); 1378255570Strasz itv.it_interval.tv_sec = 1; 1379255570Strasz itv.it_value.tv_sec = conf->conf_timeout; 1380255570Strasz 1381255570Strasz log_debugx("setting session timeout to %d seconds", 1382255570Strasz conf->conf_timeout); 1383255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 1384255570Strasz if (error != 0) 1385255570Strasz log_err(1, "setitimer"); 1386255570Strasz} 1387255570Strasz 1388255570Straszstatic int 1389255570Straszwait_for_children(bool block) 1390255570Strasz{ 1391255570Strasz pid_t pid; 1392255570Strasz int status; 1393255570Strasz int num = 0; 1394255570Strasz 1395255570Strasz for (;;) { 1396255570Strasz /* 1397255570Strasz * If "block" is true, wait for at least one process. 1398255570Strasz */ 1399255570Strasz if (block && num == 0) 1400255570Strasz pid = wait4(-1, &status, 0, NULL); 1401255570Strasz else 1402255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 1403255570Strasz if (pid <= 0) 1404255570Strasz break; 1405255570Strasz if (WIFSIGNALED(status)) { 1406255570Strasz log_warnx("child process %d terminated with signal %d", 1407255570Strasz pid, WTERMSIG(status)); 1408255570Strasz } else if (WEXITSTATUS(status) != 0) { 1409255570Strasz log_warnx("child process %d terminated with exit status %d", 1410255570Strasz pid, WEXITSTATUS(status)); 1411255570Strasz } else { 1412255570Strasz log_debugx("child process %d terminated gracefully", pid); 1413255570Strasz } 1414255570Strasz num++; 1415255570Strasz } 1416255570Strasz 1417255570Strasz return (num); 1418255570Strasz} 1419255570Strasz 1420255570Straszstatic void 1421255570Straszhandle_connection(struct portal *portal, int fd, bool dont_fork) 1422255570Strasz{ 1423255570Strasz struct connection *conn; 1424255570Strasz#ifndef ICL_KERNEL_PROXY 1425255570Strasz struct sockaddr_storage ss; 1426255570Strasz socklen_t sslen = sizeof(ss); 1427255570Strasz int error; 1428255570Strasz#endif 1429255570Strasz pid_t pid; 1430255570Strasz char host[NI_MAXHOST + 1]; 1431255570Strasz struct conf *conf; 1432255570Strasz 1433255570Strasz conf = portal->p_portal_group->pg_conf; 1434255570Strasz 1435255570Strasz if (dont_fork) { 1436255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 1437255570Strasz } else { 1438255570Strasz nchildren -= wait_for_children(false); 1439255570Strasz assert(nchildren >= 0); 1440255570Strasz 1441255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 1442255570Strasz log_debugx("maxproc limit of %d child processes hit; " 1443255570Strasz "waiting for child process to exit", conf->conf_maxproc); 1444255570Strasz nchildren -= wait_for_children(true); 1445255570Strasz assert(nchildren >= 0); 1446255570Strasz } 1447255570Strasz log_debugx("incoming connection; forking child process #%d", 1448255570Strasz nchildren); 1449255570Strasz nchildren++; 1450255570Strasz pid = fork(); 1451255570Strasz if (pid < 0) 1452255570Strasz log_err(1, "fork"); 1453255570Strasz if (pid > 0) { 1454255570Strasz close(fd); 1455255570Strasz return; 1456255570Strasz } 1457255570Strasz } 1458255570Strasz pidfile_close(conf->conf_pidfh); 1459255570Strasz 1460255570Strasz#ifdef ICL_KERNEL_PROXY 1461255570Strasz /* 1462255570Strasz * XXX 1463255570Strasz */ 1464255570Strasz log_set_peer_addr("XXX"); 1465255570Strasz#else 1466255570Strasz error = getpeername(fd, (struct sockaddr *)&ss, &sslen); 1467255570Strasz if (error != 0) 1468255570Strasz log_err(1, "getpeername"); 1469255570Strasz error = getnameinfo((struct sockaddr *)&ss, sslen, 1470255570Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 1471255570Strasz if (error != 0) 1472255570Strasz log_errx(1, "getaddrinfo: %s", gai_strerror(error)); 1473255570Strasz 1474255570Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 1475255570Strasz host, portal->p_portal_group->pg_name); 1476255570Strasz log_set_peer_addr(host); 1477255570Strasz setproctitle("%s", host); 1478255570Strasz#endif 1479255570Strasz 1480255570Strasz conn = connection_new(portal, fd, host); 1481255570Strasz set_timeout(conf); 1482255570Strasz kernel_capsicate(); 1483255570Strasz login(conn); 1484255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 1485255570Strasz kernel_handoff(conn); 1486255570Strasz log_debugx("connection handed off to the kernel"); 1487255570Strasz } else { 1488255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 1489255570Strasz discovery(conn); 1490255570Strasz } 1491255570Strasz log_debugx("nothing more to do; exiting"); 1492255570Strasz exit(0); 1493255570Strasz} 1494255570Strasz 1495255570Strasz#ifndef ICL_KERNEL_PROXY 1496255570Straszstatic int 1497255570Straszfd_add(int fd, fd_set *fdset, int nfds) 1498255570Strasz{ 1499255570Strasz 1500255570Strasz /* 1501255570Strasz * Skip sockets which we failed to bind. 1502255570Strasz */ 1503255570Strasz if (fd <= 0) 1504255570Strasz return (nfds); 1505255570Strasz 1506255570Strasz FD_SET(fd, fdset); 1507255570Strasz if (fd > nfds) 1508255570Strasz nfds = fd; 1509255570Strasz return (nfds); 1510255570Strasz} 1511255570Strasz#endif 1512255570Strasz 1513255570Straszstatic void 1514255570Straszmain_loop(struct conf *conf, bool dont_fork) 1515255570Strasz{ 1516255570Strasz struct portal_group *pg; 1517255570Strasz struct portal *portal; 1518255570Strasz#ifdef ICL_KERNEL_PROXY 1519255570Strasz int connection_id; 1520255570Strasz#else 1521255570Strasz fd_set fdset; 1522255570Strasz int error, nfds, client_fd; 1523255570Strasz#endif 1524255570Strasz 1525255570Strasz pidfile_write(conf->conf_pidfh); 1526255570Strasz 1527255570Strasz for (;;) { 1528255570Strasz if (sighup_received || sigterm_received) 1529255570Strasz return; 1530255570Strasz 1531255570Strasz#ifdef ICL_KERNEL_PROXY 1532255570Strasz connection_id = kernel_accept(); 1533255570Strasz if (connection_id == 0) 1534255570Strasz continue; 1535255570Strasz 1536255570Strasz /* 1537255570Strasz * XXX: This is obviously temporary. 1538255570Strasz */ 1539255570Strasz pg = TAILQ_FIRST(&conf->conf_portal_groups); 1540255570Strasz portal = TAILQ_FIRST(&pg->pg_portals); 1541255570Strasz 1542255570Strasz handle_connection(portal, connection_id, dont_fork); 1543255570Strasz#else 1544255570Strasz FD_ZERO(&fdset); 1545255570Strasz nfds = 0; 1546255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1547255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1548255570Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 1549255570Strasz } 1550255570Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 1551255570Strasz if (error <= 0) { 1552255570Strasz if (errno == EINTR) 1553255570Strasz return; 1554255570Strasz log_err(1, "select"); 1555255570Strasz } 1556255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1557255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 1558255570Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 1559255570Strasz continue; 1560255570Strasz client_fd = accept(portal->p_socket, NULL, 0); 1561255570Strasz if (client_fd < 0) 1562255570Strasz log_err(1, "accept"); 1563255570Strasz handle_connection(portal, client_fd, dont_fork); 1564255570Strasz break; 1565255570Strasz } 1566255570Strasz } 1567255570Strasz#endif /* !ICL_KERNEL_PROXY */ 1568255570Strasz } 1569255570Strasz} 1570255570Strasz 1571255570Straszstatic void 1572255570Straszsighup_handler(int dummy __unused) 1573255570Strasz{ 1574255570Strasz 1575255570Strasz sighup_received = true; 1576255570Strasz} 1577255570Strasz 1578255570Straszstatic void 1579255570Straszsigterm_handler(int dummy __unused) 1580255570Strasz{ 1581255570Strasz 1582255570Strasz sigterm_received = true; 1583255570Strasz} 1584255570Strasz 1585255570Straszstatic void 1586255570Straszregister_signals(void) 1587255570Strasz{ 1588255570Strasz struct sigaction sa; 1589255570Strasz int error; 1590255570Strasz 1591255570Strasz bzero(&sa, sizeof(sa)); 1592255570Strasz sa.sa_handler = sighup_handler; 1593255570Strasz sigfillset(&sa.sa_mask); 1594255570Strasz error = sigaction(SIGHUP, &sa, NULL); 1595255570Strasz if (error != 0) 1596255570Strasz log_err(1, "sigaction"); 1597255570Strasz 1598255570Strasz sa.sa_handler = sigterm_handler; 1599255570Strasz error = sigaction(SIGTERM, &sa, NULL); 1600255570Strasz if (error != 0) 1601255570Strasz log_err(1, "sigaction"); 1602255570Strasz 1603255570Strasz sa.sa_handler = sigterm_handler; 1604255570Strasz error = sigaction(SIGINT, &sa, NULL); 1605255570Strasz if (error != 0) 1606255570Strasz log_err(1, "sigaction"); 1607255570Strasz} 1608255570Strasz 1609255570Straszint 1610255570Straszmain(int argc, char **argv) 1611255570Strasz{ 1612255570Strasz struct conf *oldconf, *newconf, *tmpconf; 1613255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 1614255570Strasz int debug = 0, ch, error; 1615255570Strasz bool dont_daemonize = false; 1616255570Strasz 1617255570Strasz while ((ch = getopt(argc, argv, "df:")) != -1) { 1618255570Strasz switch (ch) { 1619255570Strasz case 'd': 1620255570Strasz dont_daemonize = true; 1621255570Strasz debug++; 1622255570Strasz break; 1623255570Strasz case 'f': 1624255570Strasz config_path = optarg; 1625255570Strasz break; 1626255570Strasz case '?': 1627255570Strasz default: 1628255570Strasz usage(); 1629255570Strasz } 1630255570Strasz } 1631255570Strasz argc -= optind; 1632255570Strasz if (argc != 0) 1633255570Strasz usage(); 1634255570Strasz 1635255570Strasz log_init(debug); 1636255570Strasz kernel_init(); 1637255570Strasz 1638255570Strasz oldconf = conf_new_from_kernel(); 1639255570Strasz newconf = conf_new_from_file(config_path); 1640255570Strasz if (newconf == NULL) 1641255570Strasz log_errx(1, "configuration error, exiting"); 1642255570Strasz if (debug > 0) { 1643255570Strasz oldconf->conf_debug = debug; 1644255570Strasz newconf->conf_debug = debug; 1645255570Strasz } 1646255570Strasz 1647255570Strasz if (dont_daemonize == false) { 1648255570Strasz if (daemon(0, 0) == -1) { 1649255570Strasz log_warn("cannot daemonize"); 1650255570Strasz pidfile_remove(newconf->conf_pidfh); 1651255570Strasz exit(1); 1652255570Strasz } 1653255570Strasz } 1654255570Strasz 1655255570Strasz#ifdef ICL_KERNEL_PROXY 1656255570Strasz log_debugx("enabling CTL iSCSI port"); 1657255570Strasz error = kernel_port_on(); 1658255570Strasz if (error != 0) 1659255570Strasz log_errx(1, "failed to enable CTL iSCSI port, exiting"); 1660255570Strasz#endif 1661255570Strasz 1662255570Strasz error = conf_apply(oldconf, newconf); 1663255570Strasz if (error != 0) 1664255570Strasz log_errx(1, "failed to apply configuration, exiting"); 1665255570Strasz conf_delete(oldconf); 1666255570Strasz oldconf = NULL; 1667255570Strasz 1668255570Strasz register_signals(); 1669255570Strasz 1670255570Strasz#ifndef ICL_KERNEL_PROXY 1671255570Strasz log_debugx("enabling CTL iSCSI port"); 1672255570Strasz error = kernel_port_on(); 1673255570Strasz if (error != 0) 1674255570Strasz log_errx(1, "failed to enable CTL iSCSI port, exiting"); 1675255570Strasz#endif 1676255570Strasz 1677255570Strasz for (;;) { 1678255570Strasz main_loop(newconf, dont_daemonize); 1679255570Strasz if (sighup_received) { 1680255570Strasz sighup_received = false; 1681255570Strasz log_debugx("received SIGHUP, reloading configuration"); 1682255570Strasz tmpconf = conf_new_from_file(config_path); 1683255570Strasz if (tmpconf == NULL) { 1684255570Strasz log_warnx("configuration error, " 1685255570Strasz "continuing with old configuration"); 1686255570Strasz } else { 1687255570Strasz if (debug > 0) 1688255570Strasz tmpconf->conf_debug = debug; 1689255570Strasz oldconf = newconf; 1690255570Strasz newconf = tmpconf; 1691255570Strasz error = conf_apply(oldconf, newconf); 1692255570Strasz if (error != 0) 1693255570Strasz log_warnx("failed to reload " 1694255570Strasz "configuration"); 1695255570Strasz conf_delete(oldconf); 1696255570Strasz oldconf = NULL; 1697255570Strasz } 1698255570Strasz } else if (sigterm_received) { 1699255570Strasz log_debugx("exiting on signal; " 1700255570Strasz "reloading empty configuration"); 1701255570Strasz 1702255570Strasz log_debugx("disabling CTL iSCSI port " 1703255570Strasz "and terminating all connections"); 1704255570Strasz error = kernel_port_off(); 1705255570Strasz if (error != 0) 1706255570Strasz log_warnx("failed to disable CTL iSCSI port"); 1707255570Strasz 1708255570Strasz oldconf = newconf; 1709255570Strasz newconf = conf_new(); 1710255570Strasz if (debug > 0) 1711255570Strasz newconf->conf_debug = debug; 1712255570Strasz error = conf_apply(oldconf, newconf); 1713255570Strasz if (error != 0) 1714255570Strasz log_warnx("failed to apply configuration"); 1715255570Strasz 1716255570Strasz log_warnx("exiting on signal"); 1717255570Strasz exit(0); 1718255570Strasz } else { 1719255570Strasz nchildren -= wait_for_children(false); 1720255570Strasz assert(nchildren >= 0); 1721255570Strasz } 1722255570Strasz } 1723255570Strasz /* NOTREACHED */ 1724255570Strasz} 1725