util.c revision 276305
1/* $NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $ */ 2 3/* 4 * Missing stuff from OS's 5 * 6 * $Id: util.c,v 1.33 2014/01/02 02:29:49 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 15static char rcsid[] = "$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $"; 16#else 17#ifndef lint 18__RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $"); 19#endif 20#endif 21 22#include <errno.h> 23#include <time.h> 24#include <signal.h> 25 26#if !defined(HAVE_STRERROR) 27extern int errno, sys_nerr; 28extern char *sys_errlist[]; 29 30char * 31strerror(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) 44extern char **environ; 45 46static char * 47findenv(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 66char * 67getenv(const char *name) 68{ 69 int offset; 70 71 return(findenv(name, &offset)); 72} 73 74int 75unsetenv(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 93int 94setenv(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++ = '='; 144copy: 145 (void)memcpy(c, value, l_value + 1); 146 return 0; 147} 148 149#ifdef TEST 150int 151main(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 */ 168static char * 169strrcpy(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 180char *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 226int 227killpg(int pid, int sig) 228{ 229 return kill(-pid, sig); 230} 231 232#if !defined(__hpux__) && !defined(__hpux) 233void 234srandom(long seed) 235{ 236 srand48(seed); 237} 238 239long 240random(void) 241{ 242 return lrand48(); 243} 244#endif 245 246#if !defined(__hpux__) && !defined(__hpux) 247int 248utimes(char *file, struct timeval tvp[2]) 249{ 250 struct utimbuf t; 251 252 t.actime = tvp[0].tv_sec; 253 t.modtime = tvp[1].tv_sec; 254 return(utime(file, &t)); 255} 256#endif 257 258#if !defined(BSD) && !defined(d_fileno) 259# define d_fileno d_ino 260#endif 261 262#ifndef DEV_DEV_COMPARE 263# define DEV_DEV_COMPARE(a, b) ((a) == (b)) 264#endif 265#define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/'))) 266#define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1]))) 267 268char * 269getwd(char *pathname) 270{ 271 DIR *dp; 272 struct dirent *d; 273 extern int errno; 274 275 struct stat st_root, st_cur, st_next, st_dotdot; 276 char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2]; 277 char *pathptr, *nextpathptr, *cur_name_add; 278 279 /* find the inode of root */ 280 if (stat("/", &st_root) == -1) { 281 (void)sprintf(pathname, 282 "getwd: Cannot stat \"/\" (%s)", strerror(errno)); 283 return NULL; 284 } 285 pathbuf[MAXPATHLEN - 1] = '\0'; 286 pathptr = &pathbuf[MAXPATHLEN - 1]; 287 nextpathbuf[MAXPATHLEN - 1] = '\0'; 288 cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1]; 289 290 /* find the inode of the current directory */ 291 if (lstat(".", &st_cur) == -1) { 292 (void)sprintf(pathname, 293 "getwd: Cannot stat \".\" (%s)", strerror(errno)); 294 return NULL; 295 } 296 nextpathptr = strrcpy(nextpathptr, "../"); 297 298 /* Descend to root */ 299 for (;;) { 300 301 /* look if we found root yet */ 302 if (st_cur.st_ino == st_root.st_ino && 303 DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) { 304 (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr); 305 return (pathname); 306 } 307 308 /* open the parent directory */ 309 if (stat(nextpathptr, &st_dotdot) == -1) { 310 (void)sprintf(pathname, 311 "getwd: Cannot stat directory \"%s\" (%s)", 312 nextpathptr, strerror(errno)); 313 return NULL; 314 } 315 if ((dp = opendir(nextpathptr)) == NULL) { 316 (void)sprintf(pathname, 317 "getwd: Cannot open directory \"%s\" (%s)", 318 nextpathptr, strerror(errno)); 319 return NULL; 320 } 321 322 /* look in the parent for the entry with the same inode */ 323 if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) { 324 /* Parent has same device. No need to stat every member */ 325 for (d = readdir(dp); d != NULL; d = readdir(dp)) 326 if (d->d_fileno == st_cur.st_ino) 327 break; 328 } 329 else { 330 /* 331 * Parent has a different device. This is a mount point so we 332 * need to stat every member 333 */ 334 for (d = readdir(dp); d != NULL; d = readdir(dp)) { 335 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name)) 336 continue; 337 (void)strcpy(cur_name_add, d->d_name); 338 if (lstat(nextpathptr, &st_next) == -1) { 339 (void)sprintf(pathname, 340 "getwd: Cannot stat \"%s\" (%s)", 341 d->d_name, strerror(errno)); 342 (void)closedir(dp); 343 return NULL; 344 } 345 /* check if we found it yet */ 346 if (st_next.st_ino == st_cur.st_ino && 347 DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) 348 break; 349 } 350 } 351 if (d == NULL) { 352 (void)sprintf(pathname, 353 "getwd: Cannot find \".\" in \"..\""); 354 (void)closedir(dp); 355 return NULL; 356 } 357 st_cur = st_dotdot; 358 pathptr = strrcpy(pathptr, d->d_name); 359 pathptr = strrcpy(pathptr, "/"); 360 nextpathptr = strrcpy(nextpathptr, "../"); 361 (void)closedir(dp); 362 *cur_name_add = '\0'; 363 } 364} /* end getwd */ 365 366#endif /* __hpux */ 367 368#if !defined(HAVE_GETCWD) 369char * 370getcwd(path, sz) 371 char *path; 372 int sz; 373{ 374 return getwd(path); 375} 376#endif 377 378/* force posix signals */ 379void (* 380bmake_signal(int s, void (*a)(int)))(int) 381{ 382 struct sigaction sa, osa; 383 384 sa.sa_handler = a; 385 sigemptyset(&sa.sa_mask); 386 sa.sa_flags = SA_RESTART; 387 388 if (sigaction(s, &sa, &osa) == -1) 389 return SIG_ERR; 390 else 391 return osa.sa_handler; 392} 393 394#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF) 395#include <stdarg.h> 396#endif 397 398#if !defined(HAVE_VSNPRINTF) 399#if !defined(__osf__) 400#ifdef _IOSTRG 401#define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */ 402#else 403#if 0 404#define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */ 405#endif 406#endif /* _IOSTRG */ 407#endif /* __osf__ */ 408 409int 410vsnprintf(char *s, size_t n, const char *fmt, va_list args) 411{ 412#ifdef STRFLAG 413 FILE fakebuf; 414 415 fakebuf._flag = STRFLAG; 416 /* 417 * Some os's are char * _ptr, others are unsigned char *_ptr... 418 * We cast to void * to make everyone happy. 419 */ 420 fakebuf._ptr = (void *)s; 421 fakebuf._cnt = n-1; 422 fakebuf._file = -1; 423 _doprnt(fmt, args, &fakebuf); 424 fakebuf._cnt++; 425 putc('\0', &fakebuf); 426 if (fakebuf._cnt<0) 427 fakebuf._cnt = 0; 428 return (n-fakebuf._cnt-1); 429#else 430#ifndef _PATH_DEVNULL 431# define _PATH_DEVNULL "/dev/null" 432#endif 433 /* 434 * Rats... we don't want to clobber anything... 435 * do a printf to /dev/null to see how much space we need. 436 */ 437 static FILE *nullfp; 438 int need = 0; /* XXX what's a useful error return? */ 439 440 if (!nullfp) 441 nullfp = fopen(_PATH_DEVNULL, "w"); 442 if (nullfp) { 443 need = vfprintf(nullfp, fmt, args); 444 if (need < n) 445 (void)vsprintf(s, fmt, args); 446 } 447 return need; 448#endif 449} 450#endif 451 452#if !defined(HAVE_SNPRINTF) 453int 454snprintf(char *s, size_t n, const char *fmt, ...) 455{ 456 va_list ap; 457 int rv; 458 459 va_start(ap, fmt); 460 rv = vsnprintf(s, n, fmt, ap); 461 va_end(ap); 462 return rv; 463} 464#endif 465 466#if !defined(HAVE_STRFTIME) 467size_t 468strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) 469{ 470 static char months[][4] = { 471 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 472 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 473 }; 474 475 size_t s; 476 char *b = buf; 477 478 while (*fmt) { 479 if (len == 0) 480 return buf - b; 481 if (*fmt != '%') { 482 *buf++ = *fmt++; 483 len--; 484 continue; 485 } 486 switch (*fmt++) { 487 case '%': 488 *buf++ = '%'; 489 len--; 490 if (len == 0) return buf - b; 491 /*FALLTHROUGH*/ 492 case '\0': 493 *buf = '%'; 494 s = 1; 495 break; 496 case 'k': 497 s = snprintf(buf, len, "%d", tm->tm_hour); 498 break; 499 case 'M': 500 s = snprintf(buf, len, "%02d", tm->tm_min); 501 break; 502 case 'S': 503 s = snprintf(buf, len, "%02d", tm->tm_sec); 504 break; 505 case 'b': 506 if (tm->tm_mon >= 12) 507 return buf - b; 508 s = snprintf(buf, len, "%s", months[tm->tm_mon]); 509 break; 510 case 'd': 511 s = snprintf(buf, len, "%02d", tm->tm_mday); 512 break; 513 case 'Y': 514 s = snprintf(buf, len, "%d", 1900 + tm->tm_year); 515 break; 516 default: 517 s = snprintf(buf, len, "Unsupported format %c", 518 fmt[-1]); 519 break; 520 } 521 buf += s; 522 len -= s; 523 } 524} 525#endif 526 527#if !defined(HAVE_KILLPG) 528#if !defined(__hpux__) && !defined(__hpux) 529int 530killpg(int pid, int sig) 531{ 532 return kill(-pid, sig); 533} 534#endif 535#endif 536 537#if !defined(HAVE_WARNX) 538static void 539vwarnx(const char *fmt, va_list args) 540{ 541 fprintf(stderr, "%s: ", progname); 542 if ((fmt)) { 543 vfprintf(stderr, fmt, args); 544 fprintf(stderr, ": "); 545 } 546} 547#endif 548 549#if !defined(HAVE_WARN) 550static void 551vwarn(const char *fmt, va_list args) 552{ 553 vwarnx(fmt, args); 554 fprintf(stderr, "%s\n", strerror(errno)); 555} 556#endif 557 558#if !defined(HAVE_ERR) 559static void 560verr(int eval, const char *fmt, va_list args) 561{ 562 vwarn(fmt, args); 563 exit(eval); 564} 565#endif 566 567#if !defined(HAVE_ERRX) 568static void 569verrx(int eval, const char *fmt, va_list args) 570{ 571 vwarnx(fmt, args); 572 exit(eval); 573} 574#endif 575 576#if !defined(HAVE_ERR) 577void 578err(int eval, const char *fmt, ...) 579{ 580 va_list ap; 581 582 va_start(ap, fmt); 583 verr(eval, fmt, ap); 584 va_end(ap); 585} 586#endif 587 588#if !defined(HAVE_ERRX) 589void 590errx(int eval, const char *fmt, ...) 591{ 592 va_list ap; 593 594 va_start(ap, fmt); 595 verrx(eval, fmt, ap); 596 va_end(ap); 597} 598#endif 599 600#if !defined(HAVE_WARN) 601void 602warn(const char *fmt, ...) 603{ 604 va_list ap; 605 606 va_start(ap, fmt); 607 vwarn(fmt, ap); 608 va_end(ap); 609} 610#endif 611 612#if !defined(HAVE_WARNX) 613void 614warnx(const char *fmt, ...) 615{ 616 va_list ap; 617 618 va_start(ap, fmt); 619 vwarnx(fmt, ap); 620 va_end(ap); 621} 622#endif 623