1 /* xwrap.c - wrappers around existing library functions. 2 * 3 * Functions with the x prefix are wrappers that either succeed or kill the 4 * program with an error message, but never return failure. They usually have 5 * the same arguments and return value as the function they wrap. 6 * 7 * Copyright 2006 Rob Landley <rob (at) landley.net> 8 */ 9 10 #include "toys.h" 11 12 // strcpy and strncat with size checking. Size is the total space in "dest", 13 // including null terminator. Exit if there's not enough space for the string 14 // (including space for the null terminator), because silently truncating is 15 // still broken behavior. (And leaving the string unterminated is INSANE.) 16 void xstrncpy(char *dest, char *src, size_t size) 17 { 18 if (strlen(src)+1 > size) error_exit("'%s' > %ld bytes", src, (long)size); 19 strcpy(dest, src); 20 } 21 22 void xstrncat(char *dest, char *src, size_t size) 23 { 24 long len = strlen(src); 25 26 if (len+strlen(dest)+1 > size) 27 error_exit("'%s%s' > %ld bytes", dest, src, (long)size); 28 strcpy(dest+len, src); 29 } 30 31 void xexit(void) 32 { 33 if (fflush(NULL) || ferror(stdout)) 34 if (!toys.exitval) perror_msg("write"); 35 if (toys.rebound) longjmp(*toys.rebound, 1); 36 else exit(toys.exitval); 37 } 38 39 // Die unless we can allocate memory. 40 void *xmalloc(size_t size) 41 { 42 void *ret = malloc(size); 43 if (!ret) error_exit("xmalloc"); 44 45 return ret; 46 } 47 48 // Die unless we can allocate prezeroed memory. 49 void *xzalloc(size_t size) 50 { 51 void *ret = xmalloc(size); 52 memset(ret, 0, size); 53 return ret; 54 } 55 56 // Die unless we can change the size of an existing allocation, possibly 57 // moving it. (Notice different arguments from libc function.) 58 void *xrealloc(void *ptr, size_t size) 59 { 60 ptr = realloc(ptr, size); 61 if (!ptr) error_exit("xrealloc"); 62 63 return ptr; 64 } 65 66 // Die unless we can allocate a copy of this many bytes of string. 67 char *xstrndup(char *s, size_t n) 68 { 69 char *ret = strndup(s, ++n); 70 71 if (!ret) error_exit("xstrndup"); 72 ret[--n] = 0; 73 74 return ret; 75 } 76 77 // Die unless we can allocate a copy of this string. 78 char *xstrdup(char *s) 79 { 80 return xstrndup(s, strlen(s)); 81 } 82 83 // Die unless we can allocate enough space to sprintf() into. 84 char *xmprintf(char *format, ...) 85 { 86 va_list va, va2; 87 int len; 88 char *ret; 89 90 va_start(va, format); 91 va_copy(va2, va); 92 93 // How long is it? 94 len = vsnprintf(0, 0, format, va); 95 len++; 96 va_end(va); 97 98 // Allocate and do the sprintf() 99 ret = xmalloc(len); 100 vsnprintf(ret, len, format, va2); 101 va_end(va2); 102 103 return ret; 104 } 105 106 void xprintf(char *format, ...) 107 { 108 va_list va; 109 va_start(va, format); 110 111 vprintf(format, va); 112 va_end(va); 113 if (fflush(stdout) || ferror(stdout)) perror_exit("write"); 114 } 115 116 void xputs(char *s) 117 { 118 if (EOF == puts(s) || fflush(stdout) || ferror(stdout)) perror_exit("write"); 119 } 120 121 void xputc(char c) 122 { 123 if (EOF == fputc(c, stdout) || fflush(stdout) || ferror(stdout)) 124 perror_exit("write"); 125 } 126 127 void xflush(void) 128 { 129 if (fflush(stdout) || ferror(stdout)) perror_exit("write");; 130 } 131 132 // Die unless we can exec argv[] (or run builtin command). Note that anything 133 // with a path isn't a builtin, so /bin/sh won't match the builtin sh. 134 void xexec(char **argv) 135 { 136 if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE) toy_exec(argv); 137 execvp(argv[0], argv); 138 139 perror_exit("exec %s", argv[0]); 140 } 141 142 // Spawn child process, capturing stdin/stdout. 143 // argv[]: command to exec. If null, child returns to original program. 144 // pipes[2]: stdin, stdout of new process. If -1 will not have pipe allocated. 145 // return: pid of child process 146 pid_t xpopen_both(char **argv, int *pipes) 147 { 148 int cestnepasun[4], pid; 149 150 // Make the pipes? Not this won't set either pipe to 0 because if fds are 151 // allocated in order and if fd0 was free it would go to cestnepasun[0] 152 if (pipes) { 153 for (pid = 0; pid < 2; pid++) { 154 if (pipes[pid] == -1) continue; 155 if (pipe(cestnepasun+(2*pid))) perror_exit("pipe"); 156 pipes[pid] = cestnepasun[pid+1]; 157 } 158 } 159 160 // Child process 161 if (!(pid = xfork())) { 162 // Dance of the stdin/stdout redirection. 163 if (pipes) { 164 // if we had no stdin/out, pipe handles could overlap, so test for it 165 // and free up potentially overlapping pipe handles before reuse 166 if (pipes[1] != -1) close(cestnepasun[2]); 167 if (pipes[0] != -1) { 168 close(cestnepasun[1]); 169 if (cestnepasun[0]) { 170 dup2(cestnepasun[0], 0); 171 close(cestnepasun[0]); 172 } 173 } 174 if (pipes[1] != -1) { 175 dup2(cestnepasun[3], 1); 176 dup2(cestnepasun[3], 2); 177 if (cestnepasun[3] > 2 || !cestnepasun[3]) close(cestnepasun[3]); 178 } 179 } 180 if (argv) { 181 if (CFG_TOYBOX) toy_exec(argv); 182 execvp(argv[0], argv); 183 _exit(127); 184 } 185 return 0; 186 187 } 188 189 // Parent process 190 if (pipes) { 191 if (pipes[0] != -1) close(cestnepasun[0]); 192 if (pipes[1] != -1) close(cestnepasun[3]); 193 } 194 195 return pid; 196 } 197 198 int xpclose_both(pid_t pid, int *pipes) 199 { 200 int rc = 127; 201 202 if (pipes) { 203 close(pipes[0]); 204 close(pipes[1]); 205 } 206 waitpid(pid, &rc, 0); 207 208 return WIFEXITED(rc) ? WEXITSTATUS(rc) : WTERMSIG(rc) + 127; 209 } 210 211 // Wrapper to xpopen with a pipe for just one of stdin/stdout 212 pid_t xpopen(char **argv, int *pipe, int stdout) 213 { 214 int pipes[2], pid; 215 216 pipes[!stdout] = -1; 217 pipes[!!stdout] = 0; 218 pid = xpopen_both(argv, pipes); 219 *pipe = pid ? pipes[!!stdout] : -1; 220 221 return pid; 222 } 223 224 int xpclose(pid_t pid, int pipe) 225 { 226 close(pipe); 227 228 return xpclose_both(pid, 0); 229 } 230 231 // Call xpopen and wait for it to finish, keeping existing stdin/stdout. 232 int xrun(char **argv) 233 { 234 return xpclose_both(xpopen_both(argv, 0), 0); 235 } 236 237 void xaccess(char *path, int flags) 238 { 239 if (access(path, flags)) perror_exit("Can't access '%s'", path); 240 } 241 242 // Die unless we can delete a file. (File must exist to be deleted.) 243 void xunlink(char *path) 244 { 245 if (unlink(path)) perror_exit("unlink '%s'", path); 246 } 247 248 // Die unless we can open/create a file, returning file descriptor. 249 int xcreate(char *path, int flags, int mode) 250 { 251 int fd = open(path, flags^O_CLOEXEC, mode); 252 if (fd == -1) perror_exit("%s", path); 253 return fd; 254 } 255 256 // Die unless we can open a file, returning file descriptor. 257 int xopen(char *path, int flags) 258 { 259 return xcreate(path, flags, 0); 260 } 261 262 void xclose(int fd) 263 { 264 if (close(fd)) perror_exit("xclose"); 265 } 266 267 int xdup(int fd) 268 { 269 if (fd != -1) { 270 fd = dup(fd); 271 if (fd == -1) perror_exit("xdup"); 272 } 273 return fd; 274 } 275 276 FILE *xfdopen(int fd, char *mode) 277 { 278 FILE *f = fdopen(fd, mode); 279 280 if (!f) perror_exit("xfdopen"); 281 282 return f; 283 } 284 285 // Die unless we can open/create a file, returning FILE *. 286 FILE *xfopen(char *path, char *mode) 287 { 288 FILE *f = fopen(path, mode); 289 if (!f) perror_exit("No file %s", path); 290 return f; 291 } 292 293 // Die if there's an error other than EOF. 294 size_t xread(int fd, void *buf, size_t len) 295 { 296 ssize_t ret = read(fd, buf, len); 297 if (ret < 0) perror_exit("xread"); 298 299 return ret; 300 } 301 302 void xreadall(int fd, void *buf, size_t len) 303 { 304 if (len != readall(fd, buf, len)) perror_exit("xreadall"); 305 } 306 307 // There's no xwriteall(), just xwrite(). When we read, there may or may not 308 // be more data waiting. When we write, there is data and it had better go 309 // somewhere. 310 311 void xwrite(int fd, void *buf, size_t len) 312 { 313 if (len != writeall(fd, buf, len)) perror_exit("xwrite"); 314 } 315 316 // Die if lseek fails, probably due to being called on a pipe. 317 318 off_t xlseek(int fd, off_t offset, int whence) 319 { 320 offset = lseek(fd, offset, whence); 321 if (offset<0) perror_exit("lseek"); 322 323 return offset; 324 } 325 326 char *xgetcwd(void) 327 { 328 char *buf = getcwd(NULL, 0); 329 if (!buf) perror_exit("xgetcwd"); 330 331 return buf; 332 } 333 334 void xstat(char *path, struct stat *st) 335 { 336 if(stat(path, st)) perror_exit("Can't stat %s", path); 337 } 338 339 // Cannonicalize path, even to file with one or more missing components at end. 340 // if exact, require last path component to exist 341 char *xabspath(char *path, int exact) 342 { 343 struct string_list *todo, *done = 0; 344 int try = 9999, dirfd = open("/", 0);; 345 char buf[4096], *ret; 346 347 // If this isn't an absolute path, start with cwd. 348 if (*path != '/') { 349 char *temp = xgetcwd(); 350 351 splitpath(path, splitpath(temp, &todo)); 352 free(temp); 353 } else splitpath(path, &todo); 354 355 // Iterate through path components 356 while (todo) { 357 struct string_list *new = llist_pop(&todo), **tail; 358 ssize_t len; 359 360 if (!try--) { 361 errno = ELOOP; 362 goto error; 363 } 364 365 // Removable path componenents. 366 if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) { 367 int x = new->str[1]; 368 369 free(new); 370 if (x) { 371 if (done) free(llist_pop(&done)); 372 len = 0; 373 } else continue; 374 375 // Is this a symlink? 376 } else len=readlinkat(dirfd, new->str, buf, 4096); 377 378 if (len>4095) goto error; 379 if (len<1) { 380 int fd; 381 char *s = ".."; 382 383 // For .. just move dirfd 384 if (len) { 385 // Not a symlink: add to linked list, move dirfd, fail if error 386 if ((exact || todo) && errno != EINVAL) goto error; 387 new->next = done; 388 done = new; 389 if (errno == EINVAL && !todo) break; 390 s = new->str; 391 } 392 fd = openat(dirfd, s, 0); 393 if (fd == -1 && (exact || todo || errno != ENOENT)) goto error; 394 close(dirfd); 395 dirfd = fd; 396 continue; 397 } 398 399 // If this symlink is to an absolute path, discard existing resolved path 400 buf[len] = 0; 401 if (*buf == '/') { 402 llist_traverse(done, free); 403 done=0; 404 close(dirfd); 405 dirfd = open("/", 0); 406 } 407 free(new); 408 409 // prepend components of new path. Note symlink to "/" will leave new NULL 410 tail = splitpath(buf, &new); 411 412 // symlink to "/" will return null and leave tail alone 413 if (new) { 414 *tail = todo; 415 todo = new; 416 } 417 } 418 close(dirfd); 419 420 // At this point done has the path, in reverse order. Reverse list while 421 // calculating buffer length. 422 423 try = 2; 424 while (done) { 425 struct string_list *temp = llist_pop(&done);; 426 427 if (todo) try++; 428 try += strlen(temp->str); 429 temp->next = todo; 430 todo = temp; 431 } 432 433 // Assemble return buffer 434 435 ret = xmalloc(try); 436 *ret = '/'; 437 ret [try = 1] = 0; 438 while (todo) { 439 if (try>1) ret[try++] = '/'; 440 try = stpcpy(ret+try, todo->str) - ret; 441 free(llist_pop(&todo)); 442 } 443 444 return ret; 445 446 error: 447 close(dirfd); 448 llist_traverse(todo, free); 449 llist_traverse(done, free); 450 451 return NULL; 452 } 453 454 void xchdir(char *path) 455 { 456 if (chdir(path)) error_exit("chdir '%s'", path); 457 } 458 459 void xchroot(char *path) 460 { 461 if (chroot(path)) error_exit("chroot '%s'", path); 462 xchdir("/"); 463 } 464 465 struct passwd *xgetpwuid(uid_t uid) 466 { 467 struct passwd *pwd = getpwuid(uid); 468 if (!pwd) error_exit("bad uid %ld", (long)uid); 469 return pwd; 470 } 471 472 struct group *xgetgrgid(gid_t gid) 473 { 474 struct group *group = getgrgid(gid); 475 476 if (!group) perror_exit("gid %ld", (long)gid); 477 return group; 478 } 479 480 struct passwd *xgetpwnamid(char *user) 481 { 482 struct passwd *up = getpwnam(user); 483 uid_t uid; 484 485 if (!up) { 486 char *s = 0; 487 488 uid = estrtol(user, &s, 10); 489 if (!errno && s && !*s) up = getpwuid(uid); 490 } 491 if (!up) perror_exit("user '%s'", user); 492 493 return up; 494 } 495 496 struct group *xgetgrnamid(char *group) 497 { 498 struct group *gr = getgrnam(group); 499 gid_t gid; 500 501 if (!gr) { 502 char *s = 0; 503 504 gid = estrtol(group, &s, 10); 505 if (!errno && s && !*s) gr = getgrgid(gid); 506 } 507 if (!gr) perror_exit("group '%s'", group); 508 509 return gr; 510 } 511 512 struct passwd *xgetpwnam(char *name) 513 { 514 struct passwd *up = getpwnam(name); 515 516 if (!up) perror_exit("user '%s'", name); 517 return up; 518 } 519 520 struct group *xgetgrnam(char *name) 521 { 522 struct group *gr = getgrnam(name); 523 524 if (!gr) perror_exit("group '%s'", name); 525 return gr; 526 } 527 528 // setuid() can fail (for example, too many processes belonging to that user), 529 // which opens a security hole if the process continues as the original user. 530 531 void xsetuser(struct passwd *pwd) 532 { 533 if (initgroups(pwd->pw_name, pwd->pw_gid) || setgid(pwd->pw_uid) 534 || setuid(pwd->pw_uid)) perror_exit("xsetuser '%s'", pwd->pw_name); 535 } 536 537 // This can return null (meaning file not found). It just won't return null 538 // for memory allocation reasons. 539 char *xreadlink(char *name) 540 { 541 int len, size = 0; 542 char *buf = 0; 543 544 // Grow by 64 byte chunks until it's big enough. 545 for(;;) { 546 size +=64; 547 buf = xrealloc(buf, size); 548 len = readlink(name, buf, size); 549 550 if (len<0) { 551 free(buf); 552 return 0; 553 } 554 if (len<size) { 555 buf[len]=0; 556 return buf; 557 } 558 } 559 } 560 561 char *xreadfile(char *name, char *buf, off_t len) 562 { 563 if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name); 564 565 return buf; 566 } 567 568 int xioctl(int fd, int request, void *data) 569 { 570 int rc; 571 572 errno = 0; 573 rc = ioctl(fd, request, data); 574 if (rc == -1 && errno) perror_exit("ioctl %x", request); 575 576 return rc; 577 } 578 579 // Open a /var/run/NAME.pid file, dying if we can't write it or if it currently 580 // exists and is this executable. 581 void xpidfile(char *name) 582 { 583 char pidfile[256], spid[32]; 584 int i, fd; 585 pid_t pid; 586 587 sprintf(pidfile, "/var/run/%s.pid", name); 588 // Try three times to open the sucker. 589 for (i=0; i<3; i++) { 590 fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644); 591 if (fd != -1) break; 592 593 // If it already existed, read it. Loop for race condition. 594 fd = open(pidfile, O_RDONLY); 595 if (fd == -1) continue; 596 597 // Is the old program still there? 598 spid[xread(fd, spid, sizeof(spid)-1)] = 0; 599 close(fd); 600 pid = atoi(spid); 601 if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile); 602 603 // An else with more sanity checking might be nice here. 604 } 605 606 if (i == 3) error_exit("xpidfile %s", name); 607 608 xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid())); 609 close(fd); 610 } 611 612 // Copy the rest of in to out and close both files. 613 614 void xsendfile(int in, int out) 615 { 616 long len; 617 618 if (in<0) return; 619 for (;;) { 620 len = xread(in, libbuf, sizeof(libbuf)); 621 if (len<1) break; 622 xwrite(out, libbuf, len); 623 } 624 } 625 626 // parse fractional seconds with optional s/m/h/d suffix 627 long xparsetime(char *arg, long units, long *fraction) 628 { 629 double d; 630 long l; 631 632 if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg); 633 else l = strtoul(arg, &arg, 10); 634 635 // Parse suffix 636 if (*arg) { 637 int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg); 638 639 if (i == -1) error_exit("Unknown suffix '%c'", *arg); 640 if (CFG_TOYBOX_FLOAT) d *= ismhd[i]; 641 else l *= ismhd[i]; 642 } 643 644 if (CFG_TOYBOX_FLOAT) { 645 l = (long)d; 646 if (fraction) *fraction = units*(d-l); 647 } else if (fraction) *fraction = 0; 648 649 return l; 650 } 651 652 // Compile a regular expression into a regex_t 653 void xregcomp(regex_t *preg, char *regex, int cflags) 654 { 655 int rc = regcomp(preg, regex, cflags); 656 657 if (rc) { 658 regerror(rc, preg, libbuf, sizeof(libbuf)); 659 error_exit("xregcomp: %s", libbuf); 660 } 661 } 662 663 char *xtzset(char *new) 664 { 665 char *tz = getenv("TZ"); 666 667 if (tz) tz = xstrdup(tz); 668 if (setenv("TZ", new, 1)) perror_exit("setenv"); 669 tzset(); 670 671 return tz; 672 } 673 674 // Set a signal handler 675 void xsignal(int signal, void *handler) 676 { 677 struct sigaction *sa = (void *)libbuf; 678 679 memset(sa, 0, sizeof(struct sigaction)); 680 sa->sa_handler = handler; 681 682 if (sigaction(signal, sa, 0)) perror_exit("xsignal %d", signal); 683 } 684