blob: b7eb274199e3ae49e6787b1b467a5f7774722763 [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 Landleyd8872c42014-05-31 12:33:24 -0500116pid_t xfork(void)
117{
118 pid_t pid = fork();
119
120 if (pid < 0) perror_exit("fork");
121
122 return pid;
123}
124
Rob Landley72756672013-07-17 17:22:46 -0500125// Call xexec with a chunk of optargs, starting at skip. (You can't just
126// call xexec() directly because toy_init() frees optargs.)
127void xexec_optargs(int skip)
128{
129 char **s = toys.optargs;
130
131 toys.optargs = 0;
132 xexec(s+skip);
133}
134
135
Rob Landleyd3904932013-07-16 00:04:56 -0500136// Die unless we can exec argv[] (or run builtin command). Note that anything
137// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
138void xexec(char **argv)
139{
Rob Landley977e48e2014-10-20 19:52:29 -0500140 if (CFG_TOYBOX && !CFG_TOYBOX_NORECURSE) toy_exec(argv);
Rob Landleyd3904932013-07-16 00:04:56 -0500141 execvp(argv[0], argv);
142
143 perror_exit("exec %s", argv[0]);
144}
145
Rob Landley44e68a12014-06-03 06:27:24 -0500146// Spawn child process, capturing stdin/stdout.
147// argv[]: command to exec. If null, child returns to original program.
Rob Landley360d57f2014-09-14 12:29:44 -0500148// pipes[2]: stdin, stdout of new process. If -1 will not have pipe allocated.
Rob Landley44e68a12014-06-03 06:27:24 -0500149// return: pid of child process
Rob Landley360d57f2014-09-14 12:29:44 -0500150pid_t xpopen_both(char **argv, int *pipes)
Rob Landley44e68a12014-06-03 06:27:24 -0500151{
152 int cestnepasun[4], pid;
153
Rob Landley360d57f2014-09-14 12:29:44 -0500154 // Make the pipes? Not this won't set either pipe to 0 because if fds are
155 // allocated in order and if fd0 was free it would go to cestnepasun[0]
Rob Landley44e68a12014-06-03 06:27:24 -0500156 if (pipes) {
Rob Landley360d57f2014-09-14 12:29:44 -0500157 for (pid = 0; pid < 2; pid++) {
158 if (pipes[pid] == -1) continue;
159 if (pipe(cestnepasun+(2*pid))) perror_exit("pipe");
160 pipes[pid] = cestnepasun[pid+1];
161 }
Rob Landley44e68a12014-06-03 06:27:24 -0500162 }
163
164 // Child process
165 if (!(pid = xfork())) {
166 // Dance of the stdin/stdout redirection.
167 if (pipes) {
Rob Landley360d57f2014-09-14 12:29:44 -0500168 // if we had no stdin/out, pipe handles could overlap, so test for it
169 // and free up potentially overlapping pipe handles before reuse
170 if (pipes[1] != -1) close(cestnepasun[2]);
171 if (pipes[0] != -1) {
172 close(cestnepasun[1]);
173 if (cestnepasun[0]) {
174 dup2(cestnepasun[0], 0);
175 close(cestnepasun[0]);
176 }
Rob Landley44e68a12014-06-03 06:27:24 -0500177 }
Rob Landley360d57f2014-09-14 12:29:44 -0500178 if (pipes[1] != -1) {
179 dup2(cestnepasun[3], 1);
180 dup2(cestnepasun[3], 2);
181 if (cestnepasun[3] > 2 || !cestnepasun[3]) close(cestnepasun[3]);
182 }
Rob Landley44e68a12014-06-03 06:27:24 -0500183 }
184 if (argv) {
185 if (CFG_TOYBOX) toy_exec(argv);
186 execvp(argv[0], argv);
187 _exit(127);
188 }
189 return 0;
190
Rob Landley44e68a12014-06-03 06:27:24 -0500191 }
Rob Landley360d57f2014-09-14 12:29:44 -0500192
193 // Parent process
194 if (pipes) {
195 if (pipes[0] != -1) close(cestnepasun[0]);
196 if (pipes[1] != -1) close(cestnepasun[3]);
197 }
198
199 return pid;
Rob Landley44e68a12014-06-03 06:27:24 -0500200}
201
Rob Landley360d57f2014-09-14 12:29:44 -0500202int xpclose_both(pid_t pid, int *pipes)
Rob Landley44e68a12014-06-03 06:27:24 -0500203{
204 int rc = 127;
205
206 if (pipes) {
207 close(pipes[0]);
208 close(pipes[1]);
209 }
210 waitpid(pid, &rc, 0);
211
212 return WIFEXITED(rc) ? WEXITSTATUS(rc) : WTERMSIG(rc) + 127;
213}
214
Rob Landley360d57f2014-09-14 12:29:44 -0500215// Wrapper to xpopen with a pipe for just one of stdin/stdout
216pid_t xpopen(char **argv, int *pipe, int stdout)
217{
Rob Landley8a990712014-09-14 19:54:19 -0500218 int pipes[2], pid;
Rob Landley360d57f2014-09-14 12:29:44 -0500219
Rob Landley8a990712014-09-14 19:54:19 -0500220 pipes[!stdout] = -1;
221 pipes[!!stdout] = 0;
222 pid = xpopen_both(argv, pipes);
223 *pipe = pid ? pipes[!!stdout] : -1;
Rob Landley360d57f2014-09-14 12:29:44 -0500224
Rob Landley8a990712014-09-14 19:54:19 -0500225 return pid;
Rob Landley360d57f2014-09-14 12:29:44 -0500226}
227
228int xpclose(pid_t pid, int pipe)
229{
230 close(pipe);
231
232 return xpclose_both(pid, 0);
233}
234
235// Call xpopen and wait for it to finish, keeping existing stdin/stdout.
236int xrun(char **argv)
237{
238 return xpclose_both(xpopen_both(argv, 0), 0);
239}
240
Rob Landleyd3904932013-07-16 00:04:56 -0500241void xaccess(char *path, int flags)
242{
243 if (access(path, flags)) perror_exit("Can't access '%s'", path);
244}
245
246// Die unless we can delete a file. (File must exist to be deleted.)
247void xunlink(char *path)
248{
249 if (unlink(path)) perror_exit("unlink '%s'", path);
250}
251
252// Die unless we can open/create a file, returning file descriptor.
253int xcreate(char *path, int flags, int mode)
254{
Rob Landleyccb73f82014-07-26 13:27:07 -0500255 int fd = open(path, flags^O_CLOEXEC, mode);
Rob Landleyd3904932013-07-16 00:04:56 -0500256 if (fd == -1) perror_exit("%s", path);
257 return fd;
258}
259
260// Die unless we can open a file, returning file descriptor.
261int xopen(char *path, int flags)
262{
263 return xcreate(path, flags, 0);
264}
265
266void xclose(int fd)
267{
268 if (close(fd)) perror_exit("xclose");
269}
270
271int xdup(int fd)
272{
273 if (fd != -1) {
274 fd = dup(fd);
275 if (fd == -1) perror_exit("xdup");
276 }
277 return fd;
278}
279
Rob Landley1aa75112013-08-07 12:19:51 -0500280FILE *xfdopen(int fd, char *mode)
281{
282 FILE *f = fdopen(fd, mode);
283
284 if (!f) perror_exit("xfdopen");
285
286 return f;
287}
288
Rob Landleyd3904932013-07-16 00:04:56 -0500289// Die unless we can open/create a file, returning FILE *.
290FILE *xfopen(char *path, char *mode)
291{
292 FILE *f = fopen(path, mode);
293 if (!f) perror_exit("No file %s", path);
294 return f;
295}
296
297// Die if there's an error other than EOF.
298size_t xread(int fd, void *buf, size_t len)
299{
300 ssize_t ret = read(fd, buf, len);
301 if (ret < 0) perror_exit("xread");
302
303 return ret;
304}
305
306void xreadall(int fd, void *buf, size_t len)
307{
308 if (len != readall(fd, buf, len)) perror_exit("xreadall");
309}
310
311// There's no xwriteall(), just xwrite(). When we read, there may or may not
312// be more data waiting. When we write, there is data and it had better go
313// somewhere.
314
315void xwrite(int fd, void *buf, size_t len)
316{
317 if (len != writeall(fd, buf, len)) perror_exit("xwrite");
318}
319
320// Die if lseek fails, probably due to being called on a pipe.
321
322off_t xlseek(int fd, off_t offset, int whence)
323{
324 offset = lseek(fd, offset, whence);
325 if (offset<0) perror_exit("lseek");
326
327 return offset;
328}
329
330char *xgetcwd(void)
331{
332 char *buf = getcwd(NULL, 0);
333 if (!buf) perror_exit("xgetcwd");
334
335 return buf;
336}
337
338void xstat(char *path, struct stat *st)
339{
340 if(stat(path, st)) perror_exit("Can't stat %s", path);
341}
342
343// Cannonicalize path, even to file with one or more missing components at end.
344// if exact, require last path component to exist
345char *xabspath(char *path, int exact)
346{
347 struct string_list *todo, *done = 0;
348 int try = 9999, dirfd = open("/", 0);;
349 char buf[4096], *ret;
350
351 // If this isn't an absolute path, start with cwd.
352 if (*path != '/') {
353 char *temp = xgetcwd();
354
355 splitpath(path, splitpath(temp, &todo));
356 free(temp);
357 } else splitpath(path, &todo);
358
359 // Iterate through path components
360 while (todo) {
361 struct string_list *new = llist_pop(&todo), **tail;
362 ssize_t len;
363
364 if (!try--) {
365 errno = ELOOP;
366 goto error;
367 }
368
369 // Removable path componenents.
370 if (!strcmp(new->str, ".") || !strcmp(new->str, "..")) {
371 int x = new->str[1];
372
373 free(new);
374 if (x) {
375 if (done) free(llist_pop(&done));
376 len = 0;
377 } else continue;
378
379 // Is this a symlink?
380 } else len=readlinkat(dirfd, new->str, buf, 4096);
381
382 if (len>4095) goto error;
383 if (len<1) {
384 int fd;
385 char *s = "..";
386
387 // For .. just move dirfd
388 if (len) {
389 // Not a symlink: add to linked list, move dirfd, fail if error
390 if ((exact || todo) && errno != EINVAL) goto error;
391 new->next = done;
392 done = new;
393 if (errno == EINVAL && !todo) break;
394 s = new->str;
395 }
396 fd = openat(dirfd, s, 0);
397 if (fd == -1 && (exact || todo || errno != ENOENT)) goto error;
398 close(dirfd);
399 dirfd = fd;
400 continue;
401 }
402
403 // If this symlink is to an absolute path, discard existing resolved path
404 buf[len] = 0;
405 if (*buf == '/') {
406 llist_traverse(done, free);
407 done=0;
408 close(dirfd);
409 dirfd = open("/", 0);
410 }
411 free(new);
412
413 // prepend components of new path. Note symlink to "/" will leave new NULL
414 tail = splitpath(buf, &new);
415
416 // symlink to "/" will return null and leave tail alone
417 if (new) {
418 *tail = todo;
419 todo = new;
420 }
421 }
422 close(dirfd);
423
424 // At this point done has the path, in reverse order. Reverse list while
425 // calculating buffer length.
426
427 try = 2;
428 while (done) {
429 struct string_list *temp = llist_pop(&done);;
430
431 if (todo) try++;
432 try += strlen(temp->str);
433 temp->next = todo;
434 todo = temp;
435 }
436
437 // Assemble return buffer
438
439 ret = xmalloc(try);
440 *ret = '/';
441 ret [try = 1] = 0;
442 while (todo) {
443 if (try>1) ret[try++] = '/';
444 try = stpcpy(ret+try, todo->str) - ret;
445 free(llist_pop(&todo));
446 }
447
448 return ret;
449
450error:
451 close(dirfd);
452 llist_traverse(todo, free);
453 llist_traverse(done, free);
454
455 return NULL;
456}
457
Rob Landleyd3904932013-07-16 00:04:56 -0500458void xchdir(char *path)
459{
460 if (chdir(path)) error_exit("chdir '%s'", path);
461}
462
Rob Landleyafba5b82013-12-23 06:49:38 -0600463void xchroot(char *path)
464{
465 if (chroot(path)) error_exit("chroot '%s'", path);
466 xchdir("/");
467}
468
Rob Landley9e44a582013-11-28 20:18:04 -0600469struct passwd *xgetpwuid(uid_t uid)
470{
471 struct passwd *pwd = getpwuid(uid);
Rob Landley5ec4ab32013-11-28 21:06:15 -0600472 if (!pwd) error_exit("bad uid %ld", (long)uid);
Rob Landley9e44a582013-11-28 20:18:04 -0600473 return pwd;
474}
475
476struct group *xgetgrgid(gid_t gid)
477{
478 struct group *group = getgrgid(gid);
Rob Landley4fd07e02014-07-21 19:57:36 -0500479
480 if (!group) perror_exit("gid %ld", (long)gid);
Rob Landley9e44a582013-11-28 20:18:04 -0600481 return group;
482}
483
Rob Landley5ec4ab32013-11-28 21:06:15 -0600484struct passwd *xgetpwnam(char *name)
485{
486 struct passwd *up = getpwnam(name);
Rob Landley4fd07e02014-07-21 19:57:36 -0500487
488 if (!up) perror_exit("user '%s'", name);
Rob Landley5ec4ab32013-11-28 21:06:15 -0600489 return up;
490}
491
Rob Landley60c35c42014-08-03 15:50:10 -0500492struct group *xgetgrnam(char *name)
493{
494 struct group *gr = getgrnam(name);
495
496 if (!gr) perror_exit("group '%s'", name);
497 return gr;
498}
499
Rob Landleyafba5b82013-12-23 06:49:38 -0600500// setuid() can fail (for example, too many processes belonging to that user),
501// which opens a security hole if the process continues as the original user.
502
503void xsetuser(struct passwd *pwd)
504{
505 if (initgroups(pwd->pw_name, pwd->pw_gid) || setgid(pwd->pw_uid)
506 || setuid(pwd->pw_uid)) perror_exit("xsetuser '%s'", pwd->pw_name);
507}
508
Rob Landleyd3904932013-07-16 00:04:56 -0500509// This can return null (meaning file not found). It just won't return null
510// for memory allocation reasons.
511char *xreadlink(char *name)
512{
513 int len, size = 0;
514 char *buf = 0;
515
516 // Grow by 64 byte chunks until it's big enough.
517 for(;;) {
518 size +=64;
519 buf = xrealloc(buf, size);
520 len = readlink(name, buf, size);
521
522 if (len<0) {
523 free(buf);
524 return 0;
525 }
526 if (len<size) {
527 buf[len]=0;
528 return buf;
529 }
530 }
531}
532
Rob Landleydc373172013-12-27 18:45:01 -0600533char *xreadfile(char *name, char *buf, off_t len)
Rob Landleyd3904932013-07-16 00:04:56 -0500534{
Rob Landleydc373172013-12-27 18:45:01 -0600535 if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name);
536
Rob Landleyd3904932013-07-16 00:04:56 -0500537 return buf;
538}
539
540int xioctl(int fd, int request, void *data)
541{
542 int rc;
543
544 errno = 0;
545 rc = ioctl(fd, request, data);
546 if (rc == -1 && errno) perror_exit("ioctl %x", request);
547
548 return rc;
549}
550
551// Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
552// exists and is this executable.
553void xpidfile(char *name)
554{
555 char pidfile[256], spid[32];
556 int i, fd;
557 pid_t pid;
558
559 sprintf(pidfile, "/var/run/%s.pid", name);
560 // Try three times to open the sucker.
561 for (i=0; i<3; i++) {
Felix Jandadccfb2a2013-08-26 21:55:33 +0200562 fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);
Rob Landleyd3904932013-07-16 00:04:56 -0500563 if (fd != -1) break;
564
565 // If it already existed, read it. Loop for race condition.
566 fd = open(pidfile, O_RDONLY);
567 if (fd == -1) continue;
568
569 // Is the old program still there?
570 spid[xread(fd, spid, sizeof(spid)-1)] = 0;
571 close(fd);
572 pid = atoi(spid);
Rob Landley46e8e1d2013-09-06 04:45:36 -0500573 if (pid < 1 || (kill(pid, 0) && errno == ESRCH)) unlink(pidfile);
Rob Landleyd3904932013-07-16 00:04:56 -0500574
575 // An else with more sanity checking might be nice here.
576 }
577
578 if (i == 3) error_exit("xpidfile %s", name);
579
580 xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
581 close(fd);
582}
583
584// Copy the rest of in to out and close both files.
585
586void xsendfile(int in, int out)
587{
588 long len;
589 char buf[4096];
590
591 if (in<0) return;
592 for (;;) {
593 len = xread(in, buf, 4096);
594 if (len<1) break;
595 xwrite(out, buf, len);
596 }
597}
Rob Landley72756672013-07-17 17:22:46 -0500598
599// parse fractional seconds with optional s/m/h/d suffix
600long xparsetime(char *arg, long units, long *fraction)
601{
602 double d;
603 long l;
604
605 if (CFG_TOYBOX_FLOAT) d = strtod(arg, &arg);
606 else l = strtoul(arg, &arg, 10);
607
608 // Parse suffix
609 if (*arg) {
610 int ismhd[]={1,60,3600,86400}, i = stridx("smhd", *arg);
611
612 if (i == -1) error_exit("Unknown suffix '%c'", *arg);
613 if (CFG_TOYBOX_FLOAT) d *= ismhd[i];
614 else l *= ismhd[i];
615 }
616
617 if (CFG_TOYBOX_FLOAT) {
618 l = (long)d;
619 if (fraction) *fraction = units*(d-l);
620 } else if (fraction) *fraction = 0;
621
622 return l;
623}
Rob Landley5b405822014-03-29 18:11:00 -0500624
625// Compile a regular expression into a regex_t
626void xregcomp(regex_t *preg, char *regex, int cflags)
627{
628 int rc = regcomp(preg, regex, cflags);
629
630 if (rc) {
631 regerror(rc, preg, libbuf, sizeof(libbuf));
632 error_exit("xregcomp: %s", libbuf);
633 }
634}