ctld.c revision 263717
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 263717 2014-03-25 11:53:47Z 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; 876263717Strasz 877263717Strasz if (lun->l_backend == NULL) 878263717Strasz lun_set_backend(lun, "block"); 879263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 880263717Strasz if (lun->l_path == NULL) { 881263717Strasz log_warnx("missing path for lun %d, target \"%s\"", 882263717Strasz lun->l_lun, lun->l_target->t_iqn); 883263717Strasz return (1); 884263717Strasz } 885263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 886263717Strasz if (lun->l_size == 0) { 887263717Strasz log_warnx("missing size for ramdisk-backed lun %d, " 888263717Strasz "target \"%s\"", lun->l_lun, lun->l_target->t_iqn); 889263717Strasz return (1); 890263717Strasz } 891263717Strasz if (lun->l_path != NULL) { 892263717Strasz log_warnx("path must not be specified " 893263717Strasz "for ramdisk-backed lun %d, target \"%s\"", 894263717Strasz lun->l_lun, lun->l_target->t_iqn); 895263717Strasz return (1); 896263717Strasz } 897263717Strasz } 898263717Strasz if (lun->l_lun < 0 || lun->l_lun > 255) { 899263717Strasz log_warnx("invalid lun number for lun %d, target \"%s\"; " 900263717Strasz "must be between 0 and 255", lun->l_lun, 901263717Strasz lun->l_target->t_iqn); 902263717Strasz return (1); 903263717Strasz } 904263717Strasz#if 1 /* Should we? */ 905263717Strasz TAILQ_FOREACH(lun2, &lun->l_target->t_luns, l_next) { 906263717Strasz if (lun == lun2) 907263717Strasz continue; 908263717Strasz if (lun->l_path != NULL && lun2->l_path != NULL && 909263717Strasz strcmp(lun->l_path, lun2->l_path) == 0) 910263717Strasz log_debugx("WARNING: duplicate path for lun %d, " 911263717Strasz "target \"%s\"", lun->l_lun, lun->l_target->t_iqn); 912263717Strasz } 913263717Strasz#endif 914263717Strasz if (lun->l_blocksize == 0) { 915263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 916263717Strasz } else if (lun->l_blocksize < 0) { 917263717Strasz log_warnx("invalid blocksize for lun %d, target \"%s\"; " 918263717Strasz "must be larger than 0", lun->l_lun, lun->l_target->t_iqn); 919263717Strasz return (1); 920263717Strasz } 921263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 922263717Strasz log_warnx("invalid size for lun %d, target \"%s\"; " 923263717Strasz "must be multiple of blocksize", lun->l_lun, 924263717Strasz lun->l_target->t_iqn); 925263717Strasz return (1); 926263717Strasz } 927263717Strasz 928263717Strasz return (0); 929263717Strasz} 930263717Strasz 931255570Straszint 932255570Straszconf_verify(struct conf *conf) 933255570Strasz{ 934255570Strasz struct auth_group *ag; 935255570Strasz struct portal_group *pg; 936255570Strasz struct target *targ; 937263717Strasz struct lun *lun; 938255570Strasz bool found_lun0; 939263717Strasz int error; 940255570Strasz 941255570Strasz if (conf->conf_pidfile_path == NULL) 942255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 943255570Strasz 944255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 945255570Strasz if (targ->t_auth_group == NULL) { 946255570Strasz log_warnx("missing authentication for target \"%s\"; " 947255570Strasz "must specify either \"auth-group\", \"chap\", " 948255570Strasz "or \"chap-mutual\"", targ->t_iqn); 949255570Strasz return (1); 950255570Strasz } 951255570Strasz if (targ->t_portal_group == NULL) { 952255570Strasz targ->t_portal_group = portal_group_find(conf, 953255570Strasz "default"); 954255570Strasz assert(targ->t_portal_group != NULL); 955255570Strasz } 956255570Strasz found_lun0 = false; 957255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 958263717Strasz error = conf_verify_lun(lun); 959263717Strasz if (error != 0) 960263717Strasz return (error); 961255570Strasz if (lun->l_lun == 0) 962255570Strasz found_lun0 = true; 963255570Strasz } 964255570Strasz if (!found_lun0) { 965255570Strasz log_warnx("mandatory LUN 0 not configured " 966255570Strasz "for target \"%s\"", targ->t_iqn); 967255570Strasz return (1); 968255570Strasz } 969255570Strasz } 970255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 971255570Strasz assert(pg->pg_name != NULL); 972255570Strasz if (pg->pg_discovery_auth_group == NULL) { 973255570Strasz pg->pg_discovery_auth_group = 974255570Strasz auth_group_find(conf, "no-access"); 975255570Strasz assert(pg->pg_discovery_auth_group != NULL); 976255570Strasz } 977255570Strasz 978255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 979255570Strasz if (targ->t_portal_group == pg) 980255570Strasz break; 981255570Strasz } 982255570Strasz if (targ == NULL) { 983255570Strasz if (strcmp(pg->pg_name, "default") != 0) 984255570Strasz log_warnx("portal-group \"%s\" not assigned " 985255570Strasz "to any target", pg->pg_name); 986255570Strasz pg->pg_unassigned = true; 987255570Strasz } else 988255570Strasz pg->pg_unassigned = false; 989255570Strasz } 990255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 991255570Strasz if (ag->ag_name == NULL) 992255570Strasz assert(ag->ag_target != NULL); 993255570Strasz else 994255570Strasz assert(ag->ag_target == NULL); 995255570Strasz 996255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 997255570Strasz if (targ->t_auth_group == ag) 998255570Strasz break; 999255570Strasz } 1000255570Strasz if (targ == NULL && ag->ag_name != NULL && 1001255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1002255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1003255570Strasz log_warnx("auth-group \"%s\" not assigned " 1004255570Strasz "to any target", ag->ag_name); 1005255570Strasz } 1006255570Strasz } 1007255570Strasz 1008255570Strasz return (0); 1009255570Strasz} 1010255570Strasz 1011255570Straszstatic int 1012255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1013255570Strasz{ 1014255570Strasz struct target *oldtarg, *newtarg, *tmptarg; 1015255570Strasz struct lun *oldlun, *newlun, *tmplun; 1016255570Strasz struct portal_group *oldpg, *newpg; 1017255570Strasz struct portal *oldp, *newp; 1018255570Strasz pid_t otherpid; 1019255570Strasz int changed, cumulated_error = 0, error; 1020255570Strasz#ifndef ICL_KERNEL_PROXY 1021255570Strasz int one = 1; 1022255570Strasz#endif 1023255570Strasz 1024255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1025255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1026255570Strasz log_init(newconf->conf_debug); 1027255570Strasz } 1028255570Strasz 1029255570Strasz if (oldconf->conf_pidfh != NULL) { 1030255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1031255570Strasz if (newconf->conf_pidfile_path != NULL && 1032255570Strasz strcmp(oldconf->conf_pidfile_path, 1033255570Strasz newconf->conf_pidfile_path) == 0) { 1034255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1035255570Strasz oldconf->conf_pidfh = NULL; 1036255570Strasz } else { 1037255570Strasz log_debugx("removing pidfile %s", 1038255570Strasz oldconf->conf_pidfile_path); 1039255570Strasz pidfile_remove(oldconf->conf_pidfh); 1040255570Strasz oldconf->conf_pidfh = NULL; 1041255570Strasz } 1042255570Strasz } 1043255570Strasz 1044255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1045255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1046255570Strasz newconf->conf_pidfh = 1047255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1048255570Strasz if (newconf->conf_pidfh == NULL) { 1049255570Strasz if (errno == EEXIST) 1050255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1051255570Strasz (intmax_t)otherpid); 1052255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1053255570Strasz newconf->conf_pidfile_path); 1054255570Strasz } 1055255570Strasz } 1056255570Strasz 1057255570Strasz TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { 1058255570Strasz /* 1059255570Strasz * First, remove any targets present in the old configuration 1060255570Strasz * and missing in the new one. 1061255570Strasz */ 1062255570Strasz newtarg = target_find(newconf, oldtarg->t_iqn); 1063255570Strasz if (newtarg == NULL) { 1064255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, 1065255570Strasz tmplun) { 1066263716Strasz log_debugx("target %s not found in new " 1067263716Strasz "configuration; removing its lun %d, " 1068255570Strasz "backed by CTL lun %d", 1069255570Strasz oldtarg->t_iqn, oldlun->l_lun, 1070255570Strasz oldlun->l_ctl_lun); 1071255570Strasz error = kernel_lun_remove(oldlun); 1072255570Strasz if (error != 0) { 1073255570Strasz log_warnx("failed to remove lun %d, " 1074255570Strasz "target %s, CTL lun %d", 1075255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1076255570Strasz oldlun->l_ctl_lun); 1077255570Strasz cumulated_error++; 1078255570Strasz } 1079255570Strasz lun_delete(oldlun); 1080255570Strasz } 1081255570Strasz target_delete(oldtarg); 1082255570Strasz continue; 1083255570Strasz } 1084255570Strasz 1085255570Strasz /* 1086255570Strasz * Second, remove any LUNs present in the old target 1087255570Strasz * and missing in the new one. 1088255570Strasz */ 1089255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, tmplun) { 1090255570Strasz newlun = lun_find(newtarg, oldlun->l_lun); 1091255570Strasz if (newlun == NULL) { 1092255570Strasz log_debugx("lun %d, target %s, CTL lun %d " 1093263716Strasz "not found in new configuration; " 1094255570Strasz "removing", oldlun->l_lun, oldtarg->t_iqn, 1095255570Strasz oldlun->l_ctl_lun); 1096255570Strasz error = kernel_lun_remove(oldlun); 1097255570Strasz if (error != 0) { 1098255570Strasz log_warnx("failed to remove lun %d, " 1099255570Strasz "target %s, CTL lun %d", 1100255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1101255570Strasz oldlun->l_ctl_lun); 1102255570Strasz cumulated_error++; 1103255570Strasz } 1104255570Strasz lun_delete(oldlun); 1105255570Strasz continue; 1106255570Strasz } 1107255570Strasz 1108255570Strasz /* 1109255570Strasz * Also remove the LUNs changed by more than size. 1110255570Strasz */ 1111255570Strasz changed = 0; 1112255570Strasz assert(oldlun->l_backend != NULL); 1113255570Strasz assert(newlun->l_backend != NULL); 1114255570Strasz if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1115255570Strasz log_debugx("backend for lun %d, target %s, " 1116255570Strasz "CTL lun %d changed; removing", 1117255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1118255570Strasz oldlun->l_ctl_lun); 1119255570Strasz changed = 1; 1120255570Strasz } 1121255570Strasz if (oldlun->l_blocksize != newlun->l_blocksize) { 1122255570Strasz log_debugx("blocksize for lun %d, target %s, " 1123255570Strasz "CTL lun %d changed; removing", 1124255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1125255570Strasz oldlun->l_ctl_lun); 1126255570Strasz changed = 1; 1127255570Strasz } 1128255570Strasz if (newlun->l_device_id != NULL && 1129255570Strasz (oldlun->l_device_id == NULL || 1130255570Strasz strcmp(oldlun->l_device_id, newlun->l_device_id) != 1131255570Strasz 0)) { 1132255570Strasz log_debugx("device-id for lun %d, target %s, " 1133255570Strasz "CTL lun %d changed; removing", 1134255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1135255570Strasz oldlun->l_ctl_lun); 1136255570Strasz changed = 1; 1137255570Strasz } 1138255570Strasz if (newlun->l_path != NULL && 1139255570Strasz (oldlun->l_path == NULL || 1140255570Strasz strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1141255570Strasz log_debugx("path for lun %d, target %s, " 1142255570Strasz "CTL lun %d, changed; removing", 1143255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1144255570Strasz oldlun->l_ctl_lun); 1145255570Strasz changed = 1; 1146255570Strasz } 1147255570Strasz if (newlun->l_serial != NULL && 1148255570Strasz (oldlun->l_serial == NULL || 1149255570Strasz strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1150255570Strasz log_debugx("serial for lun %d, target %s, " 1151255570Strasz "CTL lun %d changed; removing", 1152255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1153255570Strasz oldlun->l_ctl_lun); 1154255570Strasz changed = 1; 1155255570Strasz } 1156255570Strasz if (changed) { 1157255570Strasz error = kernel_lun_remove(oldlun); 1158255570Strasz if (error != 0) { 1159255570Strasz log_warnx("failed to remove lun %d, " 1160255570Strasz "target %s, CTL lun %d", 1161255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1162255570Strasz oldlun->l_ctl_lun); 1163255570Strasz cumulated_error++; 1164255570Strasz } 1165255570Strasz lun_delete(oldlun); 1166255570Strasz continue; 1167255570Strasz } 1168255570Strasz 1169255570Strasz lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1170255570Strasz } 1171255570Strasz } 1172255570Strasz 1173255570Strasz /* 1174255570Strasz * Now add new targets or modify existing ones. 1175255570Strasz */ 1176255570Strasz TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { 1177255570Strasz oldtarg = target_find(oldconf, newtarg->t_iqn); 1178255570Strasz 1179255570Strasz TAILQ_FOREACH(newlun, &newtarg->t_luns, l_next) { 1180255570Strasz if (oldtarg != NULL) { 1181255570Strasz oldlun = lun_find(oldtarg, newlun->l_lun); 1182255570Strasz if (oldlun != NULL) { 1183255570Strasz if (newlun->l_size != oldlun->l_size) { 1184255570Strasz log_debugx("resizing lun %d, " 1185255570Strasz "target %s, CTL lun %d", 1186255570Strasz newlun->l_lun, 1187255570Strasz newtarg->t_iqn, 1188255570Strasz newlun->l_ctl_lun); 1189255570Strasz error = 1190255570Strasz kernel_lun_resize(newlun); 1191255570Strasz if (error != 0) { 1192255570Strasz log_warnx("failed to " 1193255570Strasz "resize lun %d, " 1194255570Strasz "target %s, " 1195255570Strasz "CTL lun %d", 1196255570Strasz newlun->l_lun, 1197255570Strasz newtarg->t_iqn, 1198255570Strasz newlun->l_lun); 1199255570Strasz cumulated_error++; 1200255570Strasz } 1201255570Strasz } 1202255570Strasz continue; 1203255570Strasz } 1204255570Strasz } 1205255570Strasz log_debugx("adding lun %d, target %s", 1206255570Strasz newlun->l_lun, newtarg->t_iqn); 1207255570Strasz error = kernel_lun_add(newlun); 1208255570Strasz if (error != 0) { 1209255570Strasz log_warnx("failed to add lun %d, target %s", 1210255570Strasz newlun->l_lun, newtarg->t_iqn); 1211255570Strasz cumulated_error++; 1212255570Strasz } 1213255570Strasz } 1214255570Strasz } 1215255570Strasz 1216255570Strasz /* 1217255570Strasz * Go through the new portals, opening the sockets as neccessary. 1218255570Strasz */ 1219255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1220255570Strasz if (newpg->pg_unassigned) { 1221255570Strasz log_debugx("not listening on portal-group \"%s\", " 1222255570Strasz "not assigned to any target", 1223255570Strasz newpg->pg_name); 1224255570Strasz continue; 1225255570Strasz } 1226255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1227255570Strasz /* 1228255570Strasz * Try to find already open portal and reuse 1229255570Strasz * the listening socket. We don't care about 1230255570Strasz * what portal or portal group that was, what 1231255570Strasz * matters is the listening address. 1232255570Strasz */ 1233255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1234255570Strasz pg_next) { 1235255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1236255570Strasz p_next) { 1237255570Strasz if (strcmp(newp->p_listen, 1238255570Strasz oldp->p_listen) == 0 && 1239255570Strasz oldp->p_socket > 0) { 1240255570Strasz newp->p_socket = 1241255570Strasz oldp->p_socket; 1242255570Strasz oldp->p_socket = 0; 1243255570Strasz break; 1244255570Strasz } 1245255570Strasz } 1246255570Strasz } 1247255570Strasz if (newp->p_socket > 0) { 1248255570Strasz /* 1249255570Strasz * We're done with this portal. 1250255570Strasz */ 1251255570Strasz continue; 1252255570Strasz } 1253255570Strasz 1254255570Strasz#ifdef ICL_KERNEL_PROXY 1255255570Strasz log_debugx("listening on %s, portal-group \"%s\" using ICL proxy", 1256255570Strasz newp->p_listen, newpg->pg_name); 1257255570Strasz kernel_listen(newp->p_ai, newp->p_iser); 1258255570Strasz#else 1259255570Strasz assert(newp->p_iser == false); 1260255570Strasz 1261255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1262255570Strasz newp->p_listen, newpg->pg_name); 1263255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1264255570Strasz newp->p_ai->ai_socktype, 1265255570Strasz newp->p_ai->ai_protocol); 1266255570Strasz if (newp->p_socket < 0) { 1267255570Strasz log_warn("socket(2) failed for %s", 1268255570Strasz newp->p_listen); 1269255570Strasz cumulated_error++; 1270255570Strasz continue; 1271255570Strasz } 1272255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1273255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1274255570Strasz if (error != 0) { 1275255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1276255570Strasz "for %s", newp->p_listen); 1277255570Strasz close(newp->p_socket); 1278255570Strasz newp->p_socket = 0; 1279255570Strasz cumulated_error++; 1280255570Strasz continue; 1281255570Strasz } 1282255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1283255570Strasz newp->p_ai->ai_addrlen); 1284255570Strasz if (error != 0) { 1285255570Strasz log_warn("bind(2) failed for %s", 1286255570Strasz newp->p_listen); 1287255570Strasz close(newp->p_socket); 1288255570Strasz newp->p_socket = 0; 1289255570Strasz cumulated_error++; 1290255570Strasz continue; 1291255570Strasz } 1292255570Strasz error = listen(newp->p_socket, -1); 1293255570Strasz if (error != 0) { 1294255570Strasz log_warn("listen(2) failed for %s", 1295255570Strasz newp->p_listen); 1296255570Strasz close(newp->p_socket); 1297255570Strasz newp->p_socket = 0; 1298255570Strasz cumulated_error++; 1299255570Strasz continue; 1300255570Strasz } 1301255570Strasz#endif /* !ICL_KERNEL_PROXY */ 1302255570Strasz } 1303255570Strasz } 1304255570Strasz 1305255570Strasz /* 1306255570Strasz * Go through the no longer used sockets, closing them. 1307255570Strasz */ 1308255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 1309255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 1310255570Strasz if (oldp->p_socket <= 0) 1311255570Strasz continue; 1312255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 1313255570Strasz oldp->p_listen, oldpg->pg_name); 1314255570Strasz close(oldp->p_socket); 1315255570Strasz oldp->p_socket = 0; 1316255570Strasz } 1317255570Strasz } 1318255570Strasz 1319255570Strasz return (cumulated_error); 1320255570Strasz} 1321255570Strasz 1322255570Straszbool 1323255570Strasztimed_out(void) 1324255570Strasz{ 1325255570Strasz 1326255570Strasz return (sigalrm_received); 1327255570Strasz} 1328255570Strasz 1329255570Straszstatic void 1330255570Straszsigalrm_handler(int dummy __unused) 1331255570Strasz{ 1332255570Strasz /* 1333255570Strasz * It would be easiest to just log an error and exit. We can't 1334255570Strasz * do this, though, because log_errx() is not signal safe, since 1335255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 1336255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 1337255570Strasz * to notice, we'll exit here one second later. 1338255570Strasz */ 1339255570Strasz if (sigalrm_received) { 1340255570Strasz /* 1341255570Strasz * Oh well. Just give up and quit. 1342255570Strasz */ 1343255570Strasz _exit(2); 1344255570Strasz } 1345255570Strasz 1346255570Strasz sigalrm_received = true; 1347255570Strasz} 1348255570Strasz 1349255570Straszstatic void 1350255570Straszset_timeout(const struct conf *conf) 1351255570Strasz{ 1352255570Strasz struct sigaction sa; 1353255570Strasz struct itimerval itv; 1354255570Strasz int error; 1355255570Strasz 1356255570Strasz if (conf->conf_timeout <= 0) { 1357255570Strasz log_debugx("session timeout disabled"); 1358255570Strasz return; 1359255570Strasz } 1360255570Strasz 1361255570Strasz bzero(&sa, sizeof(sa)); 1362255570Strasz sa.sa_handler = sigalrm_handler; 1363255570Strasz sigfillset(&sa.sa_mask); 1364255570Strasz error = sigaction(SIGALRM, &sa, NULL); 1365255570Strasz if (error != 0) 1366255570Strasz log_err(1, "sigaction"); 1367255570Strasz 1368255570Strasz /* 1369255570Strasz * First SIGALRM will arive after conf_timeout seconds. 1370255570Strasz * If we do nothing, another one will arrive a second later. 1371255570Strasz */ 1372255570Strasz bzero(&itv, sizeof(itv)); 1373255570Strasz itv.it_interval.tv_sec = 1; 1374255570Strasz itv.it_value.tv_sec = conf->conf_timeout; 1375255570Strasz 1376255570Strasz log_debugx("setting session timeout to %d seconds", 1377255570Strasz conf->conf_timeout); 1378255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 1379255570Strasz if (error != 0) 1380255570Strasz log_err(1, "setitimer"); 1381255570Strasz} 1382255570Strasz 1383255570Straszstatic int 1384255570Straszwait_for_children(bool block) 1385255570Strasz{ 1386255570Strasz pid_t pid; 1387255570Strasz int status; 1388255570Strasz int num = 0; 1389255570Strasz 1390255570Strasz for (;;) { 1391255570Strasz /* 1392255570Strasz * If "block" is true, wait for at least one process. 1393255570Strasz */ 1394255570Strasz if (block && num == 0) 1395255570Strasz pid = wait4(-1, &status, 0, NULL); 1396255570Strasz else 1397255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 1398255570Strasz if (pid <= 0) 1399255570Strasz break; 1400255570Strasz if (WIFSIGNALED(status)) { 1401255570Strasz log_warnx("child process %d terminated with signal %d", 1402255570Strasz pid, WTERMSIG(status)); 1403255570Strasz } else if (WEXITSTATUS(status) != 0) { 1404255570Strasz log_warnx("child process %d terminated with exit status %d", 1405255570Strasz pid, WEXITSTATUS(status)); 1406255570Strasz } else { 1407255570Strasz log_debugx("child process %d terminated gracefully", pid); 1408255570Strasz } 1409255570Strasz num++; 1410255570Strasz } 1411255570Strasz 1412255570Strasz return (num); 1413255570Strasz} 1414255570Strasz 1415255570Straszstatic void 1416255570Straszhandle_connection(struct portal *portal, int fd, bool dont_fork) 1417255570Strasz{ 1418255570Strasz struct connection *conn; 1419255570Strasz#ifndef ICL_KERNEL_PROXY 1420255570Strasz struct sockaddr_storage ss; 1421255570Strasz socklen_t sslen = sizeof(ss); 1422255570Strasz int error; 1423255570Strasz#endif 1424255570Strasz pid_t pid; 1425255570Strasz char host[NI_MAXHOST + 1]; 1426255570Strasz struct conf *conf; 1427255570Strasz 1428255570Strasz conf = portal->p_portal_group->pg_conf; 1429255570Strasz 1430255570Strasz if (dont_fork) { 1431255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 1432255570Strasz } else { 1433255570Strasz nchildren -= wait_for_children(false); 1434255570Strasz assert(nchildren >= 0); 1435255570Strasz 1436255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 1437255570Strasz log_debugx("maxproc limit of %d child processes hit; " 1438255570Strasz "waiting for child process to exit", conf->conf_maxproc); 1439255570Strasz nchildren -= wait_for_children(true); 1440255570Strasz assert(nchildren >= 0); 1441255570Strasz } 1442255570Strasz log_debugx("incoming connection; forking child process #%d", 1443255570Strasz nchildren); 1444255570Strasz nchildren++; 1445255570Strasz pid = fork(); 1446255570Strasz if (pid < 0) 1447255570Strasz log_err(1, "fork"); 1448255570Strasz if (pid > 0) { 1449255570Strasz close(fd); 1450255570Strasz return; 1451255570Strasz } 1452255570Strasz } 1453255570Strasz pidfile_close(conf->conf_pidfh); 1454255570Strasz 1455255570Strasz#ifdef ICL_KERNEL_PROXY 1456255570Strasz /* 1457255570Strasz * XXX 1458255570Strasz */ 1459255570Strasz log_set_peer_addr("XXX"); 1460255570Strasz#else 1461255570Strasz error = getpeername(fd, (struct sockaddr *)&ss, &sslen); 1462255570Strasz if (error != 0) 1463255570Strasz log_err(1, "getpeername"); 1464255570Strasz error = getnameinfo((struct sockaddr *)&ss, sslen, 1465255570Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 1466255570Strasz if (error != 0) 1467255570Strasz log_errx(1, "getaddrinfo: %s", gai_strerror(error)); 1468255570Strasz 1469255570Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 1470255570Strasz host, portal->p_portal_group->pg_name); 1471255570Strasz log_set_peer_addr(host); 1472255570Strasz setproctitle("%s", host); 1473255570Strasz#endif 1474255570Strasz 1475255570Strasz conn = connection_new(portal, fd, host); 1476255570Strasz set_timeout(conf); 1477255570Strasz kernel_capsicate(); 1478255570Strasz login(conn); 1479255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 1480255570Strasz kernel_handoff(conn); 1481255570Strasz log_debugx("connection handed off to the kernel"); 1482255570Strasz } else { 1483255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 1484255570Strasz discovery(conn); 1485255570Strasz } 1486255570Strasz log_debugx("nothing more to do; exiting"); 1487255570Strasz exit(0); 1488255570Strasz} 1489255570Strasz 1490255570Strasz#ifndef ICL_KERNEL_PROXY 1491255570Straszstatic int 1492255570Straszfd_add(int fd, fd_set *fdset, int nfds) 1493255570Strasz{ 1494255570Strasz 1495255570Strasz /* 1496255570Strasz * Skip sockets which we failed to bind. 1497255570Strasz */ 1498255570Strasz if (fd <= 0) 1499255570Strasz return (nfds); 1500255570Strasz 1501255570Strasz FD_SET(fd, fdset); 1502255570Strasz if (fd > nfds) 1503255570Strasz nfds = fd; 1504255570Strasz return (nfds); 1505255570Strasz} 1506255570Strasz#endif 1507255570Strasz 1508255570Straszstatic void 1509255570Straszmain_loop(struct conf *conf, bool dont_fork) 1510255570Strasz{ 1511255570Strasz struct portal_group *pg; 1512255570Strasz struct portal *portal; 1513255570Strasz#ifdef ICL_KERNEL_PROXY 1514255570Strasz int connection_id; 1515255570Strasz#else 1516255570Strasz fd_set fdset; 1517255570Strasz int error, nfds, client_fd; 1518255570Strasz#endif 1519255570Strasz 1520255570Strasz pidfile_write(conf->conf_pidfh); 1521255570Strasz 1522255570Strasz for (;;) { 1523255570Strasz if (sighup_received || sigterm_received) 1524255570Strasz return; 1525255570Strasz 1526255570Strasz#ifdef ICL_KERNEL_PROXY 1527255570Strasz connection_id = kernel_accept(); 1528255570Strasz if (connection_id == 0) 1529255570Strasz continue; 1530255570Strasz 1531255570Strasz /* 1532255570Strasz * XXX: This is obviously temporary. 1533255570Strasz */ 1534255570Strasz pg = TAILQ_FIRST(&conf->conf_portal_groups); 1535255570Strasz portal = TAILQ_FIRST(&pg->pg_portals); 1536255570Strasz 1537255570Strasz handle_connection(portal, connection_id, dont_fork); 1538255570Strasz#else 1539255570Strasz FD_ZERO(&fdset); 1540255570Strasz nfds = 0; 1541255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1542255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1543255570Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 1544255570Strasz } 1545255570Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 1546255570Strasz if (error <= 0) { 1547255570Strasz if (errno == EINTR) 1548255570Strasz return; 1549255570Strasz log_err(1, "select"); 1550255570Strasz } 1551255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1552255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 1553255570Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 1554255570Strasz continue; 1555255570Strasz client_fd = accept(portal->p_socket, NULL, 0); 1556255570Strasz if (client_fd < 0) 1557255570Strasz log_err(1, "accept"); 1558255570Strasz handle_connection(portal, client_fd, dont_fork); 1559255570Strasz break; 1560255570Strasz } 1561255570Strasz } 1562255570Strasz#endif /* !ICL_KERNEL_PROXY */ 1563255570Strasz } 1564255570Strasz} 1565255570Strasz 1566255570Straszstatic void 1567255570Straszsighup_handler(int dummy __unused) 1568255570Strasz{ 1569255570Strasz 1570255570Strasz sighup_received = true; 1571255570Strasz} 1572255570Strasz 1573255570Straszstatic void 1574255570Straszsigterm_handler(int dummy __unused) 1575255570Strasz{ 1576255570Strasz 1577255570Strasz sigterm_received = true; 1578255570Strasz} 1579255570Strasz 1580255570Straszstatic void 1581255570Straszregister_signals(void) 1582255570Strasz{ 1583255570Strasz struct sigaction sa; 1584255570Strasz int error; 1585255570Strasz 1586255570Strasz bzero(&sa, sizeof(sa)); 1587255570Strasz sa.sa_handler = sighup_handler; 1588255570Strasz sigfillset(&sa.sa_mask); 1589255570Strasz error = sigaction(SIGHUP, &sa, NULL); 1590255570Strasz if (error != 0) 1591255570Strasz log_err(1, "sigaction"); 1592255570Strasz 1593255570Strasz sa.sa_handler = sigterm_handler; 1594255570Strasz error = sigaction(SIGTERM, &sa, NULL); 1595255570Strasz if (error != 0) 1596255570Strasz log_err(1, "sigaction"); 1597255570Strasz 1598255570Strasz sa.sa_handler = sigterm_handler; 1599255570Strasz error = sigaction(SIGINT, &sa, NULL); 1600255570Strasz if (error != 0) 1601255570Strasz log_err(1, "sigaction"); 1602255570Strasz} 1603255570Strasz 1604255570Straszint 1605255570Straszmain(int argc, char **argv) 1606255570Strasz{ 1607255570Strasz struct conf *oldconf, *newconf, *tmpconf; 1608255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 1609255570Strasz int debug = 0, ch, error; 1610255570Strasz bool dont_daemonize = false; 1611255570Strasz 1612255570Strasz while ((ch = getopt(argc, argv, "df:")) != -1) { 1613255570Strasz switch (ch) { 1614255570Strasz case 'd': 1615255570Strasz dont_daemonize = true; 1616255570Strasz debug++; 1617255570Strasz break; 1618255570Strasz case 'f': 1619255570Strasz config_path = optarg; 1620255570Strasz break; 1621255570Strasz case '?': 1622255570Strasz default: 1623255570Strasz usage(); 1624255570Strasz } 1625255570Strasz } 1626255570Strasz argc -= optind; 1627255570Strasz if (argc != 0) 1628255570Strasz usage(); 1629255570Strasz 1630255570Strasz log_init(debug); 1631255570Strasz kernel_init(); 1632255570Strasz 1633255570Strasz oldconf = conf_new_from_kernel(); 1634255570Strasz newconf = conf_new_from_file(config_path); 1635255570Strasz if (newconf == NULL) 1636255570Strasz log_errx(1, "configuration error, exiting"); 1637255570Strasz if (debug > 0) { 1638255570Strasz oldconf->conf_debug = debug; 1639255570Strasz newconf->conf_debug = debug; 1640255570Strasz } 1641255570Strasz 1642255570Strasz if (dont_daemonize == false) { 1643255570Strasz if (daemon(0, 0) == -1) { 1644255570Strasz log_warn("cannot daemonize"); 1645255570Strasz pidfile_remove(newconf->conf_pidfh); 1646255570Strasz exit(1); 1647255570Strasz } 1648255570Strasz } 1649255570Strasz 1650255570Strasz#ifdef ICL_KERNEL_PROXY 1651255570Strasz log_debugx("enabling CTL iSCSI port"); 1652255570Strasz error = kernel_port_on(); 1653255570Strasz if (error != 0) 1654255570Strasz log_errx(1, "failed to enable CTL iSCSI port, exiting"); 1655255570Strasz#endif 1656255570Strasz 1657255570Strasz error = conf_apply(oldconf, newconf); 1658255570Strasz if (error != 0) 1659255570Strasz log_errx(1, "failed to apply configuration, exiting"); 1660255570Strasz conf_delete(oldconf); 1661255570Strasz oldconf = NULL; 1662255570Strasz 1663255570Strasz register_signals(); 1664255570Strasz 1665255570Strasz#ifndef ICL_KERNEL_PROXY 1666255570Strasz log_debugx("enabling CTL iSCSI port"); 1667255570Strasz error = kernel_port_on(); 1668255570Strasz if (error != 0) 1669255570Strasz log_errx(1, "failed to enable CTL iSCSI port, exiting"); 1670255570Strasz#endif 1671255570Strasz 1672255570Strasz for (;;) { 1673255570Strasz main_loop(newconf, dont_daemonize); 1674255570Strasz if (sighup_received) { 1675255570Strasz sighup_received = false; 1676255570Strasz log_debugx("received SIGHUP, reloading configuration"); 1677255570Strasz tmpconf = conf_new_from_file(config_path); 1678255570Strasz if (tmpconf == NULL) { 1679255570Strasz log_warnx("configuration error, " 1680255570Strasz "continuing with old configuration"); 1681255570Strasz } else { 1682255570Strasz if (debug > 0) 1683255570Strasz tmpconf->conf_debug = debug; 1684255570Strasz oldconf = newconf; 1685255570Strasz newconf = tmpconf; 1686255570Strasz error = conf_apply(oldconf, newconf); 1687255570Strasz if (error != 0) 1688255570Strasz log_warnx("failed to reload " 1689255570Strasz "configuration"); 1690255570Strasz conf_delete(oldconf); 1691255570Strasz oldconf = NULL; 1692255570Strasz } 1693255570Strasz } else if (sigterm_received) { 1694255570Strasz log_debugx("exiting on signal; " 1695255570Strasz "reloading empty configuration"); 1696255570Strasz 1697255570Strasz log_debugx("disabling CTL iSCSI port " 1698255570Strasz "and terminating all connections"); 1699255570Strasz error = kernel_port_off(); 1700255570Strasz if (error != 0) 1701255570Strasz log_warnx("failed to disable CTL iSCSI port"); 1702255570Strasz 1703255570Strasz oldconf = newconf; 1704255570Strasz newconf = conf_new(); 1705255570Strasz if (debug > 0) 1706255570Strasz newconf->conf_debug = debug; 1707255570Strasz error = conf_apply(oldconf, newconf); 1708255570Strasz if (error != 0) 1709255570Strasz log_warnx("failed to apply configuration"); 1710255570Strasz 1711255570Strasz log_warnx("exiting on signal"); 1712255570Strasz exit(0); 1713255570Strasz } else { 1714255570Strasz nchildren -= wait_for_children(false); 1715255570Strasz assert(nchildren >= 0); 1716255570Strasz } 1717255570Strasz } 1718255570Strasz /* NOTREACHED */ 1719255570Strasz} 1720