xref: /netbsd/usr.bin/make/util.c (revision 43c15f27)
1 /*	$NetBSD: util.c,v 1.78 2021/12/15 12:58:01 rillig Exp $	*/
2 
3 /*
4  * Missing stuff from OS's
5  */
6 #if defined(__MINT__) || defined(__linux__)
7 #include <signal.h>
8 #endif
9 
10 #include <sys/param.h>
11 
12 #include <errno.h>
13 #include <time.h>
14 #include <signal.h>
15 
16 #include "make.h"
17 
18 MAKE_RCSID("$NetBSD: util.c,v 1.78 2021/12/15 12:58:01 rillig Exp $");
19 
20 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRERROR)
21 extern int errno, sys_nerr;
22 extern char *sys_errlist[];
23 
24 char *
strerror(int e)25 strerror(int e)
26 {
27 	static char buf[100];
28 	if (e < 0 || e >= sys_nerr) {
29 		snprintf(buf, sizeof buf, "Unknown error %d", e);
30 		return buf;
31 	} else
32 		return sys_errlist[e];
33 }
34 #endif
35 
36 #if !defined(MAKE_NATIVE) && !defined(HAVE_SETENV)
37 extern char **environ;
38 
39 static char *
findenv(const char * name,int * offset)40 findenv(const char *name, int *offset)
41 {
42 	size_t i, len;
43 	char *p, *q;
44 
45 	len = strlen(name);
46 	for (i = 0; (q = environ[i]); i++) {
47 		p = strchr(q, '=');
48 		if (p == NULL || p - q != len)
49 			continue;
50 		if (strncmp(name, q, len) == 0) {
51 			*offset = i;
52 			return q + len + 1;
53 		}
54 	}
55 	*offset = i;
56 	return NULL;
57 }
58 
59 char *
getenv(const char * name)60 getenv(const char *name)
61 {
62 	int offset;
63 
64 	return findenv(name, &offset);
65 }
66 
67 int
unsetenv(const char * name)68 unsetenv(const char *name)
69 {
70 	char **p;
71 	int offset;
72 
73 	if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) {
74 		errno = EINVAL;
75 		return -1;
76 	}
77 
78 	while (findenv(name, &offset)) {	/* if set multiple times */
79 		for (p = &environ[offset];; p++)
80 			if (!(*p = *(p + 1)))
81 				break;
82 	}
83 	return 0;
84 }
85 
86 int
setenv(const char * name,const char * value,int rewrite)87 setenv(const char *name, const char *value, int rewrite)
88 {
89 	char *c, **newenv;
90 	const char *cc;
91 	size_t l_value, size;
92 	int offset;
93 
94 	if (name == NULL || value == NULL) {
95 		errno = EINVAL;
96 		return -1;
97 	}
98 
99 	if (*value == '=')	/* no `=' in value */
100 		value++;
101 	l_value = strlen(value);
102 
103 	/* find if already exists */
104 	if ((c = findenv(name, &offset))) {
105 		if (!rewrite)
106 			return 0;
107 		if (strlen(c) >= l_value)	/* old larger; copy over */
108 			goto copy;
109 	} else {					/* create new slot */
110 		size = sizeof(char *) * (offset + 2);
111 		if (savedEnv == environ) {		/* just increase size */
112 			if ((newenv = realloc(savedEnv, size)) == NULL)
113 				return -1;
114 			savedEnv = newenv;
115 		} else {				/* get new space */
116 			/*
117 			 * We don't free here because we don't know if
118 			 * the first allocation is valid on all OS's
119 			 */
120 			if ((savedEnv = malloc(size)) == NULL)
121 				return -1;
122 			(void)memcpy(savedEnv, environ, size - sizeof(char *));
123 		}
124 		environ = savedEnv;
125 		environ[offset + 1] = NULL;
126 	}
127 	for (cc = name; *cc && *cc != '='; cc++)	/* no `=' in name */
128 		continue;
129 	size = cc - name;
130 	/* name + `=' + value */
131 	if ((environ[offset] = malloc(size + l_value + 2)) == NULL)
132 		return -1;
133 	c = environ[offset];
134 	(void)memcpy(c, name, size);
135 	c += size;
136 	*c++ = '=';
137 copy:
138 	(void)memcpy(c, value, l_value + 1);
139 	return 0;
140 }
141 
142 #ifdef TEST
143 int
main(int argc,char * argv[])144 main(int argc, char *argv[])
145 {
146 	setenv(argv[1], argv[2], 0);
147 	printf("%s\n", getenv(argv[1]));
148 	unsetenv(argv[1]);
149 	printf("%s\n", getenv(argv[1]));
150 	return 0;
151 }
152 #endif
153 
154 #endif
155 
156 #if defined(__hpux__) || defined(__hpux)
157 /*
158  * strrcpy():
159  *	Like strcpy, going backwards and returning the new pointer
160  */
161 static char *
strrcpy(char * ptr,char * str)162 strrcpy(char *ptr, char *str)
163 {
164 	int len = strlen(str);
165 
166 	while (len != 0)
167 		*--ptr = str[--len];
168 
169 	return ptr;
170 }
171 
172 char *sys_siglist[] = {
173 	"Signal 0",
174 	"Hangup",			/* SIGHUP    */
175 	"Interrupt",			/* SIGINT    */
176 	"Quit",				/* SIGQUIT   */
177 	"Illegal instruction",		/* SIGILL    */
178 	"Trace/BPT trap",		/* SIGTRAP   */
179 	"IOT trap",			/* SIGIOT    */
180 	"EMT trap",			/* SIGEMT    */
181 	"Floating point exception",	/* SIGFPE    */
182 	"Killed",			/* SIGKILL   */
183 	"Bus error",			/* SIGBUS    */
184 	"Segmentation fault",		/* SIGSEGV   */
185 	"Bad system call",		/* SIGSYS    */
186 	"Broken pipe",			/* SIGPIPE   */
187 	"Alarm clock",			/* SIGALRM   */
188 	"Terminated",			/* SIGTERM   */
189 	"User defined signal 1",	/* SIGUSR1   */
190 	"User defined signal 2",	/* SIGUSR2   */
191 	"Child exited",			/* SIGCLD    */
192 	"Power-fail restart",		/* SIGPWR    */
193 	"Virtual timer expired",	/* SIGVTALRM */
194 	"Profiling timer expired",	/* SIGPROF   */
195 	"I/O possible",			/* SIGIO     */
196 	"Window size changes",		/* SIGWINDOW */
197 	"Stopped (signal)",		/* SIGSTOP   */
198 	"Stopped",			/* SIGTSTP   */
199 	"Continued",			/* SIGCONT   */
200 	"Stopped (tty input)",		/* SIGTTIN   */
201 	"Stopped (tty output)",		/* SIGTTOU   */
202 	"Urgent I/O condition",		/* SIGURG    */
203 	"Remote lock lost (NFS)",	/* SIGLOST   */
204 	"Signal 31",			/* reserved  */
205 	"DIL signal"			/* SIGDIL    */
206 };
207 #endif /* __hpux__ || __hpux */
208 
209 #if defined(__hpux__) || defined(__hpux)
210 #include <sys/types.h>
211 #include <sys/syscall.h>
212 #include <sys/signal.h>
213 #include <sys/stat.h>
214 #include <dirent.h>
215 #include <sys/time.h>
216 #include <unistd.h>
217 
218 int
killpg(int pid,int sig)219 killpg(int pid, int sig)
220 {
221 	return kill(-pid, sig);
222 }
223 
224 #if !defined(BSD) && !defined(d_fileno)
225 # define d_fileno d_ino
226 #endif
227 
228 #ifndef DEV_DEV_COMPARE
229 # define DEV_DEV_COMPARE(a, b) ((a) == (b))
230 #endif
231 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/')))
232 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1])))
233 
234 char *
getwd(char * pathname)235 getwd(char *pathname)
236 {
237     DIR    *dp;
238     struct dirent *d;
239     extern int errno;
240 
241     struct stat st_root, st_cur, st_next, st_dotdot;
242     char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
243     char   *pathptr, *nextpathptr, *cur_name_add;
244 
245     /* find the inode of root */
246     if (stat("/", &st_root) == -1) {
247 	(void)sprintf(pathname,
248 			"getwd: Cannot stat \"/\" (%s)", strerror(errno));
249 	return NULL;
250     }
251     pathbuf[MAXPATHLEN - 1] = '\0';
252     pathptr = &pathbuf[MAXPATHLEN - 1];
253     nextpathbuf[MAXPATHLEN - 1] = '\0';
254     cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
255 
256     /* find the inode of the current directory */
257     if (lstat(".", &st_cur) == -1) {
258 	(void)sprintf(pathname,
259 			"getwd: Cannot stat \".\" (%s)", strerror(errno));
260 	return NULL;
261     }
262     nextpathptr = strrcpy(nextpathptr, "../");
263 
264     /* Descend to root */
265     for (;;) {
266 
267 	/* look if we found root yet */
268 	if (st_cur.st_ino == st_root.st_ino &&
269 	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
270 	    (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
271 	    return pathname;
272 	}
273 
274 	/* open the parent directory */
275 	if (stat(nextpathptr, &st_dotdot) == -1) {
276 	    (void)sprintf(pathname,
277 			    "getwd: Cannot stat directory \"%s\" (%s)",
278 			    nextpathptr, strerror(errno));
279 	    return NULL;
280 	}
281 	if ((dp = opendir(nextpathptr)) == NULL) {
282 	    (void)sprintf(pathname,
283 			    "getwd: Cannot open directory \"%s\" (%s)",
284 			    nextpathptr, strerror(errno));
285 	    return NULL;
286 	}
287 
288 	/* look in the parent for the entry with the same inode */
289 	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
290 	    /* Parent has same device. No need to stat every member */
291 	    for (d = readdir(dp); d != NULL; d = readdir(dp))
292 		if (d->d_fileno == st_cur.st_ino)
293 		    break;
294 	} else {
295 	    /*
296 	     * Parent has a different device. This is a mount point so we
297 	     * need to stat every member
298 	     */
299 	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
300 		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
301 		    continue;
302 		(void)strcpy(cur_name_add, d->d_name);
303 		if (lstat(nextpathptr, &st_next) == -1) {
304 		    (void)sprintf(pathname,
305 			"getwd: Cannot stat \"%s\" (%s)",
306 			d->d_name, strerror(errno));
307 		    (void)closedir(dp);
308 		    return NULL;
309 		}
310 		/* check if we found it yet */
311 		if (st_next.st_ino == st_cur.st_ino &&
312 		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
313 		    break;
314 	    }
315 	}
316 	if (d == NULL) {
317 	    (void)sprintf(pathname,
318 		"getwd: Cannot find \".\" in \"..\"");
319 	    (void)closedir(dp);
320 	    return NULL;
321 	}
322 	st_cur = st_dotdot;
323 	pathptr = strrcpy(pathptr, d->d_name);
324 	pathptr = strrcpy(pathptr, "/");
325 	nextpathptr = strrcpy(nextpathptr, "../");
326 	(void)closedir(dp);
327 	*cur_name_add = '\0';
328     }
329 } /* end getwd */
330 #endif /* __hpux */
331 
332 /* force posix signals */
333 SignalProc
bmake_signal(int s,SignalProc a)334 bmake_signal(int s, SignalProc a)
335 {
336 	struct sigaction sa, osa;
337 
338 	sa.sa_handler = a;
339 	sigemptyset(&sa.sa_mask);
340 	sa.sa_flags = SA_RESTART;
341 
342 	if (sigaction(s, &sa, &osa) == -1)
343 		return SIG_ERR;
344 	else
345 		return osa.sa_handler;
346 }
347 
348 #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF)
349 #include <stdarg.h>
350 
351 #if !defined(__osf__)
352 #ifdef _IOSTRG
353 #define STRFLAG	(_IOSTRG|_IOWRT)	/* no _IOWRT: avoid stdio bug */
354 #else
355 #if 0
356 #define STRFLAG	(_IOREAD)		/* XXX: Assume svr4 stdio */
357 #endif
358 #endif /* _IOSTRG */
359 #endif /* __osf__ */
360 
361 int
vsnprintf(char * s,size_t n,const char * fmt,va_list args)362 vsnprintf(char *s, size_t n, const char *fmt, va_list args)
363 {
364 #ifdef STRFLAG
365 	FILE fakebuf;
366 
367 	fakebuf._flag = STRFLAG;
368 	/*
369 	 * Some os's are char * _ptr, others are unsigned char *_ptr...
370 	 * We cast to void * to make everyone happy.
371 	 */
372 	fakebuf._ptr = (void *)s;
373 	fakebuf._cnt = n - 1;
374 	fakebuf._file = -1;
375 	_doprnt(fmt, args, &fakebuf);
376 	fakebuf._cnt++;
377 	putc('\0', &fakebuf);
378 	if (fakebuf._cnt < 0)
379 		fakebuf._cnt = 0;
380 	return n - fakebuf._cnt - 1;
381 #else
382 	::: "error: vsnprintf must be available";
383 #endif
384 }
385 
386 int
snprintf(char * s,size_t n,const char * fmt,...)387 snprintf(char *s, size_t n, const char *fmt, ...)
388 {
389 	va_list ap;
390 	int rv;
391 
392 	va_start(ap, fmt);
393 	rv = vsnprintf(s, n, fmt, ap);
394 	va_end(ap);
395 	return rv;
396 }
397 
398 #endif
399