xref: /netbsd-src/usr.bin/make/util.c (revision a536ee5124e62c9a0051a252f7833dc8f50f44c9)
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 
7 #ifndef MAKE_NATIVE
8 static char rcsid[] = "$NetBSD: util.c,v 1.53 2012/06/04 22:45:05 sjg Exp $";
9 #else
10 #include <sys/cdefs.h>
11 #ifndef lint
12 __RCSID("$NetBSD: util.c,v 1.53 2012/06/04 22:45:05 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 	len = strlen(name);
52 	for (i = 0; (q = environ[i]); i++) {
53 		p = strchr(q, '=');
54 		if (p == NULL || p - q != len)
55 			continue;
56 		if (strncmp(name, q, len) == 0) {
57 			*offset = i;
58 			return q + len + 1;
59 		}
60 	}
61 	*offset = i;
62 	return NULL;
63 }
64 
65 char *
66 getenv(const char *name)
67 {
68     int offset;
69 
70     return(findenv(name, &offset));
71 }
72 
73 int
74 unsetenv(const char *name)
75 {
76 	char **p;
77 	int offset;
78 
79 	if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) {
80 		errno = EINVAL;
81 		return -1;
82 	}
83 
84 	while (findenv(name, &offset))	{ /* if set multiple times */
85 		for (p = &environ[offset];; ++p)
86 			if (!(*p = *(p + 1)))
87 				break;
88 	}
89 	return 0;
90 }
91 
92 int
93 setenv(const char *name, const char *value, int rewrite)
94 {
95 	char *c, **newenv;
96 	const char *cc;
97 	size_t l_value, size;
98 	int offset;
99 
100 	if (name == NULL || value == NULL) {
101 		errno = EINVAL;
102 		return -1;
103 	}
104 
105 	if (*value == '=')			/* no `=' in value */
106 		++value;
107 	l_value = strlen(value);
108 
109 	/* find if already exists */
110 	if ((c = findenv(name, &offset))) {
111 		if (!rewrite)
112 			return 0;
113 		if (strlen(c) >= l_value)	/* old larger; copy over */
114 			goto copy;
115 	} else {					/* create new slot */
116 		size = sizeof(char *) * (offset + 2);
117 		if (savedEnv == environ) {		/* just increase size */
118 			if ((newenv = realloc(savedEnv, size)) == NULL)
119 				return -1;
120 			savedEnv = newenv;
121 		} else {				/* get new space */
122 			/*
123 			 * We don't free here because we don't know if
124 			 * the first allocation is valid on all OS's
125 			 */
126 			if ((savedEnv = malloc(size)) == NULL)
127 				return -1;
128 			(void)memcpy(savedEnv, environ, size - sizeof(char *));
129 		}
130 		environ = savedEnv;
131 		environ[offset + 1] = NULL;
132 	}
133 	for (cc = name; *cc && *cc != '='; ++cc)	/* no `=' in name */
134 		continue;
135 	size = cc - name;
136 	/* name + `=' + value */
137 	if ((environ[offset] = malloc(size + l_value + 2)) == NULL)
138 		return -1;
139 	c = environ[offset];
140 	(void)memcpy(c, name, size);
141 	c += size;
142 	*c++ = '=';
143 copy:
144 	(void)memcpy(c, value, l_value + 1);
145 	return 0;
146 }
147 
148 #ifdef TEST
149 int
150 main(int argc, char *argv[])
151 {
152 	setenv(argv[1], argv[2], 0);
153 	printf("%s\n", getenv(argv[1]));
154 	unsetenv(argv[1]);
155 	printf("%s\n", getenv(argv[1]));
156 	return 0;
157 }
158 #endif
159 
160 #endif
161 
162 #if defined(__hpux__) || defined(__hpux)
163 /* strrcpy():
164  *	Like strcpy, going backwards and returning the new pointer
165  */
166 static char *
167 strrcpy(char *ptr, char *str)
168 {
169     int len = strlen(str);
170 
171     while (len)
172 	*--ptr = str[--len];
173 
174     return (ptr);
175 } /* end strrcpy */
176 
177 char    *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 
223 int
224 killpg(int pid, int sig)
225 {
226     return kill(-pid, sig);
227 }
228 
229 #if !defined(__hpux__) && !defined(__hpux)
230 void
231 srandom(long seed)
232 {
233     srand48(seed);
234 }
235 
236 long
237 random(void)
238 {
239     return lrand48();
240 }
241 #endif
242 
243 #if !defined(__hpux__) && !defined(__hpux)
244 int
245 utimes(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 
265 char *
266 getwd(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 #endif /* __hpux */
363 
364 /* force posix signals */
365 void (*
366 bmake_signal(int s, void (*a)(int)))(int)
367 {
368     struct sigaction sa, osa;
369 
370     sa.sa_handler = a;
371     sigemptyset(&sa.sa_mask);
372     sa.sa_flags = SA_RESTART;
373 
374     if (sigaction(s, &sa, &osa) == -1)
375 	return SIG_ERR;
376     else
377 	return osa.sa_handler;
378 }
379 
380 #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF)
381 #include <stdarg.h>
382 
383 #if !defined(__osf__)
384 #ifdef _IOSTRG
385 #define STRFLAG	(_IOSTRG|_IOWRT)	/* no _IOWRT: avoid stdio bug */
386 #else
387 #if 0
388 #define STRFLAG	(_IOREAD)		/* XXX: Assume svr4 stdio */
389 #endif
390 #endif /* _IOSTRG */
391 #endif /* __osf__ */
392 
393 int
394 vsnprintf(char *s, size_t n, const char *fmt, va_list args)
395 {
396 #ifdef STRFLAG
397 	FILE fakebuf;
398 
399 	fakebuf._flag = STRFLAG;
400 	/*
401 	 * Some os's are char * _ptr, others are unsigned char *_ptr...
402 	 * We cast to void * to make everyone happy.
403 	 */
404 	fakebuf._ptr = (void *)s;
405 	fakebuf._cnt = n-1;
406 	fakebuf._file = -1;
407 	_doprnt(fmt, args, &fakebuf);
408 	fakebuf._cnt++;
409 	putc('\0', &fakebuf);
410 	if (fakebuf._cnt<0)
411 	    fakebuf._cnt = 0;
412 	return (n-fakebuf._cnt-1);
413 #else
414 	(void)vsprintf(s, fmt, args);
415 	return strlen(s);
416 #endif
417 }
418 
419 int
420 snprintf(char *s, size_t n, const char *fmt, ...)
421 {
422 	va_list ap;
423 	int rv;
424 
425 	va_start(ap, fmt);
426 	rv = vsnprintf(s, n, fmt, ap);
427 	va_end(ap);
428 	return rv;
429 }
430 
431 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRFTIME)
432 size_t
433 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
434 {
435 	static char months[][4] = {
436 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
437 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
438 	};
439 
440 	size_t s;
441 	char *b = buf;
442 
443 	while (*fmt) {
444 		if (len == 0)
445 			return buf - b;
446 		if (*fmt != '%') {
447 			*buf++ = *fmt++;
448 			len--;
449 			continue;
450 		}
451 		switch (*fmt++) {
452 		case '%':
453 			*buf++ = '%';
454 			len--;
455 			if (len == 0) return buf - b;
456 			/*FALLTHROUGH*/
457 		case '\0':
458 			*buf = '%';
459 			s = 1;
460 			break;
461 		case 'k':
462 			s = snprintf(buf, len, "%d", tm->tm_hour);
463 			break;
464 		case 'M':
465 			s = snprintf(buf, len, "%02d", tm->tm_min);
466 			break;
467 		case 'S':
468 			s = snprintf(buf, len, "%02d", tm->tm_sec);
469 			break;
470 		case 'b':
471 			if (tm->tm_mon >= 12)
472 				return buf - b;
473 			s = snprintf(buf, len, "%s", months[tm->tm_mon]);
474 			break;
475 		case 'd':
476 			s = snprintf(buf, len, "%02d", tm->tm_mday);
477 			break;
478 		case 'Y':
479 			s = snprintf(buf, len, "%d", 1900 + tm->tm_year);
480 			break;
481 		default:
482 			s = snprintf(buf, len, "Unsupported format %c",
483 			    fmt[-1]);
484 			break;
485 		}
486 		buf += s;
487 		len -= s;
488 	}
489 }
490 #endif
491 #endif
492