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