xref: /netbsd-src/usr.bin/make/util.c (revision 466a16a118933bd295a8a104f095714fadf9cf68)
1 /*	$NetBSD: util.c,v 1.47 2008/12/13 15:19:29 dsl Exp $	*/
2 
3 /*
4  * Missing stuff from OS's
5  */
6 
7 #ifndef MAKE_NATIVE
8 static char rcsid[] = "$NetBSD: util.c,v 1.47 2008/12/13 15:19:29 dsl Exp $";
9 #else
10 #include <sys/cdefs.h>
11 #ifndef lint
12 __RCSID("$NetBSD: util.c,v 1.47 2008/12/13 15:19:29 dsl 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 
22 #include "make.h"
23 
24 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRERROR)
25 extern int errno, sys_nerr;
26 extern char *sys_errlist[];
27 
28 char *
29 strerror(int e)
30 {
31     static char buf[100];
32     if (e < 0 || e >= sys_nerr) {
33 	snprintf(buf, sizeof(buf), "Unknown error %d", e);
34 	return buf;
35     }
36     else
37 	return sys_errlist[e];
38 }
39 #endif
40 
41 #if !defined(MAKE_NATIVE) && !defined(HAVE_SETENV)
42 extern char **environ;
43 
44 static char *
45 findenv(const char *name, int *offset)
46 {
47 	size_t i, len;
48 	char *p, *q;
49 
50 	for (i = 0; (q = environ[i]); i++) {
51 		char *p = strchr(q, '=');
52 		if (p == NULL)
53 			continue;
54 		if (strncmp(name, q, len = p - q) == 0) {
55 			*offset = i;
56 			return q + len + 1;
57 		}
58 	}
59 	*offset = i;
60 	return NULL;
61 }
62 
63 int
64 unsetenv(const char *name)
65 {
66 	char **p;
67 	int offset;
68 
69 	if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) {
70 		errno = EINVAL;
71 		return -1;
72 	}
73 
74 	while (findenv(name, &offset))	{ /* if set multiple times */
75 		for (p = &environ[offset];; ++p)
76 			if (!(*p = *(p + 1)))
77 				break;
78 	}
79 	return 0;
80 }
81 
82 int
83 setenv(const char *name, const char *value, int rewrite)
84 {
85 	static char **saveenv;	/* copy of previously allocated space */
86 	char *c, **newenv;
87 	const char *cc;
88 	size_t l_value, size;
89 	int offset;
90 
91 	if (name == NULL || value == NULL) {
92 		errno = EINVAL;
93 		return -1;
94 	}
95 
96 	if (*value == '=')			/* no `=' in value */
97 		++value;
98 	l_value = strlen(value);
99 
100 	/* find if already exists */
101 	if ((c = findenv(name, &offset))) {
102 		if (!rewrite)
103 			return 0;
104 		if (strlen(c) >= l_value)	/* old larger; copy over */
105 			goto copy;
106 	} else {					/* create new slot */
107 		size = sizeof(char *) * (offset + 2);
108 		if (saveenv == environ) {		/* just increase size */
109 			if ((newenv = realloc(saveenv, size)) == NULL)
110 				return -1;
111 			saveenv = newenv;
112 		} else {				/* get new space */
113 			/*
114 			 * We don't free here because we don't know if
115 			 * the first allocation is valid on all OS's
116 			 */
117 			if ((saveenv = malloc(size)) == NULL)
118 				return -1;
119 			(void)memcpy(saveenv, environ, size - sizeof(char *));
120 		}
121 		environ = saveenv;
122 		environ[offset + 1] = NULL;
123 	}
124 	for (cc = name; *cc && *cc != '='; ++cc)	/* no `=' in name */
125 		continue;
126 	size = cc - name;
127 	/* name + `=' + value */
128 	if ((environ[offset] = malloc(size + l_value + 2)) == NULL)
129 		return -1;
130 	c = environ[offset];
131 	(void)memcpy(c, name, size);
132 	c += size;
133 	*c++ = '=';
134 copy:
135 	(void)memcpy(c, value, l_value + 1);
136 	return 0;
137 }
138 
139 #ifdef TEST
140 int
141 main(int argc, char *argv[])
142 {
143 	setenv(argv[1], argv[2], 0);
144 	printf("%s\n", getenv(argv[1]));
145 	unsetenv(argv[1]);
146 	printf("%s\n", getenv(argv[1]));
147 	return 0;
148 }
149 #endif
150 
151 #endif
152 
153 #if defined(__hpux__) || defined(__hpux)
154 /* strrcpy():
155  *	Like strcpy, going backwards and returning the new pointer
156  */
157 static char *
158 strrcpy(char *ptr, char *str)
159 {
160     int len = strlen(str);
161 
162     while (len)
163 	*--ptr = str[--len];
164 
165     return (ptr);
166 } /* end strrcpy */
167 
168 char    *sys_siglist[] = {
169         "Signal 0",
170         "Hangup",                       /* SIGHUP    */
171         "Interrupt",                    /* SIGINT    */
172         "Quit",                         /* SIGQUIT   */
173         "Illegal instruction",          /* SIGILL    */
174         "Trace/BPT trap",               /* SIGTRAP   */
175         "IOT trap",                     /* SIGIOT    */
176         "EMT trap",                     /* SIGEMT    */
177         "Floating point exception",     /* SIGFPE    */
178         "Killed",                       /* SIGKILL   */
179         "Bus error",                    /* SIGBUS    */
180         "Segmentation fault",           /* SIGSEGV   */
181         "Bad system call",              /* SIGSYS    */
182         "Broken pipe",                  /* SIGPIPE   */
183         "Alarm clock",                  /* SIGALRM   */
184         "Terminated",                   /* SIGTERM   */
185         "User defined signal 1",        /* SIGUSR1   */
186         "User defined signal 2",        /* SIGUSR2   */
187         "Child exited",                 /* SIGCLD    */
188         "Power-fail restart",           /* SIGPWR    */
189         "Virtual timer expired",        /* SIGVTALRM */
190         "Profiling timer expired",      /* SIGPROF   */
191         "I/O possible",                 /* SIGIO     */
192         "Window size changes",          /* SIGWINDOW */
193         "Stopped (signal)",             /* SIGSTOP   */
194         "Stopped",                      /* SIGTSTP   */
195         "Continued",                    /* SIGCONT   */
196         "Stopped (tty input)",          /* SIGTTIN   */
197         "Stopped (tty output)",         /* SIGTTOU   */
198         "Urgent I/O condition",         /* SIGURG    */
199         "Remote lock lost (NFS)",       /* SIGLOST   */
200         "Signal 31",                    /* reserved  */
201         "DIL signal"                    /* SIGDIL    */
202 };
203 #endif /* __hpux__ || __hpux */
204 
205 #if defined(__hpux__) || defined(__hpux)
206 #include <sys/types.h>
207 #include <sys/syscall.h>
208 #include <sys/signal.h>
209 #include <sys/stat.h>
210 #include <dirent.h>
211 #include <sys/time.h>
212 #include <unistd.h>
213 
214 int
215 killpg(int pid, int sig)
216 {
217     return kill(-pid, sig);
218 }
219 
220 #if !defined(__hpux__) && !defined(__hpux)
221 void
222 srandom(long seed)
223 {
224     srand48(seed);
225 }
226 
227 long
228 random(void)
229 {
230     return lrand48();
231 }
232 #endif
233 
234 /* turn into bsd signals */
235 void (*
236 signal(int s, void (*a)(int)))(int)
237 {
238     struct sigvec osv, sv;
239 
240     (void)sigvector(s, NULL, &osv);
241     sv = osv;
242     sv.sv_handler = a;
243 #ifdef SV_BSDSIG
244     sv.sv_flags = SV_BSDSIG;
245 #endif
246 
247     if (sigvector(s, &sv, NULL) == -1)
248         return (BADSIG);
249     return (osv.sv_handler);
250 }
251 
252 #if !defined(__hpux__) && !defined(__hpux)
253 int
254 utimes(char *file, struct timeval tvp[2])
255 {
256     struct utimbuf t;
257 
258     t.actime  = tvp[0].tv_sec;
259     t.modtime = tvp[1].tv_sec;
260     return(utime(file, &t));
261 }
262 #endif
263 
264 #if !defined(BSD) && !defined(d_fileno)
265 # define d_fileno d_ino
266 #endif
267 
268 #ifndef DEV_DEV_COMPARE
269 # define DEV_DEV_COMPARE(a, b) ((a) == (b))
270 #endif
271 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/')))
272 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1])))
273 
274 char *
275 getwd(char *pathname)
276 {
277     DIR    *dp;
278     struct dirent *d;
279     extern int errno;
280 
281     struct stat st_root, st_cur, st_next, st_dotdot;
282     char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
283     char   *pathptr, *nextpathptr, *cur_name_add;
284 
285     /* find the inode of root */
286     if (stat("/", &st_root) == -1) {
287 	(void)sprintf(pathname,
288 			"getwd: Cannot stat \"/\" (%s)", strerror(errno));
289 	return NULL;
290     }
291     pathbuf[MAXPATHLEN - 1] = '\0';
292     pathptr = &pathbuf[MAXPATHLEN - 1];
293     nextpathbuf[MAXPATHLEN - 1] = '\0';
294     cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
295 
296     /* find the inode of the current directory */
297     if (lstat(".", &st_cur) == -1) {
298 	(void)sprintf(pathname,
299 			"getwd: Cannot stat \".\" (%s)", strerror(errno));
300 	return NULL;
301     }
302     nextpathptr = strrcpy(nextpathptr, "../");
303 
304     /* Descend to root */
305     for (;;) {
306 
307 	/* look if we found root yet */
308 	if (st_cur.st_ino == st_root.st_ino &&
309 	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
310 	    (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
311 	    return (pathname);
312 	}
313 
314 	/* open the parent directory */
315 	if (stat(nextpathptr, &st_dotdot) == -1) {
316 	    (void)sprintf(pathname,
317 			    "getwd: Cannot stat directory \"%s\" (%s)",
318 			    nextpathptr, strerror(errno));
319 	    return NULL;
320 	}
321 	if ((dp = opendir(nextpathptr)) == NULL) {
322 	    (void)sprintf(pathname,
323 			    "getwd: Cannot open directory \"%s\" (%s)",
324 			    nextpathptr, strerror(errno));
325 	    return NULL;
326 	}
327 
328 	/* look in the parent for the entry with the same inode */
329 	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
330 	    /* Parent has same device. No need to stat every member */
331 	    for (d = readdir(dp); d != NULL; d = readdir(dp))
332 		if (d->d_fileno == st_cur.st_ino)
333 		    break;
334 	}
335 	else {
336 	    /*
337 	     * Parent has a different device. This is a mount point so we
338 	     * need to stat every member
339 	     */
340 	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
341 		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
342 		    continue;
343 		(void)strcpy(cur_name_add, d->d_name);
344 		if (lstat(nextpathptr, &st_next) == -1) {
345 		    (void)sprintf(pathname,
346 			"getwd: Cannot stat \"%s\" (%s)",
347 			d->d_name, strerror(errno));
348 		    (void)closedir(dp);
349 		    return NULL;
350 		}
351 		/* check if we found it yet */
352 		if (st_next.st_ino == st_cur.st_ino &&
353 		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
354 		    break;
355 	    }
356 	}
357 	if (d == NULL) {
358 	    (void)sprintf(pathname,
359 		"getwd: Cannot find \".\" in \"..\"");
360 	    (void)closedir(dp);
361 	    return NULL;
362 	}
363 	st_cur = st_dotdot;
364 	pathptr = strrcpy(pathptr, d->d_name);
365 	pathptr = strrcpy(pathptr, "/");
366 	nextpathptr = strrcpy(nextpathptr, "../");
367 	(void)closedir(dp);
368 	*cur_name_add = '\0';
369     }
370 } /* end getwd */
371 #endif /* __hpux */
372 
373 #if defined(sun) && defined(__svr4__)
374 #include <signal.h>
375 
376 /* turn into bsd signals */
377 void (*
378 signal(int s, void (*a)(int)))(int)
379 {
380     struct sigaction sa, osa;
381 
382     sa.sa_handler = a;
383     sigemptyset(&sa.sa_mask);
384     sa.sa_flags = SA_RESTART;
385 
386     if (sigaction(s, &sa, &osa) == -1)
387 	return SIG_ERR;
388     else
389 	return osa.sa_handler;
390 }
391 #endif
392 
393 #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF)
394 #include <stdarg.h>
395 
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 
406 int
407 vsnprintf(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 	(void)vsprintf(s, fmt, args);
428 	return strlen(s);
429 #endif
430 }
431 
432 int
433 snprintf(char *s, size_t n, const char *fmt, ...)
434 {
435 	va_list ap;
436 	int rv;
437 
438 	va_start(ap, fmt);
439 	rv = vsnprintf(s, n, fmt, ap);
440 	va_end(ap);
441 	return rv;
442 }
443 
444 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRFTIME)
445 size_t
446 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
447 {
448 	static char months[][4] = {
449 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
450 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
451 	};
452 
453 	size_t s;
454 	char *b = buf;
455 
456 	while (*fmt) {
457 		if (len == 0)
458 			return buf - b;
459 		if (*fmt != '%') {
460 			*buf++ = *fmt++;
461 			len--;
462 			continue;
463 		}
464 		switch (*fmt++) {
465 		case '%':
466 			*buf++ = '%';
467 			len--;
468 			if (len == 0) return buf - b;
469 			/*FALLTHROUGH*/
470 		case '\0':
471 			*buf = '%';
472 			s = 1;
473 			break;
474 		case 'k':
475 			s = snprintf(buf, len, "%d", tm->tm_hour);
476 			break;
477 		case 'M':
478 			s = snprintf(buf, len, "%02d", tm->tm_min);
479 			break;
480 		case 'S':
481 			s = snprintf(buf, len, "%02d", tm->tm_sec);
482 			break;
483 		case 'b':
484 			if (tm->tm_mon >= 12)
485 				return buf - b;
486 			s = snprintf(buf, len, "%s", months[tm->tm_mon]);
487 			break;
488 		case 'd':
489 			s = snprintf(buf, len, "%s", tm->tm_mday);
490 			break;
491 		case 'Y':
492 			s = snprintf(buf, len, "%s", 1900 + tm->tm_year);
493 			break;
494 		default:
495 			s = snprintf(buf, len, "Unsupported format %c",
496 			    fmt[-1]);
497 			break;
498 		}
499 		buf += s;
500 		len -= s;
501 	}
502 }
503 #endif
504 #endif
505