1 /* $NetBSD: util.c,v 1.64 2020/10/06 21:51:33 rillig Exp $ */ 2 3 /* 4 * Missing stuff from OS's 5 * 6 * $Id: util.c,v 1.39 2020/10/10 19:42:02 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.64 2020/10/06 21:51:33 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 } 30 else 31 return sys_errlist[e]; 32 } 33 #endif 34 35 #if !defined(HAVE_GETENV) || !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) 36 extern char **environ; 37 38 static char * 39 findenv(const char *name, int *offset) 40 { 41 size_t i, len; 42 char *p, *q; 43 44 len = strlen(name); 45 for (i = 0; (q = environ[i]); i++) { 46 p = strchr(q, '='); 47 if (p == NULL || p - q != len) 48 continue; 49 if (strncmp(name, q, len) == 0) { 50 *offset = i; 51 return q + len + 1; 52 } 53 } 54 *offset = i; 55 return NULL; 56 } 57 58 char * 59 getenv(const char *name) 60 { 61 int offset; 62 63 return findenv(name, &offset); 64 } 65 66 int 67 unsetenv(const char *name) 68 { 69 char **p; 70 int offset; 71 72 if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) { 73 errno = EINVAL; 74 return -1; 75 } 76 77 while (findenv(name, &offset)) { /* if set multiple times */ 78 for (p = &environ[offset];; ++p) 79 if (!(*p = *(p + 1))) 80 break; 81 } 82 return 0; 83 } 84 85 int 86 setenv(const char *name, const char *value, int rewrite) 87 { 88 char *c, **newenv; 89 const char *cc; 90 size_t l_value, size; 91 int offset; 92 93 if (name == NULL || value == NULL) { 94 errno = EINVAL; 95 return -1; 96 } 97 98 if (*value == '=') /* no `=' in value */ 99 ++value; 100 l_value = strlen(value); 101 102 /* find if already exists */ 103 if ((c = findenv(name, &offset))) { 104 if (!rewrite) 105 return 0; 106 if (strlen(c) >= l_value) /* old larger; copy over */ 107 goto copy; 108 } else { /* create new slot */ 109 size = sizeof(char *) * (offset + 2); 110 if (savedEnv == environ) { /* just increase size */ 111 if ((newenv = realloc(savedEnv, size)) == NULL) 112 return -1; 113 savedEnv = newenv; 114 } else { /* get new space */ 115 /* 116 * We don't free here because we don't know if 117 * the first allocation is valid on all OS's 118 */ 119 if ((savedEnv = malloc(size)) == NULL) 120 return -1; 121 (void)memcpy(savedEnv, environ, size - sizeof(char *)); 122 } 123 environ = savedEnv; 124 environ[offset + 1] = NULL; 125 } 126 for (cc = name; *cc && *cc != '='; ++cc) /* no `=' in name */ 127 continue; 128 size = cc - name; 129 /* name + `=' + value */ 130 if ((environ[offset] = malloc(size + l_value + 2)) == NULL) 131 return -1; 132 c = environ[offset]; 133 (void)memcpy(c, name, size); 134 c += size; 135 *c++ = '='; 136 copy: 137 (void)memcpy(c, value, l_value + 1); 138 return 0; 139 } 140 141 #ifdef TEST 142 int 143 main(int argc, char *argv[]) 144 { 145 setenv(argv[1], argv[2], 0); 146 printf("%s\n", getenv(argv[1])); 147 unsetenv(argv[1]); 148 printf("%s\n", getenv(argv[1])); 149 return 0; 150 } 151 #endif 152 153 #endif 154 155 156 #if defined(__hpux__) || defined(__hpux) 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) 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 } 295 else { 296 /* 297 * Parent has a different device. This is a mount point so we 298 * need to stat every member 299 */ 300 for (d = readdir(dp); d != NULL; d = readdir(dp)) { 301 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name)) 302 continue; 303 (void)strcpy(cur_name_add, d->d_name); 304 if (lstat(nextpathptr, &st_next) == -1) { 305 (void)sprintf(pathname, 306 "getwd: Cannot stat \"%s\" (%s)", 307 d->d_name, strerror(errno)); 308 (void)closedir(dp); 309 return NULL; 310 } 311 /* check if we found it yet */ 312 if (st_next.st_ino == st_cur.st_ino && 313 DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) 314 break; 315 } 316 } 317 if (d == NULL) { 318 (void)sprintf(pathname, 319 "getwd: Cannot find \".\" in \"..\""); 320 (void)closedir(dp); 321 return NULL; 322 } 323 st_cur = st_dotdot; 324 pathptr = strrcpy(pathptr, d->d_name); 325 pathptr = strrcpy(pathptr, "/"); 326 nextpathptr = strrcpy(nextpathptr, "../"); 327 (void)closedir(dp); 328 *cur_name_add = '\0'; 329 } 330 } /* end getwd */ 331 332 #endif /* __hpux */ 333 334 #if !defined(HAVE_GETCWD) 335 char * 336 getcwd(path, sz) 337 char *path; 338 int sz; 339 { 340 return getwd(path); 341 } 342 #endif 343 344 /* force posix signals */ 345 SignalProc 346 bmake_signal(int s, SignalProc a) 347 { 348 struct sigaction sa, osa; 349 350 sa.sa_handler = a; 351 sigemptyset(&sa.sa_mask); 352 sa.sa_flags = SA_RESTART; 353 354 if (sigaction(s, &sa, &osa) == -1) 355 return SIG_ERR; 356 else 357 return osa.sa_handler; 358 } 359 360 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF) 361 #include <stdarg.h> 362 #endif 363 364 #if !defined(HAVE_VSNPRINTF) 365 #if !defined(__osf__) 366 #ifdef _IOSTRG 367 #define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */ 368 #else 369 #if 0 370 #define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */ 371 #endif 372 #endif /* _IOSTRG */ 373 #endif /* __osf__ */ 374 375 int 376 vsnprintf(char *s, size_t n, const char *fmt, va_list args) 377 { 378 #ifdef STRFLAG 379 FILE fakebuf; 380 381 fakebuf._flag = STRFLAG; 382 /* 383 * Some os's are char * _ptr, others are unsigned char *_ptr... 384 * We cast to void * to make everyone happy. 385 */ 386 fakebuf._ptr = (void *)s; 387 fakebuf._cnt = n-1; 388 fakebuf._file = -1; 389 _doprnt(fmt, args, &fakebuf); 390 fakebuf._cnt++; 391 putc('\0', &fakebuf); 392 if (fakebuf._cnt<0) 393 fakebuf._cnt = 0; 394 return n-fakebuf._cnt-1; 395 #else 396 #ifndef _PATH_DEVNULL 397 # define _PATH_DEVNULL "/dev/null" 398 #endif 399 /* 400 * Rats... we don't want to clobber anything... 401 * do a printf to /dev/null to see how much space we need. 402 */ 403 static FILE *nullfp; 404 int need = 0; /* XXX what's a useful error return? */ 405 406 if (!nullfp) 407 nullfp = fopen(_PATH_DEVNULL, "w"); 408 if (nullfp) { 409 need = vfprintf(nullfp, fmt, args); 410 if (need < n) 411 (void)vsprintf(s, fmt, args); 412 } 413 return need; 414 #endif 415 } 416 #endif 417 418 #if !defined(HAVE_SNPRINTF) 419 int 420 snprintf(char *s, size_t n, const char *fmt, ...) 421 { 422 va_list ap; 423 int rv; 424 425 va_start(ap, fmt); 426 rv = vsnprintf(s, n, fmt, ap); 427 va_end(ap); 428 return rv; 429 } 430 #endif 431 432 #if !defined(HAVE_STRFTIME) 433 size_t 434 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) 435 { 436 static char months[][4] = { 437 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 438 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 439 }; 440 441 size_t s; 442 char *b = buf; 443 444 while (*fmt) { 445 if (len == 0) 446 return buf - b; 447 if (*fmt != '%') { 448 *buf++ = *fmt++; 449 len--; 450 continue; 451 } 452 switch (*fmt++) { 453 case '%': 454 *buf++ = '%'; 455 len--; 456 if (len == 0) return buf - b; 457 /*FALLTHROUGH*/ 458 case '\0': 459 *buf = '%'; 460 s = 1; 461 break; 462 case 'k': 463 s = snprintf(buf, len, "%d", tm->tm_hour); 464 break; 465 case 'M': 466 s = snprintf(buf, len, "%02d", tm->tm_min); 467 break; 468 case 'S': 469 s = snprintf(buf, len, "%02d", tm->tm_sec); 470 break; 471 case 'b': 472 if (tm->tm_mon >= 12) 473 return buf - b; 474 s = snprintf(buf, len, "%s", months[tm->tm_mon]); 475 break; 476 case 'd': 477 s = snprintf(buf, len, "%02d", tm->tm_mday); 478 break; 479 case 'Y': 480 s = snprintf(buf, len, "%d", 1900 + tm->tm_year); 481 break; 482 default: 483 s = snprintf(buf, len, "Unsupported format %c", 484 fmt[-1]); 485 break; 486 } 487 buf += s; 488 len -= s; 489 } 490 return buf - b; 491 } 492 #endif 493 494 #if !defined(HAVE_KILLPG) 495 #if !defined(__hpux__) && !defined(__hpux) 496 int 497 killpg(int pid, int sig) 498 { 499 return kill(-pid, sig); 500 } 501 #endif 502 #endif 503 504 #if !defined(HAVE_WARNX) 505 static void 506 vwarnx(const char *fmt, va_list args) 507 { 508 fprintf(stderr, "%s: ", progname); 509 if ((fmt)) { 510 vfprintf(stderr, fmt, args); 511 fprintf(stderr, ": "); 512 } 513 } 514 #endif 515 516 #if !defined(HAVE_WARN) 517 static void 518 vwarn(const char *fmt, va_list args) 519 { 520 vwarnx(fmt, args); 521 fprintf(stderr, "%s\n", strerror(errno)); 522 } 523 #endif 524 525 #if !defined(HAVE_ERR) 526 static void 527 verr(int eval, const char *fmt, va_list args) 528 { 529 vwarn(fmt, args); 530 exit(eval); 531 } 532 #endif 533 534 #if !defined(HAVE_ERRX) 535 static void 536 verrx(int eval, const char *fmt, va_list args) 537 { 538 vwarnx(fmt, args); 539 exit(eval); 540 } 541 #endif 542 543 #if !defined(HAVE_ERR) 544 void 545 err(int eval, const char *fmt, ...) 546 { 547 va_list ap; 548 549 va_start(ap, fmt); 550 verr(eval, fmt, ap); 551 va_end(ap); 552 } 553 #endif 554 555 #if !defined(HAVE_ERRX) 556 void 557 errx(int eval, const char *fmt, ...) 558 { 559 va_list ap; 560 561 va_start(ap, fmt); 562 verrx(eval, fmt, ap); 563 va_end(ap); 564 } 565 #endif 566 567 #if !defined(HAVE_WARN) 568 void 569 warn(const char *fmt, ...) 570 { 571 va_list ap; 572 573 va_start(ap, fmt); 574 vwarn(fmt, ap); 575 va_end(ap); 576 } 577 #endif 578 579 #if !defined(HAVE_WARNX) 580 void 581 warnx(const char *fmt, ...) 582 { 583 va_list ap; 584 585 va_start(ap, fmt); 586 vwarnx(fmt, ap); 587 va_end(ap); 588 } 589 #endif 590