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