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