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.53 2024/07/12 18:37:25 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 #ifndef SA_RESTART
347 # define SA_RESTART 0
348 #endif
349
350 /* force posix signals */
351 SignalProc
bmake_signal(int s,SignalProc a)352 bmake_signal(int s, SignalProc a)
353 {
354 struct sigaction sa, osa;
355
356 sa.sa_handler = a;
357 sigemptyset(&sa.sa_mask);
358 sa.sa_flags = SA_RESTART;
359
360 if (sigaction(s, &sa, &osa) == -1)
361 return SIG_ERR;
362 else
363 return osa.sa_handler;
364 }
365
366 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF)
367 #include <stdarg.h>
368 #endif
369
370 #if !defined(HAVE_VSNPRINTF)
371 #if !defined(__osf__)
372 #ifdef _IOSTRG
373 #define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */
374 #else
375 #if 0
376 #define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */
377 #endif
378 #endif /* _IOSTRG */
379 #endif /* __osf__ */
380
381 int
vsnprintf(char * s,size_t n,const char * fmt,va_list args)382 vsnprintf(char *s, size_t n, const char *fmt, va_list args)
383 {
384 #ifdef STRFLAG
385 FILE fakebuf;
386
387 fakebuf._flag = STRFLAG;
388 /*
389 * Some os's are char * _ptr, others are unsigned char *_ptr...
390 * We cast to void * to make everyone happy.
391 */
392 fakebuf._ptr = (void *)s;
393 fakebuf._cnt = n - 1;
394 fakebuf._file = -1;
395 _doprnt(fmt, args, &fakebuf);
396 fakebuf._cnt++;
397 putc('\0', &fakebuf);
398 if (fakebuf._cnt < 0)
399 fakebuf._cnt = 0;
400 return n - fakebuf._cnt - 1;
401 #else
402 #ifndef _PATH_DEVNULL
403 # define _PATH_DEVNULL "/dev/null"
404 #endif
405 /*
406 * Rats... we don't want to clobber anything...
407 * do a printf to /dev/null to see how much space we need.
408 */
409 static FILE *nullfp;
410 int need = 0; /* XXX what's a useful error return? */
411
412 if (!nullfp)
413 nullfp = fopen(_PATH_DEVNULL, "w");
414 if (nullfp) {
415 need = vfprintf(nullfp, fmt, args);
416 if (need < n)
417 (void)vsprintf(s, fmt, args);
418 }
419 return need;
420 #endif
421 }
422 #endif
423
424 #if !defined(HAVE_SNPRINTF)
425 int
snprintf(char * s,size_t n,const char * fmt,...)426 snprintf(char *s, size_t n, const char *fmt, ...)
427 {
428 va_list ap;
429 int rv;
430
431 va_start(ap, fmt);
432 rv = vsnprintf(s, n, fmt, ap);
433 va_end(ap);
434 return rv;
435 }
436 #endif
437
438 #if !defined(HAVE_STRFTIME) || defined(FORCE_BMAKE_STRFTIME)
439 /* we only implement enough to pass our unit-tests */
440 size_t
strftime(char * buf,size_t len,const char * fmt,const struct tm * tm)441 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
442 {
443 static const char *months[] = {
444 "January", "February", "March",
445 "April", "May", "June",
446 "July", "August", "September",
447 "October", "November", "December"
448 };
449 static const char *days[] = {
450 "Sunday", "Monday", "Tuesday", "Wednesday",
451 "Thursday", "Friday", "Saturday"
452 };
453 int i;
454 size_t s;
455 char *b = buf;
456 char *cp;
457
458 if (fmt == NULL || *fmt == '\0')
459 fmt = "%c";
460 while (*fmt) {
461 if (len == 0)
462 return buf - b;
463 if (*fmt != '%') {
464 *buf++ = *fmt++;
465 len--;
466 continue;
467 }
468 fmt++;
469 switch (*fmt++) {
470 case '%':
471 *buf++ = '%';
472 len--;
473 if (len == 0) return buf - b;
474 /*FALLTHROUGH*/
475 case '\0':
476 *buf = '%';
477 s = 1;
478 break;
479 case 'A':
480 s = snprintf(buf, len, "%s", days[tm->tm_wday]);
481 break;
482 case 'a':
483 s = snprintf(buf, len, "%.3s", days[tm->tm_wday]);
484 break;
485 case 'B':
486 if (tm->tm_mon >= 12)
487 return buf - b;
488 s = snprintf(buf, len, "%s", months[tm->tm_mon]);
489 break;
490 case 'b':
491 if (tm->tm_mon >= 12)
492 return buf - b;
493 s = snprintf(buf, len, "%.3s", months[tm->tm_mon]);
494 break;
495 case 'c':
496 s = strftime(buf, len, "%a %b %e %H:%M:%S %Y", tm);
497 break;
498 case 'd':
499 s = snprintf(buf, len, "%02d", tm->tm_mday);
500 break;
501 case 'e':
502 s = snprintf(buf, len, "%2d", tm->tm_mday);
503 break;
504 case 'F':
505 s = strftime(buf, len, "%y-%m-%d", tm);
506 break;
507 case 'H':
508 s = snprintf(buf, len, "%02d", tm->tm_hour);
509 break;
510 case 'I':
511 if ((i = tm->tm_hour) == 0)
512 i = 24;
513 s = snprintf(buf, len, "%02d", (i > 12) ? (i - 12) : i);
514 break;
515 case 'j':
516 s = snprintf(buf, len, "%03d", tm->tm_yday + 1);
517 break;
518 case 'k':
519 s = snprintf(buf, len, "%d", tm->tm_hour);
520 break;
521 case 'M':
522 s = snprintf(buf, len, "%02d", tm->tm_min);
523 break;
524 case 'm':
525 s = snprintf(buf, len, "%02d", 1 + tm->tm_mon);
526 break;
527 case 'S':
528 s = snprintf(buf, len, "%02d", tm->tm_sec);
529 break;
530 case 's':
531 s = snprintf(buf, len, "%ld", (long)time(NULL));
532 break;
533 case 'T':
534 s = strftime(buf, len, "%H:%M:%S", tm);
535 break;
536 case 'w':
537 s = snprintf(buf, len, "%02d", tm->tm_wday);
538 break;
539 case 'Y':
540 s = snprintf(buf, len, "%d", 1900 + tm->tm_year);
541 break;
542 case 'y':
543 s = snprintf(buf, len, "%02d", tm->tm_year % 100);
544 break;
545 case 'Z':
546 if ((cp = getenv("TZ")) != NULL) {
547 char tz[20];
548
549 i = snprintf(tz, sizeof(tz), "%s", cp);
550 if (i > 5) {
551 cp = &tz[i - 3];
552 tz[3] = '\0';
553 } else
554 cp = tz;
555 s = snprintf(buf, len, "%s",
556 tm->tm_isdst ? cp : tz);
557 } else
558 s = 0;
559 break;
560 default:
561 s = snprintf(buf, len, "Unsupported format %c",
562 fmt[-1]);
563 break;
564 }
565 buf += s;
566 len -= s;
567 }
568 return buf - b;
569 }
570 #endif
571
572 #if !defined(HAVE_KILLPG)
573 #if !defined(__hpux__) && !defined(__hpux)
574 int
killpg(int pid,int sig)575 killpg(int pid, int sig)
576 {
577 return kill(-pid, sig);
578 }
579 #endif
580 #endif
581
582 #if !defined(HAVE_WARNX)
583 static void
vwarnx(const char * fmt,va_list args)584 vwarnx(const char *fmt, va_list args)
585 {
586 fprintf(stderr, "%s: ", progname);
587 if ((fmt)) {
588 vfprintf(stderr, fmt, args);
589 fprintf(stderr, ": ");
590 }
591 }
592 #endif
593
594 #if !defined(HAVE_WARN)
595 static void
vwarn(const char * fmt,va_list args)596 vwarn(const char *fmt, va_list args)
597 {
598 vwarnx(fmt, args);
599 fprintf(stderr, "%s\n", strerror(errno));
600 }
601 #endif
602
603 #if !defined(HAVE_ERR)
604 static void
verr(int eval,const char * fmt,va_list args)605 verr(int eval, const char *fmt, va_list args)
606 {
607 vwarn(fmt, args);
608 exit(eval);
609 }
610 #endif
611
612 #if !defined(HAVE_ERRX)
613 static void
verrx(int eval,const char * fmt,va_list args)614 verrx(int eval, const char *fmt, va_list args)
615 {
616 vwarnx(fmt, args);
617 exit(eval);
618 }
619 #endif
620
621 #if !defined(HAVE_ERR)
622 void
err(int eval,const char * fmt,...)623 err(int eval, const char *fmt, ...)
624 {
625 va_list ap;
626
627 va_start(ap, fmt);
628 verr(eval, fmt, ap);
629 va_end(ap);
630 }
631 #endif
632
633 #if !defined(HAVE_ERRX)
634 void
errx(int eval,const char * fmt,...)635 errx(int eval, const char *fmt, ...)
636 {
637 va_list ap;
638
639 va_start(ap, fmt);
640 verrx(eval, fmt, ap);
641 va_end(ap);
642 }
643 #endif
644
645 #if !defined(HAVE_WARN)
646 void
warn(const char * fmt,...)647 warn(const char *fmt, ...)
648 {
649 va_list ap;
650
651 va_start(ap, fmt);
652 vwarn(fmt, ap);
653 va_end(ap);
654 }
655 #endif
656
657 #if !defined(HAVE_WARNX)
658 void
warnx(const char * fmt,...)659 warnx(const char *fmt, ...)
660 {
661 va_list ap;
662
663 va_start(ap, fmt);
664 vwarnx(fmt, ap);
665 va_end(ap);
666 }
667 #endif
668
669 #ifdef HAVE_INTTYPES_H
670 #include <inttypes.h>
671 #elif defined(HAVE_STDINT_H)
672 #include <stdint.h>
673 #endif
674 #ifdef HAVE_LIMITS_H
675 #include <limits.h>
676 #endif
677
678 #ifndef NUM_TYPE
679 # ifdef HAVE_LONG_LONG_INT
680 # define NUM_TYPE long long
681 # elif defined(_INT64_T_DECLARED) || defined(int64_t)
682 # define NUM_TYPE int64_t
683 # endif
684 #endif
685
686 #ifdef NUM_TYPE
687 #if !defined(HAVE_STRTOLL)
688 #define BCS_ONLY
689 #define _FUNCNAME strtoll
690 #define __INT NUM_TYPE
691 #undef __INT_MIN
692 #undef __INT_MAX
693 #ifdef LLONG_MAX
694 # define __INT_MIN LLONG_MIN
695 # define __INT_MAX LLONG_MAX
696 #elif defined(INT64_MAX)
697 # define __INT_MIN INT64_MIN
698 # define __INT_MAX INT64_MAX
699 #endif
700 #ifndef _DIAGASSERT
701 # define _DIAGASSERT(e)
702 #endif
703 #ifndef __UNCONST
704 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
705 #endif
706 #include "_strtol.h"
707 #endif
708
709 #endif
710
711 #if !defined(HAVE_STRTOL)
712 #define BCS_ONLY
713 #define _FUNCNAME strtol
714 #define __INT long
715 #undef __INT_MIN
716 #undef __INT_MAX
717 #define __INT_MIN LONG_MIN
718 #define __INT_MAX LONG_MAX
719 #ifndef _DIAGASSERT
720 # define _DIAGASSERT(e)
721 #endif
722 #ifndef __UNCONST
723 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
724 #endif
725 #include "_strtol.h"
726 #endif
727
728 #if !defined(HAVE_STRTOUL)
729 #define BCS_ONLY
730 #define _FUNCNAME strtoul
731 #define __INT unsigned long
732 #undef __INT_MIN
733 #undef __INT_MAX
734 #define __INT_MIN 0
735 #define __INT_MAX ULONG_MAX
736 #ifndef _DIAGASSERT
737 # define _DIAGASSERT(e)
738 #endif
739 #ifndef __UNCONST
740 # define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
741 #endif
742 #include "_strtol.h"
743 #endif
744