Home | History | Annotate | Line # | Download | only in make
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