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