1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2018 Roy Marples <roy@marples.name> 4 * All rights reserved 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/stat.h> 29 #include <sys/uio.h> 30 #include <sys/wait.h> 31 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 35 #include <ctype.h> 36 #include <errno.h> 37 #include <signal.h> 38 #include <spawn.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include "config.h" 44 #include "common.h" 45 #include "dhcp.h" 46 #include "dhcp6.h" 47 #include "if.h" 48 #include "if-options.h" 49 #include "ipv4ll.h" 50 #include "ipv6nd.h" 51 #include "logerr.h" 52 #include "script.h" 53 54 /* Allow the OS to define another script env var name */ 55 #ifndef RC_SVCNAME 56 #define RC_SVCNAME "RC_SVCNAME" 57 #endif 58 59 #define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" 60 61 static const char * const if_params[] = { 62 "interface", 63 "protocol", 64 "reason", 65 "pid", 66 "ifcarrier", 67 "ifmetric", 68 "ifwireless", 69 "ifflags", 70 "ssid", 71 "profile", 72 "interface_order", 73 NULL 74 }; 75 76 void 77 if_printoptions(void) 78 { 79 const char * const *p; 80 81 for (p = if_params; *p; p++) 82 printf(" - %s\n", *p); 83 } 84 85 static int 86 exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env) 87 { 88 pid_t pid; 89 posix_spawnattr_t attr; 90 int r; 91 #ifdef USE_SIGNALS 92 size_t i; 93 short flags; 94 sigset_t defsigs; 95 #else 96 UNUSED(ctx); 97 #endif 98 99 /* posix_spawn is a safe way of executing another image 100 * and changing signals back to how they should be. */ 101 if (posix_spawnattr_init(&attr) == -1) 102 return -1; 103 #ifdef USE_SIGNALS 104 flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF; 105 posix_spawnattr_setflags(&attr, flags); 106 sigemptyset(&defsigs); 107 for (i = 0; i < dhcpcd_signals_len; i++) 108 sigaddset(&defsigs, dhcpcd_signals[i]); 109 posix_spawnattr_setsigdefault(&attr, &defsigs); 110 posix_spawnattr_setsigmask(&attr, &ctx->sigset); 111 #endif 112 errno = 0; 113 r = posix_spawn(&pid, argv[0], NULL, &attr, argv, env); 114 posix_spawnattr_destroy(&attr); 115 if (r) { 116 errno = r; 117 return -1; 118 } 119 return pid; 120 } 121 122 #ifdef INET 123 static char * 124 make_var(const char *prefix, const char *var) 125 { 126 size_t len; 127 char *v; 128 129 len = strlen(prefix) + strlen(var) + 2; 130 if ((v = malloc(len)) == NULL) { 131 logerr(__func__); 132 return NULL; 133 } 134 snprintf(v, len, "%s_%s", prefix, var); 135 return v; 136 } 137 138 139 static int 140 append_config(char ***env, size_t *len, 141 const char *prefix, const char *const *config) 142 { 143 size_t i, j, e1; 144 char **ne, *eq, **nep, *p; 145 int ret; 146 147 if (config == NULL) 148 return 0; 149 150 ne = *env; 151 ret = 0; 152 for (i = 0; config[i] != NULL; i++) { 153 eq = strchr(config[i], '='); 154 e1 = (size_t)(eq - config[i] + 1); 155 for (j = 0; j < *len; j++) { 156 if (strncmp(ne[j], prefix, strlen(prefix)) == 0 && 157 ne[j][strlen(prefix)] == '_' && 158 strncmp(ne[j] + strlen(prefix) + 1, 159 config[i], e1) == 0) 160 { 161 p = make_var(prefix, config[i]); 162 if (p == NULL) { 163 ret = -1; 164 break; 165 } 166 free(ne[j]); 167 ne[j] = p; 168 break; 169 } 170 } 171 if (j == *len) { 172 j++; 173 p = make_var(prefix, config[i]); 174 if (p == NULL) { 175 ret = -1; 176 break; 177 } 178 nep = realloc(ne, sizeof(char *) * (j + 1)); 179 if (nep == NULL) { 180 logerr(__func__); 181 free(p); 182 ret = -1; 183 break; 184 } 185 ne = nep; 186 ne[j - 1] = p; 187 *len = j; 188 } 189 } 190 *env = ne; 191 return ret; 192 } 193 #endif 194 195 static ssize_t 196 arraytostr(const char *const *argv, char **s) 197 { 198 const char *const *ap; 199 char *p; 200 size_t len, l; 201 202 if (*argv == NULL) 203 return 0; 204 len = 0; 205 ap = argv; 206 while (*ap) 207 len += strlen(*ap++) + 1; 208 *s = p = malloc(len); 209 if (p == NULL) 210 return -1; 211 ap = argv; 212 while (*ap) { 213 l = strlen(*ap) + 1; 214 memcpy(p, *ap, l); 215 p += l; 216 ap++; 217 } 218 return (ssize_t)len; 219 } 220 221 #define PROTO_LINK 0 222 #define PROTO_DHCP 1 223 #define PROTO_IPV4LL 2 224 #define PROTO_RA 3 225 #define PROTO_DHCP6 4 226 #define PROTO_STATIC6 5 227 static const char *protocols[] = { 228 "link", 229 "dhcp", 230 "ipv4ll", 231 "ra", 232 "dhcp6", 233 "static6" 234 }; 235 236 static ssize_t 237 make_env(const struct interface *ifp, const char *reason, char ***argv) 238 { 239 int protocol, r; 240 char **env, **nenv, *p; 241 size_t e, elen, l; 242 #if defined(INET) || defined(INET6) 243 ssize_t n; 244 #endif 245 const struct if_options *ifo = ifp->options; 246 const struct interface *ifp2; 247 int af; 248 #ifdef INET 249 const struct dhcp_state *state; 250 #ifdef IPV4LL 251 const struct ipv4ll_state *istate; 252 #endif 253 #endif 254 #ifdef INET6 255 const struct dhcp6_state *d6_state; 256 #endif 257 258 #ifdef INET 259 state = D_STATE(ifp); 260 #ifdef IPV4LL 261 istate = IPV4LL_CSTATE(ifp); 262 #endif 263 #endif 264 #ifdef INET6 265 d6_state = D6_CSTATE(ifp); 266 #endif 267 if (strcmp(reason, "TEST") == 0) { 268 if (1 == 2) {} 269 #ifdef INET6 270 else if (d6_state && d6_state->new) 271 protocol = PROTO_DHCP6; 272 else if (ipv6nd_hasra(ifp)) 273 protocol = PROTO_RA; 274 #endif 275 #ifdef INET 276 #ifdef IPV4LL 277 else if (istate && istate->addr != NULL) 278 protocol = PROTO_IPV4LL; 279 #endif 280 else 281 protocol = PROTO_DHCP; 282 #endif 283 } 284 #ifdef INET6 285 else if (strcmp(reason, "STATIC6") == 0) 286 protocol = PROTO_STATIC6; 287 else if (reason[strlen(reason) - 1] == '6') 288 protocol = PROTO_DHCP6; 289 else if (strcmp(reason, "ROUTERADVERT") == 0) 290 protocol = PROTO_RA; 291 #endif 292 else if (strcmp(reason, "PREINIT") == 0 || 293 strcmp(reason, "CARRIER") == 0 || 294 strcmp(reason, "NOCARRIER") == 0 || 295 strcmp(reason, "UNKNOWN") == 0 || 296 strcmp(reason, "DEPARTED") == 0 || 297 strcmp(reason, "STOPPED") == 0) 298 protocol = PROTO_LINK; 299 #ifdef INET 300 #ifdef IPV4LL 301 else if (strcmp(reason, "IPV4LL") == 0) 302 protocol = PROTO_IPV4LL; 303 #endif 304 else 305 protocol = PROTO_DHCP; 306 #endif 307 308 /* When dumping the lease, we only want to report interface and 309 reason - the other interface variables are meaningless */ 310 if (ifp->ctx->options & DHCPCD_DUMPLEASE) 311 elen = 2; 312 else 313 elen = 11; 314 315 #define EMALLOC(i, l) if ((env[(i)] = malloc((l))) == NULL) goto eexit; 316 /* Make our env + space for profile, wireless and debug */ 317 env = calloc(1, sizeof(char *) * (elen + 5 + 1)); 318 if (env == NULL) 319 goto eexit; 320 e = strlen("interface") + strlen(ifp->name) + 2; 321 EMALLOC(0, e); 322 snprintf(env[0], e, "interface=%s", ifp->name); 323 e = strlen("reason") + strlen(reason) + 2; 324 EMALLOC(1, e); 325 snprintf(env[1], e, "reason=%s", reason); 326 if (ifp->ctx->options & DHCPCD_DUMPLEASE) 327 goto dumplease; 328 e = 20; 329 EMALLOC(2, e); 330 snprintf(env[2], e, "pid=%d", getpid()); 331 EMALLOC(3, e); 332 snprintf(env[3], e, "ifcarrier=%s", 333 ifp->carrier == LINK_UNKNOWN ? "unknown" : 334 ifp->carrier == LINK_UP ? "up" : "down"); 335 EMALLOC(4, e); 336 snprintf(env[4], e, "ifmetric=%d", ifp->metric); 337 EMALLOC(5, e); 338 snprintf(env[5], e, "ifwireless=%d", ifp->wireless); 339 EMALLOC(6, e); 340 snprintf(env[6], e, "ifflags=%u", ifp->flags); 341 EMALLOC(7, e); 342 snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp)); 343 l = e = strlen("interface_order="); 344 TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { 345 e += strlen(ifp2->name) + 1; 346 } 347 EMALLOC(8, e); 348 p = env[8]; 349 strlcpy(p, "interface_order=", e); 350 e -= l; 351 p += l; 352 TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { 353 l = strlcpy(p, ifp2->name, e); 354 p += l; 355 e -= l; 356 *p++ = ' '; 357 e--; 358 } 359 *--p = '\0'; 360 if (strcmp(reason, "STOPPED") == 0) { 361 env[9] = strdup("if_up=false"); 362 if (ifo->options & DHCPCD_RELEASE) 363 env[10] = strdup("if_down=true"); 364 else 365 env[10] = strdup("if_down=false"); 366 } else if (strcmp(reason, "TEST") == 0 || 367 strcmp(reason, "PREINIT") == 0 || 368 strcmp(reason, "CARRIER") == 0 || 369 strcmp(reason, "UNKNOWN") == 0) 370 { 371 env[9] = strdup("if_up=false"); 372 env[10] = strdup("if_down=false"); 373 } else if (1 == 2 /* appease ifdefs */ 374 #ifdef INET 375 || (protocol == PROTO_DHCP && state && state->new) 376 #ifdef IPV4LL 377 || (protocol == PROTO_IPV4LL && IPV4LL_STATE_RUNNING(ifp)) 378 #endif 379 #endif 380 #ifdef INET6 381 || (protocol == PROTO_STATIC6 && IPV6_STATE_RUNNING(ifp)) 382 || (protocol == PROTO_DHCP6 && d6_state && d6_state->new) 383 || (protocol == PROTO_RA && ipv6nd_hasra(ifp)) 384 #endif 385 ) 386 { 387 env[9] = strdup("if_up=true"); 388 env[10] = strdup("if_down=false"); 389 } else { 390 env[9] = strdup("if_up=false"); 391 env[10] = strdup("if_down=true"); 392 } 393 if (env[9] == NULL || env[10] == NULL) 394 goto eexit; 395 if (protocols[protocol] != NULL) { 396 r = asprintf(&env[elen], "protocol=%s", protocols[protocol]); 397 if (r == -1) 398 goto eexit; 399 elen++; 400 } 401 if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) { 402 e = 20; 403 EMALLOC(elen, e); 404 snprintf(env[elen++], e, "if_afwaiting=%d", af); 405 } 406 if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) { 407 TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { 408 if ((af = dhcpcd_ifafwaiting(ifp2)) != AF_MAX) 409 break; 410 } 411 } 412 if (af != AF_MAX) { 413 e = 20; 414 EMALLOC(elen, e); 415 snprintf(env[elen++], e, "af_waiting=%d", af); 416 } 417 if (ifo->options & DHCPCD_DEBUG) { 418 e = strlen("syslog_debug=true") + 1; 419 EMALLOC(elen, e); 420 snprintf(env[elen++], e, "syslog_debug=true"); 421 } 422 if (*ifp->profile) { 423 e = strlen("profile=") + strlen(ifp->profile) + 1; 424 EMALLOC(elen, e); 425 snprintf(env[elen++], e, "profile=%s", ifp->profile); 426 } 427 if (ifp->wireless) { 428 static const char *pfx = "ifssid="; 429 size_t pfx_len; 430 ssize_t psl; 431 432 pfx_len = strlen(pfx); 433 psl = print_string(NULL, 0, OT_ESCSTRING, 434 (const uint8_t *)ifp->ssid, ifp->ssid_len); 435 if (psl != -1) { 436 EMALLOC(elen, pfx_len + (size_t)psl + 1); 437 memcpy(env[elen], pfx, pfx_len); 438 print_string(env[elen] + pfx_len, (size_t)psl + 1, 439 OT_ESCSTRING, 440 (const uint8_t *)ifp->ssid, ifp->ssid_len); 441 elen++; 442 } 443 } 444 #ifdef INET 445 if (protocol == PROTO_DHCP && state && state->old) { 446 n = dhcp_env(NULL, NULL, state->old, state->old_len, ifp); 447 if (n == -1) 448 goto eexit; 449 if (n > 0) { 450 nenv = realloc(env, sizeof(char *) * 451 (elen + (size_t)n + 1)); 452 if (nenv == NULL) 453 goto eexit; 454 env = nenv; 455 n = dhcp_env(env + elen, "old", 456 state->old, state->old_len, ifp); 457 if (n == -1) 458 goto eexit; 459 elen += (size_t)n; 460 } 461 if (append_config(&env, &elen, "old", 462 (const char *const *)ifo->config) == -1) 463 goto eexit; 464 } 465 #endif 466 #ifdef INET6 467 if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) { 468 n = dhcp6_env(NULL, NULL, ifp, 469 d6_state->old, d6_state->old_len); 470 if (n > 0) { 471 nenv = realloc(env, sizeof(char *) * 472 (elen + (size_t)n + 1)); 473 if (nenv == NULL) 474 goto eexit; 475 env = nenv; 476 n = dhcp6_env(env + elen, "old", ifp, 477 d6_state->old, d6_state->old_len); 478 if (n == -1) 479 goto eexit; 480 elen += (size_t)n; 481 } 482 } 483 #endif 484 485 dumplease: 486 #ifdef INET 487 #ifdef IPV4LL 488 if (protocol == PROTO_IPV4LL) { 489 n = ipv4ll_env(NULL, NULL, ifp); 490 if (n > 0) { 491 nenv = realloc(env, sizeof(char *) * 492 (elen + (size_t)n + 1)); 493 if (nenv == NULL) 494 goto eexit; 495 env = nenv; 496 if ((n = ipv4ll_env(env + elen, 497 istate->down ? "old" : "new", ifp)) == -1) 498 goto eexit; 499 elen += (size_t)n; 500 } 501 } 502 #endif 503 if (protocol == PROTO_DHCP && state && state->new) { 504 n = dhcp_env(NULL, NULL, state->new, state->new_len, ifp); 505 if (n > 0) { 506 nenv = realloc(env, sizeof(char *) * 507 (elen + (size_t)n + 1)); 508 if (nenv == NULL) 509 goto eexit; 510 env = nenv; 511 n = dhcp_env(env + elen, "new", 512 state->new, state->new_len, ifp); 513 if (n == -1) 514 goto eexit; 515 elen += (size_t)n; 516 } 517 if (append_config(&env, &elen, "new", 518 (const char *const *)ifo->config) == -1) 519 goto eexit; 520 } 521 #endif 522 #ifdef INET6 523 if (protocol == PROTO_STATIC6) { 524 n = ipv6_env(NULL, NULL, ifp); 525 if (n > 0) { 526 nenv = realloc(env, sizeof(char *) * 527 (elen + (size_t)n + 1)); 528 if (nenv == NULL) 529 goto eexit; 530 env = nenv; 531 n = ipv6_env(env + elen, "new", ifp); 532 if (n == -1) 533 goto eexit; 534 elen += (size_t)n; 535 } 536 } 537 if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) { 538 n = dhcp6_env(NULL, NULL, ifp, 539 d6_state->new, d6_state->new_len); 540 if (n > 0) { 541 nenv = realloc(env, sizeof(char *) * 542 (elen + (size_t)n + 1)); 543 if (nenv == NULL) 544 goto eexit; 545 env = nenv; 546 n = dhcp6_env(env + elen, "new", ifp, 547 d6_state->new, d6_state->new_len); 548 if (n == -1) 549 goto eexit; 550 elen += (size_t)n; 551 } 552 } 553 if (protocol == PROTO_RA) { 554 n = ipv6nd_env(NULL, NULL, ifp); 555 if (n > 0) { 556 nenv = realloc(env, sizeof(char *) * 557 (elen + (size_t)n + 1)); 558 if (nenv == NULL) 559 goto eexit; 560 env = nenv; 561 n = ipv6nd_env(env + elen, NULL, ifp); 562 if (n == -1) 563 goto eexit; 564 elen += (size_t)n; 565 } 566 } 567 #endif 568 569 /* Add our base environment */ 570 if (ifo->environ) { 571 e = 0; 572 while (ifo->environ[e++]) 573 ; 574 nenv = realloc(env, sizeof(char *) * (elen + e + 1)); 575 if (nenv == NULL) 576 goto eexit; 577 env = nenv; 578 e = 0; 579 while (ifo->environ[e]) { 580 env[elen + e] = strdup(ifo->environ[e]); 581 if (env[elen + e] == NULL) 582 goto eexit; 583 e++; 584 } 585 elen += e; 586 } 587 env[elen] = NULL; 588 589 *argv = env; 590 return (ssize_t)elen; 591 592 eexit: 593 logerr(__func__); 594 if (env) { 595 nenv = env; 596 while (*nenv) 597 free(*nenv++); 598 free(env); 599 } 600 return -1; 601 } 602 603 static int 604 send_interface1(struct fd_list *fd, const struct interface *iface, 605 const char *reason) 606 { 607 char **env, **ep, *s; 608 size_t elen; 609 int retval; 610 611 if (make_env(iface, reason, &env) == -1) 612 return -1; 613 s = NULL; 614 elen = (size_t)arraytostr((const char *const *)env, &s); 615 if ((ssize_t)elen == -1) { 616 free(s); 617 retval = -1; 618 } else 619 retval = control_queue(fd, s, elen, 1); 620 ep = env; 621 while (*ep) 622 free(*ep++); 623 free(env); 624 return retval; 625 } 626 627 int 628 send_interface(struct fd_list *fd, const struct interface *ifp) 629 { 630 const char *reason; 631 int retval = 0; 632 #ifdef INET 633 const struct dhcp_state *d; 634 #endif 635 #ifdef INET6 636 const struct dhcp6_state *d6; 637 #endif 638 639 switch (ifp->carrier) { 640 case LINK_UP: 641 reason = "CARRIER"; 642 break; 643 case LINK_DOWN: 644 reason = "NOCARRIER"; 645 break; 646 default: 647 reason = "UNKNOWN"; 648 break; 649 } 650 if (send_interface1(fd, ifp, reason) == -1) 651 retval = -1; 652 #ifdef INET 653 if (D_STATE_RUNNING(ifp)) { 654 d = D_CSTATE(ifp); 655 if (send_interface1(fd, ifp, d->reason) == -1) 656 retval = -1; 657 } 658 #ifdef IPV4LL 659 if (IPV4LL_STATE_RUNNING(ifp)) { 660 if (send_interface1(fd, ifp, "IPV4LL") == -1) 661 retval = -1; 662 } 663 #endif 664 #endif 665 666 #ifdef INET6 667 if (IPV6_STATE_RUNNING(ifp)) { 668 if (send_interface1(fd, ifp, "STATIC6") == -1) 669 retval = -1; 670 } 671 if (RS_STATE_RUNNING(ifp)) { 672 if (send_interface1(fd, ifp, "ROUTERADVERT") == -1) 673 retval = -1; 674 } 675 if (D6_STATE_RUNNING(ifp)) { 676 d6 = D6_CSTATE(ifp); 677 if (send_interface1(fd, ifp, d6->reason) == -1) 678 retval = -1; 679 } 680 #endif 681 682 return retval; 683 } 684 685 int 686 script_runreason(const struct interface *ifp, const char *reason) 687 { 688 char *argv[2]; 689 char **env = NULL, **ep; 690 char *svcname, *path, *bigenv; 691 size_t e, elen = 0; 692 pid_t pid; 693 int status = 0; 694 struct fd_list *fd; 695 696 if (ifp->options->script && 697 (ifp->options->script[0] == '\0' || 698 strcmp(ifp->options->script, "/dev/null") == 0) && 699 TAILQ_FIRST(&ifp->ctx->control_fds) == NULL) 700 return 0; 701 702 /* Make our env */ 703 elen = (size_t)make_env(ifp, reason, &env); 704 if (elen == (size_t)-1) { 705 logerr(__func__); 706 return -1; 707 } 708 709 if (ifp->options->script && 710 (ifp->options->script[0] == '\0' || 711 strcmp(ifp->options->script, "/dev/null") == 0)) 712 goto send_listeners; 713 714 argv[0] = ifp->options->script ? ifp->options->script : UNCONST(SCRIPT); 715 argv[1] = NULL; 716 logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason); 717 718 /* Resize for PATH and RC_SVCNAME */ 719 svcname = getenv(RC_SVCNAME); 720 ep = reallocarray(env, elen + 2 + (svcname ? 1 : 0), sizeof(char *)); 721 if (ep == NULL) { 722 elen = 0; 723 goto out; 724 } 725 env = ep; 726 /* Add path to it */ 727 path = getenv("PATH"); 728 if (path) { 729 e = strlen("PATH") + strlen(path) + 2; 730 env[elen] = malloc(e); 731 if (env[elen] == NULL) { 732 elen = 0; 733 goto out; 734 } 735 snprintf(env[elen], e, "PATH=%s", path); 736 } else { 737 env[elen] = strdup(DEFAULT_PATH); 738 if (env[elen] == NULL) { 739 elen = 0; 740 goto out; 741 } 742 } 743 if (svcname) { 744 e = strlen(RC_SVCNAME) + strlen(svcname) + 2; 745 env[++elen] = malloc(e); 746 if (env[elen] == NULL) { 747 elen = 0; 748 goto out; 749 } 750 snprintf(env[elen], e, "%s=%s", RC_SVCNAME, svcname); 751 } 752 env[++elen] = NULL; 753 754 pid = exec_script(ifp->ctx, argv, env); 755 if (pid == -1) 756 logerr("%s: %s", __func__, argv[0]); 757 else if (pid != 0) { 758 /* Wait for the script to finish */ 759 while (waitpid(pid, &status, 0) == -1) { 760 if (errno != EINTR) { 761 logerr("%s: waitpid", __func__); 762 status = 0; 763 break; 764 } 765 } 766 if (WIFEXITED(status)) { 767 if (WEXITSTATUS(status)) 768 logerrx("%s: %s: WEXITSTATUS %d", 769 __func__, argv[0], WEXITSTATUS(status)); 770 } else if (WIFSIGNALED(status)) 771 logerrx("%s: %s: %s", 772 __func__, argv[0], strsignal(WTERMSIG(status))); 773 } 774 775 send_listeners: 776 /* Send to our listeners */ 777 bigenv = NULL; 778 status = 0; 779 TAILQ_FOREACH(fd, &ifp->ctx->control_fds, next) { 780 if (!(fd->flags & FD_LISTEN)) 781 continue; 782 if (bigenv == NULL) { 783 elen = (size_t)arraytostr((const char *const *)env, 784 &bigenv); 785 if ((ssize_t)elen == -1) { 786 logerr("%s: arraytostr", ifp->name); 787 break; 788 } 789 } 790 if (control_queue(fd, bigenv, elen, 1) == -1) 791 logerr("%s: control_queue", __func__); 792 else 793 status = 1; 794 } 795 if (!status) 796 free(bigenv); 797 798 out: 799 /* Cleanup */ 800 ep = env; 801 while (*ep) 802 free(*ep++); 803 free(env); 804 if (elen == 0) { 805 logerr(__func__); 806 return -1; 807 } 808 return WEXITSTATUS(status); 809 } 810