1 /* 2 * Copyright (c) 2019-2020 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * This code uses concepts and configuration based on 'synth', by 8 * John R. Marino <draco@marino.st>, which was written in ada. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 3. Neither the name of The DragonFly Project nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific, prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #include "dsynth.h" 39 40 struct logerrinfo { 41 struct logerrinfo *next; 42 char *logid; 43 pid_t pid; 44 long seq; 45 int exited; 46 }; 47 48 buildenv_t *BuildEnv; 49 static buildenv_t **BuildEnvTail = &BuildEnv; 50 51 extern char **environ; 52 53 static void *dexec_logerr_thread(void *info); 54 55 #define EINFO_HSIZE 1024 56 #define EINFO_HMASK (EINFO_HSIZE - 1) 57 58 static struct logerrinfo *EInfo[EINFO_HSIZE]; 59 static pthread_t ETid; 60 static int EFds[2]; 61 static pthread_cond_t ECond; 62 63 static __inline 64 struct logerrinfo ** 65 einfohash(pid_t pid) 66 { 67 return(&EInfo[pid & EINFO_HMASK]); 68 } 69 70 __dead2 void 71 _dfatal(const char *file __unused, int line __unused, const char *func, 72 int do_errno, const char *ctl, ...) 73 { 74 va_list va; 75 76 fprintf(stderr, "%s: ", func); 77 va_start(va, ctl); 78 vfprintf(stderr, ctl, va); 79 va_end(va); 80 if (do_errno & 1) 81 fprintf(stderr, ": %s", strerror(errno)); 82 fprintf(stderr, "\n"); 83 fflush(stderr); 84 85 if (do_errno & 2) 86 kill(getpid(), SIGQUIT); 87 exit(1); 88 } 89 90 void 91 _ddprintf(int tab, const char *ctl, ...) 92 { 93 va_list va; 94 95 if (tab) 96 printf("%*.*s", tab, tab, ""); 97 va_start(va, ctl); 98 vfprintf(stdout, ctl, va); 99 va_end(va); 100 } 101 102 char * 103 strdup_or_null(char *str) 104 { 105 if (str && str[0]) 106 return(strdup(str)); 107 return NULL; 108 } 109 110 static const char *DLogNames[] = { 111 "00_last_results.log", 112 "01_success_list.log", 113 "02_failure_list.log", 114 "03_ignored_list.log", 115 "04_skipped_list.log", 116 "05_abnormal_command_output.log", 117 "06_obsolete_packages.log", 118 "07_debug.log", 119 }; 120 121 static int DLogFd[DLOG_COUNT]; 122 static pthread_mutex_t DLogFdMutex; 123 124 #define arysize(ary) (sizeof((ary)) / sizeof((ary)[0])) 125 126 static int 127 dlogfd(int which, int modes) 128 { 129 char *path; 130 int fd; 131 132 which &= DLOG_MASK; 133 if ((fd = DLogFd[which]) > 0) 134 return fd; 135 pthread_mutex_lock(&DLogFdMutex); 136 if ((fd = DLogFd[which]) <= 0) { 137 asprintf(&path, "%s/%s", LogsPath, DLogNames[which]); 138 fd = open(path, modes, 0666); 139 DLogFd[which] = fd; 140 free(path); 141 } 142 pthread_mutex_unlock(&DLogFdMutex); 143 144 return fd; 145 } 146 147 148 void 149 dlogreset(void) 150 { 151 int i; 152 153 ddassert(DLOG_COUNT == arysize(DLogNames)); 154 for (i = 0; i < DLOG_COUNT; ++i) { 155 if (DLogFd[i] > 0) { 156 close(DLogFd[i]); 157 DLogFd[i] = -1; 158 } 159 (void)dlogfd(i, O_RDWR|O_CREAT|O_TRUNC|O_APPEND); 160 } 161 } 162 163 void 164 _dlog(int which, const char *ctl, ...) 165 { 166 va_list va; 167 char *buf; 168 char *ptr; 169 size_t len; 170 int fd; 171 int filter; 172 173 filter = which; 174 which &= DLOG_MASK; 175 176 ddassert((uint)which < DLOG_COUNT); 177 va_start(va, ctl); 178 vasprintf(&buf, ctl, va); 179 va_end(va); 180 len = strlen(buf); 181 182 /* 183 * The special sequence ## right-justfies the text after the ##. 184 * 185 * NOTE: Alignment test includes \n so use 80 instead of 79 to 186 * leave one char unused on a 80-column terminal. 187 */ 188 if ((ptr = strstr(buf, "##")) != NULL) { 189 size_t l2; 190 size_t l1; 191 char *b2; 192 int spc; 193 194 l1 = (int)(ptr - buf); 195 l2 = len - l1 - 2; 196 if (l1 <= 80 - l2) { 197 spc = 80 - l1 - l2; 198 buf[l1] = 0; 199 asprintf(&b2, "%s%*.*s%s", 200 buf, spc, spc, "", ptr + 2); 201 } else { 202 buf[l1] = 0; 203 asprintf(&b2, "%s%s", buf, ptr + 2); 204 } 205 len = strlen(b2); 206 free(buf); 207 buf = b2; 208 } 209 210 /* 211 * All logs also go to log 00. 212 */ 213 if (which != DLOG_ALL) { 214 fd = dlogfd(DLOG_ALL, O_RDWR|O_CREAT|O_APPEND); 215 if (fd > 0) 216 write(fd, buf, len); 217 } 218 219 /* 220 * Nominal log target 221 */ 222 fd = dlogfd(which, O_RDWR|O_CREAT|O_APPEND); 223 write(fd, buf, len); 224 225 /* 226 * If ncurses is not being used, all log output also goes 227 * to stdout, unless filtered. 228 */ 229 if ((UseNCurses == 0 || (filter & DLOG_STDOUT)) && 230 (filter & DLOG_FILTER) == 0) { 231 if (ColorOpt) { 232 if (filter & DLOG_GRN) 233 write(1, "\x1b[0;32m", 7); 234 if (filter & DLOG_RED) 235 write(1, "\x1b[0;31m", 7); 236 } 237 write(1, buf, len); 238 if (ColorOpt && (filter & (DLOG_GRN|DLOG_RED))) { 239 write(1, "\x1b[0;39m", 7); 240 } 241 } 242 free(buf); 243 } 244 245 int 246 dlog00_fd(void) 247 { 248 return(dlogfd(DLOG_ALL, O_RDWR|O_CREAT|O_APPEND)); 249 } 250 251 /* 252 * Bulk and Build environment control. These routines are only called 253 * unthreaded or when dsynth threads are idle. 254 */ 255 void 256 addbuildenv(const char *label, const char *data, int type) 257 { 258 buildenv_t *env; 259 260 env = calloc(1, sizeof(*env)); 261 env->a1 = strdup(label); 262 env->a2 = strdup(data); 263 env->label = env->a1; 264 env->data = env->a2; 265 env->type = type; 266 *BuildEnvTail = env; 267 BuildEnvTail = &env->next; 268 } 269 270 void 271 delbuildenv(const char *label) 272 { 273 buildenv_t **envp; 274 buildenv_t *env; 275 276 envp = &BuildEnv; 277 while ((env = *envp) != NULL) { 278 if (strcmp(env->label, label) == 0) { 279 *envp = env->next; 280 if (env->a1) 281 free(env->a1); 282 if (env->a2) 283 free(env->a2); 284 free(env); 285 } else { 286 envp = &env->next; 287 } 288 } 289 BuildEnvTail = envp; 290 } 291 292 const char * 293 getbuildenv(const char *label) 294 { 295 buildenv_t **envp; 296 buildenv_t *env; 297 298 envp = &BuildEnv; 299 while ((env = *envp) != NULL) { 300 if (strcmp(env->label, label) == 0) 301 return env->data; 302 envp = &env->next; 303 } 304 return NULL; 305 } 306 307 void 308 freestrp(char **strp) 309 { 310 if (*strp) { 311 free(*strp); 312 *strp = NULL; 313 } 314 } 315 316 void 317 dupstrp(char **strp) 318 { 319 if (*strp) 320 *strp = strdup(*strp); 321 } 322 323 int 324 ipcreadmsg(int fd, wmsg_t *msg) 325 { 326 size_t res; 327 ssize_t r; 328 char *ptr; 329 330 res = sizeof(*msg); 331 ptr = (char *)(void *)msg; 332 while (res) { 333 r = read(fd, ptr, res); 334 if (r <= 0) { 335 if (errno == EINTR) 336 continue; 337 return -1; 338 } 339 res -= (size_t)r; 340 ptr += r; 341 } 342 return 0; 343 } 344 345 int 346 ipcwritemsg(int fd, wmsg_t *msg) 347 { 348 size_t res; 349 ssize_t r; 350 char *ptr; 351 352 res = sizeof(*msg); 353 ptr = (char *)(void *)msg; 354 while (res) { 355 r = write(fd, ptr, res); 356 if (r < 0) { 357 if (errno == EINTR) 358 continue; 359 return -1; 360 } 361 res -= (size_t)r; 362 ptr += r; 363 } 364 return 0; 365 } 366 367 int 368 askyn(const char *ctl, ...) 369 { 370 va_list va; 371 char buf[256]; 372 int res = 0; 373 374 if (YesOpt) 375 return 1; 376 377 for (;;) { 378 va_start(va, ctl); 379 vprintf(ctl, va); 380 va_end(va); 381 fflush(stdout); 382 if (fgets(buf, sizeof(buf), stdin) == NULL) 383 break; 384 if (buf[0] == 'y' || buf[0] == 'Y') { 385 res = 1; 386 break; 387 } 388 if (buf[0] == 'n' || buf[0] == 'N') { 389 res = 0; 390 break; 391 } 392 printf("Please type y/n\n"); 393 } 394 return res; 395 } 396 397 /* 398 * Get swap% used 0.0-1.0. 399 * 400 * NOTE: This routine is intended to return quickly. 401 * 402 * NOTE: swap_cache (caching for hard drives) is persistent and should 403 * not be counted for our purposes. 404 */ 405 double 406 getswappct(int *noswapp) 407 { 408 long swap_size = 0; 409 long swap_anon = 0; 410 long swap_cache __unused = 0; 411 size_t len; 412 double dswap; 413 414 len = sizeof(swap_size); 415 sysctlbyname("vm.swap_size", &swap_size, &len, NULL, 0); 416 len = sizeof(swap_size); 417 sysctlbyname("vm.swap_anon_use", &swap_anon, &len, NULL, 0); 418 len = sizeof(swap_size); 419 sysctlbyname("vm.swap_cache_use", &swap_cache, &len, NULL, 0); 420 if (swap_size) { 421 dswap = (double)(swap_anon /*+swap_cache*/) / (double)swap_size; 422 *noswapp = 0; 423 } else { 424 dswap = 0.0; 425 *noswapp = 1; 426 } 427 return dswap; 428 } 429 430 /* 431 * dexec_open()/fgets/dexec_close() 432 * 433 * Similar to popen() but directly exec()s the argument list (cav[0] must 434 * be an absolute path). 435 * 436 * If xenv is non-NULL its an array of local buildenv_t's to be used. 437 * The array is terminated with a NULL xenv->label. 438 * 439 * If with_env is non-zero the configured environment is included. 440 * 441 * If with_mvars is non-zero the make environment is passed as VAR=DATA 442 * elements on the command line. 443 */ 444 FILE * 445 dexec_open(const char *logid, const char **cav, int cac, 446 pid_t *pidp, buildenv_t *xenv, int with_env, int with_mvars) 447 { 448 buildenv_t *benv; 449 const char **cenv; 450 char *allocary[MAXCAC*2]; 451 int env_basei; 452 int envi; 453 int alloci; 454 int nullfd; 455 int fds[2]; /* stdout */ 456 pid_t pid; 457 FILE *fp; 458 struct logerrinfo *einfo; 459 static int warned; 460 461 /* 462 * Error logging thread setup 463 */ 464 if (ETid == 0) { 465 pthread_mutex_lock(&DLogFdMutex); 466 if (ETid == 0) { 467 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, EFds) < 0) 468 dfatal_errno("socketpair"); 469 #ifdef SO_PASSCRED 470 int optval = 1; 471 if (setsockopt(EFds[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) { 472 if (warned == 0) { 473 warned = 1; 474 fprintf(stderr, "SO_PASSCRED not supported\n"); 475 } 476 } 477 #endif 478 479 pthread_cond_init(&ECond, NULL); 480 pthread_create(&ETid, NULL, dexec_logerr_thread, NULL); 481 } 482 pthread_mutex_unlock(&DLogFdMutex); 483 } 484 485 env_basei = 0; 486 #if 0 487 /* 488 * For now we are ignoring the passed-in environment, so don't 489 * copy the existing environment into the exec environment. 490 */ 491 while (environ[env_basei]) 492 ++env_basei; 493 #endif 494 cenv = calloc(env_basei + MAXCAC, sizeof(char *)); 495 for (envi = 0; envi < env_basei; ++envi) 496 cenv[envi] = environ[envi]; 497 498 alloci = 0; 499 for (benv = BuildEnv; benv; benv = benv->next) { 500 if (with_mvars && 501 (benv->type & BENV_CMDMASK) == BENV_MAKECONF) { 502 asprintf(&allocary[alloci], "%s=%s", 503 benv->label, benv->data); 504 cav[cac++] = allocary[alloci]; 505 ++alloci; 506 } 507 if (with_env && 508 (benv->type & BENV_PKGLIST) && 509 (benv->type & BENV_CMDMASK) == BENV_ENVIRONMENT) { 510 asprintf(&allocary[alloci], "%s=%s", 511 benv->label, benv->data); 512 cenv[envi++] = allocary[alloci]; 513 ++alloci; 514 } 515 ddassert(cac < MAXCAC && envi - env_basei < MAXCAC); 516 } 517 518 /* 519 * Extra environment specific to this particular dexec 520 */ 521 while (xenv && xenv->label) { 522 asprintf(&allocary[alloci], "%s=%s", 523 xenv->label, xenv->data); 524 cenv[envi++] = allocary[alloci]; 525 ++alloci; 526 ++xenv; 527 } 528 529 cav[cac] = NULL; 530 cenv[envi] = NULL; 531 532 if (pipe2(fds, O_CLOEXEC) < 0) 533 dfatal_errno("pipe"); 534 nullfd = open("/dev/null", O_RDWR | O_CLOEXEC); 535 if (nullfd < 0) 536 dfatal_errno("open(\"/dev/null\")"); 537 538 /* 539 * We have to be very careful using vfork(), do only the bare 540 * minimum necessary in the child to set it up and exec it. 541 */ 542 pid = vfork(); 543 if (pid == 0) { 544 #if 0 545 int i; 546 printf("%s", cav[0]); 547 for (i = 0; cav[i]; ++i) 548 printf(" %s", cav[i]); 549 printf("\n"); 550 printf("ENV: "); 551 for (i = 0; cenv[i]; ++i) 552 printf(" %s", cenv[i]); 553 #endif 554 555 if (fds[1] != 1) { 556 dup2(fds[1], 1); 557 close(fds[1]); 558 } 559 if (EFds[1] != 2) { 560 dup2(EFds[1], 2); 561 close(EFds[1]); 562 } 563 close(fds[0]); /* safety */ 564 close(EFds[0]); /* safety */ 565 dup2(nullfd, 0); /* no questions! */ 566 closefrom(3); /* be nice */ 567 568 /* 569 * Self-nice to be nice (ignore any error) 570 */ 571 if (NiceOpt) 572 setpriority(PRIO_PROCESS, 0, NiceOpt); 573 574 /* 575 * Throw in some capability restrictions 576 */ 577 set_capability_restrictions(); 578 579 execve(cav[0], (void *)cav, (void *)cenv); 580 write(2, "EXEC FAILURE\n", 13); 581 _exit(1); 582 } 583 close(nullfd); 584 close(fds[1]); 585 if (pid < 0) { 586 close(fds[0]); 587 dfatal_errno("vfork failed"); 588 } 589 fp = fdopen(fds[0], "r"); 590 *pidp = pid; 591 592 /* 593 * einfo setup 594 */ 595 einfo = calloc(1, sizeof(*einfo)); 596 if (logid) 597 einfo->logid = strdup(logid); 598 599 pthread_mutex_lock(&DLogFdMutex); 600 einfo->pid = pid; 601 einfo->next = *einfohash(pid); 602 *einfohash(pid) = einfo; 603 pthread_cond_signal(&ECond); 604 pthread_mutex_unlock(&DLogFdMutex); 605 606 while (--alloci >= 0) 607 free(allocary[alloci]); 608 free(cenv); 609 610 return fp; 611 } 612 613 int 614 dexec_close(FILE *fp, pid_t pid) 615 { 616 struct logerrinfo **einfop; 617 struct logerrinfo *einfo; 618 pid_t rpid; 619 int status; 620 621 fclose(fp); 622 while ((rpid = waitpid(pid, &status, 0)) != pid) { 623 if (rpid < 0) { 624 if (errno == EINTR) 625 continue; 626 return 1; 627 } 628 } 629 630 pthread_mutex_lock(&DLogFdMutex); 631 einfop = einfohash(pid); 632 while ((einfo = *einfop) != NULL) { 633 if (einfo->pid == pid) { 634 einfo->exited = 1; 635 break; 636 } 637 einfop = &einfo->next; 638 } 639 pthread_mutex_unlock(&DLogFdMutex); 640 641 return (WEXITSTATUS(status)); 642 } 643 644 static void * 645 dexec_logerr_thread(void *dummy __unused) 646 { 647 char buf[4096]; 648 union { 649 char cbuf[CMSG_SPACE(sizeof(struct ucred))]; 650 struct cmsghdr cbuf_align; 651 } cmsg_buf; 652 struct cmsghdr *cmsg; 653 struct logerrinfo **einfop; 654 struct logerrinfo *einfo; 655 struct msghdr msg; 656 struct iovec iov; 657 ssize_t len; 658 int mflags = MSG_DONTWAIT; 659 int fd; 660 661 pthread_detach(pthread_self()); 662 663 msg.msg_name = NULL; 664 msg.msg_namelen = 0; 665 msg.msg_iov = &iov; 666 667 msg.msg_control = cmsg_buf.cbuf; 668 msg.msg_controllen = sizeof(cmsg_buf.cbuf); 669 670 fd = EFds[0]; 671 for (;;) { 672 int i; 673 674 msg.msg_iovlen = 1; 675 iov.iov_base = buf; 676 iov.iov_len = sizeof(buf) - 1; 677 678 /* 679 * Wait for message, if none are pending then clean-up 680 * exited einfos (this ensures that we have flushed all 681 * error output before freeing the structure). 682 * 683 * Don't obtain the mutex until we really need it. The 684 * parent thread can only 'add' einfo entries to the hash 685 * table so we are basically scan-safe. 686 */ 687 len = recvmsg(fd, &msg, mflags); 688 if (len < 0) { 689 if (errno != EAGAIN) { /* something messed up */ 690 fprintf(stderr, "ERRNO %d\n", errno); 691 break; 692 } 693 694 for (i = 0; i < EINFO_HSIZE; ++i) { 695 einfo = EInfo[i]; 696 while (einfo) { 697 if (einfo->exited) 698 break; 699 einfo = einfo->next; 700 } 701 if (einfo == NULL) 702 continue; 703 pthread_mutex_lock(&DLogFdMutex); 704 einfop = &EInfo[i]; 705 while ((einfo = *einfop) != NULL) { 706 if (einfo->exited) { 707 *einfop = einfo->next; 708 if (einfo->logid) 709 free(einfo->logid); 710 free(einfo); 711 } else { 712 einfop = &einfo->next; 713 } 714 } 715 pthread_mutex_unlock(&DLogFdMutex); 716 } 717 mflags = 0; 718 continue; 719 } 720 721 /* 722 * Process SCM_CREDS, if present. Throw away SCM_RIGHTS 723 * if some sub-process stupidly sent it. 724 */ 725 einfo = NULL; 726 mflags = MSG_DONTWAIT; 727 728 if (len && buf[len-1] == '\n') 729 --len; 730 buf[len] = 0; 731 732 for (cmsg = CMSG_FIRSTHDR(&msg); 733 cmsg; 734 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 735 struct cmsgcred *cred; 736 int *fds; 737 int n; 738 739 if (cmsg->cmsg_level != SOL_SOCKET) 740 continue; 741 742 switch(cmsg->cmsg_type) { 743 case SCM_CREDS: 744 745 cred = (void *)CMSG_DATA(cmsg); 746 747 einfo = *einfohash(cred->cmcred_pid); 748 while (einfo && einfo->pid != cred->cmcred_pid) 749 einfo = einfo->next; 750 break; 751 case SCM_RIGHTS: 752 fds = (void *)CMSG_DATA(cmsg); 753 n = (cmsg->cmsg_len - sizeof(cmsg)) / 754 sizeof(int); 755 for (i = 0; i < n; ++i) 756 close(fds[i]); 757 break; 758 } 759 } 760 761 if (einfo && einfo->logid) { 762 dlog(DLOG_ALL | DLOG_STDOUT, 763 "%s: %s\n", 764 einfo->logid, buf); 765 } else { 766 dlog(DLOG_ALL | DLOG_STDOUT, "%s", buf); 767 } 768 } 769 return NULL; 770 } 771 772 const char * 773 getphasestr(worker_phase_t phaseid) 774 { 775 const char *phase; 776 777 switch(phaseid) { 778 case PHASE_PENDING: 779 phase = "pending"; 780 break; 781 case PHASE_INSTALL_PKGS: 782 phase = "install-pkgs"; 783 break; 784 case PHASE_CHECK_SANITY: 785 phase = "check-sanity"; 786 break; 787 case PHASE_PKG_DEPENDS: 788 phase = "pkg-depends"; 789 break; 790 case PHASE_FETCH_DEPENDS: 791 phase = "fetch-depends"; 792 break; 793 case PHASE_FETCH: 794 phase = "fetch"; 795 break; 796 case PHASE_CHECKSUM: 797 phase = "checksum"; 798 break; 799 case PHASE_EXTRACT_DEPENDS: 800 phase = "extract-depends"; 801 break; 802 case PHASE_EXTRACT: 803 phase = "extract"; 804 break; 805 case PHASE_PATCH_DEPENDS: 806 phase = "patch-depends"; 807 break; 808 case PHASE_PATCH: 809 phase = "patch"; 810 break; 811 case PHASE_BUILD_DEPENDS: 812 phase = "build-depends"; 813 break; 814 case PHASE_LIB_DEPENDS: 815 phase = "lib-depends"; 816 break; 817 case PHASE_CONFIGURE: 818 phase = "configure"; 819 break; 820 case PHASE_BUILD: 821 phase = "build"; 822 break; 823 case PHASE_RUN_DEPENDS: 824 phase = "run-depends"; 825 break; 826 case PHASE_STAGE: 827 phase = "stage"; 828 break; 829 case PHASE_TEST: 830 phase = "test"; 831 break; 832 case PHASE_CHECK_PLIST: 833 phase = "check-plist"; 834 break; 835 case PHASE_PACKAGE: 836 phase = "package"; 837 break; 838 case PHASE_INSTALL: 839 phase = "install"; 840 break; 841 case PHASE_DEINSTALL: 842 phase = "deinstall"; 843 break; 844 case PHASE_DUMP_ENV: 845 phase = "dump-env"; 846 break; 847 case PHASE_DUMP_VAR: 848 phase = "dump-var"; 849 break; 850 case PHASE_SHOW_CONFIG: 851 phase = "show-config"; 852 break; 853 case PHASE_DUMP_MAKECONF: 854 phase = "make-conf"; 855 break; 856 default: 857 phase = "Run-Unknown"; 858 break; 859 } 860 return phase; 861 } 862 863 int 864 readlogline(monitorlog_t *log, char **bufp) 865 { 866 int r; 867 int n; 868 869 /* 870 * Reset buffer as an optimization to avoid unnecessary 871 * shifts. 872 */ 873 *bufp = NULL; 874 if (log->buf_beg == log->buf_end) { 875 log->buf_beg = 0; 876 log->buf_end = 0; 877 log->buf_scan = 0; 878 } 879 880 /* 881 * Look for newline, handle discard mode 882 */ 883 again: 884 for (n = log->buf_scan; n < log->buf_end; ++n) { 885 if (log->buf[n] == '\n') { 886 *bufp = log->buf + log->buf_beg; 887 r = n - log->buf_beg; 888 log->buf_beg = n + 1; 889 log->buf_scan = n + 1; 890 891 if (log->buf_discard_mode == 0) 892 return r; 893 log->buf_discard_mode = 0; 894 goto again; 895 } 896 } 897 898 /* 899 * Handle overflow 900 */ 901 if (n == sizeof(log->buf)) { 902 if (log->buf_beg) { 903 /* 904 * Shift the buffer to make room and read more data. 905 */ 906 bcopy(log->buf + log->buf_beg, 907 log->buf, 908 n - log->buf_beg); 909 log->buf_end -= log->buf_beg; 910 log->buf_scan -= log->buf_beg; 911 n -= log->buf_beg; 912 log->buf_beg = 0; 913 } else if (log->buf_discard_mode) { 914 /* 915 * Overflow. If in discard mode just throw it all 916 * away. Stay in discard mode. 917 */ 918 log->buf_beg = 0; 919 log->buf_end = 0; 920 log->buf_scan = 0; 921 } else { 922 /* 923 * Overflow. If not in discard mode return a truncated 924 * line and enter discard mode. 925 * 926 * The caller will temporarily set ptr[r] = 0 so make 927 * sure that does not overflow our buffer as we are not 928 * at a newline. 929 * 930 * (log->buf_beg is 0); 931 */ 932 *bufp = log->buf + log->buf_beg; 933 r = n - 1; 934 log->buf_beg = n; 935 log->buf_scan = n; 936 log->buf_discard_mode = 1; 937 938 return r; 939 } 940 } 941 942 /* 943 * Read more data. If there is no data pending then return -1, 944 * otherwise loop up to see if more complete line(s) are available. 945 */ 946 r = pread(log->fd, 947 log->buf + log->buf_end, 948 sizeof(log->buf) - log->buf_end, 949 log->offset); 950 if (r <= 0) 951 return -1; 952 log->offset += r; 953 log->buf_end += r; 954 goto again; 955 } 956 957 uint32_t 958 crcDirTree(const char *path) 959 { 960 FTS *fts; 961 FTSENT *fen; 962 struct stat *st; 963 char *pav[2]; 964 uint32_t crc; 965 uint32_t val; 966 967 crc = 0; 968 pav[0] = strdup(path); 969 pav[1] = NULL; 970 971 fts = fts_open(pav, FTS_PHYSICAL | FTS_NOCHDIR, NULL); 972 if (fts == NULL) 973 goto failed; 974 while ((fen = fts_read(fts)) != NULL) { 975 if (fen->fts_info != FTS_F && fen->fts_info != FTS_SL) 976 continue; 977 /* 978 * Ignore hidden dot files or ones ending with .core from the 979 * calculated CRC sum to prevent unnecessary rebuilds. 980 */ 981 if (fen->fts_name[0] == '.') 982 continue; 983 if (fen->fts_namelen >= 5 && 984 !strcmp(fen->fts_name + fen->fts_namelen - 5, ".core")) { 985 continue; 986 } 987 988 st = fen->fts_statp; 989 990 val = iscsi_crc32(&st->st_mtime, sizeof(st->st_mtime)); 991 val = iscsi_crc32_ext(&st->st_size, sizeof(st->st_size), val); 992 val = iscsi_crc32_ext(fen->fts_path, fen->fts_pathlen, val); 993 crc ^= val; 994 } 995 fts_close(fts); 996 failed: 997 free(pav[0]); 998 999 return crc; 1000 } 1001 1002 void 1003 set_capability_restrictions(void) 1004 { 1005 if (CapabilityRestrictions) { 1006 #if !defined(SYSCAP_UNAVAILABLE) 1007 syscap_set(SYSCAP_RESTRICTEDROOT, __SYSCAP_ALL, 1008 NULL, 0); 1009 syscap_set(SYSCAP_SENSITIVEROOT, __SYSCAP_ALL, 1010 NULL, 0); 1011 syscap_set(SYSCAP_NONET_SENSITIVE, __SYSCAP_ALL, 1012 NULL, 0); 1013 syscap_set(SYSCAP_NOVFS_SENSITIVE, __SYSCAP_ALL, 1014 NULL, 0); 1015 syscap_set(SYSCAP_NOMOUNT, __SYSCAP_ALL, 1016 NULL, 0); 1017 syscap_set(SYSCAP_NOJAIL, __SYSCAP_ALL, 1018 NULL, 0); 1019 syscap_set(SYSCAP_NONET_RESPORT, __SYSCAP_ALL, 1020 NULL, 0); 1021 syscap_set(SYSCAP_NONET_RAW, __SYSCAP_ALL, 1022 NULL, 0); 1023 #endif 1024 } 1025 } 1026