4 |
* |
* |
5 |
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
6 |
* Copyright (C) 2006 Rob Landley |
* Copyright (C) 2006 Rob Landley |
7 |
* Copyright (C) 2006 Denis Vlasenko |
* Copyright (C) 2006 Denys Vlasenko |
8 |
* |
* |
9 |
* Licensed under GPL version 2, see file LICENSE in this tarball for details. |
* Licensed under GPL version 2, see file LICENSE in this tarball for details. |
10 |
*/ |
*/ |
11 |
|
|
12 |
#include "busybox.h" |
/* We need to have separate xfuncs.c and xfuncs_printf.c because |
13 |
|
* with current linkers, even with section garbage collection, |
14 |
/* All the functions starting with "x" call bb_error_msg_and_die() if they |
* if *.o module references any of XXXprintf functions, you pull in |
15 |
* fail, so callers never need to check for errors. If it returned, it |
* entire printf machinery. Even if you do not use the function |
16 |
* succeeded. */ |
* which uses XXXprintf. |
17 |
|
* |
18 |
#ifndef DMALLOC |
* xfuncs.c contains functions (not necessarily xfuncs) |
19 |
/* dmalloc provides variants of these that do abort() on failure. |
* which do not pull in printf, directly or indirectly. |
20 |
* Since dmalloc's prototypes overwrite the impls here as they are |
* xfunc_printf.c contains those which do. |
21 |
* included after these prototypes in libbb.h, all is well. |
* |
22 |
|
* TODO: move xmalloc() and xatonum() here. |
23 |
*/ |
*/ |
|
// Die if we can't allocate size bytes of memory. |
|
|
void *xmalloc(size_t size) |
|
|
{ |
|
|
void *ptr = malloc(size); |
|
|
if (ptr == NULL && size != 0) |
|
|
bb_error_msg_and_die(bb_msg_memory_exhausted); |
|
|
return ptr; |
|
|
} |
|
|
|
|
|
// Die if we can't resize previously allocated memory. (This returns a pointer |
|
|
// to the new memory, which may or may not be the same as the old memory. |
|
|
// It'll copy the contents to a new chunk and free the old one if necessary.) |
|
|
void *xrealloc(void *ptr, size_t size) |
|
|
{ |
|
|
ptr = realloc(ptr, size); |
|
|
if (ptr == NULL && size != 0) |
|
|
bb_error_msg_and_die(bb_msg_memory_exhausted); |
|
|
return ptr; |
|
|
} |
|
|
#endif /* DMALLOC */ |
|
|
|
|
|
// Die if we can't allocate and zero size bytes of memory. |
|
|
void *xzalloc(size_t size) |
|
|
{ |
|
|
void *ptr = xmalloc(size); |
|
|
memset(ptr, 0, size); |
|
|
return ptr; |
|
|
} |
|
|
|
|
|
// Die if we can't copy a string to freshly allocated memory. |
|
|
char * xstrdup(const char *s) |
|
|
{ |
|
|
char *t; |
|
|
|
|
|
if (s == NULL) |
|
|
return NULL; |
|
|
|
|
|
t = strdup(s); |
|
|
|
|
|
if (t == NULL) |
|
|
bb_error_msg_and_die(bb_msg_memory_exhausted); |
|
|
|
|
|
return t; |
|
|
} |
|
|
|
|
|
// Die if we can't allocate n+1 bytes (space for the null terminator) and copy |
|
|
// the (possibly truncated to length n) string into it. |
|
|
char * xstrndup(const char *s, int n) |
|
|
{ |
|
|
int m; |
|
|
char *t; |
|
|
|
|
|
if (ENABLE_DEBUG && s == NULL) |
|
|
bb_error_msg_and_die("xstrndup bug"); |
|
|
|
|
|
/* We can just xmalloc(n+1) and strncpy into it, */ |
|
|
/* but think about xstrndup("abc", 10000) wastage! */ |
|
|
m = n; |
|
|
t = (char*) s; |
|
|
while (m) { |
|
|
if (!*t) break; |
|
|
m--; |
|
|
t++; |
|
|
} |
|
|
n -= m; |
|
|
t = xmalloc(n + 1); |
|
|
t[n] = '\0'; |
|
|
|
|
|
return memcpy(t, s, n); |
|
|
} |
|
|
|
|
|
// Die if we can't open a file and return a FILE * to it. |
|
|
// Notice we haven't got xfread(), This is for use with fscanf() and friends. |
|
|
FILE *xfopen(const char *path, const char *mode) |
|
|
{ |
|
|
FILE *fp = fopen(path, mode); |
|
|
if (fp == NULL) |
|
|
bb_perror_msg_and_die("%s", path); |
|
|
return fp; |
|
|
} |
|
|
|
|
|
// Die if we can't open an existing file and return an fd. |
|
|
int xopen(const char *pathname, int flags) |
|
|
{ |
|
|
//if (ENABLE_DEBUG && (flags & O_CREAT)) |
|
|
// bb_error_msg_and_die("xopen() with O_CREAT"); |
|
|
|
|
|
return xopen3(pathname, flags, 0666); |
|
|
} |
|
|
|
|
|
// Die if we can't open a new file and return an fd. |
|
|
int xopen3(const char *pathname, int flags, int mode) |
|
|
{ |
|
|
int ret; |
|
24 |
|
|
25 |
ret = open(pathname, flags, mode); |
#include "libbb.h" |
|
if (ret < 0) { |
|
|
bb_perror_msg_and_die("%s", pathname); |
|
|
} |
|
|
return ret; |
|
|
} |
|
26 |
|
|
27 |
// Turn on nonblocking I/O on a fd |
/* Turn on nonblocking I/O on a fd */ |
28 |
int ndelay_on(int fd) |
int FAST_FUNC ndelay_on(int fd) |
29 |
{ |
{ |
30 |
return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK); |
return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK); |
31 |
} |
} |
32 |
|
|
33 |
int ndelay_off(int fd) |
int FAST_FUNC ndelay_off(int fd) |
34 |
{ |
{ |
35 |
return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK); |
return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK); |
36 |
} |
} |
37 |
|
|
38 |
// Die with an error message if we can't write the entire buffer. |
int FAST_FUNC close_on_exec_on(int fd) |
|
void xwrite(int fd, const void *buf, size_t count) |
|
39 |
{ |
{ |
40 |
if (count) { |
return fcntl(fd, F_SETFD, FD_CLOEXEC); |
|
ssize_t size = full_write(fd, buf, count); |
|
|
if (size != count) |
|
|
bb_error_msg_and_die("short write"); |
|
|
} |
|
41 |
} |
} |
42 |
|
|
43 |
// Die with an error message if we can't lseek to the right spot. |
/* Convert unsigned long long value into compact 4-char |
44 |
off_t xlseek(int fd, off_t offset, int whence) |
* representation. Examples: "1234", "1.2k", " 27M", "123T" |
45 |
|
* String is not terminated (buf[4] is untouched) */ |
46 |
|
void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) |
47 |
{ |
{ |
48 |
off_t off = lseek(fd, offset, whence); |
const char *fmt; |
49 |
if (off == (off_t)-1) { |
char c; |
50 |
if (whence == SEEK_SET) |
unsigned v, u, idx = 0; |
|
bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset); |
|
|
bb_perror_msg_and_die("lseek"); |
|
|
} |
|
|
return off; |
|
|
} |
|
|
|
|
|
// Die with supplied filename if this FILE * has ferror set. |
|
|
void die_if_ferror(FILE *fp, const char *fn) |
|
|
{ |
|
|
if (ferror(fp)) { |
|
|
bb_error_msg_and_die("%s: I/O error", fn); |
|
|
} |
|
|
} |
|
|
|
|
|
// Die with an error message if stdout has ferror set. |
|
|
void die_if_ferror_stdout(void) |
|
|
{ |
|
|
die_if_ferror(stdout, bb_msg_standard_output); |
|
|
} |
|
51 |
|
|
52 |
// Die with an error message if we have trouble flushing stdout. |
if (ul > 9999) { // do not scale if 9999 or less |
53 |
void xfflush_stdout(void) |
ul *= 10; |
54 |
{ |
do { |
55 |
if (fflush(stdout)) { |
ul /= 1024; |
56 |
bb_perror_msg_and_die(bb_msg_standard_output); |
idx++; |
57 |
|
} while (ul >= 10000); |
58 |
} |
} |
59 |
} |
v = ul; // ullong divisions are expensive, avoid them |
|
|
|
|
// This does a fork/exec in one call, using vfork(). Return PID of new child, |
|
|
// -1 for failure. Runs argv[0], searching path if that has no / in it. |
|
|
pid_t spawn(char **argv) |
|
|
{ |
|
|
/* Why static? */ |
|
|
static int failed; |
|
|
pid_t pid; |
|
|
void *app = ENABLE_FEATURE_SH_STANDALONE_SHELL ? find_applet_by_name(argv[0]) : 0; |
|
|
|
|
|
// Be nice to nommu machines. |
|
|
failed = 0; |
|
|
pid = vfork(); |
|
|
if (pid < 0) return pid; |
|
|
if (!pid) { |
|
|
execvp(app ? CONFIG_BUSYBOX_EXEC_PATH : *argv, argv); |
|
|
|
|
|
// We're sharing a stack with blocked parent, let parent know we failed |
|
|
// and then exit to unblock parent (but don't run atexit() stuff, which |
|
|
// would screw up parent.) |
|
60 |
|
|
61 |
failed = errno; |
fmt = " 123456789"; |
62 |
_exit(0); |
u = v / 10; |
63 |
} |
v = v % 10; |
64 |
if (failed) { |
if (!idx) { |
65 |
errno = failed; |
// 9999 or less: use "1234" format |
66 |
return -1; |
// u is value/10, v is last digit |
67 |
|
c = buf[0] = " 123456789"[u/100]; |
68 |
|
if (c != ' ') fmt = "0123456789"; |
69 |
|
c = buf[1] = fmt[u/10%10]; |
70 |
|
if (c != ' ') fmt = "0123456789"; |
71 |
|
buf[2] = fmt[u%10]; |
72 |
|
buf[3] = "0123456789"[v]; |
73 |
|
} else { |
74 |
|
// u is value, v is 1/10ths (allows for 9.2M format) |
75 |
|
if (u >= 10) { |
76 |
|
// value is >= 10: use "123M', " 12M" formats |
77 |
|
c = buf[0] = " 123456789"[u/100]; |
78 |
|
if (c != ' ') fmt = "0123456789"; |
79 |
|
v = u % 10; |
80 |
|
u = u / 10; |
81 |
|
buf[1] = fmt[u%10]; |
82 |
|
} else { |
83 |
|
// value is < 10: use "9.2M" format |
84 |
|
buf[0] = "0123456789"[u]; |
85 |
|
buf[1] = '.'; |
86 |
|
} |
87 |
|
buf[2] = "0123456789"[v]; |
88 |
|
buf[3] = scale[idx]; /* typically scale = " kmgt..." */ |
89 |
} |
} |
|
return pid; |
|
|
} |
|
|
|
|
|
// Die with an error message if we can't spawn a child process. |
|
|
pid_t xspawn(char **argv) |
|
|
{ |
|
|
pid_t pid = spawn(argv); |
|
|
if (pid < 0) bb_perror_msg_and_die("%s", *argv); |
|
|
return pid; |
|
|
} |
|
|
|
|
|
// Wait for the specified child PID to exit, returning child's error return. |
|
|
int wait4pid(int pid) |
|
|
{ |
|
|
int status; |
|
|
|
|
|
if (pid == -1 || waitpid(pid, &status, 0) == -1) return -1; |
|
|
if (WIFEXITED(status)) return WEXITSTATUS(status); |
|
|
if (WIFSIGNALED(status)) return WTERMSIG(status); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
void xsetenv(const char *key, const char *value) |
|
|
{ |
|
|
if (setenv(key, value, 1)) |
|
|
bb_error_msg_and_die(bb_msg_memory_exhausted); |
|
90 |
} |
} |
91 |
|
|
92 |
// Converts unsigned long long value into compact 4-char |
/* Convert unsigned long long value into compact 5-char representation. |
93 |
// representation. Examples: "1234", "1.2k", " 27M", "123T" |
* String is not terminated (buf[5] is untouched) */ |
94 |
// Fifth char is always '\0' |
void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) |
|
void smart_ulltoa5(unsigned long long ul, char buf[5]) |
|
95 |
{ |
{ |
96 |
char *fmt; |
const char *fmt; |
97 |
char c; |
char c; |
98 |
unsigned v,idx = 0; |
unsigned v, u, idx = 0; |
99 |
ul *= 10; |
|
100 |
if (ul > 9999*10) { // do not scale if 9999 or less |
if (ul > 99999) { // do not scale if 99999 or less |
101 |
while (ul >= 10000) { |
ul *= 10; |
102 |
|
do { |
103 |
ul /= 1024; |
ul /= 1024; |
104 |
idx++; |
idx++; |
105 |
} |
} while (ul >= 100000); |
106 |
} |
} |
107 |
v = ul; // ullong divisions are expensive, avoid them |
v = ul; // ullong divisions are expensive, avoid them |
108 |
|
|
109 |
fmt = " 123456789"; |
fmt = " 123456789"; |
110 |
if (!idx) { // 9999 or less: use 1234 format |
u = v / 10; |
111 |
c = buf[0] = " 123456789"[v/10000]; |
v = v % 10; |
112 |
if (c!=' ') fmt = "0123456789"; |
if (!idx) { |
113 |
c = buf[1] = fmt[v/1000%10]; |
// 99999 or less: use "12345" format |
114 |
if (c!=' ') fmt = "0123456789"; |
// u is value/10, v is last digit |
115 |
buf[2] = fmt[v/100%10]; |
c = buf[0] = " 123456789"[u/1000]; |
116 |
buf[3] = "0123456789"[v/10%10]; |
if (c != ' ') fmt = "0123456789"; |
117 |
|
c = buf[1] = fmt[u/100%10]; |
118 |
|
if (c != ' ') fmt = "0123456789"; |
119 |
|
c = buf[2] = fmt[u/10%10]; |
120 |
|
if (c != ' ') fmt = "0123456789"; |
121 |
|
buf[3] = fmt[u%10]; |
122 |
|
buf[4] = "0123456789"[v]; |
123 |
} else { |
} else { |
124 |
if (v>=10*10) { // scaled value is >=10: use 123M format |
// value has been scaled into 0..9999.9 range |
125 |
c = buf[0] = " 123456789"[v/1000]; |
// u is value, v is 1/10ths (allows for 92.1M format) |
126 |
if (c!=' ') fmt = "0123456789"; |
if (u >= 100) { |
127 |
buf[1] = fmt[v/100%10]; |
// value is >= 100: use "1234M', " 123M" formats |
128 |
buf[2] = "0123456789"[v/10%10]; |
c = buf[0] = " 123456789"[u/1000]; |
129 |
} else { // scaled value is <10: use 1.2M format |
if (c != ' ') fmt = "0123456789"; |
130 |
buf[0] = "0123456789"[v/10]; |
c = buf[1] = fmt[u/100%10]; |
131 |
buf[1] = '.'; |
if (c != ' ') fmt = "0123456789"; |
132 |
buf[2] = "0123456789"[v%10]; |
v = u % 10; |
133 |
|
u = u / 10; |
134 |
|
buf[2] = fmt[u%10]; |
135 |
|
} else { |
136 |
|
// value is < 100: use "92.1M" format |
137 |
|
c = buf[0] = " 123456789"[u/10]; |
138 |
|
if (c != ' ') fmt = "0123456789"; |
139 |
|
buf[1] = fmt[u%10]; |
140 |
|
buf[2] = '.'; |
141 |
} |
} |
142 |
// see http://en.wikipedia.org/wiki/Tera |
buf[3] = "0123456789"[v]; |
143 |
buf[3] = " kMGTPEZY"[idx]; |
buf[4] = scale[idx]; /* typically scale = " kmgt..." */ |
144 |
} |
} |
|
buf[4] = '\0'; |
|
145 |
} |
} |
146 |
|
|
147 |
// Convert unsigned integer to ascii, writing into supplied buffer. A |
|
148 |
// truncated result is always null terminated (unless buflen is 0), and |
// Convert unsigned integer to ascii, writing into supplied buffer. |
149 |
// contains the first few digits of the result ala strncpy. |
// A truncated result contains the first few digits of the result ala strncpy. |
150 |
|
// Returns a pointer past last generated digit, does _not_ store NUL. |
151 |
void BUG_sizeof_unsigned_not_4(void); |
void BUG_sizeof_unsigned_not_4(void); |
152 |
void utoa_to_buf(unsigned n, char *buf, unsigned buflen) |
char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen) |
153 |
{ |
{ |
154 |
unsigned i, out, res; |
unsigned i, out, res; |
155 |
if (sizeof(unsigned) != 4) |
if (sizeof(unsigned) != 4) |
165 |
*buf++ = '0' + res; |
*buf++ = '0' + res; |
166 |
} |
} |
167 |
} |
} |
|
*buf = '\0'; |
|
168 |
} |
} |
169 |
|
return buf; |
170 |
} |
} |
171 |
|
|
172 |
// Convert signed integer to ascii, like utoa_to_buf() |
/* Convert signed integer to ascii, like utoa_to_buf() */ |
173 |
void itoa_to_buf(int n, char *buf, unsigned buflen) |
char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen) |
174 |
{ |
{ |
175 |
if (buflen && n<0) { |
if (buflen && n < 0) { |
176 |
n = -n; |
n = -n; |
177 |
*buf++ = '-'; |
*buf++ = '-'; |
178 |
buflen--; |
buflen--; |
179 |
} |
} |
180 |
utoa_to_buf((unsigned)n, buf, buflen); |
return utoa_to_buf((unsigned)n, buf, buflen); |
181 |
} |
} |
182 |
|
|
183 |
// The following two functions use a static buffer, so calling either one a |
// The following two functions use a static buffer, so calling either one a |
184 |
// second time will overwrite previous results. |
// second time will overwrite previous results. |
185 |
// |
// |
186 |
// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes. |
// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes. |
187 |
// Int should always be 32 bits on any remotely Unix-like system, see |
// It so happens that sizeof(int) * 3 is enough for 32+ bits. |
188 |
// http://www.unix.org/whitepapers/64bit.html for the reasons why. |
// (sizeof(int) * 3 + 2 is correct for any width, even 8-bit) |
189 |
|
|
190 |
static char local_buf[12]; |
static char local_buf[sizeof(int) * 3]; |
191 |
|
|
192 |
// Convert unsigned integer to ascii using a static buffer (returned). |
// Convert unsigned integer to ascii using a static buffer (returned). |
193 |
char *utoa(unsigned n) |
char* FAST_FUNC utoa(unsigned n) |
194 |
{ |
{ |
195 |
utoa_to_buf(n, local_buf, sizeof(local_buf)); |
*(utoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; |
196 |
|
|
197 |
return local_buf; |
return local_buf; |
198 |
} |
} |
199 |
|
|
200 |
// Convert signed integer to ascii using a static buffer (returned). |
/* Convert signed integer to ascii using a static buffer (returned). */ |
201 |
char *itoa(int n) |
char* FAST_FUNC itoa(int n) |
202 |
{ |
{ |
203 |
itoa_to_buf(n, local_buf, sizeof(local_buf)); |
*(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; |
204 |
|
|
205 |
return local_buf; |
return local_buf; |
206 |
} |
} |
207 |
|
|
208 |
// Emit a string of hex representation of bytes |
/* Emit a string of hex representation of bytes */ |
209 |
char *bin2hex(char *p, const char *cp, int count) |
char* FAST_FUNC bin2hex(char *p, const char *cp, int count) |
210 |
{ |
{ |
211 |
while (count) { |
while (count) { |
212 |
unsigned char c = *cp++; |
unsigned char c = *cp++; |
218 |
return p; |
return p; |
219 |
} |
} |
220 |
|
|
221 |
// Die with an error message if we can't set gid. (Because resource limits may |
/* Return how long the file at fd is, if there's any way to determine it. */ |
222 |
// limit this user to a given number of processes, and if that fills up the |
#ifdef UNUSED |
223 |
// setgid() will fail and we'll _still_be_root_, which is bad.) |
off_t FAST_FUNC fdlength(int fd) |
|
void xsetgid(gid_t gid) |
|
|
{ |
|
|
if (setgid(gid)) bb_error_msg_and_die("setgid"); |
|
|
} |
|
|
|
|
|
// Die with an error message if we can't set uid. (See xsetgid() for why.) |
|
|
void xsetuid(uid_t uid) |
|
|
{ |
|
|
if (setuid(uid)) bb_error_msg_and_die("setuid"); |
|
|
} |
|
|
|
|
|
// Return how long the file at fd is, if there's any way to determine it. |
|
|
off_t fdlength(int fd) |
|
224 |
{ |
{ |
225 |
off_t bottom = 0, top = 0, pos; |
off_t bottom = 0, top = 0, pos; |
226 |
long size; |
long size; |
258 |
|
|
259 |
return pos + 1; |
return pos + 1; |
260 |
} |
} |
|
|
|
|
// Die with an error message if we can't malloc() enough space and do an |
|
|
// sprintf() into that space. |
|
|
char *xasprintf(const char *format, ...) |
|
|
{ |
|
|
va_list p; |
|
|
int r; |
|
|
char *string_ptr; |
|
|
|
|
|
#if 1 |
|
|
// GNU extension |
|
|
va_start(p, format); |
|
|
r = vasprintf(&string_ptr, format, p); |
|
|
va_end(p); |
|
|
#else |
|
|
// Bloat for systems that haven't got the GNU extension. |
|
|
va_start(p, format); |
|
|
r = vsnprintf(NULL, 0, format, p); |
|
|
va_end(p); |
|
|
string_ptr = xmalloc(r+1); |
|
|
va_start(p, format); |
|
|
r = vsnprintf(string_ptr, r+1, format, p); |
|
|
va_end(p); |
|
|
#endif |
|
|
|
|
|
if (r < 0) bb_error_msg_and_die(bb_msg_memory_exhausted); |
|
|
return string_ptr; |
|
|
} |
|
|
|
|
|
#if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */ |
|
|
int fdprintf(int fd, const char *format, ...) |
|
|
{ |
|
|
va_list p; |
|
|
int r; |
|
|
char *string_ptr; |
|
|
|
|
|
#if 1 |
|
|
// GNU extension |
|
|
va_start(p, format); |
|
|
r = vasprintf(&string_ptr, format, p); |
|
|
va_end(p); |
|
|
#else |
|
|
// Bloat for systems that haven't got the GNU extension. |
|
|
va_start(p, format); |
|
|
r = vsnprintf(NULL, 0, format, p); |
|
|
va_end(p); |
|
|
string_ptr = xmalloc(r+1); |
|
|
va_start(p, format); |
|
|
r = vsnprintf(string_ptr, r+1, format, p); |
|
|
va_end(p); |
|
|
#endif |
|
|
|
|
|
if (r >= 0) { |
|
|
full_write(fd, string_ptr, r); |
|
|
free(string_ptr); |
|
|
} |
|
|
return r; |
|
|
} |
|
|
#endif |
|
|
|
|
|
// Die with an error message if we can't copy an entire FILE * to stdout, then |
|
|
// close that file. |
|
|
void xprint_and_close_file(FILE *file) |
|
|
{ |
|
|
fflush(stdout); |
|
|
// copyfd outputs error messages for us. |
|
|
if (bb_copyfd_eof(fileno(file), 1) == -1) |
|
|
exit(xfunc_error_retval); |
|
|
|
|
|
fclose(file); |
|
|
} |
|
|
|
|
|
// Die if we can't chdir to a new path. |
|
|
void xchdir(const char *path) |
|
|
{ |
|
|
if (chdir(path)) |
|
|
bb_perror_msg_and_die("chdir(%s)", path); |
|
|
} |
|
|
|
|
|
// Print a warning message if opendir() fails, but don't die. |
|
|
DIR *warn_opendir(const char *path) |
|
|
{ |
|
|
DIR *dp; |
|
|
|
|
|
if ((dp = opendir(path)) == NULL) { |
|
|
bb_perror_msg("cannot open '%s'", path); |
|
|
return NULL; |
|
|
} |
|
|
return dp; |
|
|
} |
|
|
|
|
|
// Die with an error message if opendir() fails. |
|
|
DIR *xopendir(const char *path) |
|
|
{ |
|
|
DIR *dp; |
|
|
|
|
|
if ((dp = opendir(path)) == NULL) |
|
|
bb_perror_msg_and_die("cannot open '%s'", path); |
|
|
return dp; |
|
|
} |
|
|
|
|
|
#ifndef BB_NOMMU |
|
|
// Die with an error message if we can't daemonize. |
|
|
void xdaemon(int nochdir, int noclose) |
|
|
{ |
|
|
if (daemon(nochdir, noclose)) |
|
|
bb_perror_msg_and_die("daemon"); |
|
|
} |
|
261 |
#endif |
#endif |
262 |
|
|
|
void bb_sanitize_stdio_maybe_daemonize(int daemonize) |
|
|
{ |
|
|
int fd; |
|
|
/* Mega-paranoid */ |
|
|
fd = xopen(bb_dev_null, O_RDWR); |
|
|
while (fd < 2) |
|
|
fd = dup(fd); /* have 0,1,2 open at least to /dev/null */ |
|
|
if (daemonize) { |
|
|
pid_t pid = fork(); |
|
|
if (pid < 0) /* wtf? */ |
|
|
bb_perror_msg_and_die("fork"); |
|
|
if (pid) /* parent */ |
|
|
exit(0); |
|
|
/* child */ |
|
|
/* if daemonizing, make sure we detach from stdio */ |
|
|
setsid(); |
|
|
dup2(fd, 0); |
|
|
dup2(fd, 1); |
|
|
dup2(fd, 2); |
|
|
} |
|
|
while (fd > 2) |
|
|
close(fd--); /* close everything after fd#2 */ |
|
|
} |
|
|
void bb_sanitize_stdio(void) |
|
|
{ |
|
|
bb_sanitize_stdio_maybe_daemonize(0); |
|
|
} |
|
|
void bb_daemonize(void) |
|
|
{ |
|
|
bb_sanitize_stdio_maybe_daemonize(1); |
|
|
} |
|
|
|
|
|
// Die with an error message if we can't open a new socket. |
|
|
int xsocket(int domain, int type, int protocol) |
|
|
{ |
|
|
int r = socket(domain, type, protocol); |
|
|
|
|
|
if (r < 0) bb_perror_msg_and_die("socket"); |
|
|
|
|
|
return r; |
|
|
} |
|
|
|
|
|
// Die with an error message if we can't bind a socket to an address. |
|
|
void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) |
|
|
{ |
|
|
if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind"); |
|
|
} |
|
|
|
|
|
// Die with an error message if we can't listen for connections on a socket. |
|
|
void xlisten(int s, int backlog) |
|
|
{ |
|
|
if (listen(s, backlog)) bb_perror_msg_and_die("listen"); |
|
|
} |
|
|
|
|
|
// xstat() - a stat() which dies on failure with meaningful error message |
|
|
void xstat(char *name, struct stat *stat_buf) |
|
|
{ |
|
|
if (stat(name, stat_buf)) |
|
|
bb_perror_msg_and_die("can't stat '%s'", name); |
|
|
} |
|
|
|
|
263 |
/* It is perfectly ok to pass in a NULL for either width or for |
/* It is perfectly ok to pass in a NULL for either width or for |
264 |
* height, in which case that value will not be set. */ |
* height, in which case that value will not be set. */ |
265 |
int get_terminal_width_height(int fd, int *width, int *height) |
int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) |
266 |
{ |
{ |
267 |
struct winsize win = { 0, 0, 0, 0 }; |
struct winsize win = { 0, 0, 0, 0 }; |
268 |
int ret = ioctl(fd, TIOCGWINSZ, &win); |
int ret = ioctl(fd, TIOCGWINSZ, &win); |
289 |
|
|
290 |
return ret; |
return ret; |
291 |
} |
} |
292 |
|
|
293 |
|
int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) |
294 |
|
{ |
295 |
|
return tcsetattr(STDIN_FILENO, TCSANOW, tp); |
296 |
|
} |