1 1.78 rillig /* $NetBSD: util.c,v 1.78 2021/12/15 12:58:01 rillig Exp $ */ 2 1.4 christos 3 1.1 cgd /* 4 1.1 cgd * Missing stuff from OS's 5 1.1 cgd */ 6 1.54 joerg #if defined(__MINT__) || defined(__linux__) 7 1.54 joerg #include <signal.h> 8 1.54 joerg #endif 9 1.4 christos 10 1.32 wiz #include <sys/param.h> 11 1.32 wiz 12 1.30 tv #include <errno.h> 13 1.24 wrstuden #include <time.h> 14 1.50 sjg #include <signal.h> 15 1.32 wiz 16 1.2 glass #include "make.h" 17 1.1 cgd 18 1.78 rillig MAKE_RCSID("$NetBSD: util.c,v 1.78 2021/12/15 12:58:01 rillig Exp $"); 19 1.60 rillig 20 1.35 ross #if !defined(MAKE_NATIVE) && !defined(HAVE_STRERROR) 21 1.1 cgd extern int errno, sys_nerr; 22 1.1 cgd extern char *sys_errlist[]; 23 1.1 cgd 24 1.1 cgd char * 25 1.32 wiz strerror(int e) 26 1.1 cgd { 27 1.77 rillig static char buf[100]; 28 1.77 rillig if (e < 0 || e >= sys_nerr) { 29 1.77 rillig snprintf(buf, sizeof buf, "Unknown error %d", e); 30 1.77 rillig return buf; 31 1.77 rillig } else 32 1.77 rillig return sys_errlist[e]; 33 1.1 cgd } 34 1.1 cgd #endif 35 1.1 cgd 36 1.35 ross #if !defined(MAKE_NATIVE) && !defined(HAVE_SETENV) 37 1.46 christos extern char **environ; 38 1.46 christos 39 1.46 christos static char * 40 1.46 christos findenv(const char *name, int *offset) 41 1.1 cgd { 42 1.46 christos size_t i, len; 43 1.46 christos char *p, *q; 44 1.1 cgd 45 1.53 sjg len = strlen(name); 46 1.46 christos for (i = 0; (q = environ[i]); i++) { 47 1.51 mbalmer p = strchr(q, '='); 48 1.76 rillig if (p == NULL || p - q != len) 49 1.46 christos continue; 50 1.53 sjg if (strncmp(name, q, len) == 0) { 51 1.46 christos *offset = i; 52 1.46 christos return q + len + 1; 53 1.46 christos } 54 1.46 christos } 55 1.46 christos *offset = i; 56 1.46 christos return NULL; 57 1.46 christos } 58 1.1 cgd 59 1.52 sjg char * 60 1.52 sjg getenv(const char *name) 61 1.52 sjg { 62 1.77 rillig int offset; 63 1.52 sjg 64 1.77 rillig return findenv(name, &offset); 65 1.52 sjg } 66 1.52 sjg 67 1.46 christos int 68 1.46 christos unsetenv(const char *name) 69 1.46 christos { 70 1.46 christos char **p; 71 1.46 christos int offset; 72 1.8 christos 73 1.46 christos if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) { 74 1.46 christos errno = EINVAL; 75 1.46 christos return -1; 76 1.46 christos } 77 1.1 cgd 78 1.78 rillig while (findenv(name, &offset)) { /* if set multiple times */ 79 1.74 rillig for (p = &environ[offset];; p++) 80 1.46 christos if (!(*p = *(p + 1))) 81 1.46 christos break; 82 1.46 christos } 83 1.46 christos return 0; 84 1.46 christos } 85 1.1 cgd 86 1.46 christos int 87 1.46 christos setenv(const char *name, const char *value, int rewrite) 88 1.46 christos { 89 1.46 christos char *c, **newenv; 90 1.46 christos const char *cc; 91 1.46 christos size_t l_value, size; 92 1.46 christos int offset; 93 1.46 christos 94 1.46 christos if (name == NULL || value == NULL) { 95 1.46 christos errno = EINVAL; 96 1.46 christos return -1; 97 1.46 christos } 98 1.1 cgd 99 1.78 rillig if (*value == '=') /* no `=' in value */ 100 1.68 rillig value++; 101 1.46 christos l_value = strlen(value); 102 1.46 christos 103 1.46 christos /* find if already exists */ 104 1.46 christos if ((c = findenv(name, &offset))) { 105 1.46 christos if (!rewrite) 106 1.46 christos return 0; 107 1.46 christos if (strlen(c) >= l_value) /* old larger; copy over */ 108 1.46 christos goto copy; 109 1.46 christos } else { /* create new slot */ 110 1.46 christos size = sizeof(char *) * (offset + 2); 111 1.52 sjg if (savedEnv == environ) { /* just increase size */ 112 1.52 sjg if ((newenv = realloc(savedEnv, size)) == NULL) 113 1.46 christos return -1; 114 1.52 sjg savedEnv = newenv; 115 1.46 christos } else { /* get new space */ 116 1.46 christos /* 117 1.46 christos * We don't free here because we don't know if 118 1.46 christos * the first allocation is valid on all OS's 119 1.46 christos */ 120 1.52 sjg if ((savedEnv = malloc(size)) == NULL) 121 1.46 christos return -1; 122 1.52 sjg (void)memcpy(savedEnv, environ, size - sizeof(char *)); 123 1.46 christos } 124 1.52 sjg environ = savedEnv; 125 1.46 christos environ[offset + 1] = NULL; 126 1.46 christos } 127 1.74 rillig for (cc = name; *cc && *cc != '='; cc++) /* no `=' in name */ 128 1.46 christos continue; 129 1.46 christos size = cc - name; 130 1.46 christos /* name + `=' + value */ 131 1.46 christos if ((environ[offset] = malloc(size + l_value + 2)) == NULL) 132 1.46 christos return -1; 133 1.46 christos c = environ[offset]; 134 1.46 christos (void)memcpy(c, name, size); 135 1.46 christos c += size; 136 1.46 christos *c++ = '='; 137 1.46 christos copy: 138 1.46 christos (void)memcpy(c, value, l_value + 1); 139 1.46 christos return 0; 140 1.46 christos } 141 1.1 cgd 142 1.46 christos #ifdef TEST 143 1.46 christos int 144 1.46 christos main(int argc, char *argv[]) 145 1.46 christos { 146 1.46 christos setenv(argv[1], argv[2], 0); 147 1.46 christos printf("%s\n", getenv(argv[1])); 148 1.46 christos unsetenv(argv[1]); 149 1.46 christos printf("%s\n", getenv(argv[1])); 150 1.46 christos return 0; 151 1.46 christos } 152 1.46 christos #endif 153 1.1 cgd 154 1.1 cgd #endif 155 1.1 cgd 156 1.26 christos #if defined(__hpux__) || defined(__hpux) 157 1.73 rillig /* 158 1.73 rillig * strrcpy(): 159 1.26 christos * Like strcpy, going backwards and returning the new pointer 160 1.26 christos */ 161 1.26 christos static char * 162 1.32 wiz strrcpy(char *ptr, char *str) 163 1.26 christos { 164 1.77 rillig int len = strlen(str); 165 1.26 christos 166 1.77 rillig while (len != 0) 167 1.77 rillig *--ptr = str[--len]; 168 1.26 christos 169 1.77 rillig return ptr; 170 1.77 rillig } 171 1.26 christos 172 1.77 rillig char *sys_siglist[] = { 173 1.58 rillig "Signal 0", 174 1.69 rillig "Hangup", /* SIGHUP */ 175 1.69 rillig "Interrupt", /* SIGINT */ 176 1.69 rillig "Quit", /* SIGQUIT */ 177 1.69 rillig "Illegal instruction", /* SIGILL */ 178 1.69 rillig "Trace/BPT trap", /* SIGTRAP */ 179 1.69 rillig "IOT trap", /* SIGIOT */ 180 1.69 rillig "EMT trap", /* SIGEMT */ 181 1.69 rillig "Floating point exception", /* SIGFPE */ 182 1.69 rillig "Killed", /* SIGKILL */ 183 1.69 rillig "Bus error", /* SIGBUS */ 184 1.69 rillig "Segmentation fault", /* SIGSEGV */ 185 1.69 rillig "Bad system call", /* SIGSYS */ 186 1.69 rillig "Broken pipe", /* SIGPIPE */ 187 1.69 rillig "Alarm clock", /* SIGALRM */ 188 1.69 rillig "Terminated", /* SIGTERM */ 189 1.69 rillig "User defined signal 1", /* SIGUSR1 */ 190 1.69 rillig "User defined signal 2", /* SIGUSR2 */ 191 1.69 rillig "Child exited", /* SIGCLD */ 192 1.69 rillig "Power-fail restart", /* SIGPWR */ 193 1.69 rillig "Virtual timer expired", /* SIGVTALRM */ 194 1.69 rillig "Profiling timer expired", /* SIGPROF */ 195 1.69 rillig "I/O possible", /* SIGIO */ 196 1.69 rillig "Window size changes", /* SIGWINDOW */ 197 1.69 rillig "Stopped (signal)", /* SIGSTOP */ 198 1.69 rillig "Stopped", /* SIGTSTP */ 199 1.69 rillig "Continued", /* SIGCONT */ 200 1.69 rillig "Stopped (tty input)", /* SIGTTIN */ 201 1.69 rillig "Stopped (tty output)", /* SIGTTOU */ 202 1.69 rillig "Urgent I/O condition", /* SIGURG */ 203 1.69 rillig "Remote lock lost (NFS)", /* SIGLOST */ 204 1.69 rillig "Signal 31", /* reserved */ 205 1.69 rillig "DIL signal" /* SIGDIL */ 206 1.26 christos }; 207 1.26 christos #endif /* __hpux__ || __hpux */ 208 1.26 christos 209 1.33 lukem #if defined(__hpux__) || defined(__hpux) 210 1.1 cgd #include <sys/types.h> 211 1.1 cgd #include <sys/syscall.h> 212 1.1 cgd #include <sys/signal.h> 213 1.1 cgd #include <sys/stat.h> 214 1.1 cgd #include <dirent.h> 215 1.1 cgd #include <sys/time.h> 216 1.1 cgd #include <unistd.h> 217 1.1 cgd 218 1.1 cgd int 219 1.44 christos killpg(int pid, int sig) 220 1.1 cgd { 221 1.77 rillig return kill(-pid, sig); 222 1.1 cgd } 223 1.1 cgd 224 1.1 cgd #if !defined(BSD) && !defined(d_fileno) 225 1.1 cgd # define d_fileno d_ino 226 1.1 cgd #endif 227 1.1 cgd 228 1.1 cgd #ifndef DEV_DEV_COMPARE 229 1.1 cgd # define DEV_DEV_COMPARE(a, b) ((a) == (b)) 230 1.1 cgd #endif 231 1.1 cgd #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/'))) 232 1.1 cgd #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1]))) 233 1.1 cgd 234 1.32 wiz char * 235 1.32 wiz getwd(char *pathname) 236 1.1 cgd { 237 1.1 cgd DIR *dp; 238 1.1 cgd struct dirent *d; 239 1.1 cgd extern int errno; 240 1.1 cgd 241 1.1 cgd struct stat st_root, st_cur, st_next, st_dotdot; 242 1.1 cgd char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2]; 243 1.1 cgd char *pathptr, *nextpathptr, *cur_name_add; 244 1.1 cgd 245 1.1 cgd /* find the inode of root */ 246 1.1 cgd if (stat("/", &st_root) == -1) { 247 1.37 christos (void)sprintf(pathname, 248 1.1 cgd "getwd: Cannot stat \"/\" (%s)", strerror(errno)); 249 1.47 dsl return NULL; 250 1.1 cgd } 251 1.1 cgd pathbuf[MAXPATHLEN - 1] = '\0'; 252 1.1 cgd pathptr = &pathbuf[MAXPATHLEN - 1]; 253 1.1 cgd nextpathbuf[MAXPATHLEN - 1] = '\0'; 254 1.1 cgd cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1]; 255 1.1 cgd 256 1.1 cgd /* find the inode of the current directory */ 257 1.1 cgd if (lstat(".", &st_cur) == -1) { 258 1.37 christos (void)sprintf(pathname, 259 1.1 cgd "getwd: Cannot stat \".\" (%s)", strerror(errno)); 260 1.47 dsl return NULL; 261 1.1 cgd } 262 1.1 cgd nextpathptr = strrcpy(nextpathptr, "../"); 263 1.1 cgd 264 1.1 cgd /* Descend to root */ 265 1.1 cgd for (;;) { 266 1.1 cgd 267 1.1 cgd /* look if we found root yet */ 268 1.1 cgd if (st_cur.st_ino == st_root.st_ino && 269 1.1 cgd DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) { 270 1.37 christos (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr); 271 1.56 rillig return pathname; 272 1.1 cgd } 273 1.1 cgd 274 1.1 cgd /* open the parent directory */ 275 1.1 cgd if (stat(nextpathptr, &st_dotdot) == -1) { 276 1.37 christos (void)sprintf(pathname, 277 1.1 cgd "getwd: Cannot stat directory \"%s\" (%s)", 278 1.1 cgd nextpathptr, strerror(errno)); 279 1.47 dsl return NULL; 280 1.1 cgd } 281 1.1 cgd if ((dp = opendir(nextpathptr)) == NULL) { 282 1.37 christos (void)sprintf(pathname, 283 1.1 cgd "getwd: Cannot open directory \"%s\" (%s)", 284 1.1 cgd nextpathptr, strerror(errno)); 285 1.47 dsl return NULL; 286 1.1 cgd } 287 1.1 cgd 288 1.1 cgd /* look in the parent for the entry with the same inode */ 289 1.1 cgd if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) { 290 1.1 cgd /* Parent has same device. No need to stat every member */ 291 1.8 christos for (d = readdir(dp); d != NULL; d = readdir(dp)) 292 1.1 cgd if (d->d_fileno == st_cur.st_ino) 293 1.1 cgd break; 294 1.67 rillig } else { 295 1.8 christos /* 296 1.8 christos * Parent has a different device. This is a mount point so we 297 1.8 christos * need to stat every member 298 1.1 cgd */ 299 1.1 cgd for (d = readdir(dp); d != NULL; d = readdir(dp)) { 300 1.1 cgd if (ISDOT(d->d_name) || ISDOTDOT(d->d_name)) 301 1.1 cgd continue; 302 1.37 christos (void)strcpy(cur_name_add, d->d_name); 303 1.1 cgd if (lstat(nextpathptr, &st_next) == -1) { 304 1.37 christos (void)sprintf(pathname, 305 1.23 christos "getwd: Cannot stat \"%s\" (%s)", 306 1.23 christos d->d_name, strerror(errno)); 307 1.37 christos (void)closedir(dp); 308 1.47 dsl return NULL; 309 1.1 cgd } 310 1.1 cgd /* check if we found it yet */ 311 1.1 cgd if (st_next.st_ino == st_cur.st_ino && 312 1.8 christos DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) 313 1.1 cgd break; 314 1.1 cgd } 315 1.1 cgd } 316 1.1 cgd if (d == NULL) { 317 1.37 christos (void)sprintf(pathname, 318 1.23 christos "getwd: Cannot find \".\" in \"..\""); 319 1.37 christos (void)closedir(dp); 320 1.47 dsl return NULL; 321 1.1 cgd } 322 1.1 cgd st_cur = st_dotdot; 323 1.1 cgd pathptr = strrcpy(pathptr, d->d_name); 324 1.1 cgd pathptr = strrcpy(pathptr, "/"); 325 1.1 cgd nextpathptr = strrcpy(nextpathptr, "../"); 326 1.37 christos (void)closedir(dp); 327 1.1 cgd *cur_name_add = '\0'; 328 1.1 cgd } 329 1.1 cgd } /* end getwd */ 330 1.1 cgd #endif /* __hpux */ 331 1.5 christos 332 1.50 sjg /* force posix signals */ 333 1.59 rillig SignalProc 334 1.59 rillig bmake_signal(int s, SignalProc a) 335 1.5 christos { 336 1.72 rillig struct sigaction sa, osa; 337 1.5 christos 338 1.72 rillig sa.sa_handler = a; 339 1.72 rillig sigemptyset(&sa.sa_mask); 340 1.72 rillig sa.sa_flags = SA_RESTART; 341 1.72 rillig 342 1.72 rillig if (sigaction(s, &sa, &osa) == -1) 343 1.72 rillig return SIG_ERR; 344 1.72 rillig else 345 1.72 rillig return osa.sa_handler; 346 1.5 christos } 347 1.10 christos 348 1.35 ross #if !defined(MAKE_NATIVE) && !defined(HAVE_VSNPRINTF) 349 1.10 christos #include <stdarg.h> 350 1.10 christos 351 1.25 drochner #if !defined(__osf__) 352 1.10 christos #ifdef _IOSTRG 353 1.10 christos #define STRFLAG (_IOSTRG|_IOWRT) /* no _IOWRT: avoid stdio bug */ 354 1.10 christos #else 355 1.11 christos #if 0 356 1.10 christos #define STRFLAG (_IOREAD) /* XXX: Assume svr4 stdio */ 357 1.10 christos #endif 358 1.25 drochner #endif /* _IOSTRG */ 359 1.25 drochner #endif /* __osf__ */ 360 1.10 christos 361 1.10 christos int 362 1.32 wiz vsnprintf(char *s, size_t n, const char *fmt, va_list args) 363 1.10 christos { 364 1.19 christos #ifdef STRFLAG 365 1.10 christos FILE fakebuf; 366 1.10 christos 367 1.10 christos fakebuf._flag = STRFLAG; 368 1.10 christos /* 369 1.10 christos * Some os's are char * _ptr, others are unsigned char *_ptr... 370 1.10 christos * We cast to void * to make everyone happy. 371 1.10 christos */ 372 1.39 christos fakebuf._ptr = (void *)s; 373 1.66 rillig fakebuf._cnt = n - 1; 374 1.10 christos fakebuf._file = -1; 375 1.10 christos _doprnt(fmt, args, &fakebuf); 376 1.10 christos fakebuf._cnt++; 377 1.10 christos putc('\0', &fakebuf); 378 1.66 rillig if (fakebuf._cnt < 0) 379 1.77 rillig fakebuf._cnt = 0; 380 1.66 rillig return n - fakebuf._cnt - 1; 381 1.11 christos #else 382 1.71 rillig ::: "error: vsnprintf must be available"; 383 1.11 christos #endif 384 1.10 christos } 385 1.10 christos 386 1.10 christos int 387 1.10 christos snprintf(char *s, size_t n, const char *fmt, ...) 388 1.10 christos { 389 1.10 christos va_list ap; 390 1.10 christos int rv; 391 1.32 wiz 392 1.10 christos va_start(ap, fmt); 393 1.10 christos rv = vsnprintf(s, n, fmt, ap); 394 1.10 christos va_end(ap); 395 1.10 christos return rv; 396 1.16 christos } 397 1.16 christos 398 1.5 christos #endif 399