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