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 #if defined(__MINT__) || defined(__linux__) 7 #include <signal.h> 8 #endif 9 10 #ifndef MAKE_NATIVE 11 static char rcsid[] = "$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $"; 12 #else 13 #include <sys/cdefs.h> 14 #ifndef lint 15 __RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $"); 16 #endif 17 #endif 18 19 #include <sys/param.h> 20 21 #include <errno.h> 22 #include <stdio.h> 23 #include <time.h> 24 #include <signal.h> 25 26 #include "make.h" 27 28 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRERROR) 29 extern int errno, sys_nerr; 30 extern char *sys_errlist[]; 31 32 char * 33 strerror(int e) 34 { 35 static char buf[100]; 36 if (e < 0 || e >= sys_nerr) { 37 snprintf(buf, sizeof(buf), "Unknown error %d", e); 38 return buf; 39 } 40 else 41 return sys_errlist[e]; 42 } 43 #endif 44 45 #if !defined(MAKE_NATIVE) && !defined(HAVE_SETENV) 46 extern char **environ; 47 48 static char * 49 findenv(const char *name, int *offset) 50 { 51 size_t i, len; 52 char *p, *q; 53 54 len = strlen(name); 55 for (i = 0; (q = environ[i]); i++) { 56 p = strchr(q, '='); 57 if (p == NULL || p - q != len) 58 continue; 59 if (strncmp(name, q, len) == 0) { 60 *offset = i; 61 return q + len + 1; 62 } 63 } 64 *offset = i; 65 return NULL; 66 } 67 68 char * 69 getenv(const char *name) 70 { 71 int offset; 72 73 return(findenv(name, &offset)); 74 } 75 76 int 77 unsetenv(const char *name) 78 { 79 char **p; 80 int offset; 81 82 if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) { 83 errno = EINVAL; 84 return -1; 85 } 86 87 while (findenv(name, &offset)) { /* if set multiple times */ 88 for (p = &environ[offset];; ++p) 89 if (!(*p = *(p + 1))) 90 break; 91 } 92 return 0; 93 } 94 95 int 96 setenv(const char *name, const char *value, int rewrite) 97 { 98 char *c, **newenv; 99 const char *cc; 100 size_t l_value, size; 101 int offset; 102 103 if (name == NULL || value == NULL) { 104 errno = EINVAL; 105 return -1; 106 } 107 108 if (*value == '=') /* no `=' in value */ 109 ++value; 110 l_value = strlen(value); 111 112 /* find if already exists */ 113 if ((c = findenv(name, &offset))) { 114 if (!rewrite) 115 return 0; 116 if (strlen(c) >= l_value) /* old larger; copy over */ 117 goto copy; 118 } else { /* create new slot */ 119 size = sizeof(char *) * (offset + 2); 120 if (savedEnv == environ) { /* just increase size */ 121 if ((newenv = realloc(savedEnv, size)) == NULL) 122 return -1; 123 savedEnv = newenv; 124 } else { /* get new space */ 125 /* 126 * We don't free here because we don't know if 127 * the first allocation is valid on all OS's 128 */ 129 if ((savedEnv = malloc(size)) == NULL) 130 return -1; 131 (void)memcpy(savedEnv, environ, size - sizeof(char *)); 132 } 133 environ = savedEnv; 134 environ[offset + 1] = NULL; 135 } 136 for (cc = name; *cc && *cc != '='; ++cc) /* no `=' in name */ 137 continue; 138 size = cc - name; 139 /* name + `=' + value */ 140 if ((environ[offset] = malloc(size + l_value + 2)) == NULL) 141 return -1; 142 c = environ[offset]; 143 (void)memcpy(c, name, size); 144 c += size; 145 *c++ = '='; 146 copy: 147 (void)memcpy(c, value, l_value + 1); 148 return 0; 149 } 150 151 #ifdef TEST 152 int 153 main(int argc, char *argv[]) 154 { 155 setenv(argv[1], argv[2], 0); 156 printf("%s\n", getenv(argv[1])); 157 unsetenv(argv[1]); 158 printf("%s\n", getenv(argv[1])); 159 return 0; 160 } 161 #endif 162 163 #endif 164 165 #if defined(__hpux__) || defined(__hpux) 166 /* strrcpy(): 167 * Like strcpy, going backwards and returning the new pointer 168 */ 169 static char * 170 strrcpy(char *ptr, char *str) 171 { 172 int len = strlen(str); 173 174 while (len) 175 *--ptr = str[--len]; 176 177 return (ptr); 178 } /* end strrcpy */ 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(__hpux__) && !defined(__hpux) 233 void 234 srandom(long seed) 235 { 236 srand48(seed); 237 } 238 239 long 240 random(void) 241 { 242 return lrand48(); 243 } 244 #endif 245 246 #if !defined(__hpux__) && !defined(__hpux) 247 int 248 utimes(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 268 char * 269 getwd(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 #endif /* __hpux */ 366 367 /* force posix signals */ 368 void (* 369 bmake_signal(int s, void (*a)(int)))(int) 370 { 371 struct sigaction sa, osa; 372 373 sa.sa_handler = a; 374 sigemptyset(&sa.sa_mask); 375 sa.sa_flags = SA_RESTART; 376 377 if (sigaction(s, &sa, &osa) == -1) 378 return SIG_ERR; 379 else 380 return osa.sa_handler; 381 } 382 383 #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF) 384 #include <stdarg.h> 385 386 #if !defined(__osf__) 387 #ifdef _IOSTRG 388 #define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */ 389 #else 390 #if 0 391 #define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */ 392 #endif 393 #endif /* _IOSTRG */ 394 #endif /* __osf__ */ 395 396 int 397 vsnprintf(char *s, size_t n, const char *fmt, va_list args) 398 { 399 #ifdef STRFLAG 400 FILE fakebuf; 401 402 fakebuf._flag = STRFLAG; 403 /* 404 * Some os's are char * _ptr, others are unsigned char *_ptr... 405 * We cast to void * to make everyone happy. 406 */ 407 fakebuf._ptr = (void *)s; 408 fakebuf._cnt = n-1; 409 fakebuf._file = -1; 410 _doprnt(fmt, args, &fakebuf); 411 fakebuf._cnt++; 412 putc('\0', &fakebuf); 413 if (fakebuf._cnt<0) 414 fakebuf._cnt = 0; 415 return (n-fakebuf._cnt-1); 416 #else 417 (void)vsprintf(s, fmt, args); 418 return strlen(s); 419 #endif 420 } 421 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 434 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRFTIME) 435 size_t 436 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) 437 { 438 static char months[][4] = { 439 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 440 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 441 }; 442 443 size_t s; 444 char *b = buf; 445 446 while (*fmt) { 447 if (len == 0) 448 return buf - b; 449 if (*fmt != '%') { 450 *buf++ = *fmt++; 451 len--; 452 continue; 453 } 454 switch (*fmt++) { 455 case '%': 456 *buf++ = '%'; 457 len--; 458 if (len == 0) return buf - b; 459 /*FALLTHROUGH*/ 460 case '\0': 461 *buf = '%'; 462 s = 1; 463 break; 464 case 'k': 465 s = snprintf(buf, len, "%d", tm->tm_hour); 466 break; 467 case 'M': 468 s = snprintf(buf, len, "%02d", tm->tm_min); 469 break; 470 case 'S': 471 s = snprintf(buf, len, "%02d", tm->tm_sec); 472 break; 473 case 'b': 474 if (tm->tm_mon >= 12) 475 return buf - b; 476 s = snprintf(buf, len, "%s", months[tm->tm_mon]); 477 break; 478 case 'd': 479 s = snprintf(buf, len, "%02d", tm->tm_mday); 480 break; 481 case 'Y': 482 s = snprintf(buf, len, "%d", 1900 + tm->tm_year); 483 break; 484 default: 485 s = snprintf(buf, len, "Unsupported format %c", 486 fmt[-1]); 487 break; 488 } 489 buf += s; 490 len -= s; 491 } 492 } 493 #endif 494 #endif 495