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