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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 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.