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