xwrap.c revision 46e8e1dcb3f616a675bf33c83531ee05a4dd8374
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
12d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Strcpy with size checking: exit if there's not enough space for the string.
13d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xstrncpy(char *dest, char *src, size_t size)
14d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
15d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (strlen(src)+1 > size) error_exit("xstrcpy");
16d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  strcpy(dest, src);
17d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
18d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
19d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xexit(void)
20d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
21d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (toys.rebound) longjmp(*toys.rebound, 1);
22d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  else exit(toys.exitval);
23d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
24d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
25d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate memory.
26d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid *xmalloc(size_t size)
27d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
28d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  void *ret = malloc(size);
29d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!ret) error_exit("xmalloc");
30d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
31d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
32d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
33d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
34d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate prezeroed memory.
35d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid *xzalloc(size_t size)
36d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
37d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  void *ret = xmalloc(size);
38d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  memset(ret, 0, size);
39d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
40d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
41d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
42d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can change the size of an existing allocation, possibly
43d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// moving it.  (Notice different arguments from libc function.)
44d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid *xrealloc(void *ptr, size_t size)
45d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
46d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ptr = realloc(ptr, size);
47d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!ptr) error_exit("xrealloc");
48d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
49d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ptr;
50d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
51d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
52d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate a copy of this many bytes of string.
53d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xstrndup(char *s, size_t n)
54d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
55d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *ret = xmalloc(++n);
56d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  strncpy(ret, s, n);
57d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ret[--n]=0;
58d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
59d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
60d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
61d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
62d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate a copy of this string.
63d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xstrdup(char *s)
64d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
65d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return xstrndup(s, strlen(s));
66d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
67d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
68d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can allocate enough space to sprintf() into.
69d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xmsprintf(char *format, ...)
70d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
71d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_list va, va2;
72d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int len;
73d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *ret;
74d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
75d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_start(va, format);
76d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_copy(va2, va);
77d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
78d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // How long is it?
79d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  len = vsnprintf(0, 0, format, va);
80d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  len++;
81d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_end(va);
82d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
83d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Allocate and do the sprintf()
84d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ret = xmalloc(len);
85d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  vsnprintf(ret, len, format, va2);
86d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_end(va2);
87d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
88d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
89d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
90d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
91d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xprintf(char *format, ...)
92d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
93d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_list va;
94d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  va_start(va, format);
95d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
96d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  vprintf(format, va);
97d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (ferror(stdout)) perror_exit("write");
98d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
99d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
100d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xputs(char *s)
101d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
102d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (EOF == puts(s) || fflush(stdout)) perror_exit("write");
103d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
104d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
105d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xputc(char c)
106d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
107d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (EOF == fputc(c, stdout) || fflush(stdout)) perror_exit("write");
108d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
109d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
110d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xflush(void)
111d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
112d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (fflush(stdout)) perror_exit("write");;
113d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
114d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
11572756670274dac9562b869761c50c59ed57b7295Rob Landley// Call xexec with a chunk of optargs, starting at skip. (You can't just
11672756670274dac9562b869761c50c59ed57b7295Rob Landley// call xexec() directly because toy_init() frees optargs.)
11772756670274dac9562b869761c50c59ed57b7295Rob Landleyvoid xexec_optargs(int skip)
11872756670274dac9562b869761c50c59ed57b7295Rob Landley{
11972756670274dac9562b869761c50c59ed57b7295Rob Landley  char **s = toys.optargs;
12072756670274dac9562b869761c50c59ed57b7295Rob Landley
12172756670274dac9562b869761c50c59ed57b7295Rob Landley  toys.optargs = 0;
12272756670274dac9562b869761c50c59ed57b7295Rob Landley  xexec(s+skip);
12372756670274dac9562b869761c50c59ed57b7295Rob Landley}
12472756670274dac9562b869761c50c59ed57b7295Rob Landley
12572756670274dac9562b869761c50c59ed57b7295Rob Landley
126d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can exec argv[] (or run builtin command).  Note that anything
127d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
128d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xexec(char **argv)
129d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
130d04dc1feb92a279e27e4487c502944f454d43837Rob Landley  if (CFG_TOYBOX) toy_exec(argv);
131d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  execvp(argv[0], argv);
132d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
133d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  perror_exit("exec %s", argv[0]);
134d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
135d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
136d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xaccess(char *path, int flags)
137d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
138d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (access(path, flags)) perror_exit("Can't access '%s'", path);
139d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
140d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
141d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can delete a file.  (File must exist to be deleted.)
142d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xunlink(char *path)
143d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
144d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (unlink(path)) perror_exit("unlink '%s'", path);
145d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
146d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
147d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can open/create a file, returning file descriptor.
148d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xcreate(char *path, int flags, int mode)
149d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
150d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int fd = open(path, flags, mode);
151d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (fd == -1) perror_exit("%s", path);
152d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return fd;
153d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
154d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
155d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can open a file, returning file descriptor.
156d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xopen(char *path, int flags)
157d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
158d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return xcreate(path, flags, 0);
159d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
160d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
161d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xclose(int fd)
162d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
163d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (close(fd)) perror_exit("xclose");
164d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
165d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
166d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xdup(int fd)
167d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
168d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (fd != -1) {
169d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    fd = dup(fd);
170d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (fd == -1) perror_exit("xdup");
171d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
172d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return fd;
173d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
174d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
1751aa75118c46c8fbe0eeead18974d25e5f13274d5Rob LandleyFILE *xfdopen(int fd, char *mode)
1761aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley{
1771aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley  FILE *f = fdopen(fd, mode);
1781aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley
1791aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley  if (!f) perror_exit("xfdopen");
1801aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley
1811aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley  return f;
1821aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley}
1831aa75118c46c8fbe0eeead18974d25e5f13274d5Rob Landley
184d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die unless we can open/create a file, returning FILE *.
185d390493d76c4cda76c1c6d21897b0f246857e588Rob LandleyFILE *xfopen(char *path, char *mode)
186d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
187d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  FILE *f = fopen(path, mode);
188d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!f) perror_exit("No file %s", path);
189d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return f;
190d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
191d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
192d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die if there's an error other than EOF.
193d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleysize_t xread(int fd, void *buf, size_t len)
194d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
195d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ssize_t ret = read(fd, buf, len);
196d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (ret < 0) perror_exit("xread");
197d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
198d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
199d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
200d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
201d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xreadall(int fd, void *buf, size_t len)
202d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
203d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (len != readall(fd, buf, len)) perror_exit("xreadall");
204d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
205d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
206d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// There's no xwriteall(), just xwrite().  When we read, there may or may not
207d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// be more data waiting.  When we write, there is data and it had better go
208d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// somewhere.
209d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
210d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xwrite(int fd, void *buf, size_t len)
211d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
212d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (len != writeall(fd, buf, len)) perror_exit("xwrite");
213d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
214d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
215d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Die if lseek fails, probably due to being called on a pipe.
216d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
217d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyoff_t xlseek(int fd, off_t offset, int whence)
218d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
219d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  offset = lseek(fd, offset, whence);
220d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (offset<0) perror_exit("lseek");
221d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
222d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return offset;
223d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
224d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
225d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xgetcwd(void)
226d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
227d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *buf = getcwd(NULL, 0);
228d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!buf) perror_exit("xgetcwd");
229d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
230d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return buf;
231d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
232d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
233d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xstat(char *path, struct stat *st)
234d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
235d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if(stat(path, st)) perror_exit("Can't stat %s", path);
236d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
237d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
238d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Cannonicalize path, even to file with one or more missing components at end.
239d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// if exact, require last path component to exist
240d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xabspath(char *path, int exact)
241d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
242d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  struct string_list *todo, *done = 0;
243d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int try = 9999, dirfd = open("/", 0);;
244d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char buf[4096], *ret;
245d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
246d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // If this isn't an absolute path, start with cwd.
247d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (*path != '/') {
248d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    char *temp = xgetcwd();
249d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
250d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    splitpath(path, splitpath(temp, &todo));
251d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    free(temp);
252d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  } else splitpath(path, &todo);
253d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
254d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Iterate through path components
255d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  while (todo) {
256d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    struct string_list *new = llist_pop(&todo), **tail;
257d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    ssize_t len;
258d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
259d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (!try--) {
260d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      errno = ELOOP;
261d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      goto error;
262d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
263d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
264d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // Removable path componenents.
265d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) {
266d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      int x = new->str[1];
267d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
268d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      free(new);
269d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if (x) {
270d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        if (done) free(llist_pop(&done));
271d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        len = 0;
272d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      } else continue;
273d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
274d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // Is this a symlink?
275d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    } else len=readlinkat(dirfd, new->str, buf, 4096);
276d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
277d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len>4095) goto error;
278d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<1) {
279d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      int fd;
280d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      char *s = "..";
281d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
282d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      // For .. just move dirfd
283d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if (len) {
284d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        // Not a symlink: add to linked list, move dirfd, fail if error
285d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        if ((exact || todo) && errno != EINVAL) goto error;
286d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        new->next = done;
287d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        done = new;
288d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        if (errno == EINVAL && !todo) break;
289d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        s = new->str;
290d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      }
291d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      fd = openat(dirfd, s, 0);
292d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
293d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      close(dirfd);
294d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      dirfd = fd;
295d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      continue;
296d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
297d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
298d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // If this symlink is to an absolute path, discard existing resolved path
299d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    buf[len] = 0;
300d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (*buf == '/') {
301d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      llist_traverse(done, free);
302d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      done=0;
303d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      close(dirfd);
304d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      dirfd = open("/", 0);
305d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
306d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    free(new);
307d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
308d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // prepend components of new path. Note symlink to "/" will leave new NULL
309d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    tail = splitpath(buf, &new);
310d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
311d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // symlink to "/" will return null and leave tail alone
312d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (new) {
313d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      *tail = todo;
314d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      todo = new;
315d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
316d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
317d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  close(dirfd);
318d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
319d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // At this point done has the path, in reverse order. Reverse list while
320d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // calculating buffer length.
321d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
322d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  try = 2;
323d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  while (done) {
324d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    struct string_list *temp = llist_pop(&done);;
325d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
326d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (todo) try++;
327d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    try += strlen(temp->str);
328d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    temp->next = todo;
329d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    todo = temp;
330d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
331d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
332d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Assemble return buffer
333d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
334d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ret = xmalloc(try);
335d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  *ret = '/';
336d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  ret [try = 1] = 0;
337d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  while (todo) {
338d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (try>1) ret[try++] = '/';
339d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    try = stpcpy(ret+try, todo->str) - ret;
340d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    free(llist_pop(&todo));
341d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
342d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
343d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return ret;
344d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
345d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyerror:
346d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  close(dirfd);
347d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  llist_traverse(todo, free);
348d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  llist_traverse(done, free);
349d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
350d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return NULL;
351d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
352d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
353d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Resolve all symlinks, returning malloc() memory.
354d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xrealpath(char *path)
355d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
356d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *new = realpath(path, NULL);
357d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!new) perror_exit("realpath '%s'", path);
358d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return new;
359d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
360d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
361d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xchdir(char *path)
362d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
363d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (chdir(path)) error_exit("chdir '%s'", path);
364d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
365d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
366d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Ensure entire path exists.
367d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// If mode != -1 set permissions on newly created dirs.
368d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Requires that path string be writable (for temporary null terminators).
369d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xmkpath(char *path, int mode)
370d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
371d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *p, old;
372d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  mode_t mask;
373d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int rc;
374d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  struct stat st;
375d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
376d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  for (p = path; ; p++) {
377d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (!*p || *p == '/') {
378d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      old = *p;
379d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      *p = rc = 0;
380d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
381d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        if (mode != -1) {
382d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley          mask=umask(0);
383d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley          rc = mkdir(path, mode);
384d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley          umask(mask);
385d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley        } else rc = mkdir(path, 0777);
386d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      }
387d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      *p = old;
388d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      if(rc) perror_exit("mkpath '%s'", path);
389d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
390d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (!*p) break;
391d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
392d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
393d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
394d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// setuid() can fail (for example, too many processes belonging to that user),
395d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// which opens a security hole if the process continues as the original user.
396d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
397d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xsetuid(uid_t uid)
398d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
399d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (setuid(uid)) perror_exit("xsetuid");
400d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
401d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
402d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// This can return null (meaning file not found).  It just won't return null
403d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// for memory allocation reasons.
404d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xreadlink(char *name)
405d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
406d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int len, size = 0;
407d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char *buf = 0;
408d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
409d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Grow by 64 byte chunks until it's big enough.
410d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  for(;;) {
411d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    size +=64;
412d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    buf = xrealloc(buf, size);
413d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    len = readlink(name, buf, size);
414d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
415d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<0) {
416d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      free(buf);
417d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      return 0;
418d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
419d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<size) {
420d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      buf[len]=0;
421d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley      return buf;
422d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    }
423d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
424d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
425d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
426d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleychar *xreadfile(char *name)
427d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
4288fdcfdb4479dff7a993a25a63253f0e749fd99feRob Landley  char *buf = readfile(name, 0, 0);
429d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (!buf) perror_exit("xreadfile %s", name);
430d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return buf;
431d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
432d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
433d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyint xioctl(int fd, int request, void *data)
434d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
435d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int rc;
436d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
437d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  errno = 0;
438d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  rc = ioctl(fd, request, data);
439d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (rc == -1 && errno) perror_exit("ioctl %x", request);
440d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
441d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  return rc;
442d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
443d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
444d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
445d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// exists and is this executable.
446d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xpidfile(char *name)
447d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
448d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char pidfile[256], spid[32];
449d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  int i, fd;
450d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  pid_t pid;
451d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
452d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  sprintf(pidfile, "/var/run/%s.pid", name);
453d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  // Try three times to open the sucker.
454d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  for (i=0; i<3; i++) {
455dccfb2a9c156d03b6399120ae3dd4b23ff00b43fFelix Janda <felix.janda at    fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
456d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (fd != -1) break;
457d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
458d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // If it already existed, read it.  Loop for race condition.
459d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    fd = open(pidfile, O_RDONLY);
460d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (fd == -1) continue;
461d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
462d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // Is the old program still there?
463d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    spid[xread(fd, spid, sizeof(spid)-1)] = 0;
464d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    close(fd);
465d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    pid = atoi(spid);
46646e8e1dcb3f616a675bf33c83531ee05a4dd8374Rob Landley    if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile);
467d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
468d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    // An else with more sanity checking might be nice here.
469d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
470d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
471d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (i == 3) error_exit("xpidfile %s", name);
472d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
473d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
474d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  close(fd);
475d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
476d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
477d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley// Copy the rest of in to out and close both files.
478d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
479d390493d76c4cda76c1c6d21897b0f246857e588Rob Landleyvoid xsendfile(int in, int out)
480d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley{
481d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  long len;
482d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  char buf[4096];
483d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley
484d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  if (in<0) return;
485d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  for (;;) {
486d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    len = xread(in, buf, 4096);
487d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    if (len<1) break;
488d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley    xwrite(out, buf, len);
489d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley  }
490d390493d76c4cda76c1c6d21897b0f246857e588Rob Landley}
49172756670274dac9562b869761c50c59ed57b7295Rob Landley
49272756670274dac9562b869761c50c59ed57b7295Rob Landley// parse fractional seconds with optional s/m/h/d suffix
49372756670274dac9562b869761c50c59ed57b7295Rob Landleylong xparsetime(char *arg, long units, long *fraction)
49472756670274dac9562b869761c50c59ed57b7295Rob Landley{
49572756670274dac9562b869761c50c59ed57b7295Rob Landley  double d;
49672756670274dac9562b869761c50c59ed57b7295Rob Landley  long l;
49772756670274dac9562b869761c50c59ed57b7295Rob Landley
49872756670274dac9562b869761c50c59ed57b7295Rob Landley  if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg);
49972756670274dac9562b869761c50c59ed57b7295Rob Landley  else l = strtoul(arg, &arg, 10);
50072756670274dac9562b869761c50c59ed57b7295Rob Landley
50172756670274dac9562b869761c50c59ed57b7295Rob Landley  // Parse suffix
50272756670274dac9562b869761c50c59ed57b7295Rob Landley  if (*arg) {
50372756670274dac9562b869761c50c59ed57b7295Rob Landley    int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg);
50472756670274dac9562b869761c50c59ed57b7295Rob Landley
50572756670274dac9562b869761c50c59ed57b7295Rob Landley    if (i == -1) error_exit("Unknown suffix '%c'", *arg);
50672756670274dac9562b869761c50c59ed57b7295Rob Landley    if (CFG_TOYBOX_FLOAT) d *= ismhd[i];
50772756670274dac9562b869761c50c59ed57b7295Rob Landley    else l *= ismhd[i];
50872756670274dac9562b869761c50c59ed57b7295Rob Landley  }
50972756670274dac9562b869761c50c59ed57b7295Rob Landley
51072756670274dac9562b869761c50c59ed57b7295Rob Landley  if (CFG_TOYBOX_FLOAT) {
51172756670274dac9562b869761c50c59ed57b7295Rob Landley    l = (long)d;
51272756670274dac9562b869761c50c59ed57b7295Rob Landley    if (fraction) *fraction = units*(d-l);
51372756670274dac9562b869761c50c59ed57b7295Rob Landley  } else if (fraction) *fraction = 0;
51472756670274dac9562b869761c50c59ed57b7295Rob Landley
51572756670274dac9562b869761c50c59ed57b7295Rob Landley  return l;
51672756670274dac9562b869761c50c59ed57b7295Rob Landley}
517