1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4 * All rights reserved. 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/linker.h> 36 #include <sys/module.h> 37 #include <sys/wait.h> 38 39 #include <assert.h> 40 #include <err.h> 41 #include <errno.h> 42 #include <libutil.h> 43 #include <signal.h> 44 #include <stdbool.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <sysexits.h> 49 #include <unistd.h> 50 51 #include <activemap.h> 52 #include <pjdlog.h> 53 54 #include "control.h" 55 #include "hast.h" 56 #include "hast_proto.h" 57 #include "hastd.h" 58 #include "subr.h" 59 60 /* Path to configuration file. */ 61 const char *cfgpath = HAST_CONFIG; 62 /* Hastd configuration. */ 63 static struct hastd_config *cfg; 64 /* Was SIGCHLD signal received? */ 65 static bool sigchld_received = false; 66 /* Was SIGHUP signal received? */ 67 bool sighup_received = false; 68 /* Was SIGINT or SIGTERM signal received? */ 69 bool sigexit_received = false; 70 /* PID file handle. */ 71 struct pidfh *pfh; 72 73 static void 74 usage(void) 75 { 76 77 errx(EX_USAGE, "[-dFh] [-c config] [-P pidfile]"); 78 } 79 80 static void 81 sighandler(int sig) 82 { 83 84 switch (sig) { 85 case SIGCHLD: 86 sigchld_received = true; 87 break; 88 case SIGHUP: 89 sighup_received = true; 90 break; 91 default: 92 assert(!"invalid condition"); 93 } 94 } 95 96 static void 97 g_gate_load(void) 98 { 99 100 if (modfind("g_gate") == -1) { 101 /* Not present in kernel, try loading it. */ 102 if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) { 103 if (errno != EEXIST) { 104 pjdlog_exit(EX_OSERR, 105 "Unable to load geom_gate module"); 106 } 107 } 108 } 109 } 110 111 static void 112 child_exit_log(unsigned int pid, int status) 113 { 114 115 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 116 pjdlog_debug(1, "Worker process exited gracefully (pid=%u).", 117 pid); 118 } else if (WIFSIGNALED(status)) { 119 pjdlog_error("Worker process killed (pid=%u, signal=%d).", 120 pid, WTERMSIG(status)); 121 } else { 122 pjdlog_error("Worker process exited ungracefully (pid=%u, exitcode=%d).", 123 pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1); 124 } 125 } 126 127 static void 128 child_exit(void) 129 { 130 struct hast_resource *res; 131 int status; 132 pid_t pid; 133 134 while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { 135 /* Find resource related to the process that just exited. */ 136 TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 137 if (pid == res->hr_workerpid) 138 break; 139 } 140 if (res == NULL) { 141 /* 142 * This can happen when new connection arrives and we 143 * cancel child responsible for the old one. 144 */ 145 continue; 146 } 147 pjdlog_prefix_set("[%s] (%s) ", res->hr_name, 148 role2str(res->hr_role)); 149 child_exit_log(pid, status); 150 proto_close(res->hr_ctrl); 151 res->hr_workerpid = 0; 152 if (res->hr_role == HAST_ROLE_PRIMARY) { 153 /* 154 * Restart child process if it was killed by signal 155 * or exited because of temporary problem. 156 */ 157 if (WIFSIGNALED(status) || 158 (WIFEXITED(status) && 159 WEXITSTATUS(status) == EX_TEMPFAIL)) { 160 sleep(1); 161 pjdlog_info("Restarting worker process."); 162 hastd_primary(res); 163 } else { 164 res->hr_role = HAST_ROLE_INIT; 165 pjdlog_info("Changing resource role back to %s.", 166 role2str(res->hr_role)); 167 } 168 } 169 pjdlog_prefix_set("%s", ""); 170 } 171 } 172 173 static bool 174 resource_needs_restart(const struct hast_resource *res0, 175 const struct hast_resource *res1) 176 { 177 178 assert(strcmp(res0->hr_name, res1->hr_name) == 0); 179 180 if (strcmp(res0->hr_provname, res1->hr_provname) != 0) 181 return (true); 182 if (strcmp(res0->hr_localpath, res1->hr_localpath) != 0) 183 return (true); 184 if (res0->hr_role == HAST_ROLE_INIT || 185 res0->hr_role == HAST_ROLE_SECONDARY) { 186 if (strcmp(res0->hr_remoteaddr, res1->hr_remoteaddr) != 0) 187 return (true); 188 if (res0->hr_replication != res1->hr_replication) 189 return (true); 190 if (res0->hr_timeout != res1->hr_timeout) 191 return (true); 192 } 193 return (false); 194 } 195 196 static bool 197 resource_needs_reload(const struct hast_resource *res0, 198 const struct hast_resource *res1) 199 { 200 201 assert(strcmp(res0->hr_name, res1->hr_name) == 0); 202 assert(strcmp(res0->hr_provname, res1->hr_provname) == 0); 203 assert(strcmp(res0->hr_localpath, res1->hr_localpath) == 0); 204 205 if (res0->hr_role != HAST_ROLE_PRIMARY) 206 return (false); 207 208 if (strcmp(res0->hr_remoteaddr, res1->hr_remoteaddr) != 0) 209 return (true); 210 if (res0->hr_replication != res1->hr_replication) 211 return (true); 212 if (res0->hr_timeout != res1->hr_timeout) 213 return (true); 214 return (false); 215 } 216 217 static void 218 hastd_reload(void) 219 { 220 struct hastd_config *newcfg; 221 struct hast_resource *nres, *cres, *tres; 222 uint8_t role; 223 224 pjdlog_info("Reloading configuration..."); 225 226 newcfg = yy_config_parse(cfgpath, false); 227 if (newcfg == NULL) 228 goto failed; 229 230 /* 231 * Check if control address has changed. 232 */ 233 if (strcmp(cfg->hc_controladdr, newcfg->hc_controladdr) != 0) { 234 if (proto_server(newcfg->hc_controladdr, 235 &newcfg->hc_controlconn) < 0) { 236 pjdlog_errno(LOG_ERR, 237 "Unable to listen on control address %s", 238 newcfg->hc_controladdr); 239 goto failed; 240 } 241 } 242 /* 243 * Check if listen address has changed. 244 */ 245 if (strcmp(cfg->hc_listenaddr, newcfg->hc_listenaddr) != 0) { 246 if (proto_server(newcfg->hc_listenaddr, 247 &newcfg->hc_listenconn) < 0) { 248 pjdlog_errno(LOG_ERR, "Unable to listen on address %s", 249 newcfg->hc_listenaddr); 250 goto failed; 251 } 252 } 253 /* 254 * Only when both control and listen sockets are successfully 255 * initialized switch them to new configuration. 256 */ 257 if (newcfg->hc_controlconn != NULL) { 258 pjdlog_info("Control socket changed from %s to %s.", 259 cfg->hc_controladdr, newcfg->hc_controladdr); 260 proto_close(cfg->hc_controlconn); 261 cfg->hc_controlconn = newcfg->hc_controlconn; 262 newcfg->hc_controlconn = NULL; 263 strlcpy(cfg->hc_controladdr, newcfg->hc_controladdr, 264 sizeof(cfg->hc_controladdr)); 265 } 266 if (newcfg->hc_listenconn != NULL) { 267 pjdlog_info("Listen socket changed from %s to %s.", 268 cfg->hc_listenaddr, newcfg->hc_listenaddr); 269 proto_close(cfg->hc_listenconn); 270 cfg->hc_listenconn = newcfg->hc_listenconn; 271 newcfg->hc_listenconn = NULL; 272 strlcpy(cfg->hc_listenaddr, newcfg->hc_listenaddr, 273 sizeof(cfg->hc_listenaddr)); 274 } 275 276 /* 277 * Stop and remove resources that were removed from the configuration. 278 */ 279 TAILQ_FOREACH_SAFE(cres, &cfg->hc_resources, hr_next, tres) { 280 TAILQ_FOREACH(nres, &newcfg->hc_resources, hr_next) { 281 if (strcmp(cres->hr_name, nres->hr_name) == 0) 282 break; 283 } 284 if (nres == NULL) { 285 control_set_role(cres, HAST_ROLE_INIT); 286 TAILQ_REMOVE(&cfg->hc_resources, cres, hr_next); 287 pjdlog_info("Resource %s removed.", cres->hr_name); 288 free(cres); 289 } 290 } 291 /* 292 * Move new resources to the current configuration. 293 */ 294 TAILQ_FOREACH_SAFE(nres, &newcfg->hc_resources, hr_next, tres) { 295 TAILQ_FOREACH(cres, &cfg->hc_resources, hr_next) { 296 if (strcmp(cres->hr_name, nres->hr_name) == 0) 297 break; 298 } 299 if (cres == NULL) { 300 TAILQ_REMOVE(&newcfg->hc_resources, nres, hr_next); 301 TAILQ_INSERT_TAIL(&cfg->hc_resources, nres, hr_next); 302 pjdlog_info("Resource %s added.", nres->hr_name); 303 } 304 } 305 /* 306 * Deal with modified resources. 307 * Depending on what has changed exactly we might want to perform 308 * different actions. 309 * 310 * We do full resource restart in the following situations: 311 * Resource role is INIT or SECONDARY. 312 * Resource role is PRIMARY and path to local component or provider 313 * name has changed. 314 * In case of PRIMARY, the worker process will be killed and restarted, 315 * which also means removing /dev/hast/<name> provider and 316 * recreating it. 317 * 318 * We do just reload (send SIGHUP to worker process) if we act as 319 * PRIMARY, but only remote address, replication mode and timeout 320 * has changed. For those, there is no need to restart worker process. 321 * If PRIMARY receives SIGHUP, it will reconnect if remote address or 322 * replication mode has changed or simply set new timeout if only 323 * timeout has changed. 324 */ 325 TAILQ_FOREACH_SAFE(nres, &newcfg->hc_resources, hr_next, tres) { 326 TAILQ_FOREACH(cres, &cfg->hc_resources, hr_next) { 327 if (strcmp(cres->hr_name, nres->hr_name) == 0) 328 break; 329 } 330 assert(cres != NULL); 331 if (resource_needs_restart(cres, nres)) { 332 pjdlog_info("Resource %s configuration was modified, restarting it.", 333 cres->hr_name); 334 role = cres->hr_role; 335 control_set_role(cres, HAST_ROLE_INIT); 336 TAILQ_REMOVE(&cfg->hc_resources, cres, hr_next); 337 free(cres); 338 TAILQ_REMOVE(&newcfg->hc_resources, nres, hr_next); 339 TAILQ_INSERT_TAIL(&cfg->hc_resources, nres, hr_next); 340 control_set_role(nres, role); 341 } else if (resource_needs_reload(cres, nres)) { 342 pjdlog_info("Resource %s configuration was modified, reloading it.", 343 cres->hr_name); 344 strlcpy(cres->hr_remoteaddr, nres->hr_remoteaddr, 345 sizeof(cres->hr_remoteaddr)); 346 cres->hr_replication = nres->hr_replication; 347 cres->hr_timeout = nres->hr_timeout; 348 if (cres->hr_workerpid != 0) { 349 if (kill(cres->hr_workerpid, SIGHUP) < 0) { 350 pjdlog_errno(LOG_WARNING, 351 "Unable to send SIGHUP to worker process %u", 352 (unsigned int)cres->hr_workerpid); 353 } 354 } 355 } 356 } 357 358 yy_config_free(newcfg); 359 pjdlog_info("Configuration reloaded successfully."); 360 return; 361 failed: 362 if (newcfg != NULL) { 363 if (newcfg->hc_controlconn != NULL) 364 proto_close(newcfg->hc_controlconn); 365 if (newcfg->hc_listenconn != NULL) 366 proto_close(newcfg->hc_listenconn); 367 yy_config_free(newcfg); 368 } 369 pjdlog_warning("Configuration not reloaded."); 370 } 371 372 static void 373 listen_accept(void) 374 { 375 struct hast_resource *res; 376 struct proto_conn *conn; 377 struct nv *nvin, *nvout, *nverr; 378 const char *resname; 379 const unsigned char *token; 380 char laddr[256], raddr[256]; 381 size_t size; 382 pid_t pid; 383 int status; 384 385 proto_local_address(cfg->hc_listenconn, laddr, sizeof(laddr)); 386 pjdlog_debug(1, "Accepting connection to %s.", laddr); 387 388 if (proto_accept(cfg->hc_listenconn, &conn) < 0) { 389 pjdlog_errno(LOG_ERR, "Unable to accept connection %s", laddr); 390 return; 391 } 392 393 proto_local_address(conn, laddr, sizeof(laddr)); 394 proto_remote_address(conn, raddr, sizeof(raddr)); 395 pjdlog_info("Connection from %s to %s.", raddr, laddr); 396 397 /* Error in setting timeout is not critical, but why should it fail? */ 398 if (proto_timeout(conn, HAST_TIMEOUT) < 0) 399 pjdlog_errno(LOG_WARNING, "Unable to set connection timeout"); 400 401 nvin = nvout = nverr = NULL; 402 403 /* 404 * Before receiving any data see if remote host have access to any 405 * resource. 406 */ 407 TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 408 if (proto_address_match(conn, res->hr_remoteaddr)) 409 break; 410 } 411 if (res == NULL) { 412 pjdlog_error("Client %s isn't known.", raddr); 413 goto close; 414 } 415 /* Ok, remote host can access at least one resource. */ 416 417 if (hast_proto_recv_hdr(conn, &nvin) < 0) { 418 pjdlog_errno(LOG_ERR, "Unable to receive header from %s", 419 raddr); 420 goto close; 421 } 422 423 resname = nv_get_string(nvin, "resource"); 424 if (resname == NULL) { 425 pjdlog_error("No 'resource' field in the header received from %s.", 426 raddr); 427 goto close; 428 } 429 pjdlog_debug(2, "%s: resource=%s", raddr, resname); 430 token = nv_get_uint8_array(nvin, &size, "token"); 431 /* 432 * NULL token means that this is first conection. 433 */ 434 if (token != NULL && size != sizeof(res->hr_token)) { 435 pjdlog_error("Received token of invalid size from %s (expected %zu, got %zu).", 436 raddr, sizeof(res->hr_token), size); 437 goto close; 438 } 439 440 /* 441 * From now on we want to send errors to the remote node. 442 */ 443 nverr = nv_alloc(); 444 445 /* Find resource related to this connection. */ 446 TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 447 if (strcmp(resname, res->hr_name) == 0) 448 break; 449 } 450 /* Have we found the resource? */ 451 if (res == NULL) { 452 pjdlog_error("No resource '%s' as requested by %s.", 453 resname, raddr); 454 nv_add_stringf(nverr, "errmsg", "Resource not configured."); 455 goto fail; 456 } 457 458 /* Now that we know resource name setup log prefix. */ 459 pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role)); 460 461 /* Does the remote host have access to this resource? */ 462 if (!proto_address_match(conn, res->hr_remoteaddr)) { 463 pjdlog_error("Client %s has no access to the resource.", raddr); 464 nv_add_stringf(nverr, "errmsg", "No access to the resource."); 465 goto fail; 466 } 467 /* Is the resource marked as secondary? */ 468 if (res->hr_role != HAST_ROLE_SECONDARY) { 469 pjdlog_error("We act as %s for the resource and not as %s as requested by %s.", 470 role2str(res->hr_role), role2str(HAST_ROLE_SECONDARY), 471 raddr); 472 nv_add_stringf(nverr, "errmsg", 473 "Remote node acts as %s for the resource and not as %s.", 474 role2str(res->hr_role), role2str(HAST_ROLE_SECONDARY)); 475 goto fail; 476 } 477 /* Does token (if exists) match? */ 478 if (token != NULL && memcmp(token, res->hr_token, 479 sizeof(res->hr_token)) != 0) { 480 pjdlog_error("Token received from %s doesn't match.", raddr); 481 nv_add_stringf(nverr, "errmsg", "Token doesn't match."); 482 goto fail; 483 } 484 /* 485 * If there is no token, but we have half-open connection 486 * (only remotein) or full connection (worker process is running) 487 * we have to cancel those and accept the new connection. 488 */ 489 if (token == NULL) { 490 assert(res->hr_remoteout == NULL); 491 pjdlog_debug(1, "Initial connection from %s.", raddr); 492 if (res->hr_workerpid != 0) { 493 assert(res->hr_remotein == NULL); 494 pjdlog_debug(1, 495 "Worker process exists (pid=%u), stopping it.", 496 (unsigned int)res->hr_workerpid); 497 /* Stop child process. */ 498 if (kill(res->hr_workerpid, SIGINT) < 0) { 499 pjdlog_errno(LOG_ERR, 500 "Unable to stop worker process (pid=%u)", 501 (unsigned int)res->hr_workerpid); 502 /* 503 * Other than logging the problem we 504 * ignore it - nothing smart to do. 505 */ 506 } 507 /* Wait for it to exit. */ 508 else if ((pid = waitpid(res->hr_workerpid, 509 &status, 0)) != res->hr_workerpid) { 510 /* We can only log the problem. */ 511 pjdlog_errno(LOG_ERR, 512 "Waiting for worker process (pid=%u) failed", 513 (unsigned int)res->hr_workerpid); 514 } else { 515 child_exit_log(res->hr_workerpid, status); 516 } 517 res->hr_workerpid = 0; 518 } else if (res->hr_remotein != NULL) { 519 char oaddr[256]; 520 521 proto_remote_address(conn, oaddr, sizeof(oaddr)); 522 pjdlog_debug(1, 523 "Canceling half-open connection from %s on connection from %s.", 524 oaddr, raddr); 525 proto_close(res->hr_remotein); 526 res->hr_remotein = NULL; 527 } 528 } 529 530 /* 531 * Checks and cleanups are done. 532 */ 533 534 if (token == NULL) { 535 arc4random_buf(res->hr_token, sizeof(res->hr_token)); 536 nvout = nv_alloc(); 537 nv_add_uint8_array(nvout, res->hr_token, 538 sizeof(res->hr_token), "token"); 539 if (nv_error(nvout) != 0) { 540 pjdlog_common(LOG_ERR, 0, nv_error(nvout), 541 "Unable to prepare return header for %s", raddr); 542 nv_add_stringf(nverr, "errmsg", 543 "Remote node was unable to prepare return header: %s.", 544 strerror(nv_error(nvout))); 545 goto fail; 546 } 547 if (hast_proto_send(NULL, conn, nvout, NULL, 0) < 0) { 548 int error = errno; 549 550 pjdlog_errno(LOG_ERR, "Unable to send response to %s", 551 raddr); 552 nv_add_stringf(nverr, "errmsg", 553 "Remote node was unable to send response: %s.", 554 strerror(error)); 555 goto fail; 556 } 557 res->hr_remotein = conn; 558 pjdlog_debug(1, "Incoming connection from %s configured.", 559 raddr); 560 } else { 561 res->hr_remoteout = conn; 562 pjdlog_debug(1, "Outgoing connection to %s configured.", raddr); 563 hastd_secondary(res, nvin); 564 } 565 nv_free(nvin); 566 nv_free(nvout); 567 nv_free(nverr); 568 pjdlog_prefix_set("%s", ""); 569 return; 570 fail: 571 if (nv_error(nverr) != 0) { 572 pjdlog_common(LOG_ERR, 0, nv_error(nverr), 573 "Unable to prepare error header for %s", raddr); 574 goto close; 575 } 576 if (hast_proto_send(NULL, conn, nverr, NULL, 0) < 0) { 577 pjdlog_errno(LOG_ERR, "Unable to send error to %s", raddr); 578 goto close; 579 } 580 close: 581 if (nvin != NULL) 582 nv_free(nvin); 583 if (nvout != NULL) 584 nv_free(nvout); 585 if (nverr != NULL) 586 nv_free(nverr); 587 proto_close(conn); 588 pjdlog_prefix_set("%s", ""); 589 } 590 591 static void 592 main_loop(void) 593 { 594 fd_set rfds, wfds; 595 int cfd, lfd, maxfd, ret; 596 597 for (;;) { 598 if (sigchld_received) { 599 sigchld_received = false; 600 child_exit(); 601 } 602 if (sighup_received) { 603 sighup_received = false; 604 hastd_reload(); 605 } 606 607 cfd = proto_descriptor(cfg->hc_controlconn); 608 lfd = proto_descriptor(cfg->hc_listenconn); 609 maxfd = cfd > lfd ? cfd : lfd; 610 611 /* Setup descriptors for select(2). */ 612 FD_ZERO(&rfds); 613 FD_SET(cfd, &rfds); 614 FD_SET(lfd, &rfds); 615 FD_ZERO(&wfds); 616 FD_SET(cfd, &wfds); 617 FD_SET(lfd, &wfds); 618 619 ret = select(maxfd + 1, &rfds, &wfds, NULL, NULL); 620 if (ret == -1) { 621 if (errno == EINTR) 622 continue; 623 KEEP_ERRNO((void)pidfile_remove(pfh)); 624 pjdlog_exit(EX_OSERR, "select() failed"); 625 } 626 627 if (FD_ISSET(cfd, &rfds) || FD_ISSET(cfd, &wfds)) 628 control_handle(cfg); 629 if (FD_ISSET(lfd, &rfds) || FD_ISSET(lfd, &wfds)) 630 listen_accept(); 631 } 632 } 633 634 int 635 main(int argc, char *argv[]) 636 { 637 const char *pidfile; 638 pid_t otherpid; 639 bool foreground; 640 int debuglevel; 641 642 g_gate_load(); 643 644 foreground = false; 645 debuglevel = 0; 646 pidfile = HASTD_PIDFILE; 647 648 for (;;) { 649 int ch; 650 651 ch = getopt(argc, argv, "c:dFhP:"); 652 if (ch == -1) 653 break; 654 switch (ch) { 655 case 'c': 656 cfgpath = optarg; 657 break; 658 case 'd': 659 debuglevel++; 660 break; 661 case 'F': 662 foreground = true; 663 break; 664 case 'P': 665 pidfile = optarg; 666 break; 667 case 'h': 668 default: 669 usage(); 670 } 671 } 672 argc -= optind; 673 argv += optind; 674 675 pjdlog_debug_set(debuglevel); 676 677 pfh = pidfile_open(pidfile, 0600, &otherpid); 678 if (pfh == NULL) { 679 if (errno == EEXIST) { 680 pjdlog_exitx(EX_TEMPFAIL, 681 "Another hastd is already running, pid: %jd.", 682 (intmax_t)otherpid); 683 } 684 /* If we cannot create pidfile from other reasons, only warn. */ 685 pjdlog_errno(LOG_WARNING, "Unable to open or create pidfile"); 686 } 687 688 cfg = yy_config_parse(cfgpath, true); 689 assert(cfg != NULL); 690 691 signal(SIGHUP, sighandler); 692 signal(SIGCHLD, sighandler); 693 694 /* Listen on control address. */ 695 if (proto_server(cfg->hc_controladdr, &cfg->hc_controlconn) < 0) { 696 KEEP_ERRNO((void)pidfile_remove(pfh)); 697 pjdlog_exit(EX_OSERR, "Unable to listen on control address %s", 698 cfg->hc_controladdr); 699 } 700 /* Listen for remote connections. */ 701 if (proto_server(cfg->hc_listenaddr, &cfg->hc_listenconn) < 0) { 702 KEEP_ERRNO((void)pidfile_remove(pfh)); 703 pjdlog_exit(EX_OSERR, "Unable to listen on address %s", 704 cfg->hc_listenaddr); 705 } 706 707 if (!foreground) { 708 if (daemon(0, 0) < 0) { 709 KEEP_ERRNO((void)pidfile_remove(pfh)); 710 pjdlog_exit(EX_OSERR, "Unable to daemonize"); 711 } 712 713 /* Start logging to syslog. */ 714 pjdlog_mode_set(PJDLOG_MODE_SYSLOG); 715 716 /* Write PID to a file. */ 717 if (pidfile_write(pfh) < 0) { 718 pjdlog_errno(LOG_WARNING, 719 "Unable to write PID to a file"); 720 } 721 } 722 723 main_loop(); 724 725 exit(0); 726 } 727