util.c revision 276305
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 *	$Id: util.c,v 1.33 2014/01/02 02:29:49 sjg Exp $
7 */
8#if defined(__MINT__) || defined(__linux__)
9#include <signal.h>
10#endif
11
12#include "make.h"
13
14#ifndef MAKE_NATIVE
15static char rcsid[] = "$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $";
16#else
17#ifndef lint
18__RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $");
19#endif
20#endif
21
22#include <errno.h>
23#include <time.h>
24#include <signal.h>
25
26#if !defined(HAVE_STRERROR)
27extern int errno, sys_nerr;
28extern char *sys_errlist[];
29
30char *
31strerror(int e)
32{
33    static char buf[100];
34    if (e < 0 || e >= sys_nerr) {
35	snprintf(buf, sizeof(buf), "Unknown error %d", e);
36	return buf;
37    }
38    else
39	return sys_errlist[e];
40}
41#endif
42
43#if !defined(HAVE_GETENV) || !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV)
44extern char **environ;
45
46static char *
47findenv(const char *name, int *offset)
48{
49	size_t i, len;
50	char *p, *q;
51
52	len = strlen(name);
53	for (i = 0; (q = environ[i]); i++) {
54		p = strchr(q, '=');
55		if (p == NULL || p - q != len)
56			continue;
57		if (strncmp(name, q, len) == 0) {
58			*offset = i;
59			return q + len + 1;
60		}
61	}
62	*offset = i;
63	return NULL;
64}
65
66char *
67getenv(const char *name)
68{
69    int offset;
70
71    return(findenv(name, &offset));
72}
73
74int
75unsetenv(const char *name)
76{
77	char **p;
78	int offset;
79
80	if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) {
81		errno = EINVAL;
82		return -1;
83	}
84
85	while (findenv(name, &offset))	{ /* if set multiple times */
86		for (p = &environ[offset];; ++p)
87			if (!(*p = *(p + 1)))
88				break;
89	}
90	return 0;
91}
92
93int
94setenv(const char *name, const char *value, int rewrite)
95{
96	char *c, **newenv;
97	const char *cc;
98	size_t l_value, size;
99	int offset;
100
101	if (name == NULL || value == NULL) {
102		errno = EINVAL;
103		return -1;
104	}
105
106	if (*value == '=')			/* no `=' in value */
107		++value;
108	l_value = strlen(value);
109
110	/* find if already exists */
111	if ((c = findenv(name, &offset))) {
112		if (!rewrite)
113			return 0;
114		if (strlen(c) >= l_value)	/* old larger; copy over */
115			goto copy;
116	} else {					/* create new slot */
117		size = sizeof(char *) * (offset + 2);
118		if (savedEnv == environ) {		/* just increase size */
119			if ((newenv = realloc(savedEnv, size)) == NULL)
120				return -1;
121			savedEnv = newenv;
122		} else {				/* get new space */
123			/*
124			 * We don't free here because we don't know if
125			 * the first allocation is valid on all OS's
126			 */
127			if ((savedEnv = malloc(size)) == NULL)
128				return -1;
129			(void)memcpy(savedEnv, environ, size - sizeof(char *));
130		}
131		environ = savedEnv;
132		environ[offset + 1] = NULL;
133	}
134	for (cc = name; *cc && *cc != '='; ++cc)	/* no `=' in name */
135		continue;
136	size = cc - name;
137	/* name + `=' + value */
138	if ((environ[offset] = malloc(size + l_value + 2)) == NULL)
139		return -1;
140	c = environ[offset];
141	(void)memcpy(c, name, size);
142	c += size;
143	*c++ = '=';
144copy:
145	(void)memcpy(c, value, l_value + 1);
146	return 0;
147}
148
149#ifdef TEST
150int
151main(int argc, char *argv[])
152{
153	setenv(argv[1], argv[2], 0);
154	printf("%s\n", getenv(argv[1]));
155	unsetenv(argv[1]);
156	printf("%s\n", getenv(argv[1]));
157	return 0;
158}
159#endif
160
161#endif
162
163
164#if defined(__hpux__) || defined(__hpux)
165/* strrcpy():
166 *	Like strcpy, going backwards and returning the new pointer
167 */
168static char *
169strrcpy(char *ptr, char *str)
170{
171    int len = strlen(str);
172
173    while (len)
174	*--ptr = str[--len];
175
176    return (ptr);
177} /* end strrcpy */
178
179
180char    *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
226int
227killpg(int pid, int sig)
228{
229    return kill(-pid, sig);
230}
231
232#if !defined(__hpux__) && !defined(__hpux)
233void
234srandom(long seed)
235{
236    srand48(seed);
237}
238
239long
240random(void)
241{
242    return lrand48();
243}
244#endif
245
246#if !defined(__hpux__) && !defined(__hpux)
247int
248utimes(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
268char *
269getwd(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
366#endif /* __hpux */
367
368#if !defined(HAVE_GETCWD)
369char *
370getcwd(path, sz)
371     char *path;
372     int sz;
373{
374	return getwd(path);
375}
376#endif
377
378/* force posix signals */
379void (*
380bmake_signal(int s, void (*a)(int)))(int)
381{
382    struct sigaction sa, osa;
383
384    sa.sa_handler = a;
385    sigemptyset(&sa.sa_mask);
386    sa.sa_flags = SA_RESTART;
387
388    if (sigaction(s, &sa, &osa) == -1)
389	return SIG_ERR;
390    else
391	return osa.sa_handler;
392}
393
394#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF)
395#include <stdarg.h>
396#endif
397
398#if !defined(HAVE_VSNPRINTF)
399#if !defined(__osf__)
400#ifdef _IOSTRG
401#define STRFLAG	(_IOSTRG|_IOWRT)	/* no _IOWRT: avoid stdio bug */
402#else
403#if 0
404#define STRFLAG	(_IOREAD)		/* XXX: Assume svr4 stdio */
405#endif
406#endif /* _IOSTRG */
407#endif /* __osf__ */
408
409int
410vsnprintf(char *s, size_t n, const char *fmt, va_list args)
411{
412#ifdef STRFLAG
413	FILE fakebuf;
414
415	fakebuf._flag = STRFLAG;
416	/*
417	 * Some os's are char * _ptr, others are unsigned char *_ptr...
418	 * We cast to void * to make everyone happy.
419	 */
420	fakebuf._ptr = (void *)s;
421	fakebuf._cnt = n-1;
422	fakebuf._file = -1;
423	_doprnt(fmt, args, &fakebuf);
424	fakebuf._cnt++;
425	putc('\0', &fakebuf);
426	if (fakebuf._cnt<0)
427	    fakebuf._cnt = 0;
428	return (n-fakebuf._cnt-1);
429#else
430#ifndef _PATH_DEVNULL
431# define _PATH_DEVNULL "/dev/null"
432#endif
433	/*
434	 * Rats... we don't want to clobber anything...
435	 * do a printf to /dev/null to see how much space we need.
436	 */
437	static FILE *nullfp;
438	int need = 0;			/* XXX what's a useful error return? */
439
440	if (!nullfp)
441		nullfp = fopen(_PATH_DEVNULL, "w");
442	if (nullfp) {
443		need = vfprintf(nullfp, fmt, args);
444		if (need < n)
445			(void)vsprintf(s, fmt, args);
446	}
447	return need;
448#endif
449}
450#endif
451
452#if !defined(HAVE_SNPRINTF)
453int
454snprintf(char *s, size_t n, const char *fmt, ...)
455{
456	va_list ap;
457	int rv;
458
459	va_start(ap, fmt);
460	rv = vsnprintf(s, n, fmt, ap);
461	va_end(ap);
462	return rv;
463}
464#endif
465
466#if !defined(HAVE_STRFTIME)
467size_t
468strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
469{
470	static char months[][4] = {
471		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
472		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
473	};
474
475	size_t s;
476	char *b = buf;
477
478	while (*fmt) {
479		if (len == 0)
480			return buf - b;
481		if (*fmt != '%') {
482			*buf++ = *fmt++;
483			len--;
484			continue;
485		}
486		switch (*fmt++) {
487		case '%':
488			*buf++ = '%';
489			len--;
490			if (len == 0) return buf - b;
491			/*FALLTHROUGH*/
492		case '\0':
493			*buf = '%';
494			s = 1;
495			break;
496		case 'k':
497			s = snprintf(buf, len, "%d", tm->tm_hour);
498			break;
499		case 'M':
500			s = snprintf(buf, len, "%02d", tm->tm_min);
501			break;
502		case 'S':
503			s = snprintf(buf, len, "%02d", tm->tm_sec);
504			break;
505		case 'b':
506			if (tm->tm_mon >= 12)
507				return buf - b;
508			s = snprintf(buf, len, "%s", months[tm->tm_mon]);
509			break;
510		case 'd':
511			s = snprintf(buf, len, "%02d", tm->tm_mday);
512			break;
513		case 'Y':
514			s = snprintf(buf, len, "%d", 1900 + tm->tm_year);
515			break;
516		default:
517			s = snprintf(buf, len, "Unsupported format %c",
518			    fmt[-1]);
519			break;
520		}
521		buf += s;
522		len -= s;
523	}
524}
525#endif
526
527#if !defined(HAVE_KILLPG)
528#if !defined(__hpux__) && !defined(__hpux)
529int
530killpg(int pid, int sig)
531{
532    return kill(-pid, sig);
533}
534#endif
535#endif
536
537#if !defined(HAVE_WARNX)
538static void
539vwarnx(const char *fmt, va_list args)
540{
541	fprintf(stderr, "%s: ", progname);
542	if ((fmt)) {
543		vfprintf(stderr, fmt, args);
544		fprintf(stderr, ": ");
545	}
546}
547#endif
548
549#if !defined(HAVE_WARN)
550static void
551vwarn(const char *fmt, va_list args)
552{
553	vwarnx(fmt, args);
554	fprintf(stderr, "%s\n", strerror(errno));
555}
556#endif
557
558#if !defined(HAVE_ERR)
559static void
560verr(int eval, const char *fmt, va_list args)
561{
562	vwarn(fmt, args);
563	exit(eval);
564}
565#endif
566
567#if !defined(HAVE_ERRX)
568static void
569verrx(int eval, const char *fmt, va_list args)
570{
571	vwarnx(fmt, args);
572	exit(eval);
573}
574#endif
575
576#if !defined(HAVE_ERR)
577void
578err(int eval, const char *fmt, ...)
579{
580        va_list ap;
581
582        va_start(ap, fmt);
583        verr(eval, fmt, ap);
584        va_end(ap);
585}
586#endif
587
588#if !defined(HAVE_ERRX)
589void
590errx(int eval, const char *fmt, ...)
591{
592        va_list ap;
593
594        va_start(ap, fmt);
595        verrx(eval, fmt, ap);
596        va_end(ap);
597}
598#endif
599
600#if !defined(HAVE_WARN)
601void
602warn(const char *fmt, ...)
603{
604        va_list ap;
605
606        va_start(ap, fmt);
607        vwarn(fmt, ap);
608        va_end(ap);
609}
610#endif
611
612#if !defined(HAVE_WARNX)
613void
614warnx(const char *fmt, ...)
615{
616        va_list ap;
617
618        va_start(ap, fmt);
619        vwarnx(fmt, ap);
620        va_end(ap);
621}
622#endif
623