blob: 69682f65d3ff2c7deb55aad90850c912c0e7fcaf [file] [log] [blame]
Rob Landleyd3904932013-07-16 00:04:56 -05001/* xwrap.c - wrappers around existing library functions.
2 *
3 * Functions with the x prefix are wrappers that either succeed or kill the
4 * program with an error message, but never return failure. They usually have
5 * the same arguments and return value as the function they wrap.
6 *
7 * Copyright 2006 Rob Landley <rob@landley.net>
8 */
9
10#include "toys.h"
11
12// Strcpy with size checking: exit if there's not enough space for the string.
13void xstrncpy(char *dest, char *src, size_t size)
14{
Rob Landley3704f822013-11-02 14:24:54 -050015 if (strlen(src)+1 > size) error_exit("'%s' > %ld bytes", src, (long)size);
Rob Landleyd3904932013-07-16 00:04:56 -050016 strcpy(dest, src);
17}
18
19void xexit(void)
20{
21 if (toys.rebound) longjmp(*toys.rebound, 1);
22 else exit(toys.exitval);
23}
24
25// Die unless we can allocate memory.
26void *xmalloc(size_t size)
27{
28 void *ret = malloc(size);
29 if (!ret) error_exit("xmalloc");
30
31 return ret;
32}
33
34// Die unless we can allocate prezeroed memory.
35void *xzalloc(size_t size)
36{
37 void *ret = xmalloc(size);
38 memset(ret, 0, size);
39 return ret;
40}
41
42// Die unless we can change the size of an existing allocation, possibly
43// moving it. (Notice different arguments from libc function.)
44void *xrealloc(void *ptr, size_t size)
45{
46 ptr = realloc(ptr, size);
47 if (!ptr) error_exit("xrealloc");
48
49 return ptr;
50}
51
52// Die unless we can allocate a copy of this many bytes of string.
53char *xstrndup(char *s, size_t n)
54{
55 char *ret = xmalloc(++n);
56 strncpy(ret, s, n);
57 ret[--n]=0;
58
59 return ret;
60}
61
62// Die unless we can allocate a copy of this string.
63char *xstrdup(char *s)
64{
65 return xstrndup(s, strlen(s));
66}
67
68// Die unless we can allocate enough space to sprintf() into.
Rob Landley59d85e22014-01-16 09:26:50 -060069char *xmprintf(char *format, ...)
Rob Landleyd3904932013-07-16 00:04:56 -050070{
71 va_list va, va2;
72 int len;
73 char *ret;
74
75 va_start(va, format);
76 va_copy(va2, va);
77
78 // How long is it?
79 len = vsnprintf(0, 0, format, va);
80 len++;
81 va_end(va);
82
83 // Allocate and do the sprintf()
84 ret = xmalloc(len);
85 vsnprintf(ret, len, format, va2);
86 va_end(va2);
87
88 return ret;
89}
90
91void xprintf(char *format, ...)
92{
93 va_list va;
94 va_start(va, format);
95
96 vprintf(format, va);
Rob Landleyddbaa712014-05-26 12:25:47 -050097 if (fflush(stdout) || ferror(stdout)) perror_exit("write");
Rob Landleyd3904932013-07-16 00:04:56 -050098}
99
100void xputs(char *s)
101{
Rob Landleyddbaa712014-05-26 12:25:47 -0500102 if (EOF == puts(s) || fflush(stdout) || ferror(stdout)) perror_exit("write");
Rob Landleyd3904932013-07-16 00:04:56 -0500103}
104
105void xputc(char c)
106{
Rob Landleyddbaa712014-05-26 12:25:47 -0500107 if (EOF == fputc(c, stdout) || fflush(stdout) || ferror(stdout))
108 perror_exit("write");
Rob Landleyd3904932013-07-16 00:04:56 -0500109}
110
111void xflush(void)
112{
Rob Landleyddbaa712014-05-26 12:25:47 -0500113 if (fflush(stdout) || ferror(stdout)) perror_exit("write");;
Rob Landleyd3904932013-07-16 00:04:56 -0500114}
115
Rob Landley72756672013-07-17 17:22:46 -0500116// Call xexec with a chunk of optargs, starting at skip. (You can't just
117// call xexec() directly because toy_init() frees optargs.)
118void xexec_optargs(int skip)
119{
120 char **s = toys.optargs;
121
122 toys.optargs = 0;
123 xexec(s+skip);
124}
125
126
Rob Landleyd3904932013-07-16 00:04:56 -0500127// Die unless we can exec argv[] (or run builtin command). Note that anything
128// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
129void xexec(char **argv)
130{
Rob Landleyd04dc1f2013-08-30 01:53:31 -0500131 if (CFG_TOYBOX) toy_exec(argv);
Rob Landleyd3904932013-07-16 00:04:56 -0500132 execvp(argv[0], argv);
133
134 perror_exit("exec %s", argv[0]);
135}
136
137void xaccess(char *path, int flags)
138{
139 if (access(path, flags)) perror_exit("Can't access '%s'", path);
140}
141
142// Die unless we can delete a file. (File must exist to be deleted.)
143void xunlink(char *path)
144{
145 if (unlink(path)) perror_exit("unlink '%s'", path);
146}
147
148// Die unless we can open/create a file, returning file descriptor.
149int xcreate(char *path, int flags, int mode)
150{
151 int fd = open(path, flags, mode);
152 if (fd == -1) perror_exit("%s", path);
153 return fd;
154}
155
156// Die unless we can open a file, returning file descriptor.
157int xopen(char *path, int flags)
158{
159 return xcreate(path, flags, 0);
160}
161
162void xclose(int fd)
163{
164 if (close(fd)) perror_exit("xclose");
165}
166
167int xdup(int fd)
168{
169 if (fd != -1) {
170 fd = dup(fd);
171 if (fd == -1) perror_exit("xdup");
172 }
173 return fd;
174}
175
Rob Landley1aa75112013-08-07 12:19:51 -0500176FILE *xfdopen(int fd, char *mode)
177{
178 FILE *f = fdopen(fd, mode);
179
180 if (!f) perror_exit("xfdopen");
181
182 return f;
183}
184
Rob Landleyd3904932013-07-16 00:04:56 -0500185// Die unless we can open/create a file, returning FILE *.
186FILE *xfopen(char *path, char *mode)
187{
188 FILE *f = fopen(path, mode);
189 if (!f) perror_exit("No file %s", path);
190 return f;
191}
192
193// Die if there's an error other than EOF.
194size_t xread(int fd, void *buf, size_t len)
195{
196 ssize_t ret = read(fd, buf, len);
197 if (ret < 0) perror_exit("xread");
198
199 return ret;
200}
201
202void xreadall(int fd, void *buf, size_t len)
203{
204 if (len != readall(fd, buf, len)) perror_exit("xreadall");
205}
206
207// There's no xwriteall(), just xwrite(). When we read, there may or may not
208// be more data waiting. When we write, there is data and it had better go
209// somewhere.
210
211void xwrite(int fd, void *buf, size_t len)
212{
213 if (len != writeall(fd, buf, len)) perror_exit("xwrite");
214}
215
216// Die if lseek fails, probably due to being called on a pipe.
217
218off_t xlseek(int fd, off_t offset, int whence)
219{
220 offset = lseek(fd, offset, whence);
221 if (offset<0) perror_exit("lseek");
222
223 return offset;
224}
225
226char *xgetcwd(void)
227{
228 char *buf = getcwd(NULL, 0);
229 if (!buf) perror_exit("xgetcwd");
230
231 return buf;
232}
233
234void xstat(char *path, struct stat *st)
235{
236 if(stat(path, st)) perror_exit("Can't stat %s", path);
237}
238
239// Cannonicalize path, even to file with one or more missing components at end.
240// if exact, require last path component to exist
241char *xabspath(char *path, int exact)
242{
243 struct string_list *todo, *done = 0;
244 int try = 9999, dirfd = open("/", 0);;
245 char buf[4096], *ret;
246
247 // If this isn't an absolute path, start with cwd.
248 if (*path != '/') {
249 char *temp = xgetcwd();
250
251 splitpath(path, splitpath(temp, &todo));
252 free(temp);
253 } else splitpath(path, &todo);
254
255 // Iterate through path components
256 while (todo) {
257 struct string_list *new = llist_pop(&todo), **tail;
258 ssize_t len;
259
260 if (!try--) {
261 errno = ELOOP;
262 goto error;
263 }
264
265 // Removable path componenents.
266 if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) {
267 int x = new->str[1];
268
269 free(new);
270 if (x) {
271 if (done) free(llist_pop(&done));
272 len = 0;
273 } else continue;
274
275 // Is this a symlink?
276 } else len=readlinkat(dirfd, new->str, buf, 4096);
277
278 if (len>4095) goto error;
279 if (len<1) {
280 int fd;
281 char *s = "..";
282
283 // For .. just move dirfd
284 if (len) {
285 // Not a symlink: add to linked list, move dirfd, fail if error
286 if ((exact || todo) && errno != EINVAL) goto error;
287 new->next = done;
288 done = new;
289 if (errno == EINVAL && !todo) break;
290 s = new->str;
291 }
292 fd = openat(dirfd, s, 0);
293 if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
294 close(dirfd);
295 dirfd = fd;
296 continue;
297 }
298
299 // If this symlink is to an absolute path, discard existing resolved path
300 buf[len] = 0;
301 if (*buf == '/') {
302 llist_traverse(done, free);
303 done=0;
304 close(dirfd);
305 dirfd = open("/", 0);
306 }
307 free(new);
308
309 // prepend components of new path. Note symlink to "/" will leave new NULL
310 tail = splitpath(buf, &new);
311
312 // symlink to "/" will return null and leave tail alone
313 if (new) {
314 *tail = todo;
315 todo = new;
316 }
317 }
318 close(dirfd);
319
320 // At this point done has the path, in reverse order. Reverse list while
321 // calculating buffer length.
322
323 try = 2;
324 while (done) {
325 struct string_list *temp = llist_pop(&done);;
326
327 if (todo) try++;
328 try += strlen(temp->str);
329 temp->next = todo;
330 todo = temp;
331 }
332
333 // Assemble return buffer
334
335 ret = xmalloc(try);
336 *ret = '/';
337 ret [try = 1] = 0;
338 while (todo) {
339 if (try>1) ret[try++] = '/';
340 try = stpcpy(ret+try, todo->str) - ret;
341 free(llist_pop(&todo));
342 }
343
344 return ret;
345
346error:
347 close(dirfd);
348 llist_traverse(todo, free);
349 llist_traverse(done, free);
350
351 return NULL;
352}
353
354// Resolve all symlinks, returning malloc() memory.
355char *xrealpath(char *path)
356{
357 char *new = realpath(path, NULL);
358 if (!new) perror_exit("realpath '%s'", path);
359 return new;
360}
361
362void xchdir(char *path)
363{
364 if (chdir(path)) error_exit("chdir '%s'", path);
365}
366
Rob Landleyafba5b82013-12-23 06:49:38 -0600367void xchroot(char *path)
368{
369 if (chroot(path)) error_exit("chroot '%s'", path);
370 xchdir("/");
371}
372
Rob Landley9e44a582013-11-28 20:18:04 -0600373struct passwd *xgetpwuid(uid_t uid)
374{
375 struct passwd *pwd = getpwuid(uid);
Rob Landley5ec4ab32013-11-28 21:06:15 -0600376 if (!pwd) error_exit("bad uid %ld", (long)uid);
Rob Landley9e44a582013-11-28 20:18:04 -0600377 return pwd;
378}
379
380struct group *xgetgrgid(gid_t gid)
381{
382 struct group *group = getgrgid(gid);
Rob Landley5ec4ab32013-11-28 21:06:15 -0600383 if (!group) error_exit("bad gid %ld", (long)gid);
Rob Landley9e44a582013-11-28 20:18:04 -0600384 return group;
385}
386
Rob Landley5ec4ab32013-11-28 21:06:15 -0600387struct passwd *xgetpwnam(char *name)
388{
389 struct passwd *up = getpwnam(name);
390 if (!up) error_exit("bad user '%s'", name);
391 return up;
392}
393
Rob Landleyafba5b82013-12-23 06:49:38 -0600394// setuid() can fail (for example, too many processes belonging to that user),
395// which opens a security hole if the process continues as the original user.
396
397void xsetuser(struct passwd *pwd)
398{
399 if (initgroups(pwd->pw_name, pwd->pw_gid) || setgid(pwd->pw_uid)
400 || setuid(pwd->pw_uid)) perror_exit("xsetuser '%s'", pwd->pw_name);
401}
402
Rob Landleyd3904932013-07-16 00:04:56 -0500403// This can return null (meaning file not found). It just won't return null
404// for memory allocation reasons.
405char *xreadlink(char *name)
406{
407 int len, size = 0;
408 char *buf = 0;
409
410 // Grow by 64 byte chunks until it's big enough.
411 for(;;) {
412 size +=64;
413 buf = xrealloc(buf, size);
414 len = readlink(name, buf, size);
415
416 if (len<0) {
417 free(buf);
418 return 0;
419 }
420 if (len<size) {
421 buf[len]=0;
422 return buf;
423 }
424 }
425}
426
Rob Landleydc373172013-12-27 18:45:01 -0600427char *xreadfile(char *name, char *buf, off_t len)
Rob Landleyd3904932013-07-16 00:04:56 -0500428{
Rob Landleydc373172013-12-27 18:45:01 -0600429 if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name);
430
Rob Landleyd3904932013-07-16 00:04:56 -0500431 return buf;
432}
433
434int xioctl(int fd, int request, void *data)
435{
436 int rc;
437
438 errno = 0;
439 rc = ioctl(fd, request, data);
440 if (rc == -1 && errno) perror_exit("ioctl %x", request);
441
442 return rc;
443}
444
445// Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
446// exists and is this executable.
447void xpidfile(char *name)
448{
449 char pidfile[256], spid[32];
450 int i, fd;
451 pid_t pid;
452
453 sprintf(pidfile, "/var/run/%s.pid", name);
454 // Try three times to open the sucker.
455 for (i=0; i<3; i++) {
Felix Jandadccfb2a2013-08-26 21:55:33 +0200456 fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
Rob Landleyd3904932013-07-16 00:04:56 -0500457 if (fd != -1) break;
458
459 // If it already existed, read it. Loop for race condition.
460 fd = open(pidfile, O_RDONLY);
461 if (fd == -1) continue;
462
463 // Is the old program still there?
464 spid[xread(fd, spid, sizeof(spid)-1)] = 0;
465 close(fd);
466 pid = atoi(spid);
Rob Landley46e8e1d2013-09-06 04:45:36 -0500467 if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile);
Rob Landleyd3904932013-07-16 00:04:56 -0500468
469 // An else with more sanity checking might be nice here.
470 }
471
472 if (i == 3) error_exit("xpidfile %s", name);
473
474 xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
475 close(fd);
476}
477
478// Copy the rest of in to out and close both files.
479
480void xsendfile(int in, int out)
481{
482 long len;
483 char buf[4096];
484
485 if (in<0) return;
486 for (;;) {
487 len = xread(in, buf, 4096);
488 if (len<1) break;
489 xwrite(out, buf, len);
490 }
491}
Rob Landley72756672013-07-17 17:22:46 -0500492
493// parse fractional seconds with optional s/m/h/d suffix
494long xparsetime(char *arg, long units, long *fraction)
495{
496 double d;
497 long l;
498
499 if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg);
500 else l = strtoul(arg, &arg, 10);
501
502 // Parse suffix
503 if (*arg) {
504 int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg);
505
506 if (i == -1) error_exit("Unknown suffix '%c'", *arg);
507 if (CFG_TOYBOX_FLOAT) d *= ismhd[i];
508 else l *= ismhd[i];
509 }
510
511 if (CFG_TOYBOX_FLOAT) {
512 l = (long)d;
513 if (fraction) *fraction = units*(d-l);
514 } else if (fraction) *fraction = 0;
515
516 return l;
517}
Rob Landley5b405822014-03-29 18:11:00 -0500518
519// Compile a regular expression into a regex_t
520void xregcomp(regex_t *preg, char *regex, int cflags)
521{
522 int rc = regcomp(preg, regex, cflags);
523
524 if (rc) {
525 regerror(rc, preg, libbuf, sizeof(libbuf));
526 error_exit("xregcomp: %s", libbuf);
527 }
528}