source: branches/stable/mindi-busybox/libbb/xfuncs.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 15.7 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 Denis Vlasenko
8 *
9 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
10 */
11
12#include "libbb.h"
13
14/* All the functions starting with "x" call bb_error_msg_and_die() if they
15 * fail, so callers never need to check for errors.  If it returned, it
16 * succeeded. */
17
18#ifndef DMALLOC
19/* dmalloc provides variants of these that do abort() on failure.
20 * Since dmalloc's prototypes overwrite the impls here as they are
21 * included after these prototypes in libbb.h, all is well.
22 */
23// Warn if we can't allocate size bytes of memory.
24void *malloc_or_warn(size_t size)
25{
26    void *ptr = malloc(size);
27    if (ptr == NULL && size != 0)
28        bb_error_msg(bb_msg_memory_exhausted);
29    return ptr;
30}
31
32// Die if we can't allocate size bytes of memory.
33void *xmalloc(size_t size)
34{
35    void *ptr = malloc(size);
36    if (ptr == NULL && size != 0)
37        bb_error_msg_and_die(bb_msg_memory_exhausted);
38    return ptr;
39}
40
41// Die if we can't resize previously allocated memory.  (This returns a pointer
42// to the new memory, which may or may not be the same as the old memory.
43// It'll copy the contents to a new chunk and free the old one if necessary.)
44void *xrealloc(void *ptr, size_t size)
45{
46    ptr = realloc(ptr, size);
47    if (ptr == NULL && size != 0)
48        bb_error_msg_and_die(bb_msg_memory_exhausted);
49    return ptr;
50}
51#endif /* DMALLOC */
52
53// Die if we can't allocate and zero size bytes of memory.
54void *xzalloc(size_t size)
55{
56    void *ptr = xmalloc(size);
57    memset(ptr, 0, size);
58    return ptr;
59}
60
61// Die if we can't copy a string to freshly allocated memory.
62char * xstrdup(const char *s)
63{
64    char *t;
65
66    if (s == NULL)
67        return NULL;
68
69    t = strdup(s);
70
71    if (t == NULL)
72        bb_error_msg_and_die(bb_msg_memory_exhausted);
73
74    return t;
75}
76
77// Die if we can't allocate n+1 bytes (space for the null terminator) and copy
78// the (possibly truncated to length n) string into it.
79char * xstrndup(const char *s, int n)
80{
81    int m;
82    char *t;
83
84    if (ENABLE_DEBUG && s == NULL)
85        bb_error_msg_and_die("xstrndup bug");
86
87    /* We can just xmalloc(n+1) and strncpy into it, */
88    /* but think about xstrndup("abc", 10000) wastage! */
89    m = n;
90    t = (char*) s;
91    while (m) {
92        if (!*t) break;
93        m--;
94        t++;
95    }
96    n -= m;
97    t = xmalloc(n + 1);
98    t[n] = '\0';
99
100    return memcpy(t, s, n);
101}
102
103// Die if we can't open a file and return a FILE * to it.
104// Notice we haven't got xfread(), This is for use with fscanf() and friends.
105FILE *xfopen(const char *path, const char *mode)
106{
107    FILE *fp = fopen(path, mode);
108    if (fp == NULL)
109        bb_perror_msg_and_die("can't open '%s'", path);
110    return fp;
111}
112
113// Die if we can't open a file and return a fd.
114int xopen3(const char *pathname, int flags, int mode)
115{
116    int ret;
117
118    ret = open(pathname, flags, mode);
119    if (ret < 0) {
120        bb_perror_msg_and_die("can't open '%s'", pathname);
121    }
122    return ret;
123}
124
125// Die if we can't open an existing file and return a fd.
126int xopen(const char *pathname, int flags)
127{
128    return xopen3(pathname, flags, 0666);
129}
130
131// Warn if we can't open a file and return a fd.
132int open3_or_warn(const char *pathname, int flags, int mode)
133{
134    int ret;
135
136    ret = open(pathname, flags, mode);
137    if (ret < 0) {
138        bb_perror_msg("can't open '%s'", pathname);
139    }
140    return ret;
141}
142
143// Warn if we can't open a file and return a fd.
144int open_or_warn(const char *pathname, int flags)
145{
146    return open3_or_warn(pathname, flags, 0666);
147}
148
149void xpipe(int filedes[2])
150{
151    if (pipe(filedes))
152        bb_perror_msg_and_die("can't create pipe");
153}
154
155void xunlink(const char *pathname)
156{
157    if (unlink(pathname))
158        bb_perror_msg_and_die("can't remove file '%s'", pathname);
159}
160
161// Turn on nonblocking I/O on a fd
162int ndelay_on(int fd)
163{
164    return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);
165}
166
167int ndelay_off(int fd)
168{
169    return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK);
170}
171
172void xdup2(int from, int to)
173{
174    if (dup2(from, to) != to)
175        bb_perror_msg_and_die("can't duplicate file descriptor");
176}
177
178// "Renumber" opened fd
179void xmove_fd(int from, int to)
180{
181    if (from == to)
182        return;
183    xdup2(from, to);
184    close(from);
185}
186
187// Die with an error message if we can't write the entire buffer.
188void xwrite(int fd, const void *buf, size_t count)
189{
190    if (count) {
191        ssize_t size = full_write(fd, buf, count);
192        if (size != count)
193            bb_error_msg_and_die("short write");
194    }
195}
196
197// Die with an error message if we can't lseek to the right spot.
198off_t xlseek(int fd, off_t offset, int whence)
199{
200    off_t off = lseek(fd, offset, whence);
201    if (off == (off_t)-1) {
202        if (whence == SEEK_SET)
203            bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
204        bb_perror_msg_and_die("lseek");
205    }
206    return off;
207}
208
209// Die with supplied filename if this FILE * has ferror set.
210void die_if_ferror(FILE *fp, const char *fn)
211{
212    if (ferror(fp)) {
213        /* ferror doesn't set useful errno */
214        bb_error_msg_and_die("%s: I/O error", fn);
215    }
216}
217
218// Die with an error message if stdout has ferror set.
219void die_if_ferror_stdout(void)
220{
221    die_if_ferror(stdout, bb_msg_standard_output);
222}
223
224// Die with an error message if we have trouble flushing stdout.
225void xfflush_stdout(void)
226{
227    if (fflush(stdout)) {
228        bb_perror_msg_and_die(bb_msg_standard_output);
229    }
230}
231
232void sig_block(int sig)
233{
234    sigset_t ss;
235    sigemptyset(&ss);
236    sigaddset(&ss, sig);
237    sigprocmask(SIG_BLOCK, &ss, NULL);
238}
239
240void sig_unblock(int sig)
241{
242    sigset_t ss;
243    sigemptyset(&ss);
244    sigaddset(&ss, sig);
245    sigprocmask(SIG_UNBLOCK, &ss, NULL);
246}
247
248#if 0
249void sig_blocknone(void)
250{
251    sigset_t ss;
252    sigemptyset(&ss);
253    sigprocmask(SIG_SETMASK, &ss, NULL);
254}
255#endif
256
257void sig_catch(int sig, void (*f)(int))
258{
259    struct sigaction sa;
260    sa.sa_handler = f;
261    sa.sa_flags = 0;
262    sigemptyset(&sa.sa_mask);
263    sigaction(sig, &sa, NULL);
264}
265
266void sig_pause(void)
267{
268    sigset_t ss;
269    sigemptyset(&ss);
270    sigsuspend(&ss);
271}
272
273
274void xsetenv(const char *key, const char *value)
275{
276    if (setenv(key, value, 1))
277        bb_error_msg_and_die(bb_msg_memory_exhausted);
278}
279
280// Converts unsigned long long value into compact 4-char
281// representation. Examples: "1234", "1.2k", " 27M", "123T"
282// Fifth char is always '\0'
283void smart_ulltoa5(unsigned long long ul, char buf[5])
284{
285    const char *fmt;
286    char c;
287    unsigned v,idx = 0;
288    ul *= 10;
289    if (ul > 9999*10) { // do not scale if 9999 or less
290        while (ul >= 10000) {
291            ul /= 1024;
292            idx++;
293        }
294    }
295    v = ul; // ullong divisions are expensive, avoid them
296
297    fmt = " 123456789";
298    if (!idx) {     // 9999 or less: use 1234 format
299        c = buf[0] = " 123456789"[v/10000];
300        if (c != ' ') fmt = "0123456789";
301        c = buf[1] = fmt[v/1000%10];
302        if (c != ' ') fmt = "0123456789";
303        buf[2] = fmt[v/100%10];
304        buf[3] = "0123456789"[v/10%10];
305    } else {
306        if (v >= 10*10) {   // scaled value is >=10: use 123M format
307            c = buf[0] = " 123456789"[v/1000];
308            if (c != ' ') fmt = "0123456789";
309            buf[1] = fmt[v/100%10];
310            buf[2] = "0123456789"[v/10%10];
311        } else {    // scaled value is <10: use 1.2M format
312            buf[0] = "0123456789"[v/10];
313            buf[1] = '.';
314            buf[2] = "0123456789"[v%10];
315        }
316        // see http://en.wikipedia.org/wiki/Tera
317        buf[3] = " kMGTPEZY"[idx];
318    }
319    buf[4] = '\0';
320}
321
322// Convert unsigned integer to ascii, writing into supplied buffer.
323// A truncated result contains the first few digits of the result ala strncpy.
324// Returns a pointer past last generated digit, does _not_ store NUL.
325void BUG_sizeof_unsigned_not_4(void);
326char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
327{
328    unsigned i, out, res;
329    if (sizeof(unsigned) != 4)
330        BUG_sizeof_unsigned_not_4();
331    if (buflen) {
332        out = 0;
333        for (i = 1000000000; i; i /= 10) {
334            res = n / i;
335            if (res || out || i == 1) {
336                if (!--buflen) break;
337                out++;
338                n -= res*i;
339                *buf++ = '0' + res;
340            }
341        }
342    }
343    return buf;
344}
345
346// Convert signed integer to ascii, like utoa_to_buf()
347char *itoa_to_buf(int n, char *buf, unsigned buflen)
348{
349    if (buflen && n<0) {
350        n = -n;
351        *buf++ = '-';
352        buflen--;
353    }
354    return utoa_to_buf((unsigned)n, buf, buflen);
355}
356
357// The following two functions use a static buffer, so calling either one a
358// second time will overwrite previous results.
359//
360// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes.
361// Int should always be 32 bits on any remotely Unix-like system, see
362// http://www.unix.org/whitepapers/64bit.html for the reasons why.
363
364static char local_buf[12];
365
366// Convert unsigned integer to ascii using a static buffer (returned).
367char *utoa(unsigned n)
368{
369    *(utoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
370
371    return local_buf;
372}
373
374// Convert signed integer to ascii using a static buffer (returned).
375char *itoa(int n)
376{
377    *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
378
379    return local_buf;
380}
381
382// Emit a string of hex representation of bytes
383char *bin2hex(char *p, const char *cp, int count)
384{
385    while (count) {
386        unsigned char c = *cp++;
387        /* put lowercase hex digits */
388        *p++ = 0x20 | bb_hexdigits_upcase[c >> 4];
389        *p++ = 0x20 | bb_hexdigits_upcase[c & 0xf];
390        count--;
391    }
392    return p;
393}
394
395// Die with an error message if we can't set gid.  (Because resource limits may
396// limit this user to a given number of processes, and if that fills up the
397// setgid() will fail and we'll _still_be_root_, which is bad.)
398void xsetgid(gid_t gid)
399{
400    if (setgid(gid)) bb_perror_msg_and_die("setgid");
401}
402
403// Die with an error message if we can't set uid.  (See xsetgid() for why.)
404void xsetuid(uid_t uid)
405{
406    if (setuid(uid)) bb_perror_msg_and_die("setuid");
407}
408
409// Return how long the file at fd is, if there's any way to determine it.
410off_t fdlength(int fd)
411{
412    off_t bottom = 0, top = 0, pos;
413    long size;
414
415    // If the ioctl works for this, return it.
416
417    if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512;
418
419    // FIXME: explain why lseek(SEEK_END) is not used here!
420
421    // If not, do a binary search for the last location we can read.  (Some
422    // block devices don't do BLKGETSIZE right.)
423
424    do {
425        char temp;
426
427        pos = bottom + (top - bottom) / 2;
428
429        // If we can read from the current location, it's bigger.
430
431        if (lseek(fd, pos, SEEK_SET)>=0 && safe_read(fd, &temp, 1)==1) {
432            if (bottom == top) bottom = top = (top+1) * 2;
433            else bottom = pos;
434
435        // If we can't, it's smaller.
436
437        } else {
438            if (bottom == top) {
439                if (!top) return 0;
440                bottom = top/2;
441            }
442            else top = pos;
443        }
444    } while (bottom + 1 != top);
445
446    return pos + 1;
447}
448
449// Die with an error message if we can't malloc() enough space and do an
450// sprintf() into that space.
451char *xasprintf(const char *format, ...)
452{
453    va_list p;
454    int r;
455    char *string_ptr;
456
457#if 1
458    // GNU extension
459    va_start(p, format);
460    r = vasprintf(&string_ptr, format, p);
461    va_end(p);
462#else
463    // Bloat for systems that haven't got the GNU extension.
464    va_start(p, format);
465    r = vsnprintf(NULL, 0, format, p);
466    va_end(p);
467    string_ptr = xmalloc(r+1);
468    va_start(p, format);
469    r = vsnprintf(string_ptr, r+1, format, p);
470    va_end(p);
471#endif
472
473    if (r < 0) bb_error_msg_and_die(bb_msg_memory_exhausted);
474    return string_ptr;
475}
476
477#if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */
478int fdprintf(int fd, const char *format, ...)
479{
480    va_list p;
481    int r;
482    char *string_ptr;
483
484#if 1
485    // GNU extension
486    va_start(p, format);
487    r = vasprintf(&string_ptr, format, p);
488    va_end(p);
489#else
490    // Bloat for systems that haven't got the GNU extension.
491    va_start(p, format);
492    r = vsnprintf(NULL, 0, format, p) + 1;
493    va_end(p);
494    string_ptr = malloc(r);
495    if (string_ptr) {
496        va_start(p, format);
497        r = vsnprintf(string_ptr, r, format, p);
498        va_end(p);
499    }
500#endif
501
502    if (r >= 0) {
503        full_write(fd, string_ptr, r);
504        free(string_ptr);
505    }
506    return r;
507}
508#endif
509
510// Die with an error message if we can't copy an entire FILE * to stdout, then
511// close that file.
512void xprint_and_close_file(FILE *file)
513{
514    fflush(stdout);
515    // copyfd outputs error messages for us.
516    if (bb_copyfd_eof(fileno(file), 1) == -1)
517        xfunc_die();
518
519    fclose(file);
520}
521
522// Die if we can't chdir to a new path.
523void xchdir(const char *path)
524{
525    if (chdir(path))
526        bb_perror_msg_and_die("chdir(%s)", path);
527}
528
529// Print a warning message if opendir() fails, but don't die.
530DIR *warn_opendir(const char *path)
531{
532    DIR *dp;
533
534    dp = opendir(path);
535    if (!dp)
536        bb_perror_msg("can't open '%s'", path);
537    return dp;
538}
539
540// Die with an error message if opendir() fails.
541DIR *xopendir(const char *path)
542{
543    DIR *dp;
544
545    dp = opendir(path);
546    if (!dp)
547        bb_perror_msg_and_die("can't open '%s'", path);
548    return dp;
549}
550
551// Die with an error message if we can't open a new socket.
552int xsocket(int domain, int type, int protocol)
553{
554    int r = socket(domain, type, protocol);
555
556    if (r < 0) {
557        /* Hijack vaguely related config option */
558#if ENABLE_VERBOSE_RESOLUTION_ERRORS
559        const char *s = "INET";
560        if (domain == AF_PACKET) s = "PACKET";
561        if (domain == AF_NETLINK) s = "NETLINK";
562USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
563        bb_perror_msg_and_die("socket(AF_%s)", s);
564#else
565        bb_perror_msg_and_die("socket");
566#endif
567    }
568
569    return r;
570}
571
572// Die with an error message if we can't bind a socket to an address.
573void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
574{
575    if (bind(sockfd, my_addr, addrlen)) bb_perror_msg_and_die("bind");
576}
577
578// Die with an error message if we can't listen for connections on a socket.
579void xlisten(int s, int backlog)
580{
581    if (listen(s, backlog)) bb_perror_msg_and_die("listen");
582}
583
584/* Die with an error message if sendto failed.
585 * Return bytes sent otherwise  */
586ssize_t xsendto(int s, const  void *buf, size_t len, const struct sockaddr *to,
587                socklen_t tolen)
588{
589    ssize_t ret = sendto(s, buf, len, 0, to, tolen);
590    if (ret < 0) {
591        if (ENABLE_FEATURE_CLEAN_UP)
592            close(s);
593        bb_perror_msg_and_die("sendto");
594    }
595    return ret;
596}
597
598// xstat() - a stat() which dies on failure with meaningful error message
599void xstat(const char *name, struct stat *stat_buf)
600{
601    if (stat(name, stat_buf))
602        bb_perror_msg_and_die("can't stat '%s'", name);
603}
604
605// selinux_or_die() - die if SELinux is disabled.
606void selinux_or_die(void)
607{
608#if ENABLE_SELINUX
609    int rc = is_selinux_enabled();
610    if (rc == 0) {
611        bb_error_msg_and_die("SELinux is disabled");
612    } else if (rc < 0) {
613        bb_error_msg_and_die("is_selinux_enabled() failed");
614    }
615#else
616    bb_error_msg_and_die("SELinux support is disabled");
617#endif
618}
619
620/* It is perfectly ok to pass in a NULL for either width or for
621 * height, in which case that value will not be set.  */
622int get_terminal_width_height(int fd, int *width, int *height)
623{
624    struct winsize win = { 0, 0, 0, 0 };
625    int ret = ioctl(fd, TIOCGWINSZ, &win);
626
627    if (height) {
628        if (!win.ws_row) {
629            char *s = getenv("LINES");
630            if (s) win.ws_row = atoi(s);
631        }
632        if (win.ws_row <= 1 || win.ws_row >= 30000)
633            win.ws_row = 24;
634        *height = (int) win.ws_row;
635    }
636
637    if (width) {
638        if (!win.ws_col) {
639            char *s = getenv("COLUMNS");
640            if (s) win.ws_col = atoi(s);
641        }
642        if (win.ws_col <= 1 || win.ws_col >= 30000)
643            win.ws_col = 80;
644        *width = (int) win.ws_col;
645    }
646
647    return ret;
648}
649
650void ioctl_or_perror_and_die(int fd, int request, void *argp, const char *fmt,...)
651{
652    va_list p;
653
654    if (ioctl(fd, request, argp) < 0) {
655        va_start(p, fmt);
656        bb_verror_msg(fmt, p, strerror(errno));
657        /* xfunc_die can actually longjmp, so be nice */
658        va_end(p);
659        xfunc_die();
660    }
661}
662
663int ioctl_or_perror(int fd, int request, void *argp, const char *fmt,...)
664{
665    va_list p;
666    int ret = ioctl(fd, request, argp);
667
668    if (ret < 0) {
669        va_start(p, fmt);
670        bb_verror_msg(fmt, p, strerror(errno));
671        va_end(p);
672    }
673    return ret;
674}
675
676#if ENABLE_IOCTL_HEX2STR_ERROR
677int bb_ioctl_or_warn(int fd, int request, void *argp, const char *ioctl_name)
678{
679    int ret;
680
681    ret = ioctl(fd, request, argp);
682    if (ret < 0)
683        bb_perror_msg("%s", ioctl_name);
684    return ret;
685}
686void bb_xioctl(int fd, int request, void *argp, const char *ioctl_name)
687{
688    if (ioctl(fd, request, argp) < 0)
689        bb_perror_msg_and_die("%s", ioctl_name);
690}
691#else
692int bb_ioctl_or_warn(int fd, int request, void *argp)
693{
694    int ret;
695
696    ret = ioctl(fd, request, argp);
697    if (ret < 0)
698        bb_perror_msg("ioctl %#x failed", request);
699    return ret;
700}
701void bb_xioctl(int fd, int request, void *argp)
702{
703    if (ioctl(fd, request, argp) < 0)
704        bb_perror_msg_and_die("ioctl %#x failed", request);
705}
706#endif
Note: See TracBrowser for help on using the repository browser.