Home | History | Annotate | Line # | Download | only in make
util.c revision 1.70
      1 /*	$NetBSD: util.c,v 1.70 2020/11/23 23:41:11 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.70 2020/11/23 23:41:11 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 *
     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 *
     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 *
     60 getenv(const char *name)
     61 {
     62     int offset;
     63 
     64     return findenv(name, &offset);
     65 }
     66 
     67 int
     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
     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
    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 /* strrcpy():
    158  *	Like strcpy, going backwards and returning the new pointer
    159  */
    160 static char *
    161 strrcpy(char *ptr, char *str)
    162 {
    163     int len = strlen(str);
    164 
    165     while (len != 0)
    166 	*--ptr = str[--len];
    167 
    168     return ptr;
    169 } /* end strrcpy */
    170 
    171 char    *sys_siglist[] = {
    172 	"Signal 0",
    173 	"Hangup",			/* SIGHUP    */
    174 	"Interrupt",			/* SIGINT    */
    175 	"Quit",				/* SIGQUIT   */
    176 	"Illegal instruction",		/* SIGILL    */
    177 	"Trace/BPT trap",		/* SIGTRAP   */
    178 	"IOT trap",			/* SIGIOT    */
    179 	"EMT trap",			/* SIGEMT    */
    180 	"Floating point exception",	/* SIGFPE    */
    181 	"Killed",			/* SIGKILL   */
    182 	"Bus error",			/* SIGBUS    */
    183 	"Segmentation fault",		/* SIGSEGV   */
    184 	"Bad system call",		/* SIGSYS    */
    185 	"Broken pipe",			/* SIGPIPE   */
    186 	"Alarm clock",			/* SIGALRM   */
    187 	"Terminated",			/* SIGTERM   */
    188 	"User defined signal 1",	/* SIGUSR1   */
    189 	"User defined signal 2",	/* SIGUSR2   */
    190 	"Child exited",			/* SIGCLD    */
    191 	"Power-fail restart",		/* SIGPWR    */
    192 	"Virtual timer expired",	/* SIGVTALRM */
    193 	"Profiling timer expired",	/* SIGPROF   */
    194 	"I/O possible",			/* SIGIO     */
    195 	"Window size changes",		/* SIGWINDOW */
    196 	"Stopped (signal)",		/* SIGSTOP   */
    197 	"Stopped",			/* SIGTSTP   */
    198 	"Continued",			/* SIGCONT   */
    199 	"Stopped (tty input)",		/* SIGTTIN   */
    200 	"Stopped (tty output)",		/* SIGTTOU   */
    201 	"Urgent I/O condition",		/* SIGURG    */
    202 	"Remote lock lost (NFS)",	/* SIGLOST   */
    203 	"Signal 31",			/* reserved  */
    204 	"DIL signal"			/* SIGDIL    */
    205 };
    206 #endif /* __hpux__ || __hpux */
    207 
    208 #if defined(__hpux__) || defined(__hpux)
    209 #include <sys/types.h>
    210 #include <sys/syscall.h>
    211 #include <sys/signal.h>
    212 #include <sys/stat.h>
    213 #include <dirent.h>
    214 #include <sys/time.h>
    215 #include <unistd.h>
    216 
    217 int
    218 killpg(int pid, int sig)
    219 {
    220     return kill(-pid, sig);
    221 }
    222 
    223 #if !defined(BSD) && !defined(d_fileno)
    224 # define d_fileno d_ino
    225 #endif
    226 
    227 #ifndef DEV_DEV_COMPARE
    228 # define DEV_DEV_COMPARE(a, b) ((a) == (b))
    229 #endif
    230 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/')))
    231 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1])))
    232 
    233 char *
    234 getwd(char *pathname)
    235 {
    236     DIR    *dp;
    237     struct dirent *d;
    238     extern int errno;
    239 
    240     struct stat st_root, st_cur, st_next, st_dotdot;
    241     char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
    242     char   *pathptr, *nextpathptr, *cur_name_add;
    243 
    244     /* find the inode of root */
    245     if (stat("/", &st_root) == -1) {
    246 	(void)sprintf(pathname,
    247 			"getwd: Cannot stat \"/\" (%s)", strerror(errno));
    248 	return NULL;
    249     }
    250     pathbuf[MAXPATHLEN - 1] = '\0';
    251     pathptr = &pathbuf[MAXPATHLEN - 1];
    252     nextpathbuf[MAXPATHLEN - 1] = '\0';
    253     cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
    254 
    255     /* find the inode of the current directory */
    256     if (lstat(".", &st_cur) == -1) {
    257 	(void)sprintf(pathname,
    258 			"getwd: Cannot stat \".\" (%s)", strerror(errno));
    259 	return NULL;
    260     }
    261     nextpathptr = strrcpy(nextpathptr, "../");
    262 
    263     /* Descend to root */
    264     for (;;) {
    265 
    266 	/* look if we found root yet */
    267 	if (st_cur.st_ino == st_root.st_ino &&
    268 	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
    269 	    (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
    270 	    return pathname;
    271 	}
    272 
    273 	/* open the parent directory */
    274 	if (stat(nextpathptr, &st_dotdot) == -1) {
    275 	    (void)sprintf(pathname,
    276 			    "getwd: Cannot stat directory \"%s\" (%s)",
    277 			    nextpathptr, strerror(errno));
    278 	    return NULL;
    279 	}
    280 	if ((dp = opendir(nextpathptr)) == NULL) {
    281 	    (void)sprintf(pathname,
    282 			    "getwd: Cannot open directory \"%s\" (%s)",
    283 			    nextpathptr, strerror(errno));
    284 	    return NULL;
    285 	}
    286 
    287 	/* look in the parent for the entry with the same inode */
    288 	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
    289 	    /* Parent has same device. No need to stat every member */
    290 	    for (d = readdir(dp); d != NULL; d = readdir(dp))
    291 		if (d->d_fileno == st_cur.st_ino)
    292 		    break;
    293 	} else {
    294 	    /*
    295 	     * Parent has a different device. This is a mount point so we
    296 	     * need to stat every member
    297 	     */
    298 	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
    299 		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
    300 		    continue;
    301 		(void)strcpy(cur_name_add, d->d_name);
    302 		if (lstat(nextpathptr, &st_next) == -1) {
    303 		    (void)sprintf(pathname,
    304 			"getwd: Cannot stat \"%s\" (%s)",
    305 			d->d_name, strerror(errno));
    306 		    (void)closedir(dp);
    307 		    return NULL;
    308 		}
    309 		/* check if we found it yet */
    310 		if (st_next.st_ino == st_cur.st_ino &&
    311 		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
    312 		    break;
    313 	    }
    314 	}
    315 	if (d == NULL) {
    316 	    (void)sprintf(pathname,
    317 		"getwd: Cannot find \".\" in \"..\"");
    318 	    (void)closedir(dp);
    319 	    return NULL;
    320 	}
    321 	st_cur = st_dotdot;
    322 	pathptr = strrcpy(pathptr, d->d_name);
    323 	pathptr = strrcpy(pathptr, "/");
    324 	nextpathptr = strrcpy(nextpathptr, "../");
    325 	(void)closedir(dp);
    326 	*cur_name_add = '\0';
    327     }
    328 } /* end getwd */
    329 #endif /* __hpux */
    330 
    331 /* force posix signals */
    332 SignalProc
    333 bmake_signal(int s, SignalProc a)
    334 {
    335     struct sigaction sa, osa;
    336 
    337     sa.sa_handler = a;
    338     sigemptyset(&sa.sa_mask);
    339     sa.sa_flags = SA_RESTART;
    340 
    341     if (sigaction(s, &sa, &osa) == -1)
    342 	return SIG_ERR;
    343     else
    344 	return osa.sa_handler;
    345 }
    346 
    347 #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF)
    348 #include <stdarg.h>
    349 
    350 #if !defined(__osf__)
    351 #ifdef _IOSTRG
    352 #define STRFLAG	(_IOSTRG|_IOWRT)	/* no _IOWRT: avoid stdio bug */
    353 #else
    354 #if 0
    355 #define STRFLAG	(_IOREAD)		/* XXX: Assume svr4 stdio */
    356 #endif
    357 #endif /* _IOSTRG */
    358 #endif /* __osf__ */
    359 
    360 int
    361 vsnprintf(char *s, size_t n, const char *fmt, va_list args)
    362 {
    363 #ifdef STRFLAG
    364 	FILE fakebuf;
    365 
    366 	fakebuf._flag = STRFLAG;
    367 	/*
    368 	 * Some os's are char * _ptr, others are unsigned char *_ptr...
    369 	 * We cast to void * to make everyone happy.
    370 	 */
    371 	fakebuf._ptr = (void *)s;
    372 	fakebuf._cnt = n - 1;
    373 	fakebuf._file = -1;
    374 	_doprnt(fmt, args, &fakebuf);
    375 	fakebuf._cnt++;
    376 	putc('\0', &fakebuf);
    377 	if (fakebuf._cnt < 0)
    378 	    fakebuf._cnt = 0;
    379 	return n - fakebuf._cnt - 1;
    380 #else
    381 	(void)vsprintf(s, fmt, args);
    382 	return strlen(s);
    383 #endif
    384 }
    385 
    386 int
    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