source: MondoRescue/branches/3.3/mindi-busybox/libbb/xfuncs_printf.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 15.8 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * Copyright (C) 2006 Rob Landley
7 * Copyright (C) 2006 Denys Vlasenko
8 *
9 * Licensed under GPLv2, see file LICENSE in this source tree.
10 */
11
12/* We need to have separate xfuncs.c and xfuncs_printf.c because
13 * with current linkers, even with section garbage collection,
14 * if *.o module references any of XXXprintf functions, you pull in
15 * entire printf machinery. Even if you do not use the function
16 * which uses XXXprintf.
17 *
18 * xfuncs.c contains functions (not necessarily xfuncs)
19 * which do not pull in printf, directly or indirectly.
20 * xfunc_printf.c contains those which do.
21 */
22
23#include "libbb.h"
24
25
26/* All the functions starting with "x" call bb_error_msg_and_die() if they
27 * fail, so callers never need to check for errors. If it returned, it
28 * succeeded. */
29
30#ifndef DMALLOC
31/* dmalloc provides variants of these that do abort() on failure.
32 * Since dmalloc's prototypes overwrite the impls here as they are
33 * included after these prototypes in libbb.h, all is well.
34 */
35// Warn if we can't allocate size bytes of memory.
36void* FAST_FUNC malloc_or_warn(size_t size)
37{
38 void *ptr = malloc(size);
39 if (ptr == NULL && size != 0)
40 bb_error_msg(bb_msg_memory_exhausted);
41 return ptr;
42}
43
44// Die if we can't allocate size bytes of memory.
45void* FAST_FUNC xmalloc(size_t size)
46{
47 void *ptr = malloc(size);
48 if (ptr == NULL && size != 0)
49 bb_error_msg_and_die(bb_msg_memory_exhausted);
50 return ptr;
51}
52
53// Die if we can't resize previously allocated memory. (This returns a pointer
54// to the new memory, which may or may not be the same as the old memory.
55// It'll copy the contents to a new chunk and free the old one if necessary.)
56void* FAST_FUNC xrealloc(void *ptr, size_t size)
57{
58 ptr = realloc(ptr, size);
59 if (ptr == NULL && size != 0)
60 bb_error_msg_and_die(bb_msg_memory_exhausted);
61 return ptr;
62}
63#endif /* DMALLOC */
64
65// Die if we can't allocate and zero size bytes of memory.
66void* FAST_FUNC xzalloc(size_t size)
67{
68 void *ptr = xmalloc(size);
69 memset(ptr, 0, size);
70 return ptr;
71}
72
73// Die if we can't copy a string to freshly allocated memory.
74char* FAST_FUNC xstrdup(const char *s)
75{
76 char *t;
77
78 if (s == NULL)
79 return NULL;
80
81 t = strdup(s);
82
83 if (t == NULL)
84 bb_error_msg_and_die(bb_msg_memory_exhausted);
85
86 return t;
87}
88
89// Die if we can't allocate n+1 bytes (space for the null terminator) and copy
90// the (possibly truncated to length n) string into it.
91char* FAST_FUNC xstrndup(const char *s, int n)
92{
93 int m;
94 char *t;
95
96 if (ENABLE_DEBUG && s == NULL)
97 bb_error_msg_and_die("xstrndup bug");
98
99 /* We can just xmalloc(n+1) and strncpy into it, */
100 /* but think about xstrndup("abc", 10000) wastage! */
101 m = n;
102 t = (char*) s;
103 while (m) {
104 if (!*t) break;
105 m--;
106 t++;
107 }
108 n -= m;
109 t = xmalloc(n + 1);
110 t[n] = '\0';
111
112 return memcpy(t, s, n);
113}
114
115void* FAST_FUNC xmemdup(const void *s, int n)
116{
117 return memcpy(xmalloc(n), s, n);
118}
119
120// Die if we can't open a file and return a FILE* to it.
121// Notice we haven't got xfread(), This is for use with fscanf() and friends.
122FILE* FAST_FUNC xfopen(const char *path, const char *mode)
123{
124 FILE *fp = fopen(path, mode);
125 if (fp == NULL)
126 bb_perror_msg_and_die("can't open '%s'", path);
127 return fp;
128}
129
130// Die if we can't open a file and return a fd.
131int FAST_FUNC xopen3(const char *pathname, int flags, int mode)
132{
133 int ret;
134
135 ret = open(pathname, flags, mode);
136 if (ret < 0) {
137 bb_perror_msg_and_die("can't open '%s'", pathname);
138 }
139 return ret;
140}
141
142// Die if we can't open a file and return a fd.
143int FAST_FUNC xopen(const char *pathname, int flags)
144{
145 return xopen3(pathname, flags, 0666);
146}
147
148// Warn if we can't open a file and return a fd.
149int FAST_FUNC open3_or_warn(const char *pathname, int flags, int mode)
150{
151 int ret;
152
153 ret = open(pathname, flags, mode);
154 if (ret < 0) {
155 bb_perror_msg("can't open '%s'", pathname);
156 }
157 return ret;
158}
159
160// Warn if we can't open a file and return a fd.
161int FAST_FUNC open_or_warn(const char *pathname, int flags)
162{
163 return open3_or_warn(pathname, flags, 0666);
164}
165
166/* Die if we can't open an existing file readonly with O_NONBLOCK
167 * and return the fd.
168 * Note that for ioctl O_RDONLY is sufficient.
169 */
170int FAST_FUNC xopen_nonblocking(const char *pathname)
171{
172 return xopen(pathname, O_RDONLY | O_NONBLOCK);
173}
174
175int FAST_FUNC xopen_as_uid_gid(const char *pathname, int flags, uid_t u, gid_t g)
176{
177 int fd;
178 uid_t old_euid = geteuid();
179 gid_t old_egid = getegid();
180
181 xsetegid(g);
182 xseteuid(u);
183
184 fd = xopen(pathname, flags);
185
186 xseteuid(old_euid);
187 xsetegid(old_egid);
188
189 return fd;
190}
191
192void FAST_FUNC xunlink(const char *pathname)
193{
194 if (unlink(pathname))
195 bb_perror_msg_and_die("can't remove file '%s'", pathname);
196}
197
198void FAST_FUNC xrename(const char *oldpath, const char *newpath)
199{
200 if (rename(oldpath, newpath))
201 bb_perror_msg_and_die("can't move '%s' to '%s'", oldpath, newpath);
202}
203
204int FAST_FUNC rename_or_warn(const char *oldpath, const char *newpath)
205{
206 int n = rename(oldpath, newpath);
207 if (n)
208 bb_perror_msg("can't move '%s' to '%s'", oldpath, newpath);
209 return n;
210}
211
212void FAST_FUNC xpipe(int filedes[2])
213{
214 if (pipe(filedes))
215 bb_perror_msg_and_die("can't create pipe");
216}
217
218void FAST_FUNC xdup2(int from, int to)
219{
220 if (dup2(from, to) != to)
221 bb_perror_msg_and_die("can't duplicate file descriptor");
222}
223
224// "Renumber" opened fd
225void FAST_FUNC xmove_fd(int from, int to)
226{
227 if (from == to)
228 return;
229 xdup2(from, to);
230 close(from);
231}
232
233// Die with an error message if we can't write the entire buffer.
234void FAST_FUNC xwrite(int fd, const void *buf, size_t count)
235{
236 if (count) {
237 ssize_t size = full_write(fd, buf, count);
238 if ((size_t)size != count)
239 bb_error_msg_and_die("short write");
240 }
241}
242void FAST_FUNC xwrite_str(int fd, const char *str)
243{
244 xwrite(fd, str, strlen(str));
245}
246
247void FAST_FUNC xclose(int fd)
248{
249 if (close(fd))
250 bb_perror_msg_and_die("close failed");
251}
252
253// Die with an error message if we can't lseek to the right spot.
254off_t FAST_FUNC xlseek(int fd, off_t offset, int whence)
255{
256 off_t off = lseek(fd, offset, whence);
257 if (off == (off_t)-1) {
258 if (whence == SEEK_SET)
259 bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
260 bb_perror_msg_and_die("lseek");
261 }
262 return off;
263}
264
265int FAST_FUNC xmkstemp(char *template)
266{
267 int fd = mkstemp(template);
268 if (fd < 0)
269 bb_perror_msg_and_die("can't create temp file '%s'", template);
270 return fd;
271}
272
273// Die with supplied filename if this FILE* has ferror set.
274void FAST_FUNC die_if_ferror(FILE *fp, const char *fn)
275{
276 if (ferror(fp)) {
277 /* ferror doesn't set useful errno */
278 bb_error_msg_and_die("%s: I/O error", fn);
279 }
280}
281
282// Die with an error message if stdout has ferror set.
283void FAST_FUNC die_if_ferror_stdout(void)
284{
285 die_if_ferror(stdout, bb_msg_standard_output);
286}
287
288int FAST_FUNC fflush_all(void)
289{
290 return fflush(NULL);
291}
292
293
294int FAST_FUNC bb_putchar(int ch)
295{
296 return putchar(ch);
297}
298
299/* Die with an error message if we can't copy an entire FILE* to stdout,
300 * then close that file. */
301void FAST_FUNC xprint_and_close_file(FILE *file)
302{
303 fflush_all();
304 // copyfd outputs error messages for us.
305 if (bb_copyfd_eof(fileno(file), STDOUT_FILENO) == -1)
306 xfunc_die();
307
308 fclose(file);
309}
310
311// Die with an error message if we can't malloc() enough space and do an
312// sprintf() into that space.
313char* FAST_FUNC xasprintf(const char *format, ...)
314{
315 va_list p;
316 int r;
317 char *string_ptr;
318
319 va_start(p, format);
320 r = vasprintf(&string_ptr, format, p);
321 va_end(p);
322
323 if (r < 0)
324 bb_error_msg_and_die(bb_msg_memory_exhausted);
325 return string_ptr;
326}
327
328void FAST_FUNC xsetenv(const char *key, const char *value)
329{
330 if (setenv(key, value, 1))
331 bb_error_msg_and_die(bb_msg_memory_exhausted);
332}
333
334/* Handles "VAR=VAL" strings, even those which are part of environ
335 * _right now_
336 */
337void FAST_FUNC bb_unsetenv(const char *var)
338{
339 char *tp = strchr(var, '=');
340
341 if (!tp) {
342 unsetenv(var);
343 return;
344 }
345
346 /* In case var was putenv'ed, we can't replace '='
347 * with NUL and unsetenv(var) - it won't work,
348 * env is modified by the replacement, unsetenv
349 * sees "VAR" instead of "VAR=VAL" and does not remove it!
350 * horror :( */
351 tp = xstrndup(var, tp - var);
352 unsetenv(tp);
353 free(tp);
354}
355
356void FAST_FUNC bb_unsetenv_and_free(char *var)
357{
358 bb_unsetenv(var);
359 free(var);
360}
361
362// Die with an error message if we can't set gid. (Because resource limits may
363// limit this user to a given number of processes, and if that fills up the
364// setgid() will fail and we'll _still_be_root_, which is bad.)
365void FAST_FUNC xsetgid(gid_t gid)
366{
367 if (setgid(gid)) bb_perror_msg_and_die("setgid");
368}
369
370// Die with an error message if we can't set uid. (See xsetgid() for why.)
371void FAST_FUNC xsetuid(uid_t uid)
372{
373 if (setuid(uid)) bb_perror_msg_and_die("setuid");
374}
375
376void FAST_FUNC xsetegid(gid_t egid)
377{
378 if (setegid(egid)) bb_perror_msg_and_die("setegid");
379}
380
381void FAST_FUNC xseteuid(uid_t euid)
382{
383 if (seteuid(euid)) bb_perror_msg_and_die("seteuid");
384}
385
386// Die if we can't chdir to a new path.
387void FAST_FUNC xchdir(const char *path)
388{
389 if (chdir(path))
390 bb_perror_msg_and_die("can't change directory to '%s'", path);
391}
392
393void FAST_FUNC xfchdir(int fd)
394{
395 if (fchdir(fd))
396 bb_perror_msg_and_die("fchdir");
397}
398
399void FAST_FUNC xchroot(const char *path)
400{
401 if (chroot(path))
402 bb_perror_msg_and_die("can't change root directory to '%s'", path);
403 xchdir("/");
404}
405
406// Print a warning message if opendir() fails, but don't die.
407DIR* FAST_FUNC warn_opendir(const char *path)
408{
409 DIR *dp;
410
411 dp = opendir(path);
412 if (!dp)
413 bb_perror_msg("can't open '%s'", path);
414 return dp;
415}
416
417// Die with an error message if opendir() fails.
418DIR* FAST_FUNC xopendir(const char *path)
419{
420 DIR *dp;
421
422 dp = opendir(path);
423 if (!dp)
424 bb_perror_msg_and_die("can't open '%s'", path);
425 return dp;
426}
427
428// Die with an error message if we can't open a new socket.
429int FAST_FUNC xsocket(int domain, int type, int protocol)
430{
431 int r = socket(domain, type, protocol);
432
433 if (r < 0) {
434 /* Hijack vaguely related config option */
435#if ENABLE_VERBOSE_RESOLUTION_ERRORS
436 const char *s = "INET";
437# ifdef AF_PACKET
438 if (domain == AF_PACKET) s = "PACKET";
439# endif
440# ifdef AF_NETLINK
441 if (domain == AF_NETLINK) s = "NETLINK";
442# endif
443IF_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
444 bb_perror_msg_and_die("socket(AF_%s,%d,%d)", s, type, protocol);
445#else
446 bb_perror_msg_and_die("socket");
447#endif
448 }
449
450 return r;
451}
452
453// Die with an error message if we can't bind a socket to an address.
454void FAST_FUNC xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
455{
456 if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind");
457}
458
459// Die with an error message if we can't listen for connections on a socket.
460void FAST_FUNC xlisten(int s, int backlog)
461{
462 if (listen(s, backlog)) bb_perror_msg_and_die("listen");
463}
464
465/* Die with an error message if sendto failed.
466 * Return bytes sent otherwise */
467ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
468 socklen_t tolen)
469{
470 ssize_t ret = sendto(s, buf, len, 0, to, tolen);
471 if (ret < 0) {
472 if (ENABLE_FEATURE_CLEAN_UP)
473 close(s);
474 bb_perror_msg_and_die("sendto");
475 }
476 return ret;
477}
478
479// xstat() - a stat() which dies on failure with meaningful error message
480void FAST_FUNC xstat(const char *name, struct stat *stat_buf)
481{
482 if (stat(name, stat_buf))
483 bb_perror_msg_and_die("can't stat '%s'", name);
484}
485
486void FAST_FUNC xfstat(int fd, struct stat *stat_buf, const char *errmsg)
487{
488 /* errmsg is usually a file name, but not always:
489 * xfstat may be called in a spot where file name is no longer
490 * available, and caller may give e.g. "can't stat input file" string.
491 */
492 if (fstat(fd, stat_buf))
493 bb_simple_perror_msg_and_die(errmsg);
494}
495
496// selinux_or_die() - die if SELinux is disabled.
497void FAST_FUNC selinux_or_die(void)
498{
499#if ENABLE_SELINUX
500 int rc = is_selinux_enabled();
501 if (rc == 0) {
502 bb_error_msg_and_die("SELinux is disabled");
503 } else if (rc < 0) {
504 bb_error_msg_and_die("is_selinux_enabled() failed");
505 }
506#else
507 bb_error_msg_and_die("SELinux support is disabled");
508#endif
509}
510
511int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
512{
513 int ret;
514 va_list p;
515
516 ret = ioctl(fd, request, argp);
517 if (ret < 0) {
518 va_start(p, fmt);
519 bb_verror_msg(fmt, p, strerror(errno));
520 /* xfunc_die can actually longjmp, so be nice */
521 va_end(p);
522 xfunc_die();
523 }
524 return ret;
525}
526
527int FAST_FUNC ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...)
528{
529 va_list p;
530 int ret = ioctl(fd, request, argp);
531
532 if (ret < 0) {
533 va_start(p, fmt);
534 bb_verror_msg(fmt, p, strerror(errno));
535 va_end(p);
536 }
537 return ret;
538}
539
540#if ENABLE_IOCTL_HEX2STR_ERROR
541int FAST_FUNC bb_ioctl_or_warn(int fd, unsigned request, void *argp, const char *ioctl_name)
542{
543 int ret;
544
545 ret = ioctl(fd, request, argp);
546 if (ret < 0)
547 bb_simple_perror_msg(ioctl_name);
548 return ret;
549}
550int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp, const char *ioctl_name)
551{
552 int ret;
553
554 ret = ioctl(fd, request, argp);
555 if (ret < 0)
556 bb_simple_perror_msg_and_die(ioctl_name);
557 return ret;
558}
559#else
560int FAST_FUNC bb_ioctl_or_warn(int fd, unsigned request, void *argp)
561{
562 int ret;
563
564 ret = ioctl(fd, request, argp);
565 if (ret < 0)
566 bb_perror_msg("ioctl %#x failed", request);
567 return ret;
568}
569int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp)
570{
571 int ret;
572
573 ret = ioctl(fd, request, argp);
574 if (ret < 0)
575 bb_perror_msg_and_die("ioctl %#x failed", request);
576 return ret;
577}
578#endif
579
580char* FAST_FUNC xmalloc_ttyname(int fd)
581{
582 char buf[128];
583 int r = ttyname_r(fd, buf, sizeof(buf) - 1);
584 if (r)
585 return NULL;
586 return xstrdup(buf);
587}
588
589void FAST_FUNC generate_uuid(uint8_t *buf)
590{
591 /* http://www.ietf.org/rfc/rfc4122.txt
592 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
593 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
594 * | time_low |
595 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
596 * | time_mid | time_hi_and_version |
597 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
598 * |clk_seq_and_variant | node (0-1) |
599 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
600 * | node (2-5) |
601 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
602 * IOW, uuid has this layout:
603 * uint32_t time_low (big endian)
604 * uint16_t time_mid (big endian)
605 * uint16_t time_hi_and_version (big endian)
606 * version is a 4-bit field:
607 * 1 Time-based
608 * 2 DCE Security, with embedded POSIX UIDs
609 * 3 Name-based (MD5)
610 * 4 Randomly generated
611 * 5 Name-based (SHA-1)
612 * uint16_t clk_seq_and_variant (big endian)
613 * variant is a 3-bit field:
614 * 0xx Reserved, NCS backward compatibility
615 * 10x The variant specified in rfc4122
616 * 110 Reserved, Microsoft backward compatibility
617 * 111 Reserved for future definition
618 * uint8_t node[6]
619 *
620 * For version 4, these bits are set/cleared:
621 * time_hi_and_version & 0x0fff | 0x4000
622 * clk_seq_and_variant & 0x3fff | 0x8000
623 */
624 pid_t pid;
625 int i;
626
627 i = open("/dev/urandom", O_RDONLY);
628 if (i >= 0) {
629 read(i, buf, 16);
630 close(i);
631 }
632 /* Paranoia. /dev/urandom may be missing.
633 * rand() is guaranteed to generate at least [0, 2^15) range,
634 * but lowest bits in some libc are not so "random". */
635 srand(monotonic_us()); /* pulls in printf */
636 pid = getpid();
637 while (1) {
638 for (i = 0; i < 16; i++)
639 buf[i] ^= rand() >> 5;
640 if (pid == 0)
641 break;
642 srand(pid);
643 pid = 0;
644 }
645
646 /* version = 4 */
647 buf[4 + 2 ] = (buf[4 + 2 ] & 0x0f) | 0x40;
648 /* variant = 10x */
649 buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80;
650}
651
652#if BB_MMU
653pid_t FAST_FUNC xfork(void)
654{
655 pid_t pid;
656 pid = fork();
657 if (pid < 0) /* wtf? */
658 bb_perror_msg_and_die("vfork"+1);
659 return pid;
660}
661#endif
662
663void FAST_FUNC xvfork_parent_waits_and_exits(void)
664{
665 pid_t pid;
666
667 fflush_all();
668 pid = xvfork();
669 if (pid > 0) {
670 /* Parent */
671 int exit_status = wait_for_exitstatus(pid);
672 if (WIFSIGNALED(exit_status))
673 kill_myself_with_sig(WTERMSIG(exit_status));
674 _exit(WEXITSTATUS(exit_status));
675 }
676 /* Child continues */
677}
Note: See TracBrowser for help on using the repository browser.