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@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.) 16void 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 22void 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 31void 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. 40void *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. 49void *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.) 58void *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. 67char *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. 78char *xstrdup(char *s) 79{ 80 return xstrndup(s, strlen(s)); 81} 82 83// Die unless we can allocate enough space to sprintf() into. 84char *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 106void 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 116void xputs(char *s) 117{ 118 if (EOF == puts(s) || fflush(stdout) || ferror(stdout)) perror_exit("write"); 119} 120 121void xputc(char c) 122{ 123 if (EOF == fputc(c, stdout) || fflush(stdout) || ferror(stdout)) 124 perror_exit("write"); 125} 126 127void 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. 134void 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 146pid_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 198int 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 212pid_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 224int 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. 232int xrun(char **argv) 233{ 234 return xpclose_both(xpopen_both(argv, 0), 0); 235} 236 237void 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.) 243void 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. 249int 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. 257int xopen(char *path, int flags) 258{ 259 return xcreate(path, flags, 0); 260} 261 262void xclose(int fd) 263{ 264 if (close(fd)) perror_exit("xclose"); 265} 266 267int 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 276FILE *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 *. 286FILE *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. 294size_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 302void 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 311void 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 318off_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 326char *xgetcwd(void) 327{ 328 char *buf = getcwd(NULL, 0); 329 if (!buf) perror_exit("xgetcwd"); 330 331 return buf; 332} 333 334void 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 341char *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 446error: 447 close(dirfd); 448 llist_traverse(todo, free); 449 llist_traverse(done, free); 450 451 return NULL; 452} 453 454void xchdir(char *path) 455{ 456 if (chdir(path)) error_exit("chdir '%s'", path); 457} 458 459void xchroot(char *path) 460{ 461 if (chroot(path)) error_exit("chroot '%s'", path); 462 xchdir("/"); 463} 464 465struct 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 472struct 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 480struct 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 496struct 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 512struct 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 520struct 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 531void 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. 539char *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 561char *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 568int 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. 581void 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 614void 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 627long 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 653void 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 663char *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 675void 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