diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-04-09 00:33:53 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-04-09 00:33:53 +0000 |
commit | 858ebf130ae3c337f64af7c510ac86d412c055ed (patch) | |
tree | af1924c817274a6b161f7ff50fbb373b81b0c3f0 /libbb | |
parent | b12b1c87b590a4bcdcafc8c6bc221ae6390bee93 (diff) | |
download | busybox-w32-858ebf130ae3c337f64af7c510ac86d412c055ed.tar.gz busybox-w32-858ebf130ae3c337f64af7c510ac86d412c055ed.tar.bz2 busybox-w32-858ebf130ae3c337f64af7c510ac86d412c055ed.zip |
actually adding xfuncs_printf.c :(
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/xfuncs_printf.c | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c new file mode 100644 index 000000000..dd8687dc6 --- /dev/null +++ b/libbb/xfuncs_printf.c | |||
@@ -0,0 +1,521 @@ | |||
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 GPL version 2, see file LICENSE in this tarball for details. | ||
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. | ||
36 | void *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. | ||
45 | void *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.) | ||
56 | void *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. | ||
66 | void *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. | ||
74 | char * 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. | ||
91 | char *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 | |||
115 | // Die if we can't open a file and return a FILE * to it. | ||
116 | // Notice we haven't got xfread(), This is for use with fscanf() and friends. | ||
117 | FILE *xfopen(const char *path, const char *mode) | ||
118 | { | ||
119 | FILE *fp = fopen(path, mode); | ||
120 | if (fp == NULL) | ||
121 | bb_perror_msg_and_die("can't open '%s'", path); | ||
122 | return fp; | ||
123 | } | ||
124 | |||
125 | // Die if we can't open a file and return a fd. | ||
126 | int xopen3(const char *pathname, int flags, int mode) | ||
127 | { | ||
128 | int ret; | ||
129 | |||
130 | ret = open(pathname, flags, mode); | ||
131 | if (ret < 0) { | ||
132 | bb_perror_msg_and_die("can't open '%s'", pathname); | ||
133 | } | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | // Die if we can't open an existing file and return a fd. | ||
138 | int xopen(const char *pathname, int flags) | ||
139 | { | ||
140 | return xopen3(pathname, flags, 0666); | ||
141 | } | ||
142 | |||
143 | // Warn if we can't open a file and return a fd. | ||
144 | int open3_or_warn(const char *pathname, int flags, int mode) | ||
145 | { | ||
146 | int ret; | ||
147 | |||
148 | ret = open(pathname, flags, mode); | ||
149 | if (ret < 0) { | ||
150 | bb_perror_msg("can't open '%s'", pathname); | ||
151 | } | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | // Warn if we can't open a file and return a fd. | ||
156 | int open_or_warn(const char *pathname, int flags) | ||
157 | { | ||
158 | return open3_or_warn(pathname, flags, 0666); | ||
159 | } | ||
160 | |||
161 | void xunlink(const char *pathname) | ||
162 | { | ||
163 | if (unlink(pathname)) | ||
164 | bb_perror_msg_and_die("can't remove file '%s'", pathname); | ||
165 | } | ||
166 | |||
167 | void xrename(const char *oldpath, const char *newpath) | ||
168 | { | ||
169 | if (rename(oldpath, newpath)) | ||
170 | bb_perror_msg_and_die("can't move '%s' to '%s'", oldpath, newpath); | ||
171 | } | ||
172 | |||
173 | int rename_or_warn(const char *oldpath, const char *newpath) | ||
174 | { | ||
175 | int n = rename(oldpath, newpath); | ||
176 | if (n) | ||
177 | bb_perror_msg("can't move '%s' to '%s'", oldpath, newpath); | ||
178 | return n; | ||
179 | } | ||
180 | |||
181 | void xpipe(int filedes[2]) | ||
182 | { | ||
183 | if (pipe(filedes)) | ||
184 | bb_perror_msg_and_die("can't create pipe"); | ||
185 | } | ||
186 | |||
187 | void xdup2(int from, int to) | ||
188 | { | ||
189 | if (dup2(from, to) != to) | ||
190 | bb_perror_msg_and_die("can't duplicate file descriptor"); | ||
191 | } | ||
192 | |||
193 | // "Renumber" opened fd | ||
194 | void xmove_fd(int from, int to) | ||
195 | { | ||
196 | if (from == to) | ||
197 | return; | ||
198 | xdup2(from, to); | ||
199 | close(from); | ||
200 | } | ||
201 | |||
202 | // Die with an error message if we can't write the entire buffer. | ||
203 | void xwrite(int fd, const void *buf, size_t count) | ||
204 | { | ||
205 | if (count) { | ||
206 | ssize_t size = full_write(fd, buf, count); | ||
207 | if (size != count) | ||
208 | bb_error_msg_and_die("short write"); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | // Die with an error message if we can't lseek to the right spot. | ||
213 | off_t xlseek(int fd, off_t offset, int whence) | ||
214 | { | ||
215 | off_t off = lseek(fd, offset, whence); | ||
216 | if (off == (off_t)-1) { | ||
217 | if (whence == SEEK_SET) | ||
218 | bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset); | ||
219 | bb_perror_msg_and_die("lseek"); | ||
220 | } | ||
221 | return off; | ||
222 | } | ||
223 | |||
224 | // Die with supplied filename if this FILE * has ferror set. | ||
225 | void die_if_ferror(FILE *fp, const char *fn) | ||
226 | { | ||
227 | if (ferror(fp)) { | ||
228 | /* ferror doesn't set useful errno */ | ||
229 | bb_error_msg_and_die("%s: I/O error", fn); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | // Die with an error message if stdout has ferror set. | ||
234 | void die_if_ferror_stdout(void) | ||
235 | { | ||
236 | die_if_ferror(stdout, bb_msg_standard_output); | ||
237 | } | ||
238 | |||
239 | // Die with an error message if we have trouble flushing stdout. | ||
240 | void xfflush_stdout(void) | ||
241 | { | ||
242 | if (fflush(stdout)) { | ||
243 | bb_perror_msg_and_die(bb_msg_standard_output); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | |||
248 | int bb_putchar(int ch) | ||
249 | { | ||
250 | /* time.c needs putc(ch, stdout), not putchar(ch). | ||
251 | * it does "stdout = stderr;", but then glibc's putchar() | ||
252 | * doesn't work as expected. bad glibc, bad */ | ||
253 | return putc(ch, stdout); | ||
254 | } | ||
255 | |||
256 | /* Die with an error message if we can't copy an entire FILE * to stdout, | ||
257 | * then close that file. */ | ||
258 | void xprint_and_close_file(FILE *file) | ||
259 | { | ||
260 | fflush(stdout); | ||
261 | // copyfd outputs error messages for us. | ||
262 | if (bb_copyfd_eof(fileno(file), 1) == -1) | ||
263 | xfunc_die(); | ||
264 | |||
265 | fclose(file); | ||
266 | } | ||
267 | |||
268 | // Die with an error message if we can't malloc() enough space and do an | ||
269 | // sprintf() into that space. | ||
270 | char *xasprintf(const char *format, ...) | ||
271 | { | ||
272 | va_list p; | ||
273 | int r; | ||
274 | char *string_ptr; | ||
275 | |||
276 | #if 1 | ||
277 | // GNU extension | ||
278 | va_start(p, format); | ||
279 | r = vasprintf(&string_ptr, format, p); | ||
280 | va_end(p); | ||
281 | #else | ||
282 | // Bloat for systems that haven't got the GNU extension. | ||
283 | va_start(p, format); | ||
284 | r = vsnprintf(NULL, 0, format, p); | ||
285 | va_end(p); | ||
286 | string_ptr = xmalloc(r+1); | ||
287 | va_start(p, format); | ||
288 | r = vsnprintf(string_ptr, r+1, format, p); | ||
289 | va_end(p); | ||
290 | #endif | ||
291 | |||
292 | if (r < 0) | ||
293 | bb_error_msg_and_die(bb_msg_memory_exhausted); | ||
294 | return string_ptr; | ||
295 | } | ||
296 | |||
297 | #if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */ | ||
298 | int fdprintf(int fd, const char *format, ...) | ||
299 | { | ||
300 | va_list p; | ||
301 | int r; | ||
302 | char *string_ptr; | ||
303 | |||
304 | #if 1 | ||
305 | // GNU extension | ||
306 | va_start(p, format); | ||
307 | r = vasprintf(&string_ptr, format, p); | ||
308 | va_end(p); | ||
309 | #else | ||
310 | // Bloat for systems that haven't got the GNU extension. | ||
311 | va_start(p, format); | ||
312 | r = vsnprintf(NULL, 0, format, p) + 1; | ||
313 | va_end(p); | ||
314 | string_ptr = malloc(r); | ||
315 | if (string_ptr) { | ||
316 | va_start(p, format); | ||
317 | r = vsnprintf(string_ptr, r, format, p); | ||
318 | va_end(p); | ||
319 | } | ||
320 | #endif | ||
321 | |||
322 | if (r >= 0) { | ||
323 | full_write(fd, string_ptr, r); | ||
324 | free(string_ptr); | ||
325 | } | ||
326 | return r; | ||
327 | } | ||
328 | #endif | ||
329 | |||
330 | void xsetenv(const char *key, const char *value) | ||
331 | { | ||
332 | if (setenv(key, value, 1)) | ||
333 | bb_error_msg_and_die(bb_msg_memory_exhausted); | ||
334 | } | ||
335 | |||
336 | // Die with an error message if we can't set gid. (Because resource limits may | ||
337 | // limit this user to a given number of processes, and if that fills up the | ||
338 | // setgid() will fail and we'll _still_be_root_, which is bad.) | ||
339 | void xsetgid(gid_t gid) | ||
340 | { | ||
341 | if (setgid(gid)) bb_perror_msg_and_die("setgid"); | ||
342 | } | ||
343 | |||
344 | // Die with an error message if we can't set uid. (See xsetgid() for why.) | ||
345 | void xsetuid(uid_t uid) | ||
346 | { | ||
347 | if (setuid(uid)) bb_perror_msg_and_die("setuid"); | ||
348 | } | ||
349 | |||
350 | // Die if we can't chdir to a new path. | ||
351 | void xchdir(const char *path) | ||
352 | { | ||
353 | if (chdir(path)) | ||
354 | bb_perror_msg_and_die("chdir(%s)", path); | ||
355 | } | ||
356 | |||
357 | void xchroot(const char *path) | ||
358 | { | ||
359 | if (chroot(path)) | ||
360 | bb_perror_msg_and_die("can't change root directory to %s", path); | ||
361 | } | ||
362 | |||
363 | // Print a warning message if opendir() fails, but don't die. | ||
364 | DIR *warn_opendir(const char *path) | ||
365 | { | ||
366 | DIR *dp; | ||
367 | |||
368 | dp = opendir(path); | ||
369 | if (!dp) | ||
370 | bb_perror_msg("can't open '%s'", path); | ||
371 | return dp; | ||
372 | } | ||
373 | |||
374 | // Die with an error message if opendir() fails. | ||
375 | DIR *xopendir(const char *path) | ||
376 | { | ||
377 | DIR *dp; | ||
378 | |||
379 | dp = opendir(path); | ||
380 | if (!dp) | ||
381 | bb_perror_msg_and_die("can't open '%s'", path); | ||
382 | return dp; | ||
383 | } | ||
384 | |||
385 | // Die with an error message if we can't open a new socket. | ||
386 | int xsocket(int domain, int type, int protocol) | ||
387 | { | ||
388 | int r = socket(domain, type, protocol); | ||
389 | |||
390 | if (r < 0) { | ||
391 | /* Hijack vaguely related config option */ | ||
392 | #if ENABLE_VERBOSE_RESOLUTION_ERRORS | ||
393 | const char *s = "INET"; | ||
394 | if (domain == AF_PACKET) s = "PACKET"; | ||
395 | if (domain == AF_NETLINK) s = "NETLINK"; | ||
396 | USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";) | ||
397 | bb_perror_msg_and_die("socket(AF_%s)", s); | ||
398 | #else | ||
399 | bb_perror_msg_and_die("socket"); | ||
400 | #endif | ||
401 | } | ||
402 | |||
403 | return r; | ||
404 | } | ||
405 | |||
406 | // Die with an error message if we can't bind a socket to an address. | ||
407 | void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) | ||
408 | { | ||
409 | if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind"); | ||
410 | } | ||
411 | |||
412 | // Die with an error message if we can't listen for connections on a socket. | ||
413 | void xlisten(int s, int backlog) | ||
414 | { | ||
415 | if (listen(s, backlog)) bb_perror_msg_and_die("listen"); | ||
416 | } | ||
417 | |||
418 | /* Die with an error message if sendto failed. | ||
419 | * Return bytes sent otherwise */ | ||
420 | ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, | ||
421 | socklen_t tolen) | ||
422 | { | ||
423 | ssize_t ret = sendto(s, buf, len, 0, to, tolen); | ||
424 | if (ret < 0) { | ||
425 | if (ENABLE_FEATURE_CLEAN_UP) | ||
426 | close(s); | ||
427 | bb_perror_msg_and_die("sendto"); | ||
428 | } | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | // xstat() - a stat() which dies on failure with meaningful error message | ||
433 | void xstat(const char *name, struct stat *stat_buf) | ||
434 | { | ||
435 | if (stat(name, stat_buf)) | ||
436 | bb_perror_msg_and_die("can't stat '%s'", name); | ||
437 | } | ||
438 | |||
439 | // selinux_or_die() - die if SELinux is disabled. | ||
440 | void selinux_or_die(void) | ||
441 | { | ||
442 | #if ENABLE_SELINUX | ||
443 | int rc = is_selinux_enabled(); | ||
444 | if (rc == 0) { | ||
445 | bb_error_msg_and_die("SELinux is disabled"); | ||
446 | } else if (rc < 0) { | ||
447 | bb_error_msg_and_die("is_selinux_enabled() failed"); | ||
448 | } | ||
449 | #else | ||
450 | bb_error_msg_and_die("SELinux support is disabled"); | ||
451 | #endif | ||
452 | } | ||
453 | |||
454 | int ioctl_or_perror_and_die(int fd, int request, void *argp, const char *fmt,...) | ||
455 | { | ||
456 | int ret; | ||
457 | va_list p; | ||
458 | |||
459 | ret = ioctl(fd, request, argp); | ||
460 | if (ret < 0) { | ||
461 | va_start(p, fmt); | ||
462 | bb_verror_msg(fmt, p, strerror(errno)); | ||
463 | /* xfunc_die can actually longjmp, so be nice */ | ||
464 | va_end(p); | ||
465 | xfunc_die(); | ||
466 | } | ||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | int ioctl_or_perror(int fd, int request, void *argp, const char *fmt,...) | ||
471 | { | ||
472 | va_list p; | ||
473 | int ret = ioctl(fd, request, argp); | ||
474 | |||
475 | if (ret < 0) { | ||
476 | va_start(p, fmt); | ||
477 | bb_verror_msg(fmt, p, strerror(errno)); | ||
478 | va_end(p); | ||
479 | } | ||
480 | return ret; | ||
481 | } | ||
482 | |||
483 | #if ENABLE_IOCTL_HEX2STR_ERROR | ||
484 | int bb_ioctl_or_warn(int fd, int request, void *argp, const char *ioctl_name) | ||
485 | { | ||
486 | int ret; | ||
487 | |||
488 | ret = ioctl(fd, request, argp); | ||
489 | if (ret < 0) | ||
490 | bb_simple_perror_msg(ioctl_name); | ||
491 | return ret; | ||
492 | } | ||
493 | int bb_xioctl(int fd, int request, void *argp, const char *ioctl_name) | ||
494 | { | ||
495 | int ret; | ||
496 | |||
497 | ret = ioctl(fd, request, argp); | ||
498 | if (ret < 0) | ||
499 | bb_simple_perror_msg_and_die(ioctl_name); | ||
500 | return ret; | ||
501 | } | ||
502 | #else | ||
503 | int bb_ioctl_or_warn(int fd, int request, void *argp) | ||
504 | { | ||
505 | int ret; | ||
506 | |||
507 | ret = ioctl(fd, request, argp); | ||
508 | if (ret < 0) | ||
509 | bb_perror_msg("ioctl %#x failed", request); | ||
510 | return ret; | ||
511 | } | ||
512 | int bb_xioctl(int fd, int request, void *argp) | ||
513 | { | ||
514 | int ret; | ||
515 | |||
516 | ret = ioctl(fd, request, argp); | ||
517 | if (ret < 0) | ||
518 | bb_perror_msg_and_die("ioctl %#x failed", request); | ||
519 | return ret; | ||
520 | } | ||
521 | #endif | ||