1 /* $NetBSD: util.c,v 1.76 2021/02/03 08:00:36 rillig Exp $ */ 2 3 /* 4 * Missing stuff from OS's 5 * 6 * $Id: util.c,v 1.49 2021/10/14 19:26:52 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.76 2021/02/03 08:00:36 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 } /* end strrcpy */ 170 171 172 char *sys_siglist[] = { 173 "Signal 0", 174 "Hangup", /* SIGHUP */ 175 "Interrupt", /* SIGINT */ 176 "Quit", /* SIGQUIT */ 177 "Illegal instruction", /* SIGILL */ 178 "Trace/BPT trap", /* SIGTRAP */ 179 "IOT trap", /* SIGIOT */ 180 "EMT trap", /* SIGEMT */ 181 "Floating point exception", /* SIGFPE */ 182 "Killed", /* SIGKILL */ 183 "Bus error", /* SIGBUS */ 184 "Segmentation fault", /* SIGSEGV */ 185 "Bad system call", /* SIGSYS */ 186 "Broken pipe", /* SIGPIPE */ 187 "Alarm clock", /* SIGALRM */ 188 "Terminated", /* SIGTERM */ 189 "User defined signal 1", /* SIGUSR1 */ 190 "User defined signal 2", /* SIGUSR2 */ 191 "Child exited", /* SIGCLD */ 192 "Power-fail restart", /* SIGPWR */ 193 "Virtual timer expired", /* SIGVTALRM */ 194 "Profiling timer expired", /* SIGPROF */ 195 "I/O possible", /* SIGIO */ 196 "Window size changes", /* SIGWINDOW */ 197 "Stopped (signal)", /* SIGSTOP */ 198 "Stopped", /* SIGTSTP */ 199 "Continued", /* SIGCONT */ 200 "Stopped (tty input)", /* SIGTTIN */ 201 "Stopped (tty output)", /* SIGTTOU */ 202 "Urgent I/O condition", /* SIGURG */ 203 "Remote lock lost (NFS)", /* SIGLOST */ 204 "Signal 31", /* reserved */ 205 "DIL signal" /* SIGDIL */ 206 }; 207 #endif /* __hpux__ || __hpux */ 208 209 #if defined(__hpux__) || defined(__hpux) 210 #include <sys/types.h> 211 #include <sys/syscall.h> 212 #include <sys/signal.h> 213 #include <sys/stat.h> 214 #include <dirent.h> 215 #include <sys/time.h> 216 #include <unistd.h> 217 218 int 219 killpg(int pid, int sig) 220 { 221 return kill(-pid, sig); 222 } 223 224 #if !defined(BSD) && !defined(d_fileno) 225 # define d_fileno d_ino 226 #endif 227 228 #ifndef DEV_DEV_COMPARE 229 # define DEV_DEV_COMPARE(a, b) ((a) == (b)) 230 #endif 231 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/'))) 232 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1]))) 233 234 char * 235 getwd(char *pathname) 236 { 237 DIR *dp; 238 struct dirent *d; 239 extern int errno; 240 241 struct stat st_root, st_cur, st_next, st_dotdot; 242 char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2]; 243 char *pathptr, *nextpathptr, *cur_name_add; 244 245 /* find the inode of root */ 246 if (stat("/", &st_root) == -1) { 247 (void)sprintf(pathname, 248 "getwd: Cannot stat \"/\" (%s)", strerror(errno)); 249 return NULL; 250 } 251 pathbuf[MAXPATHLEN - 1] = '\0'; 252 pathptr = &pathbuf[MAXPATHLEN - 1]; 253 nextpathbuf[MAXPATHLEN - 1] = '\0'; 254 cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1]; 255 256 /* find the inode of the current directory */ 257 if (lstat(".", &st_cur) == -1) { 258 (void)sprintf(pathname, 259 "getwd: Cannot stat \".\" (%s)", strerror(errno)); 260 return NULL; 261 } 262 nextpathptr = strrcpy(nextpathptr, "../"); 263 264 /* Descend to root */ 265 for (;;) { 266 267 /* look if we found root yet */ 268 if (st_cur.st_ino == st_root.st_ino && 269 DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) { 270 (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr); 271 return pathname; 272 } 273 274 /* open the parent directory */ 275 if (stat(nextpathptr, &st_dotdot) == -1) { 276 (void)sprintf(pathname, 277 "getwd: Cannot stat directory \"%s\" (%s)", 278 nextpathptr, strerror(errno)); 279 return NULL; 280 } 281 if ((dp = opendir(nextpathptr)) == NULL) { 282 (void)sprintf(pathname, 283 "getwd: Cannot open directory \"%s\" (%s)", 284 nextpathptr, strerror(errno)); 285 return NULL; 286 } 287 288 /* look in the parent for the entry with the same inode */ 289 if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) { 290 /* Parent has same device. No need to stat every member */ 291 for (d = readdir(dp); d != NULL; d = readdir(dp)) 292 if (d->d_fileno == st_cur.st_ino) 293 break; 294 } else { 295 /* 296 * Parent has a different device. This is a mount point so we 297 * need to stat every member 298 */ 299 for (d = readdir(dp); d != NULL; d = readdir(dp)) { 300 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name)) 301 continue; 302 (void)strcpy(cur_name_add, d->d_name); 303 if (lstat(nextpathptr, &st_next) == -1) { 304 (void)sprintf(pathname, 305 "getwd: Cannot stat \"%s\" (%s)", 306 d->d_name, strerror(errno)); 307 (void)closedir(dp); 308 return NULL; 309 } 310 /* check if we found it yet */ 311 if (st_next.st_ino == st_cur.st_ino && 312 DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) 313 break; 314 } 315 } 316 if (d == NULL) { 317 (void)sprintf(pathname, 318 "getwd: Cannot find \".\" in \"..\""); 319 (void)closedir(dp); 320 return NULL; 321 } 322 st_cur = st_dotdot; 323 pathptr = strrcpy(pathptr, d->d_name); 324 pathptr = strrcpy(pathptr, "/"); 325 nextpathptr = strrcpy(nextpathptr, "../"); 326 (void)closedir(dp); 327 *cur_name_add = '\0'; 328 } 329 } /* end getwd */ 330 331 #endif /* __hpux */ 332 333 #if !defined(HAVE_GETCWD) 334 char * 335 getcwd(path, sz) 336 char *path; 337 int sz; 338 { 339 return getwd(path); 340 } 341 #endif 342 343 #if !defined(HAVE_SIGACTION) 344 #include "sigact.h" 345 #endif 346 347 /* force posix signals */ 348 SignalProc 349 bmake_signal(int s, SignalProc a) 350 { 351 struct sigaction sa, osa; 352 353 sa.sa_handler = a; 354 sigemptyset(&sa.sa_mask); 355 sa.sa_flags = SA_RESTART; 356 357 if (sigaction(s, &sa, &osa) == -1) 358 return SIG_ERR; 359 else 360 return osa.sa_handler; 361 } 362 363 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF) 364 #include <stdarg.h> 365 #endif 366 367 #if !defined(HAVE_VSNPRINTF) 368 #if !defined(__osf__) 369 #ifdef _IOSTRG 370 #define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */ 371 #else 372 #if 0 373 #define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */ 374 #endif 375 #endif /* _IOSTRG */ 376 #endif /* __osf__ */ 377 378 int 379 vsnprintf(char *s, size_t n, const char *fmt, va_list args) 380 { 381 #ifdef STRFLAG 382 FILE fakebuf; 383 384 fakebuf._flag = STRFLAG; 385 /* 386 * Some os's are char * _ptr, others are unsigned char *_ptr... 387 * We cast to void * to make everyone happy. 388 */ 389 fakebuf._ptr = (void *)s; 390 fakebuf._cnt = n - 1; 391 fakebuf._file = -1; 392 _doprnt(fmt, args, &fakebuf); 393 fakebuf._cnt++; 394 putc('\0', &fakebuf); 395 if (fakebuf._cnt < 0) 396 fakebuf._cnt = 0; 397 return n - fakebuf._cnt - 1; 398 #else 399 #ifndef _PATH_DEVNULL 400 # define _PATH_DEVNULL "/dev/null" 401 #endif 402 /* 403 * Rats... we don't want to clobber anything... 404 * do a printf to /dev/null to see how much space we need. 405 */ 406 static FILE *nullfp; 407 int need = 0; /* XXX what's a useful error return? */ 408 409 if (!nullfp) 410 nullfp = fopen(_PATH_DEVNULL, "w"); 411 if (nullfp) { 412 need = vfprintf(nullfp, fmt, args); 413 if (need < n) 414 (void)vsprintf(s, fmt, args); 415 } 416 return need; 417 #endif 418 } 419 #endif 420 421 #if !defined(HAVE_SNPRINTF) 422 int 423 snprintf(char *s, size_t n, const char *fmt, ...) 424 { 425 va_list ap; 426 int rv; 427 428 va_start(ap, fmt); 429 rv = vsnprintf(s, n, fmt, ap); 430 va_end(ap); 431 return rv; 432 } 433 #endif 434 435 #if !defined(HAVE_STRFTIME) 436 size_t 437 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) 438 { 439 static char months[][4] = { 440 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 441 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 442 }; 443 444 size_t s; 445 char *b = buf; 446 447 while (*fmt) { 448 if (len == 0) 449 return buf - b; 450 if (*fmt != '%') { 451 *buf++ = *fmt++; 452 len--; 453 continue; 454 } 455 switch (*fmt++) { 456 case '%': 457 *buf++ = '%'; 458 len--; 459 if (len == 0) return buf - b; 460 /*FALLTHROUGH*/ 461 case '\0': 462 *buf = '%'; 463 s = 1; 464 break; 465 case 'k': 466 s = snprintf(buf, len, "%d", tm->tm_hour); 467 break; 468 case 'M': 469 s = snprintf(buf, len, "%02d", tm->tm_min); 470 break; 471 case 'S': 472 s = snprintf(buf, len, "%02d", tm->tm_sec); 473 break; 474 case 'b': 475 if (tm->tm_mon >= 12) 476 return buf - b; 477 s = snprintf(buf, len, "%s", months[tm->tm_mon]); 478 break; 479 case 'd': 480 s = snprintf(buf, len, "%02d", tm->tm_mday); 481 break; 482 case 'Y': 483 s = snprintf(buf, len, "%d", 1900 + tm->tm_year); 484 break; 485 default: 486 s = snprintf(buf, len, "Unsupported format %c", 487 fmt[-1]); 488 break; 489 } 490 buf += s; 491 len -= s; 492 } 493 return buf - b; 494 } 495 #endif 496 497 #if !defined(HAVE_KILLPG) 498 #if !defined(__hpux__) && !defined(__hpux) 499 int 500 killpg(int pid, int sig) 501 { 502 return kill(-pid, sig); 503 } 504 #endif 505 #endif 506 507 #if !defined(HAVE_WARNX) 508 static void 509 vwarnx(const char *fmt, va_list args) 510 { 511 fprintf(stderr, "%s: ", progname); 512 if ((fmt)) { 513 vfprintf(stderr, fmt, args); 514 fprintf(stderr, ": "); 515 } 516 } 517 #endif 518 519 #if !defined(HAVE_WARN) 520 static void 521 vwarn(const char *fmt, va_list args) 522 { 523 vwarnx(fmt, args); 524 fprintf(stderr, "%s\n", strerror(errno)); 525 } 526 #endif 527 528 #if !defined(HAVE_ERR) 529 static void 530 verr(int eval, const char *fmt, va_list args) 531 { 532 vwarn(fmt, args); 533 exit(eval); 534 } 535 #endif 536 537 #if !defined(HAVE_ERRX) 538 static void 539 verrx(int eval, const char *fmt, va_list args) 540 { 541 vwarnx(fmt, args); 542 exit(eval); 543 } 544 #endif 545 546 #if !defined(HAVE_ERR) 547 void 548 err(int eval, const char *fmt, ...) 549 { 550 va_list ap; 551 552 va_start(ap, fmt); 553 verr(eval, fmt, ap); 554 va_end(ap); 555 } 556 #endif 557 558 #if !defined(HAVE_ERRX) 559 void 560 errx(int eval, const char *fmt, ...) 561 { 562 va_list ap; 563 564 va_start(ap, fmt); 565 verrx(eval, fmt, ap); 566 va_end(ap); 567 } 568 #endif 569 570 #if !defined(HAVE_WARN) 571 void 572 warn(const char *fmt, ...) 573 { 574 va_list ap; 575 576 va_start(ap, fmt); 577 vwarn(fmt, ap); 578 va_end(ap); 579 } 580 #endif 581 582 #if !defined(HAVE_WARNX) 583 void 584 warnx(const char *fmt, ...) 585 { 586 va_list ap; 587 588 va_start(ap, fmt); 589 vwarnx(fmt, ap); 590 va_end(ap); 591 } 592 #endif 593 594 #ifdef HAVE_INTTYPES_H 595 #include <inttypes.h> 596 #elif defined(HAVE_STDINT_H) 597 #include <stdint.h> 598 #endif 599 #ifdef HAVE_LIMITS_H 600 #include <limits.h> 601 #endif 602 603 #ifndef NUM_TYPE 604 # ifdef HAVE_LONG_LONG_INT 605 # define NUM_TYPE long long 606 # elif defined(_INT64_T_DECLARED) || defined(int64_t) 607 # define NUM_TYPE int64_t 608 # endif 609 #endif 610 611 #ifdef NUM_TYPE 612 #if !defined(HAVE_STRTOLL) 613 #define BCS_ONLY 614 #define _FUNCNAME strtoll 615 #define __INT NUM_TYPE 616 #undef __INT_MIN 617 #undef __INT_MAX 618 #ifdef LLONG_MAX 619 # define __INT_MIN LLONG_MIN 620 # define __INT_MAX LLONG_MAX 621 #elif defined(INT64_MAX) 622 # define __INT_MIN INT64_MIN 623 # define __INT_MAX INT64_MAX 624 #endif 625 #ifndef _DIAGASSERT 626 # define _DIAGASSERT(e) 627 #endif 628 #ifndef __UNCONST 629 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 630 #endif 631 #include "_strtol.h" 632 #endif 633 634 #endif 635 636 #if !defined(HAVE_STRTOL) 637 #define BCS_ONLY 638 #define _FUNCNAME strtol 639 #define __INT long 640 #undef __INT_MIN 641 #undef __INT_MAX 642 #define __INT_MIN LONG_MIN 643 #define __INT_MAX LONG_MAX 644 #ifndef _DIAGASSERT 645 # define _DIAGASSERT(e) 646 #endif 647 #ifndef __UNCONST 648 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 649 #endif 650 #include "_strtol.h" 651 #endif 652 653 #if !defined(HAVE_STRTOUL) 654 #define BCS_ONLY 655 #define _FUNCNAME strtoul 656 #define __INT unsigned long 657 #undef __INT_MIN 658 #undef __INT_MAX 659 #define __INT_MIN 0 660 #define __INT_MAX ULONG_MAX 661 #ifndef _DIAGASSERT 662 # define _DIAGASSERT(e) 663 #endif 664 #ifndef __UNCONST 665 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 666 #endif 667 #include "_strtol.h" 668 #endif 669