Home | History | Annotate | Line # | Download | only in make
util.c revision 1.54
      1 /*	$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg 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.54 2013/11/26 13:44:41 joerg Exp $";
     12 #else
     13 #include <sys/cdefs.h>
     14 #ifndef lint
     15 __RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg 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(__hpux__) && !defined(__hpux)
    233 void
    234 srandom(long seed)
    235 {
    236     srand48(seed);
    237 }
    238 
    239 long
    240 random(void)
    241 {
    242     return lrand48();
    243 }
    244 #endif
    245 
    246 #if !defined(__hpux__) && !defined(__hpux)
    247 int
    248 utimes(char *file, struct timeval tvp[2])
    249 {
    250     struct utimbuf t;
    251 
    252     t.actime  = tvp[0].tv_sec;
    253     t.modtime = tvp[1].tv_sec;
    254     return(utime(file, &t));
    255 }
    256 #endif
    257 
    258 #if !defined(BSD) && !defined(d_fileno)
    259 # define d_fileno d_ino
    260 #endif
    261 
    262 #ifndef DEV_DEV_COMPARE
    263 # define DEV_DEV_COMPARE(a, b) ((a) == (b))
    264 #endif
    265 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/')))
    266 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1])))
    267 
    268 char *
    269 getwd(char *pathname)
    270 {
    271     DIR    *dp;
    272     struct dirent *d;
    273     extern int errno;
    274 
    275     struct stat st_root, st_cur, st_next, st_dotdot;
    276     char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
    277     char   *pathptr, *nextpathptr, *cur_name_add;
    278 
    279     /* find the inode of root */
    280     if (stat("/", &st_root) == -1) {
    281 	(void)sprintf(pathname,
    282 			"getwd: Cannot stat \"/\" (%s)", strerror(errno));
    283 	return NULL;
    284     }
    285     pathbuf[MAXPATHLEN - 1] = '\0';
    286     pathptr = &pathbuf[MAXPATHLEN - 1];
    287     nextpathbuf[MAXPATHLEN - 1] = '\0';
    288     cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
    289 
    290     /* find the inode of the current directory */
    291     if (lstat(".", &st_cur) == -1) {
    292 	(void)sprintf(pathname,
    293 			"getwd: Cannot stat \".\" (%s)", strerror(errno));
    294 	return NULL;
    295     }
    296     nextpathptr = strrcpy(nextpathptr, "../");
    297 
    298     /* Descend to root */
    299     for (;;) {
    300 
    301 	/* look if we found root yet */
    302 	if (st_cur.st_ino == st_root.st_ino &&
    303 	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
    304 	    (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
    305 	    return (pathname);
    306 	}
    307 
    308 	/* open the parent directory */
    309 	if (stat(nextpathptr, &st_dotdot) == -1) {
    310 	    (void)sprintf(pathname,
    311 			    "getwd: Cannot stat directory \"%s\" (%s)",
    312 			    nextpathptr, strerror(errno));
    313 	    return NULL;
    314 	}
    315 	if ((dp = opendir(nextpathptr)) == NULL) {
    316 	    (void)sprintf(pathname,
    317 			    "getwd: Cannot open directory \"%s\" (%s)",
    318 			    nextpathptr, strerror(errno));
    319 	    return NULL;
    320 	}
    321 
    322 	/* look in the parent for the entry with the same inode */
    323 	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
    324 	    /* Parent has same device. No need to stat every member */
    325 	    for (d = readdir(dp); d != NULL; d = readdir(dp))
    326 		if (d->d_fileno == st_cur.st_ino)
    327 		    break;
    328 	}
    329 	else {
    330 	    /*
    331 	     * Parent has a different device. This is a mount point so we
    332 	     * need to stat every member
    333 	     */
    334 	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
    335 		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
    336 		    continue;
    337 		(void)strcpy(cur_name_add, d->d_name);
    338 		if (lstat(nextpathptr, &st_next) == -1) {
    339 		    (void)sprintf(pathname,
    340 			"getwd: Cannot stat \"%s\" (%s)",
    341 			d->d_name, strerror(errno));
    342 		    (void)closedir(dp);
    343 		    return NULL;
    344 		}
    345 		/* check if we found it yet */
    346 		if (st_next.st_ino == st_cur.st_ino &&
    347 		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
    348 		    break;
    349 	    }
    350 	}
    351 	if (d == NULL) {
    352 	    (void)sprintf(pathname,
    353 		"getwd: Cannot find \".\" in \"..\"");
    354 	    (void)closedir(dp);
    355 	    return NULL;
    356 	}
    357 	st_cur = st_dotdot;
    358 	pathptr = strrcpy(pathptr, d->d_name);
    359 	pathptr = strrcpy(pathptr, "/");
    360 	nextpathptr = strrcpy(nextpathptr, "../");
    361 	(void)closedir(dp);
    362 	*cur_name_add = '\0';
    363     }
    364 } /* end getwd */
    365 #endif /* __hpux */
    366 
    367 /* force posix signals */
    368 void (*
    369 bmake_signal(int s, void (*a)(int)))(int)
    370 {
    371     struct sigaction sa, osa;
    372 
    373     sa.sa_handler = a;
    374     sigemptyset(&sa.sa_mask);
    375     sa.sa_flags = SA_RESTART;
    376 
    377     if (sigaction(s, &sa, &osa) == -1)
    378 	return SIG_ERR;
    379     else
    380 	return osa.sa_handler;
    381 }
    382 
    383 #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF)
    384 #include <stdarg.h>
    385 
    386 #if !defined(__osf__)
    387 #ifdef _IOSTRG
    388 #define STRFLAG	(_IOSTRG|_IOWRT)	/* no _IOWRT: avoid stdio bug */
    389 #else
    390 #if 0
    391 #define STRFLAG	(_IOREAD)		/* XXX: Assume svr4 stdio */
    392 #endif
    393 #endif /* _IOSTRG */
    394 #endif /* __osf__ */
    395 
    396 int
    397 vsnprintf(char *s, size_t n, const char *fmt, va_list args)
    398 {
    399 #ifdef STRFLAG
    400 	FILE fakebuf;
    401 
    402 	fakebuf._flag = STRFLAG;
    403 	/*
    404 	 * Some os's are char * _ptr, others are unsigned char *_ptr...
    405 	 * We cast to void * to make everyone happy.
    406 	 */
    407 	fakebuf._ptr = (void *)s;
    408 	fakebuf._cnt = n-1;
    409 	fakebuf._file = -1;
    410 	_doprnt(fmt, args, &fakebuf);
    411 	fakebuf._cnt++;
    412 	putc('\0', &fakebuf);
    413 	if (fakebuf._cnt<0)
    414 	    fakebuf._cnt = 0;
    415 	return (n-fakebuf._cnt-1);
    416 #else
    417 	(void)vsprintf(s, fmt, args);
    418 	return strlen(s);
    419 #endif
    420 }
    421 
    422 int
    423 snprintf(char *s, size_t n, const char *fmt, ...)
    424 {
    425 	va_list ap;
    426 	int rv;
    427 
    428 	va_start(ap, fmt);
    429 	rv = vsnprintf(s, n, fmt, ap);
    430 	va_end(ap);
    431 	return rv;
    432 }
    433 
    434 #if !defined(MAKE_NATIVE) && !defined(HAVE_STRFTIME)
    435 size_t
    436 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
    437 {
    438 	static char months[][4] = {
    439 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
    440 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    441 	};
    442 
    443 	size_t s;
    444 	char *b = buf;
    445 
    446 	while (*fmt) {
    447 		if (len == 0)
    448 			return buf - b;
    449 		if (*fmt != '%') {
    450 			*buf++ = *fmt++;
    451 			len--;
    452 			continue;
    453 		}
    454 		switch (*fmt++) {
    455 		case '%':
    456 			*buf++ = '%';
    457 			len--;
    458 			if (len == 0) return buf - b;
    459 			/*FALLTHROUGH*/
    460 		case '\0':
    461 			*buf = '%';
    462 			s = 1;
    463 			break;
    464 		case 'k':
    465 			s = snprintf(buf, len, "%d", tm->tm_hour);
    466 			break;
    467 		case 'M':
    468 			s = snprintf(buf, len, "%02d", tm->tm_min);
    469 			break;
    470 		case 'S':
    471 			s = snprintf(buf, len, "%02d", tm->tm_sec);
    472 			break;
    473 		case 'b':
    474 			if (tm->tm_mon >= 12)
    475 				return buf - b;
    476 			s = snprintf(buf, len, "%s", months[tm->tm_mon]);
    477 			break;
    478 		case 'd':
    479 			s = snprintf(buf, len, "%02d", tm->tm_mday);
    480 			break;
    481 		case 'Y':
    482 			s = snprintf(buf, len, "%d", 1900 + tm->tm_year);
    483 			break;
    484 		default:
    485 			s = snprintf(buf, len, "Unsupported format %c",
    486 			    fmt[-1]);
    487 			break;
    488 		}
    489 		buf += s;
    490 		len -= s;
    491 	}
    492 }
    493 #endif
    494 #endif
    495