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