1 /* $NetBSD: util.c,v 1.78 2021/12/15 12:58:01 rillig Exp $ */ 2 3 /* 4 * Missing stuff from OS's 5 * 6 * $Id: util.c,v 1.53 2024/07/12 18:37:25 sjg Exp $ 7 */ 8 9 #include <sys/param.h> 10 #include <errno.h> 11 #include <time.h> 12 #include <signal.h> 13 14 #include "make.h" 15 16 MAKE_RCSID("$NetBSD: util.c,v 1.78 2021/12/15 12:58:01 rillig Exp $"); 17 18 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRERROR) 19 extern int errno, sys_nerr; 20 extern char *sys_errlist[]; 21 22 char * 23 strerror(int e) 24 { 25 static char buf[100]; 26 if (e < 0 || e >= sys_nerr) { 27 snprintf(buf, sizeof buf, "Unknown error %d", e); 28 return buf; 29 } else 30 return sys_errlist[e]; 31 } 32 #endif 33 34 #if !defined(HAVE_GETENV) || !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) 35 extern char **environ; 36 37 static char * 38 findenv(const char *name, int *offset) 39 { 40 size_t i, len; 41 char *p, *q; 42 43 len = strlen(name); 44 for (i = 0; (q = environ[i]); i++) { 45 p = strchr(q, '='); 46 if (p == NULL || p - q != len) 47 continue; 48 if (strncmp(name, q, len) == 0) { 49 *offset = i; 50 return q + len + 1; 51 } 52 } 53 *offset = i; 54 return NULL; 55 } 56 57 char * 58 getenv(const char *name) 59 { 60 int offset; 61 62 return findenv(name, &offset); 63 } 64 65 int 66 unsetenv(const char *name) 67 { 68 char **p; 69 int offset; 70 71 if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) { 72 errno = EINVAL; 73 return -1; 74 } 75 76 while (findenv(name, &offset)) { /* if set multiple times */ 77 for (p = &environ[offset];; p++) 78 if (!(*p = *(p + 1))) 79 break; 80 } 81 return 0; 82 } 83 84 int 85 setenv(const char *name, const char *value, int rewrite) 86 { 87 char *c, **newenv; 88 const char *cc; 89 size_t l_value, size; 90 int offset; 91 92 if (name == NULL || value == NULL) { 93 errno = EINVAL; 94 return -1; 95 } 96 97 if (*value == '=') /* no `=' in value */ 98 value++; 99 l_value = strlen(value); 100 101 /* find if already exists */ 102 if ((c = findenv(name, &offset))) { 103 if (!rewrite) 104 return 0; 105 if (strlen(c) >= l_value) /* old larger; copy over */ 106 goto copy; 107 } else { /* create new slot */ 108 size = sizeof(char *) * (offset + 2); 109 if (savedEnv == environ) { /* just increase size */ 110 if ((newenv = realloc(savedEnv, size)) == NULL) 111 return -1; 112 savedEnv = newenv; 113 } else { /* get new space */ 114 /* 115 * We don't free here because we don't know if 116 * the first allocation is valid on all OS's 117 */ 118 if ((savedEnv = malloc(size)) == NULL) 119 return -1; 120 (void)memcpy(savedEnv, environ, size - sizeof(char *)); 121 } 122 environ = savedEnv; 123 environ[offset + 1] = NULL; 124 } 125 for (cc = name; *cc && *cc != '='; cc++) /* no `=' in name */ 126 continue; 127 size = cc - name; 128 /* name + `=' + value */ 129 if ((environ[offset] = malloc(size + l_value + 2)) == NULL) 130 return -1; 131 c = environ[offset]; 132 (void)memcpy(c, name, size); 133 c += size; 134 *c++ = '='; 135 copy: 136 (void)memcpy(c, value, l_value + 1); 137 return 0; 138 } 139 140 #ifdef TEST 141 int 142 main(int argc, char *argv[]) 143 { 144 setenv(argv[1], argv[2], 0); 145 printf("%s\n", getenv(argv[1])); 146 unsetenv(argv[1]); 147 printf("%s\n", getenv(argv[1])); 148 return 0; 149 } 150 #endif 151 152 #endif 153 154 155 #if defined(__hpux__) || defined(__hpux) 156 /* 157 * strrcpy(): 158 * Like strcpy, going backwards and returning the new pointer 159 */ 160 static char * 161 strrcpy(char *ptr, char *str) 162 { 163 int len = strlen(str); 164 165 while (len != 0) 166 *--ptr = str[--len]; 167 168 return ptr; 169 } 170 171 char *sys_siglist[] = { 172 "Signal 0", 173 "Hangup", /* SIGHUP */ 174 "Interrupt", /* SIGINT */ 175 "Quit", /* SIGQUIT */ 176 "Illegal instruction", /* SIGILL */ 177 "Trace/BPT trap", /* SIGTRAP */ 178 "IOT trap", /* SIGIOT */ 179 "EMT trap", /* SIGEMT */ 180 "Floating point exception", /* SIGFPE */ 181 "Killed", /* SIGKILL */ 182 "Bus error", /* SIGBUS */ 183 "Segmentation fault", /* SIGSEGV */ 184 "Bad system call", /* SIGSYS */ 185 "Broken pipe", /* SIGPIPE */ 186 "Alarm clock", /* SIGALRM */ 187 "Terminated", /* SIGTERM */ 188 "User defined signal 1", /* SIGUSR1 */ 189 "User defined signal 2", /* SIGUSR2 */ 190 "Child exited", /* SIGCLD */ 191 "Power-fail restart", /* SIGPWR */ 192 "Virtual timer expired", /* SIGVTALRM */ 193 "Profiling timer expired", /* SIGPROF */ 194 "I/O possible", /* SIGIO */ 195 "Window size changes", /* SIGWINDOW */ 196 "Stopped (signal)", /* SIGSTOP */ 197 "Stopped", /* SIGTSTP */ 198 "Continued", /* SIGCONT */ 199 "Stopped (tty input)", /* SIGTTIN */ 200 "Stopped (tty output)", /* SIGTTOU */ 201 "Urgent I/O condition", /* SIGURG */ 202 "Remote lock lost (NFS)", /* SIGLOST */ 203 "Signal 31", /* reserved */ 204 "DIL signal" /* SIGDIL */ 205 }; 206 #endif /* __hpux__ || __hpux */ 207 208 #if defined(__hpux__) || defined(__hpux) 209 #include <sys/types.h> 210 #include <sys/syscall.h> 211 #include <sys/signal.h> 212 #include <sys/stat.h> 213 #include <dirent.h> 214 #include <sys/time.h> 215 #include <unistd.h> 216 217 int 218 killpg(int pid, int sig) 219 { 220 return kill(-pid, sig); 221 } 222 223 #if !defined(BSD) && !defined(d_fileno) 224 # define d_fileno d_ino 225 #endif 226 227 #ifndef DEV_DEV_COMPARE 228 # define DEV_DEV_COMPARE(a, b) ((a) == (b)) 229 #endif 230 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/'))) 231 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1]))) 232 233 char * 234 getwd(char *pathname) 235 { 236 DIR *dp; 237 struct dirent *d; 238 extern int errno; 239 240 struct stat st_root, st_cur, st_next, st_dotdot; 241 char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2]; 242 char *pathptr, *nextpathptr, *cur_name_add; 243 244 /* find the inode of root */ 245 if (stat("/", &st_root) == -1) { 246 (void)sprintf(pathname, 247 "getwd: Cannot stat \"/\" (%s)", strerror(errno)); 248 return NULL; 249 } 250 pathbuf[MAXPATHLEN - 1] = '\0'; 251 pathptr = &pathbuf[MAXPATHLEN - 1]; 252 nextpathbuf[MAXPATHLEN - 1] = '\0'; 253 cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1]; 254 255 /* find the inode of the current directory */ 256 if (lstat(".", &st_cur) == -1) { 257 (void)sprintf(pathname, 258 "getwd: Cannot stat \".\" (%s)", strerror(errno)); 259 return NULL; 260 } 261 nextpathptr = strrcpy(nextpathptr, "../"); 262 263 /* Descend to root */ 264 for (;;) { 265 266 /* look if we found root yet */ 267 if (st_cur.st_ino == st_root.st_ino && 268 DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) { 269 (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr); 270 return pathname; 271 } 272 273 /* open the parent directory */ 274 if (stat(nextpathptr, &st_dotdot) == -1) { 275 (void)sprintf(pathname, 276 "getwd: Cannot stat directory \"%s\" (%s)", 277 nextpathptr, strerror(errno)); 278 return NULL; 279 } 280 if ((dp = opendir(nextpathptr)) == NULL) { 281 (void)sprintf(pathname, 282 "getwd: Cannot open directory \"%s\" (%s)", 283 nextpathptr, strerror(errno)); 284 return NULL; 285 } 286 287 /* look in the parent for the entry with the same inode */ 288 if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) { 289 /* Parent has same device. No need to stat every member */ 290 for (d = readdir(dp); d != NULL; d = readdir(dp)) 291 if (d->d_fileno == st_cur.st_ino) 292 break; 293 } else { 294 /* 295 * Parent has a different device. This is a mount point so we 296 * need to stat every member 297 */ 298 for (d = readdir(dp); d != NULL; d = readdir(dp)) { 299 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name)) 300 continue; 301 (void)strcpy(cur_name_add, d->d_name); 302 if (lstat(nextpathptr, &st_next) == -1) { 303 (void)sprintf(pathname, 304 "getwd: Cannot stat \"%s\" (%s)", 305 d->d_name, strerror(errno)); 306 (void)closedir(dp); 307 return NULL; 308 } 309 /* check if we found it yet */ 310 if (st_next.st_ino == st_cur.st_ino && 311 DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) 312 break; 313 } 314 } 315 if (d == NULL) { 316 (void)sprintf(pathname, 317 "getwd: Cannot find \".\" in \"..\""); 318 (void)closedir(dp); 319 return NULL; 320 } 321 st_cur = st_dotdot; 322 pathptr = strrcpy(pathptr, d->d_name); 323 pathptr = strrcpy(pathptr, "/"); 324 nextpathptr = strrcpy(nextpathptr, "../"); 325 (void)closedir(dp); 326 *cur_name_add = '\0'; 327 } 328 } /* end getwd */ 329 330 #endif /* __hpux */ 331 332 #if !defined(HAVE_GETCWD) 333 char * 334 getcwd(path, sz) 335 char *path; 336 int sz; 337 { 338 return getwd(path); 339 } 340 #endif 341 342 #if !defined(HAVE_SIGACTION) 343 #include "sigact.h" 344 #endif 345 346 #ifndef SA_RESTART 347 # define SA_RESTART 0 348 #endif 349 350 /* force posix signals */ 351 SignalProc 352 bmake_signal(int s, SignalProc a) 353 { 354 struct sigaction sa, osa; 355 356 sa.sa_handler = a; 357 sigemptyset(&sa.sa_mask); 358 sa.sa_flags = SA_RESTART; 359 360 if (sigaction(s, &sa, &osa) == -1) 361 return SIG_ERR; 362 else 363 return osa.sa_handler; 364 } 365 366 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF) 367 #include <stdarg.h> 368 #endif 369 370 #if !defined(HAVE_VSNPRINTF) 371 #if !defined(__osf__) 372 #ifdef _IOSTRG 373 #define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */ 374 #else 375 #if 0 376 #define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */ 377 #endif 378 #endif /* _IOSTRG */ 379 #endif /* __osf__ */ 380 381 int 382 vsnprintf(char *s, size_t n, const char *fmt, va_list args) 383 { 384 #ifdef STRFLAG 385 FILE fakebuf; 386 387 fakebuf._flag = STRFLAG; 388 /* 389 * Some os's are char * _ptr, others are unsigned char *_ptr... 390 * We cast to void * to make everyone happy. 391 */ 392 fakebuf._ptr = (void *)s; 393 fakebuf._cnt = n - 1; 394 fakebuf._file = -1; 395 _doprnt(fmt, args, &fakebuf); 396 fakebuf._cnt++; 397 putc('\0', &fakebuf); 398 if (fakebuf._cnt < 0) 399 fakebuf._cnt = 0; 400 return n - fakebuf._cnt - 1; 401 #else 402 #ifndef _PATH_DEVNULL 403 # define _PATH_DEVNULL "/dev/null" 404 #endif 405 /* 406 * Rats... we don't want to clobber anything... 407 * do a printf to /dev/null to see how much space we need. 408 */ 409 static FILE *nullfp; 410 int need = 0; /* XXX what's a useful error return? */ 411 412 if (!nullfp) 413 nullfp = fopen(_PATH_DEVNULL, "w"); 414 if (nullfp) { 415 need = vfprintf(nullfp, fmt, args); 416 if (need < n) 417 (void)vsprintf(s, fmt, args); 418 } 419 return need; 420 #endif 421 } 422 #endif 423 424 #if !defined(HAVE_SNPRINTF) 425 int 426 snprintf(char *s, size_t n, const char *fmt, ...) 427 { 428 va_list ap; 429 int rv; 430 431 va_start(ap, fmt); 432 rv = vsnprintf(s, n, fmt, ap); 433 va_end(ap); 434 return rv; 435 } 436 #endif 437 438 #if !defined(HAVE_STRFTIME) || defined(FORCE_BMAKE_STRFTIME) 439 /* we only implement enough to pass our unit-tests */ 440 size_t 441 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) 442 { 443 static const char *months[] = { 444 "January", "February", "March", 445 "April", "May", "June", 446 "July", "August", "September", 447 "October", "November", "December" 448 }; 449 static const char *days[] = { 450 "Sunday", "Monday", "Tuesday", "Wednesday", 451 "Thursday", "Friday", "Saturday" 452 }; 453 int i; 454 size_t s; 455 char *b = buf; 456 char *cp; 457 458 if (fmt == NULL || *fmt == '\0') 459 fmt = "%c"; 460 while (*fmt) { 461 if (len == 0) 462 return buf - b; 463 if (*fmt != '%') { 464 *buf++ = *fmt++; 465 len--; 466 continue; 467 } 468 fmt++; 469 switch (*fmt++) { 470 case '%': 471 *buf++ = '%'; 472 len--; 473 if (len == 0) return buf - b; 474 /*FALLTHROUGH*/ 475 case '\0': 476 *buf = '%'; 477 s = 1; 478 break; 479 case 'A': 480 s = snprintf(buf, len, "%s", days[tm->tm_wday]); 481 break; 482 case 'a': 483 s = snprintf(buf, len, "%.3s", days[tm->tm_wday]); 484 break; 485 case 'B': 486 if (tm->tm_mon >= 12) 487 return buf - b; 488 s = snprintf(buf, len, "%s", months[tm->tm_mon]); 489 break; 490 case 'b': 491 if (tm->tm_mon >= 12) 492 return buf - b; 493 s = snprintf(buf, len, "%.3s", months[tm->tm_mon]); 494 break; 495 case 'c': 496 s = strftime(buf, len, "%a %b %e %H:%M:%S %Y", tm); 497 break; 498 case 'd': 499 s = snprintf(buf, len, "%02d", tm->tm_mday); 500 break; 501 case 'e': 502 s = snprintf(buf, len, "%2d", tm->tm_mday); 503 break; 504 case 'F': 505 s = strftime(buf, len, "%y-%m-%d", tm); 506 break; 507 case 'H': 508 s = snprintf(buf, len, "%02d", tm->tm_hour); 509 break; 510 case 'I': 511 if ((i = tm->tm_hour) == 0) 512 i = 24; 513 s = snprintf(buf, len, "%02d", (i > 12) ? (i - 12) : i); 514 break; 515 case 'j': 516 s = snprintf(buf, len, "%03d", tm->tm_yday + 1); 517 break; 518 case 'k': 519 s = snprintf(buf, len, "%d", tm->tm_hour); 520 break; 521 case 'M': 522 s = snprintf(buf, len, "%02d", tm->tm_min); 523 break; 524 case 'm': 525 s = snprintf(buf, len, "%02d", 1 + tm->tm_mon); 526 break; 527 case 'S': 528 s = snprintf(buf, len, "%02d", tm->tm_sec); 529 break; 530 case 's': 531 s = snprintf(buf, len, "%ld", (long)time(NULL)); 532 break; 533 case 'T': 534 s = strftime(buf, len, "%H:%M:%S", tm); 535 break; 536 case 'w': 537 s = snprintf(buf, len, "%02d", tm->tm_wday); 538 break; 539 case 'Y': 540 s = snprintf(buf, len, "%d", 1900 + tm->tm_year); 541 break; 542 case 'y': 543 s = snprintf(buf, len, "%02d", tm->tm_year % 100); 544 break; 545 case 'Z': 546 if ((cp = getenv("TZ")) != NULL) { 547 char tz[20]; 548 549 i = snprintf(tz, sizeof(tz), "%s", cp); 550 if (i > 5) { 551 cp = &tz[i - 3]; 552 tz[3] = '\0'; 553 } else 554 cp = tz; 555 s = snprintf(buf, len, "%s", 556 tm->tm_isdst ? cp : tz); 557 } else 558 s = 0; 559 break; 560 default: 561 s = snprintf(buf, len, "Unsupported format %c", 562 fmt[-1]); 563 break; 564 } 565 buf += s; 566 len -= s; 567 } 568 return buf - b; 569 } 570 #endif 571 572 #if !defined(HAVE_KILLPG) 573 #if !defined(__hpux__) && !defined(__hpux) 574 int 575 killpg(int pid, int sig) 576 { 577 return kill(-pid, sig); 578 } 579 #endif 580 #endif 581 582 #if !defined(HAVE_WARNX) 583 static void 584 vwarnx(const char *fmt, va_list args) 585 { 586 fprintf(stderr, "%s: ", progname); 587 if ((fmt)) { 588 vfprintf(stderr, fmt, args); 589 fprintf(stderr, ": "); 590 } 591 } 592 #endif 593 594 #if !defined(HAVE_WARN) 595 static void 596 vwarn(const char *fmt, va_list args) 597 { 598 vwarnx(fmt, args); 599 fprintf(stderr, "%s\n", strerror(errno)); 600 } 601 #endif 602 603 #if !defined(HAVE_ERR) 604 static void 605 verr(int eval, const char *fmt, va_list args) 606 { 607 vwarn(fmt, args); 608 exit(eval); 609 } 610 #endif 611 612 #if !defined(HAVE_ERRX) 613 static void 614 verrx(int eval, const char *fmt, va_list args) 615 { 616 vwarnx(fmt, args); 617 exit(eval); 618 } 619 #endif 620 621 #if !defined(HAVE_ERR) 622 void 623 err(int eval, const char *fmt, ...) 624 { 625 va_list ap; 626 627 va_start(ap, fmt); 628 verr(eval, fmt, ap); 629 va_end(ap); 630 } 631 #endif 632 633 #if !defined(HAVE_ERRX) 634 void 635 errx(int eval, const char *fmt, ...) 636 { 637 va_list ap; 638 639 va_start(ap, fmt); 640 verrx(eval, fmt, ap); 641 va_end(ap); 642 } 643 #endif 644 645 #if !defined(HAVE_WARN) 646 void 647 warn(const char *fmt, ...) 648 { 649 va_list ap; 650 651 va_start(ap, fmt); 652 vwarn(fmt, ap); 653 va_end(ap); 654 } 655 #endif 656 657 #if !defined(HAVE_WARNX) 658 void 659 warnx(const char *fmt, ...) 660 { 661 va_list ap; 662 663 va_start(ap, fmt); 664 vwarnx(fmt, ap); 665 va_end(ap); 666 } 667 #endif 668 669 #ifdef HAVE_INTTYPES_H 670 #include <inttypes.h> 671 #elif defined(HAVE_STDINT_H) 672 #include <stdint.h> 673 #endif 674 #ifdef HAVE_LIMITS_H 675 #include <limits.h> 676 #endif 677 678 #ifndef NUM_TYPE 679 # ifdef HAVE_LONG_LONG_INT 680 # define NUM_TYPE long long 681 # elif defined(_INT64_T_DECLARED) || defined(int64_t) 682 # define NUM_TYPE int64_t 683 # endif 684 #endif 685 686 #ifdef NUM_TYPE 687 #if !defined(HAVE_STRTOLL) 688 #define BCS_ONLY 689 #define _FUNCNAME strtoll 690 #define __INT NUM_TYPE 691 #undef __INT_MIN 692 #undef __INT_MAX 693 #ifdef LLONG_MAX 694 # define __INT_MIN LLONG_MIN 695 # define __INT_MAX LLONG_MAX 696 #elif defined(INT64_MAX) 697 # define __INT_MIN INT64_MIN 698 # define __INT_MAX INT64_MAX 699 #endif 700 #ifndef _DIAGASSERT 701 # define _DIAGASSERT(e) 702 #endif 703 #ifndef __UNCONST 704 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 705 #endif 706 #include "_strtol.h" 707 #endif 708 709 #endif 710 711 #if !defined(HAVE_STRTOL) 712 #define BCS_ONLY 713 #define _FUNCNAME strtol 714 #define __INT long 715 #undef __INT_MIN 716 #undef __INT_MAX 717 #define __INT_MIN LONG_MIN 718 #define __INT_MAX LONG_MAX 719 #ifndef _DIAGASSERT 720 # define _DIAGASSERT(e) 721 #endif 722 #ifndef __UNCONST 723 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 724 #endif 725 #include "_strtol.h" 726 #endif 727 728 #if !defined(HAVE_STRTOUL) 729 #define BCS_ONLY 730 #define _FUNCNAME strtoul 731 #define __INT unsigned long 732 #undef __INT_MIN 733 #undef __INT_MAX 734 #define __INT_MIN 0 735 #define __INT_MAX ULONG_MAX 736 #ifndef _DIAGASSERT 737 # define _DIAGASSERT(e) 738 #endif 739 #ifndef __UNCONST 740 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 741 #endif 742 #include "_strtol.h" 743 #endif 744