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