1d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley/* xwrap.c - wrappers around existing library functions.
2d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley *
3d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley * Functions with the x prefix are wrappers that either succeed or kill the
4d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley * program with an error message, but never return failure. They usually have
5d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley * the same arguments and return value as the function they wrap.
6d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley *
7d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley * Copyright 2006 Rob Landley <rob@landley.net>
8d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley */
9d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
10d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley#include "toys.h"
11d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
122fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley// strcpy and strncat with size checking. Size is the total space in "dest",
132fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley// including null terminator. Exit if there's not enough space for the string
142fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley// (including space for the null terminator), because silently truncating is
152fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley// still broken behavior. (And leaving the string unterminated is INSANE.)
16d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xstrncpy(char *dest, char *src, size_t size)
17d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
183704f826b42d65e9d1da3c4f4084902d32eaba3aRob Landley  if (strlen(src)+1 > size) error_exit("'%s' > %ld bytes", src, (long)size);
19d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  strcpy(dest, src);
20d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
21d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
222fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landleyvoid xstrncat(char *dest, char *src, size_t size)
232fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley{
242fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley  long len = strlen(src);
252fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley
262fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley  if (len+strlen(dest)+1 > size)
2770a84a356b1c56743618362867b9300007d11998Rob Landley    error_exit("'%s%s' > %ld bytes", dest, src, (long)size);
282fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley  strcpy(dest+len, src);
292fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley}
302fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley
31d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xexit(void)
32d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
33aad492fd87d689c443e87561c23abc2e12b785a9Rob Landley  if (fflush(NULL) || ferror(stdout))
34aad492fd87d689c443e87561c23abc2e12b785a9Rob Landley    if (!toys.exitval) perror_msg("write");
35d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (toys.rebound) longjmp(*toys.rebound, 1);
36d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  else exit(toys.exitval);
37d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
38d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
39d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate memory.
40d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid *xmalloc(size_t size)
41d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
42d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  void *ret = malloc(size);
43d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!ret) error_exit("xmalloc");
44d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
45d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
46d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
47d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
48d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate prezeroed memory.
49d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid *xzalloc(size_t size)
50d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
51d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  void *ret = xmalloc(size);
52d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  memset(ret, 0, size);
53d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
54d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
55d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
56d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can change the size of an existing allocation, possibly
57d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// moving it.  (Notice different arguments from libc function.)
58d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid *xrealloc(void *ptr, size_t size)
59d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
60d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ptr = realloc(ptr, size);
61d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!ptr) error_exit("xrealloc");
62d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
63d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ptr;
64d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
65d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
66d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate a copy of this many bytes of string.
67d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xstrndup(char *s, size_t n)
68d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
692fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley  char *ret = strndup(s, ++n);
702fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley
712fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley  if (!ret) error_exit("xstrndup");
722fb85a3588bf2271e0506c5ab3bcb6a84bf77255Rob Landley  ret[--n] = 0;
73d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
74d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
75d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
76d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
77d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate a copy of this string.
78d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xstrdup(char *s)
79d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
80d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return xstrndup(s, strlen(s));
81d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
82d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
83d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate enough space to sprintf() into.
8459d85e2bb065a3bdc27868acb7a65f89d872c7faRob Landleychar *xmprintf(char *format, ...)
85d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
86d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_list va, va2;
87d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int len;
88d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *ret;
89d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
90d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_start(va, format);
91d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_copy(va2, va);
92d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
93d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // How long is it?
94d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  len = vsnprintf(0, 0, format, va);
95d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  len++;
96d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_end(va);
97d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
98d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Allocate and do the sprintf()
99d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ret = xmalloc(len);
100d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  vsnprintf(ret, len, format, va2);
101d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_end(va2);
102d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
103d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
104d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
105d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
106d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xprintf(char *format, ...)
107d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
108d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_list va;
109d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_start(va, format);
110d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
111d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  vprintf(format, va);
11221f3c8db00f0d4a3f0989559847d2564f4c73a11Rob Landley  va_end(va);
113ddbaa718dbe3370786eae97000f4c1e8bb259a61Rob Landley  if (fflush(stdout) || ferror(stdout)) perror_exit("write");
114d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
115d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
116d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xputs(char *s)
117d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
118ddbaa718dbe3370786eae97000f4c1e8bb259a61Rob Landley  if (EOF == puts(s) || fflush(stdout) || ferror(stdout)) perror_exit("write");
119d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
120d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
121d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xputc(char c)
122d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
123ddbaa718dbe3370786eae97000f4c1e8bb259a61Rob Landley  if (EOF == fputc(c, stdout) || fflush(stdout) || ferror(stdout))
124ddbaa718dbe3370786eae97000f4c1e8bb259a61Rob Landley    perror_exit("write");
125d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
126d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
127d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xflush(void)
128d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
129ddbaa718dbe3370786eae97000f4c1e8bb259a61Rob Landley  if (fflush(stdout) || ferror(stdout)) perror_exit("write");;
130d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
131d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
132d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can exec argv[] (or run builtin command).  Note that anything
133d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
134d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xexec(char **argv)
135d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
136977e48e1626b3e3f1f1f9b14f05ffc11e252455fRob Landley  if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE) toy_exec(argv);
137d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  execvp(argv[0], argv);
138d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
139d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  perror_exit("exec %s", argv[0]);
140d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
141d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
14244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley// Spawn child process, capturing stdin/stdout.
14344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley// argv[]: command to exec. If null, child returns to original program.
144360d57f843f5435a75270e54583430dcb8f62546Rob Landley// pipes[2]: stdin, stdout of new process. If -1 will not have pipe allocated.
14544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley// return: pid of child process
146360d57f843f5435a75270e54583430dcb8f62546Rob Landleypid_t xpopen_both(char **argv, int *pipes)
14744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley{
14844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  int cestnepasun[4], pid;
14944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
150360d57f843f5435a75270e54583430dcb8f62546Rob Landley  // Make the pipes? Not this won't set either pipe to 0 because if fds are
151360d57f843f5435a75270e54583430dcb8f62546Rob Landley  // allocated in order and if fd0 was free it would go to cestnepasun[0]
15244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  if (pipes) {
153360d57f843f5435a75270e54583430dcb8f62546Rob Landley    for (pid = 0; pid < 2; pid++) {
154360d57f843f5435a75270e54583430dcb8f62546Rob Landley      if (pipes[pid] == -1) continue;
155360d57f843f5435a75270e54583430dcb8f62546Rob Landley      if (pipe(cestnepasun+(2*pid))) perror_exit("pipe");
156360d57f843f5435a75270e54583430dcb8f62546Rob Landley      pipes[pid] = cestnepasun[pid+1];
157360d57f843f5435a75270e54583430dcb8f62546Rob Landley    }
15844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  }
15944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
16044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  // Child process
16144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  if (!(pid = xfork())) {
16244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    // Dance of the stdin/stdout redirection.
16344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    if (pipes) {
164360d57f843f5435a75270e54583430dcb8f62546Rob Landley      // if we had no stdin/out, pipe handles could overlap, so test for it
165360d57f843f5435a75270e54583430dcb8f62546Rob Landley      // and free up potentially overlapping pipe handles before reuse
166360d57f843f5435a75270e54583430dcb8f62546Rob Landley      if (pipes[1] != -1) close(cestnepasun[2]);
167360d57f843f5435a75270e54583430dcb8f62546Rob Landley      if (pipes[0] != -1) {
168360d57f843f5435a75270e54583430dcb8f62546Rob Landley        close(cestnepasun[1]);
169360d57f843f5435a75270e54583430dcb8f62546Rob Landley        if (cestnepasun[0]) {
170360d57f843f5435a75270e54583430dcb8f62546Rob Landley          dup2(cestnepasun[0], 0);
171360d57f843f5435a75270e54583430dcb8f62546Rob Landley          close(cestnepasun[0]);
172360d57f843f5435a75270e54583430dcb8f62546Rob Landley        }
173360d57f843f5435a75270e54583430dcb8f62546Rob Landley      }
174360d57f843f5435a75270e54583430dcb8f62546Rob Landley      if (pipes[1] != -1) {
175360d57f843f5435a75270e54583430dcb8f62546Rob Landley        dup2(cestnepasun[3], 1);
176360d57f843f5435a75270e54583430dcb8f62546Rob Landley        dup2(cestnepasun[3], 2);
177360d57f843f5435a75270e54583430dcb8f62546Rob Landley        if (cestnepasun[3] > 2 || !cestnepasun[3]) close(cestnepasun[3]);
17844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      }
17944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    }
18044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    if (argv) {
18144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      if (CFG_TOYBOX) toy_exec(argv);
18244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      execvp(argv[0], argv);
18344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley      _exit(127);
18444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    }
18544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    return 0;
18644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
187360d57f843f5435a75270e54583430dcb8f62546Rob Landley  }
18844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
189360d57f843f5435a75270e54583430dcb8f62546Rob Landley  // Parent process
190360d57f843f5435a75270e54583430dcb8f62546Rob Landley  if (pipes) {
191360d57f843f5435a75270e54583430dcb8f62546Rob Landley    if (pipes[0] != -1) close(cestnepasun[0]);
192360d57f843f5435a75270e54583430dcb8f62546Rob Landley    if (pipes[1] != -1) close(cestnepasun[3]);
19344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  }
194360d57f843f5435a75270e54583430dcb8f62546Rob Landley
195360d57f843f5435a75270e54583430dcb8f62546Rob Landley  return pid;
19644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley}
19744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
198360d57f843f5435a75270e54583430dcb8f62546Rob Landleyint xpclose_both(pid_t pid, int *pipes)
19944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley{
20044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  int rc = 127;
20144e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
20244e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  if (pipes) {
20344e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    close(pipes[0]);
20444e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley    close(pipes[1]);
20544e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  }
20644e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  waitpid(pid, &rc, 0);
20744e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
20844e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley  return WIFEXITED(rc) ? WEXITSTATUS(rc) : WTERMSIG(rc) + 127;
20944e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley}
21044e68a1bec9b342c01e2f4e6ccf9f1e7a3ee8081Rob Landley
211360d57f843f5435a75270e54583430dcb8f62546Rob Landley// Wrapper to xpopen with a pipe for just one of stdin/stdout
212360d57f843f5435a75270e54583430dcb8f62546Rob Landleypid_t xpopen(char **argv, int *pipe, int stdout)
213360d57f843f5435a75270e54583430dcb8f62546Rob Landley{
2148a9907119bf22f2279470be40cf40027dc37018cRob Landley  int pipes[2], pid;
215360d57f843f5435a75270e54583430dcb8f62546Rob Landley
2168a9907119bf22f2279470be40cf40027dc37018cRob Landley  pipes[!stdout] = -1;
2178a9907119bf22f2279470be40cf40027dc37018cRob Landley  pipes[!!stdout] = 0;
2188a9907119bf22f2279470be40cf40027dc37018cRob Landley  pid = xpopen_both(argv, pipes);
2198a9907119bf22f2279470be40cf40027dc37018cRob Landley  *pipe = pid ? pipes[!!stdout] : -1;
220360d57f843f5435a75270e54583430dcb8f62546Rob Landley
2218a9907119bf22f2279470be40cf40027dc37018cRob Landley  return pid;
222360d57f843f5435a75270e54583430dcb8f62546Rob Landley}
223360d57f843f5435a75270e54583430dcb8f62546Rob Landley
224360d57f843f5435a75270e54583430dcb8f62546Rob Landleyint xpclose(pid_t pid, int pipe)
225360d57f843f5435a75270e54583430dcb8f62546Rob Landley{
226360d57f843f5435a75270e54583430dcb8f62546Rob Landley  close(pipe);
227360d57f843f5435a75270e54583430dcb8f62546Rob Landley
228360d57f843f5435a75270e54583430dcb8f62546Rob Landley  return xpclose_both(pid, 0);
229360d57f843f5435a75270e54583430dcb8f62546Rob Landley}
230360d57f843f5435a75270e54583430dcb8f62546Rob Landley
231360d57f843f5435a75270e54583430dcb8f62546Rob Landley// Call xpopen and wait for it to finish, keeping existing stdin/stdout.
232360d57f843f5435a75270e54583430dcb8f62546Rob Landleyint xrun(char **argv)
233360d57f843f5435a75270e54583430dcb8f62546Rob Landley{
234360d57f843f5435a75270e54583430dcb8f62546Rob Landley  return xpclose_both(xpopen_both(argv, 0), 0);
235360d57f843f5435a75270e54583430dcb8f62546Rob Landley}
236360d57f843f5435a75270e54583430dcb8f62546Rob Landley
237d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xaccess(char *path, int flags)
238d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
239d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (access(path, flags)) perror_exit("Can't access '%s'", path);
240d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
241d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
242d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can delete a file.  (File must exist to be deleted.)
243d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xunlink(char *path)
244d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
245d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (unlink(path)) perror_exit("unlink '%s'", path);
246d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
247d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
248d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can open/create a file, returning file descriptor.
249d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xcreate(char *path, int flags, int mode)
250d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
251ccb73f8bf9191c01c90975958a210c47175bd98cRob Landley  int fd = open(path, flags^O_CLOEXEC, mode);
252d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (fd == -1) perror_exit("%s", path);
253d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return fd;
254d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
255d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
256d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can open a file, returning file descriptor.
257d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xopen(char *path, int flags)
258d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
259d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return xcreate(path, flags, 0);
260d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
261d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
262d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xclose(int fd)
263d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
264d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (close(fd)) perror_exit("xclose");
265d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
266d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
267d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xdup(int fd)
268d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
269d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (fd != -1) {
270d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    fd = dup(fd);
271d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (fd == -1) perror_exit("xdup");
272d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
273d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return fd;
274d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
275d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
2761aa75118c46c8fbe0eeead18974d25e5f13274d5Rob LandleyFILE *xfdopen(int fd, char *mode)
2771aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley{
2781aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley  FILE *f = fdopen(fd, mode);
2791aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley
2801aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley  if (!f) perror_exit("xfdopen");
2811aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley
2821aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley  return f;
2831aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley}
2841aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley
285d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can open/create a file, returning FILE *.
286d390493d76c4cda76c1c6d21897b0f246857e588Rob LandleyFILE *xfopen(char *path, char *mode)
287d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
288d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  FILE *f = fopen(path, mode);
289d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!f) perror_exit("No file %s", path);
290d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return f;
291d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
292d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
293d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die if there's an error other than EOF.
294d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleysize_t xread(int fd, void *buf, size_t len)
295d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
296d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ssize_t ret = read(fd, buf, len);
297d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (ret < 0) perror_exit("xread");
298d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
299d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
300d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
301d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
302d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xreadall(int fd, void *buf, size_t len)
303d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
304d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (len != readall(fd, buf, len)) perror_exit("xreadall");
305d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
306d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
307d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// There's no xwriteall(), just xwrite().  When we read, there may or may not
308d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// be more data waiting.  When we write, there is data and it had better go
309d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// somewhere.
310d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
311d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xwrite(int fd, void *buf, size_t len)
312d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
313d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (len != writeall(fd, buf, len)) perror_exit("xwrite");
314d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
315d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
316d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die if lseek fails, probably due to being called on a pipe.
317d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
318d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyoff_t xlseek(int fd, off_t offset, int whence)
319d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
320d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  offset = lseek(fd, offset, whence);
321d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (offset<0) perror_exit("lseek");
322d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
323d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return offset;
324d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
325d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
326d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xgetcwd(void)
327d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
328d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *buf = getcwd(NULL, 0);
329d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!buf) perror_exit("xgetcwd");
330d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
331d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return buf;
332d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
333d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
334d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xstat(char *path, struct stat *st)
335d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
336d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if(stat(path, st)) perror_exit("Can't stat %s", path);
337d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
338d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
339d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Cannonicalize path, even to file with one or more missing components at end.
340d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// if exact, require last path component to exist
3412c1cf4a02783e2a570ddf7b7ea968c7bed781f91Rob Landleychar *xabspath(char *path, int exact)
342d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
343d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  struct string_list *todo, *done = 0;
344d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int try = 9999, dirfd = open("/", 0);;
345d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char buf[4096], *ret;
346d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
347d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // If this isn't an absolute path, start with cwd.
348d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (*path != '/') {
349d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    char *temp = xgetcwd();
350d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
351d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    splitpath(path, splitpath(temp, &todo));
352d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    free(temp);
353d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  } else splitpath(path, &todo);
354d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
355d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Iterate through path components
356d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  while (todo) {
357d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    struct string_list *new = llist_pop(&todo), **tail;
358d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    ssize_t len;
359d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
360d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (!try--) {
361d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      errno = ELOOP;
362d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      goto error;
363d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
364d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
365d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // Removable path componenents.
366d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) {
367d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      int x = new->str[1];
368d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
369d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      free(new);
370d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if (x) {
371d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        if (done) free(llist_pop(&done));
372d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        len = 0;
373d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      } else continue;
374d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
375d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // Is this a symlink?
376d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    } else len=readlinkat(dirfd, new->str, buf, 4096);
377d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
378d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len>4095) goto error;
379d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<1) {
380d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      int fd;
381d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      char *s = "..";
382d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
383d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      // For .. just move dirfd
384d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if (len) {
385d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        // Not a symlink: add to linked list, move dirfd, fail if error
386d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        if ((exact || todo) && errno != EINVAL) goto error;
387d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        new->next = done;
388d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        done = new;
389d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        if (errno == EINVAL && !todo) break;
390d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        s = new->str;
391d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      }
392d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      fd = openat(dirfd, s, 0);
393d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
394d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      close(dirfd);
395d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      dirfd = fd;
396d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      continue;
397d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
398d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
399d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // If this symlink is to an absolute path, discard existing resolved path
400d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    buf[len] = 0;
401d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (*buf == '/') {
402d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      llist_traverse(done, free);
403d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      done=0;
404d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      close(dirfd);
405d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      dirfd = open("/", 0);
406d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
407d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    free(new);
408d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
409d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // prepend components of new path. Note symlink to "/" will leave new NULL
410d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    tail = splitpath(buf, &new);
411d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
412d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // symlink to "/" will return null and leave tail alone
413d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (new) {
414d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      *tail = todo;
415d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      todo = new;
416d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
417d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
418d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  close(dirfd);
419d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
420d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // At this point done has the path, in reverse order. Reverse list while
421d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // calculating buffer length.
422d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
423d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  try = 2;
424d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  while (done) {
425d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    struct string_list *temp = llist_pop(&done);;
426d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
427d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (todo) try++;
428d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    try += strlen(temp->str);
429d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    temp->next = todo;
430d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    todo = temp;
431d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
432d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
433d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Assemble return buffer
434d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
435d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ret = xmalloc(try);
436d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  *ret = '/';
437d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ret [try = 1] = 0;
438d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  while (todo) {
439d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (try>1) ret[try++] = '/';
440d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    try = stpcpy(ret+try, todo->str) - ret;
441d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    free(llist_pop(&todo));
442d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
443d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
444d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
445d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
446d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyerror:
447d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  close(dirfd);
448d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  llist_traverse(todo, free);
449d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  llist_traverse(done, free);
450d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
451d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return NULL;
452d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
453d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
454d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xchdir(char *path)
455d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
456d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (chdir(path)) error_exit("chdir '%s'", path);
457d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
458d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
459afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landleyvoid xchroot(char *path)
460afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley{
461afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley  if (chroot(path)) error_exit("chroot '%s'", path);
462afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley  xchdir("/");
463afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley}
464afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley
4659e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landleystruct passwd *xgetpwuid(uid_t uid)
4669e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley{
4679e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley  struct passwd *pwd = getpwuid(uid);
4685ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley  if (!pwd) error_exit("bad uid %ld", (long)uid);
4699e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley  return pwd;
4709e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley}
4719e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley
4729e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landleystruct group *xgetgrgid(gid_t gid)
4739e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley{
4749e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley  struct group *group = getgrgid(gid);
4754fd07e0f6698cdb873aab0113369eb36c81853a9Rob Landley
4764fd07e0f6698cdb873aab0113369eb36c81853a9Rob Landley  if (!group) perror_exit("gid %ld", (long)gid);
4779e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley  return group;
4789e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley}
4799e44a5841f0ab9bc03cefb5631c80f3e4e5a60feRob Landley
480b8140d18800e7094cdacb0a61526f46181dc132dRob Landleystruct passwd *xgetpwnamid(char *user)
481b8140d18800e7094cdacb0a61526f46181dc132dRob Landley{
482b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  struct passwd *up = getpwnam(user);
483b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  uid_t uid;
484b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
485b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  if (!up) {
486b8140d18800e7094cdacb0a61526f46181dc132dRob Landley    char *s = 0;
487b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
488b8140d18800e7094cdacb0a61526f46181dc132dRob Landley    uid = estrtol(user, &s, 10);
489b8140d18800e7094cdacb0a61526f46181dc132dRob Landley    if (!errno && s && !*s) up = getpwuid(uid);
490b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  }
491b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  if (!up) perror_exit("user '%s'", user);
492b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
493b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  return up;
494b8140d18800e7094cdacb0a61526f46181dc132dRob Landley}
495b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
496b8140d18800e7094cdacb0a61526f46181dc132dRob Landleystruct group *xgetgrnamid(char *group)
497b8140d18800e7094cdacb0a61526f46181dc132dRob Landley{
498b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  struct group *gr = getgrnam(group);
499b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  gid_t gid;
500b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
501b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  if (!gr) {
502b8140d18800e7094cdacb0a61526f46181dc132dRob Landley    char *s = 0;
503b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
504b8140d18800e7094cdacb0a61526f46181dc132dRob Landley    gid = estrtol(group, &s, 10);
505b8140d18800e7094cdacb0a61526f46181dc132dRob Landley    if (!errno && s && !*s) gr = getgrgid(gid);
506b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  }
507b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  if (!gr) perror_exit("group '%s'", group);
508b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
509b8140d18800e7094cdacb0a61526f46181dc132dRob Landley  return gr;
510b8140d18800e7094cdacb0a61526f46181dc132dRob Landley}
511b8140d18800e7094cdacb0a61526f46181dc132dRob Landley
5125ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landleystruct passwd *xgetpwnam(char *name)
5135ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley{
5145ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley  struct passwd *up = getpwnam(name);
5154fd07e0f6698cdb873aab0113369eb36c81853a9Rob Landley
5164fd07e0f6698cdb873aab0113369eb36c81853a9Rob Landley  if (!up) perror_exit("user '%s'", name);
5175ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley  return up;
5185ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley}
5195ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley
52060c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landleystruct group *xgetgrnam(char *name)
52160c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landley{
52260c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landley  struct group *gr = getgrnam(name);
52360c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landley
52460c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landley  if (!gr) perror_exit("group '%s'", name);
52560c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landley  return gr;
52660c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landley}
52760c35c486a2ea1c6ea8920c599abf992b27542c5Rob Landley
528afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley// setuid() can fail (for example, too many processes belonging to that user),
529afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley// which opens a security hole if the process continues as the original user.
530afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley
531afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landleyvoid xsetuser(struct passwd *pwd)
532afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley{
533afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley  if (initgroups(pwd->pw_name, pwd->pw_gid) || setgid(pwd->pw_uid)
534afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley      || setuid(pwd->pw_uid)) perror_exit("xsetuser '%s'", pwd->pw_name);
535afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley}
536afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley
537d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// This can return null (meaning file not found).  It just won't return null
538d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// for memory allocation reasons.
539d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xreadlink(char *name)
540d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
541d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int len, size = 0;
542d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *buf = 0;
543d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
544d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Grow by 64 byte chunks until it's big enough.
545d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  for(;;) {
546d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    size +=64;
547d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    buf = xrealloc(buf, size);
548d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    len = readlink(name, buf, size);
549d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
550d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<0) {
551d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      free(buf);
552d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      return 0;
553d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
554d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<size) {
555d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      buf[len]=0;
556d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      return buf;
557d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
558d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
559d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
560d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
561dc3731783ead154d5a0d8d318566468474b43013Rob Landleychar *xreadfile(char *name, char *buf, off_t len)
562d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
563dc3731783ead154d5a0d8d318566468474b43013Rob Landley  if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name);
564dc3731783ead154d5a0d8d318566468474b43013Rob Landley
565d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return buf;
566d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
567d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
568d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xioctl(int fd, int request, void *data)
569d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
570d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int rc;
571d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
572d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  errno = 0;
573d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  rc = ioctl(fd, request, data);
574d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (rc == -1 && errno) perror_exit("ioctl %x", request);
575d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
576d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return rc;
577d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
578d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
579d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
580d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// exists and is this executable.
581d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xpidfile(char *name)
582d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
583d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char pidfile[256], spid[32];
584d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int i, fd;
585d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  pid_t pid;
586d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
587d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  sprintf(pidfile, "/var/run/%s.pid", name);
588d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Try three times to open the sucker.
589d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  for (i=0; i<3; i++) {
590dccfb2a9c156d03b6399120ae3dd4b23ff00b43fFelix Janda <felix.janda at    fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
591d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (fd != -1) break;
592d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
593d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // If it already existed, read it.  Loop for race condition.
594d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    fd = open(pidfile, O_RDONLY);
595d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (fd == -1) continue;
596d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
597d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // Is the old program still there?
598d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    spid[xread(fd, spid, sizeof(spid)-1)] = 0;
599d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    close(fd);
600d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    pid = atoi(spid);
60146e8e1dcb3f616a675bf33c83531ee05a4dd8374Rob Landley    if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile);
602d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
603d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // An else with more sanity checking might be nice here.
604d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
605d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
606d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (i == 3) error_exit("xpidfile %s", name);
607d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
608d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
609d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  close(fd);
610d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
611d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
612d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Copy the rest of in to out and close both files.
613d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
614d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xsendfile(int in, int out)
615d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
616d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  long len;
617d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
618d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (in<0) return;
619d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  for (;;) {
6206d28370f22aa6b7c97a57a434339fa57ce322c8bRob Landley    len = xread(in, libbuf, sizeof(libbuf));
621d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<1) break;
6226d28370f22aa6b7c97a57a434339fa57ce322c8bRob Landley    xwrite(out, libbuf, len);
623d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
624d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
62572756670274dac9562b869761c50c59ed57b7295Rob Landley
62672756670274dac9562b869761c50c59ed57b7295Rob Landley// parse fractional seconds with optional s/m/h/d suffix
62772756670274dac9562b869761c50c59ed57b7295Rob Landleylong xparsetime(char *arg, long units, long *fraction)
62872756670274dac9562b869761c50c59ed57b7295Rob Landley{
62972756670274dac9562b869761c50c59ed57b7295Rob Landley  double d;
63072756670274dac9562b869761c50c59ed57b7295Rob Landley  long l;
63172756670274dac9562b869761c50c59ed57b7295Rob Landley
63272756670274dac9562b869761c50c59ed57b7295Rob Landley  if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg);
63372756670274dac9562b869761c50c59ed57b7295Rob Landley  else l = strtoul(arg, &arg, 10);
6342c1cf4a02783e2a570ddf7b7ea968c7bed781f91Rob Landley
63572756670274dac9562b869761c50c59ed57b7295Rob Landley  // Parse suffix
63672756670274dac9562b869761c50c59ed57b7295Rob Landley  if (*arg) {
63772756670274dac9562b869761c50c59ed57b7295Rob Landley    int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg);
63872756670274dac9562b869761c50c59ed57b7295Rob Landley
63972756670274dac9562b869761c50c59ed57b7295Rob Landley    if (i == -1) error_exit("Unknown suffix '%c'", *arg);
64072756670274dac9562b869761c50c59ed57b7295Rob Landley    if (CFG_TOYBOX_FLOAT) d *= ismhd[i];
64172756670274dac9562b869761c50c59ed57b7295Rob Landley    else l *= ismhd[i];
64272756670274dac9562b869761c50c59ed57b7295Rob Landley  }
64372756670274dac9562b869761c50c59ed57b7295Rob Landley
64472756670274dac9562b869761c50c59ed57b7295Rob Landley  if (CFG_TOYBOX_FLOAT) {
64572756670274dac9562b869761c50c59ed57b7295Rob Landley    l = (long)d;
64672756670274dac9562b869761c50c59ed57b7295Rob Landley    if (fraction) *fraction = units*(d-l);
64772756670274dac9562b869761c50c59ed57b7295Rob Landley  } else if (fraction) *fraction = 0;
64872756670274dac9562b869761c50c59ed57b7295Rob Landley
64972756670274dac9562b869761c50c59ed57b7295Rob Landley  return l;
65072756670274dac9562b869761c50c59ed57b7295Rob Landley}
6515b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley
6525b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley// Compile a regular expression into a regex_t
6535b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landleyvoid xregcomp(regex_t *preg, char *regex, int cflags)
6545b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley{
6555b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley  int rc = regcomp(preg, regex, cflags);
6565b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley
6575b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley  if (rc) {
6585b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley    regerror(rc, preg, libbuf, sizeof(libbuf));
6595b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley    error_exit("xregcomp: %s", libbuf);
6605b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley  }
6615b405827a2fa4c928c488f3e7b0197dfec60dcc2Rob Landley}
662c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley
663c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landleychar *xtzset(char *new)
664c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley{
665c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley  char *tz = getenv("TZ");
666c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley
667c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley  if (tz) tz = xstrdup(tz);
668c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley  if (setenv("TZ", new, 1)) perror_exit("setenv");
669c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley  tzset();
670c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley
671c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley  return tz;
672c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley}
673e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley
674e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley// Set a signal handler
675e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landleyvoid xsignal(int signal, void *handler)
676e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley{
677e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley  struct sigaction *sa = (void *)libbuf;
678e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley
679e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley  memset(sa, 0, sizeof(struct sigaction));
680e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley  sa->sa_handler = handler;
681e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley
682e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley  if (sigaction(signal, sa, 0)) perror_exit("xsignal %d", signal);
683e6abb61e057d55a08c263a48648aaf7b776dfceeRob Landley}
684