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