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(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