1 /* $NetBSD: util.c,v 1.71 2020/12/05 17:25:41 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.71 2020/12/05 17:25:41 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 ::: "error: vsnprintf must be available"; 382 #endif 383 } 384 385 int 386 snprintf(char *s, size_t n, const char *fmt, ...) 387 { 388 va_list ap; 389 int rv; 390 391 va_start(ap, fmt); 392 rv = vsnprintf(s, n, fmt, ap); 393 va_end(ap); 394 return rv; 395 } 396 397 #endif 398