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