2006-07-03 01:17:05 +05:30
|
|
|
/* vi: set sw=4 ts=4: */
|
2001-11-02 17:09:46 +05:30
|
|
|
/*
|
|
|
|
* Support code for the hexdump and od applets,
|
|
|
|
* based on code from util-linux v 2.11l
|
|
|
|
*
|
|
|
|
* Copyright (c) 1989
|
2010-10-28 22:27:19 +05:30
|
|
|
* The Regents of the University of California. All rights reserved.
|
2001-11-02 17:09:46 +05:30
|
|
|
*
|
2010-08-16 23:44:46 +05:30
|
|
|
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
2001-11-02 17:09:46 +05:30
|
|
|
*
|
|
|
|
* Original copyright notice is retained at the end of this file.
|
|
|
|
*/
|
2006-06-19 01:50:07 +05:30
|
|
|
#include "libbb.h"
|
2003-03-19 14:43:01 +05:30
|
|
|
#include "dump.h"
|
2001-11-02 17:09:46 +05:30
|
|
|
|
2017-01-25 20:51:00 +05:30
|
|
|
static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
|
2001-11-02 17:09:46 +05:30
|
|
|
|
2007-08-13 02:28:27 +05:30
|
|
|
static const char size_conv_str[] ALIGN1 =
|
2003-03-19 14:43:01 +05:30
|
|
|
"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
|
2001-11-02 17:09:46 +05:30
|
|
|
|
2017-01-25 20:51:00 +05:30
|
|
|
static const char int_convs[] ALIGN1 = "diouxX";
|
2003-03-19 14:43:01 +05:30
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
|
|
|
|
typedef struct priv_dumper_t {
|
|
|
|
dumper_t pub;
|
|
|
|
|
|
|
|
char **argv;
|
|
|
|
FU *endfu;
|
|
|
|
off_t savaddress; /* saved address/offset in stream */
|
|
|
|
off_t eaddress; /* end address */
|
|
|
|
off_t address; /* address/offset in stream */
|
|
|
|
int blocksize;
|
|
|
|
smallint exitval; /* final exit value */
|
|
|
|
|
|
|
|
/* former statics */
|
|
|
|
smallint next__done;
|
|
|
|
smallint get__ateof; // = 1;
|
|
|
|
unsigned char *get__curp;
|
|
|
|
unsigned char *get__savp;
|
|
|
|
} priv_dumper_t;
|
|
|
|
|
|
|
|
dumper_t* FAST_FUNC alloc_dumper(void)
|
|
|
|
{
|
|
|
|
priv_dumper_t *dumper = xzalloc(sizeof(*dumper));
|
|
|
|
dumper->pub.dump_length = -1;
|
|
|
|
dumper->pub.dump_vflag = FIRST;
|
|
|
|
dumper->get__ateof = 1;
|
|
|
|
return &dumper->pub;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NOINLINE int bb_dump_size(FS *fs)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2006-07-01 18:38:46 +05:30
|
|
|
FU *fu;
|
|
|
|
int bcnt, cur_size;
|
|
|
|
char *fmt;
|
2003-03-19 14:43:01 +05:30
|
|
|
const char *p;
|
2001-11-02 17:09:46 +05:30
|
|
|
int prec;
|
|
|
|
|
2017-07-14 19:33:43 +05:30
|
|
|
/* figure out the data block size needed for each format unit */
|
2003-03-19 14:43:01 +05:30
|
|
|
for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
|
2001-11-02 17:09:46 +05:30
|
|
|
if (fu->bcnt) {
|
2003-03-19 14:43:01 +05:30
|
|
|
cur_size += fu->bcnt * fu->reps;
|
2001-11-02 17:09:46 +05:30
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
|
|
|
|
if (*fmt != '%')
|
|
|
|
continue;
|
|
|
|
/*
|
2008-07-16 16:30:16 +05:30
|
|
|
* skip any special chars -- save precision in
|
2001-11-02 17:09:46 +05:30
|
|
|
* case it's a %s format.
|
|
|
|
*/
|
2017-01-25 20:51:00 +05:30
|
|
|
while (strchr(dot_flags_width_chars + 1, *++fmt))
|
2011-11-18 07:17:35 +05:30
|
|
|
continue;
|
2001-11-02 17:09:46 +05:30
|
|
|
if (*fmt == '.' && isdigit(*++fmt)) {
|
|
|
|
prec = atoi(fmt);
|
2008-07-16 16:30:16 +05:30
|
|
|
while (isdigit(*++fmt))
|
|
|
|
continue;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2007-11-06 08:35:54 +05:30
|
|
|
p = strchr(size_conv_str + 12, *fmt);
|
|
|
|
if (!p) {
|
2003-03-19 14:43:01 +05:30
|
|
|
if (*fmt == 's') {
|
|
|
|
bcnt += prec;
|
2017-01-25 20:51:00 +05:30
|
|
|
}
|
|
|
|
if (*fmt == '_') {
|
2003-03-19 14:43:01 +05:30
|
|
|
++fmt;
|
|
|
|
if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
|
|
|
|
bcnt += 1;
|
|
|
|
}
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2003-03-19 14:43:01 +05:30
|
|
|
} else {
|
2017-01-25 20:51:00 +05:30
|
|
|
bcnt += p[-12];
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
}
|
2003-03-19 14:43:01 +05:30
|
|
|
cur_size += bcnt * fu->reps;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2006-11-27 22:19:55 +05:30
|
|
|
return cur_size;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
2009-10-08 15:58:08 +05:30
|
|
|
static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2006-06-19 01:50:07 +05:30
|
|
|
FU *fu;
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
2017-01-25 20:51:00 +05:30
|
|
|
PR *pr;
|
|
|
|
char *p1, *p2, *p3;
|
|
|
|
char *fmtp;
|
|
|
|
int nconv = 0;
|
2001-11-02 17:09:46 +05:30
|
|
|
/*
|
|
|
|
* break each format unit into print units; each
|
|
|
|
* conversion character gets its own.
|
|
|
|
*/
|
2017-01-25 20:51:00 +05:30
|
|
|
for (fmtp = fu->fmt; *fmtp; ) {
|
|
|
|
unsigned len;
|
|
|
|
const char *prec;
|
|
|
|
const char *byte_count_str;
|
|
|
|
|
|
|
|
/* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL */
|
|
|
|
pr = xzalloc(sizeof(*pr));
|
2001-11-02 17:09:46 +05:30
|
|
|
if (!fu->nextpr)
|
|
|
|
fu->nextpr = pr;
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
/* skip preceding text and up to the next % sign */
|
2017-01-25 20:51:00 +05:30
|
|
|
p1 = strchr(fmtp, '%');
|
|
|
|
if (!p1) { /* only text in the string */
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->fmt = fmtp;
|
|
|
|
pr->flags = F_TEXT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get precision for %s -- if have a byte count, don't
|
|
|
|
* need it.
|
|
|
|
*/
|
2017-01-25 20:51:00 +05:30
|
|
|
prec = NULL;
|
2001-11-02 17:09:46 +05:30
|
|
|
if (fu->bcnt) {
|
2008-07-16 16:30:16 +05:30
|
|
|
/* skip to conversion character */
|
2017-01-25 20:51:00 +05:30
|
|
|
while (strchr(dot_flags_width_chars, *++p1))
|
2008-07-16 12:52:14 +05:30
|
|
|
continue;
|
2001-11-02 17:09:46 +05:30
|
|
|
} else {
|
2008-07-16 16:30:16 +05:30
|
|
|
/* skip any special chars, field width */
|
2017-01-25 20:51:00 +05:30
|
|
|
while (strchr(dot_flags_width_chars + 1, *++p1))
|
2008-07-16 12:52:14 +05:30
|
|
|
continue;
|
2001-11-02 17:09:46 +05:30
|
|
|
if (*p1 == '.' && isdigit(*++p1)) {
|
2017-01-25 20:51:00 +05:30
|
|
|
prec = p1;
|
2008-07-16 12:52:14 +05:30
|
|
|
while (isdigit(*++p1))
|
|
|
|
continue;
|
2017-01-25 20:51:00 +05:30
|
|
|
}
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
p2 = p1 + 1; /* set end pointer */
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* figure out the byte count for each conversion;
|
|
|
|
* rewrite the format as necessary, set up blank-
|
2016-08-26 23:44:31 +05:30
|
|
|
* padding for end of data.
|
2001-11-02 17:09:46 +05:30
|
|
|
*/
|
2003-03-19 14:43:01 +05:30
|
|
|
if (*p1 == 'c') {
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->flags = F_CHAR;
|
2008-07-16 12:52:14 +05:30
|
|
|
DO_BYTE_COUNT_1:
|
2003-03-19 14:43:01 +05:30
|
|
|
byte_count_str = "\001";
|
2008-07-16 12:52:14 +05:30
|
|
|
DO_BYTE_COUNT:
|
2003-03-19 14:43:01 +05:30
|
|
|
if (fu->bcnt) {
|
2017-01-25 06:28:00 +05:30
|
|
|
for (;;) {
|
|
|
|
if (fu->bcnt == *byte_count_str)
|
2003-03-19 14:43:01 +05:30
|
|
|
break;
|
2017-01-25 06:28:00 +05:30
|
|
|
if (*++byte_count_str == 0)
|
|
|
|
bb_error_msg_and_die("bad byte count for conversion character %s", p1);
|
|
|
|
}
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2003-03-19 14:43:01 +05:30
|
|
|
/* Unlike the original, output the remainder of the format string. */
|
|
|
|
pr->bcnt = *byte_count_str;
|
2017-01-25 20:51:00 +05:30
|
|
|
} else
|
|
|
|
if (*p1 == 'l') { /* %ld etc */
|
|
|
|
const char *e;
|
|
|
|
|
2001-11-02 17:09:46 +05:30
|
|
|
++p2;
|
2003-03-19 14:43:01 +05:30
|
|
|
++p1;
|
2008-07-16 12:52:14 +05:30
|
|
|
DO_INT_CONV:
|
2017-01-25 20:51:00 +05:30
|
|
|
e = strchr(int_convs, *p1); /* "diouxX"? */
|
|
|
|
if (!e)
|
|
|
|
goto DO_BAD_CONV_CHAR;
|
|
|
|
pr->flags = F_INT;
|
|
|
|
if (e > int_convs + 1) /* not d or i? */
|
|
|
|
pr->flags = F_UINT;
|
|
|
|
byte_count_str = "\004\002\001";
|
|
|
|
goto DO_BYTE_COUNT;
|
|
|
|
} else
|
|
|
|
if (strchr(int_convs, *p1)) { /* %d etc */
|
2003-03-19 14:43:01 +05:30
|
|
|
goto DO_INT_CONV;
|
2017-01-25 20:51:00 +05:30
|
|
|
} else
|
|
|
|
if (strchr("eEfgG", *p1)) { /* floating point */
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->flags = F_DBL;
|
2003-03-19 14:43:01 +05:30
|
|
|
byte_count_str = "\010\004";
|
|
|
|
goto DO_BYTE_COUNT;
|
2017-01-25 20:51:00 +05:30
|
|
|
} else
|
|
|
|
if (*p1 == 's') {
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->flags = F_STR;
|
2017-01-25 20:51:00 +05:30
|
|
|
pr->bcnt = fu->bcnt;
|
|
|
|
if (fu->bcnt == 0) {
|
|
|
|
if (!prec)
|
libbb: reduce the overhead of single parameter bb_error_msg() calls
Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by
Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower
overhead call to bb_perror_msg() when only a string was being printed
with no parameters. This saves space for some CPU architectures because
it avoids the overhead of a call to a variadic function. However there
has never been a simple version of bb_error_msg(), and since 2007 many
new calls to bb_perror_msg() have been added that only take a single
parameter and so could have been using bb_simple_perror_message().
This changeset introduces 'simple' versions of bb_info_msg(),
bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and
bb_herror_msg_and_die(), and replaces all calls that only take a
single parameter, or use something like ("%s", arg), with calls to the
corresponding 'simple' version.
Since it is likely that single parameter calls to the variadic functions
may be accidentally reintroduced in the future a new debugging config
option WARN_SIMPLE_MSG has been introduced. This uses some macro magic
which will cause any such calls to generate a warning, but this is
turned off by default to avoid use of the unpleasant macros in normal
circumstances.
This is a large changeset due to the number of calls that have been
replaced. The only files that contain changes other than simple
substitution of function calls are libbb.h, libbb/herror_msg.c,
libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c,
networking/udhcp/common.h and util-linux/mdev.c additonal macros have
been added for logging so that single parameter and multiple parameter
logging variants exist.
The amount of space saved varies considerably by architecture, and was
found to be as follows (for 'defconfig' using GCC 7.4):
Arm: -92 bytes
MIPS: -52 bytes
PPC: -1836 bytes
x86_64: -938 bytes
Note that for the MIPS architecture only an exception had to be made
disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h)
because it made these files larger on MIPS.
Signed-off-by: James Byrne <james.byrne@origamienergy.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
|
|
|
bb_simple_error_msg_and_die("%%s needs precision or byte count");
|
2017-01-25 20:51:00 +05:30
|
|
|
pr->bcnt = atoi(prec);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2017-01-25 20:51:00 +05:30
|
|
|
} else
|
|
|
|
if (*p1 == '_') {
|
|
|
|
p2++; /* move past a in "%_a" */
|
2002-08-23 00:11:20 +05:30
|
|
|
switch (p1[1]) {
|
2017-01-25 20:51:00 +05:30
|
|
|
case 'A': /* %_A[dox]: print address and the end */
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->endfu = fu;
|
2001-11-02 17:09:46 +05:30
|
|
|
fu->flags |= F_IGNORE;
|
|
|
|
/* FALLTHROUGH */
|
2017-01-25 20:51:00 +05:30
|
|
|
case 'a': /* %_a[dox]: current address */
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->flags = F_ADDRESS;
|
2017-01-25 20:51:00 +05:30
|
|
|
p2++; /* move past x in "%_ax" */
|
2003-03-19 14:43:01 +05:30
|
|
|
if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
|
|
|
|
goto DO_BAD_CONV_CHAR;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2003-03-19 14:43:01 +05:30
|
|
|
*p1 = p1[2];
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2017-01-25 20:51:00 +05:30
|
|
|
case 'c': /* %_c: chars, \ooo, \n \r \t etc */
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->flags = F_C;
|
2002-08-23 00:11:20 +05:30
|
|
|
/* *p1 = 'c'; set in conv_c */
|
2003-03-19 14:43:01 +05:30
|
|
|
goto DO_BYTE_COUNT_1;
|
2017-01-25 20:51:00 +05:30
|
|
|
case 'p': /* %_p: chars, dots for nonprintable */
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->flags = F_P;
|
|
|
|
*p1 = 'c';
|
2003-03-19 14:43:01 +05:30
|
|
|
goto DO_BYTE_COUNT_1;
|
2017-01-25 20:51:00 +05:30
|
|
|
case 'u': /* %_p: chars, 'nul', 'esc' etc for nonprintable */
|
2001-11-02 17:09:46 +05:30
|
|
|
pr->flags = F_U;
|
2002-08-23 00:11:20 +05:30
|
|
|
/* *p1 = 'c'; set in conv_u */
|
2003-03-19 14:43:01 +05:30
|
|
|
goto DO_BYTE_COUNT_1;
|
2001-11-02 17:09:46 +05:30
|
|
|
default:
|
2003-03-19 14:43:01 +05:30
|
|
|
goto DO_BAD_CONV_CHAR;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2003-03-19 14:43:01 +05:30
|
|
|
} else {
|
2008-07-16 12:52:14 +05:30
|
|
|
DO_BAD_CONV_CHAR:
|
2006-10-27 14:32:31 +05:30
|
|
|
bb_error_msg_and_die("bad conversion character %%%s", p1);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* copy to PR format string, set conversion character
|
|
|
|
* pointer, update original.
|
|
|
|
*/
|
2017-01-25 20:51:00 +05:30
|
|
|
len = (p1 - fmtp) + 1;
|
|
|
|
pr->fmt = xstrndup(fmtp, len);
|
2003-04-20 04:48:35 +05:30
|
|
|
/* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
|
2004-03-15 13:59:22 +05:30
|
|
|
* Skip subsequent text and up to the next % sign and tack the
|
|
|
|
* additional text onto fmt: eg. if fmt is "%x is a HEX number",
|
2003-04-20 04:48:35 +05:30
|
|
|
* we lose the " is a HEX number" part of fmt.
|
|
|
|
*/
|
2008-07-16 12:52:14 +05:30
|
|
|
for (p3 = p2; *p3 && *p3 != '%'; p3++)
|
|
|
|
continue;
|
2017-01-25 20:51:00 +05:30
|
|
|
if ((p3 - p2) != 0) {
|
|
|
|
char *d;
|
|
|
|
pr->fmt = d = xrealloc(pr->fmt, len + (p3 - p2) + 1);
|
|
|
|
d += len;
|
|
|
|
do {
|
|
|
|
*d++ = *p2++;
|
|
|
|
} while (p2 != p3);
|
|
|
|
*d = '\0';
|
|
|
|
/* now p2 = p3 */
|
2003-04-20 04:48:35 +05:30
|
|
|
}
|
2017-01-25 20:51:00 +05:30
|
|
|
pr->cchar = pr->fmt + len - 1; /* must be after realloc! */
|
2001-11-02 17:09:46 +05:30
|
|
|
fmtp = p2;
|
|
|
|
|
|
|
|
/* only one conversion character if byte count */
|
2002-08-23 00:11:20 +05:30
|
|
|
if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
|
libbb: reduce the overhead of single parameter bb_error_msg() calls
Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by
Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower
overhead call to bb_perror_msg() when only a string was being printed
with no parameters. This saves space for some CPU architectures because
it avoids the overhead of a call to a variadic function. However there
has never been a simple version of bb_error_msg(), and since 2007 many
new calls to bb_perror_msg() have been added that only take a single
parameter and so could have been using bb_simple_perror_message().
This changeset introduces 'simple' versions of bb_info_msg(),
bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and
bb_herror_msg_and_die(), and replaces all calls that only take a
single parameter, or use something like ("%s", arg), with calls to the
corresponding 'simple' version.
Since it is likely that single parameter calls to the variadic functions
may be accidentally reintroduced in the future a new debugging config
option WARN_SIMPLE_MSG has been introduced. This uses some macro magic
which will cause any such calls to generate a warning, but this is
turned off by default to avoid use of the unpleasant macros in normal
circumstances.
This is a large changeset due to the number of calls that have been
replaced. The only files that contain changes other than simple
substitution of function calls are libbb.h, libbb/herror_msg.c,
libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c,
networking/udhcp/common.h and util-linux/mdev.c additonal macros have
been added for logging so that single parameter and multiple parameter
logging variants exist.
The amount of space saved varies considerably by architecture, and was
found to be as follows (for 'defconfig' using GCC 7.4):
Arm: -92 bytes
MIPS: -52 bytes
PPC: -1836 bytes
x86_64: -938 bytes
Note that for the MIPS architecture only an exception had to be made
disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h)
because it made these files larger on MIPS.
Signed-off-by: James Byrne <james.byrne@origamienergy.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
|
|
|
bb_simple_error_msg_and_die("byte count with multiple conversion characters");
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* if format unit byte count not specified, figure it out
|
|
|
|
* so can adjust rep count later.
|
|
|
|
*/
|
2017-01-25 20:51:00 +05:30
|
|
|
if (fu->bcnt == 0)
|
2001-11-02 17:09:46 +05:30
|
|
|
for (pr = fu->nextpr; pr; pr = pr->nextpr)
|
|
|
|
fu->bcnt += pr->bcnt;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* if the format string interprets any data at all, and it's
|
2008-07-16 16:30:16 +05:30
|
|
|
* not the same as the blocksize, and its last format unit
|
2001-11-02 17:09:46 +05:30
|
|
|
* interprets any data at all, and has no iteration count,
|
|
|
|
* repeat it as necessary.
|
|
|
|
*
|
2011-11-18 07:17:35 +05:30
|
|
|
* if rep count is greater than 1, no trailing whitespace
|
2001-11-02 17:09:46 +05:30
|
|
|
* gets output from the last iteration of the format unit.
|
|
|
|
*/
|
2008-08-24 04:45:48 +05:30
|
|
|
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
2011-11-18 07:17:35 +05:30
|
|
|
if (!fu->nextfu
|
|
|
|
&& fs->bcnt < dumper->blocksize
|
|
|
|
&& !(fu->flags & F_SETREP)
|
|
|
|
&& fu->bcnt
|
2008-07-16 12:52:14 +05:30
|
|
|
) {
|
2008-07-16 16:30:16 +05:30
|
|
|
fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
|
2008-07-16 12:52:14 +05:30
|
|
|
}
|
2011-11-18 07:17:35 +05:30
|
|
|
if (fu->reps > 1 && fu->nextpr) {
|
2017-01-25 20:51:00 +05:30
|
|
|
PR *pr;
|
|
|
|
char *p1, *p2;
|
|
|
|
|
2001-11-02 17:09:46 +05:30
|
|
|
for (pr = fu->nextpr;; pr = pr->nextpr)
|
|
|
|
if (!pr->nextpr)
|
|
|
|
break;
|
2017-01-25 20:51:00 +05:30
|
|
|
p2 = NULL;
|
|
|
|
for (p1 = pr->fmt; *p1; ++p1)
|
2001-11-02 17:09:46 +05:30
|
|
|
p2 = isspace(*p1) ? p1 : NULL;
|
|
|
|
if (p2)
|
|
|
|
pr->nospace = p2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-14 19:48:16 +05:30
|
|
|
static void do_skip(priv_dumper_t *dumper, const char *fname)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
|
|
|
struct stat sbuf;
|
|
|
|
|
2017-07-14 19:48:16 +05:30
|
|
|
xfstat(STDIN_FILENO, &sbuf, fname);
|
|
|
|
if (S_ISREG(sbuf.st_mode)
|
|
|
|
&& dumper->pub.dump_skip >= sbuf.st_size
|
|
|
|
) {
|
|
|
|
/* If st_size is valid and pub.dump_skip >= st_size */
|
|
|
|
dumper->pub.dump_skip -= sbuf.st_size;
|
|
|
|
dumper->address += sbuf.st_size;
|
|
|
|
return;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2013-03-27 19:45:33 +05:30
|
|
|
if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) {
|
2007-10-01 17:28:38 +05:30
|
|
|
bb_simple_perror_msg_and_die(fname);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->address += dumper->pub.dump_skip;
|
|
|
|
dumper->savaddress = dumper->address;
|
|
|
|
dumper->pub.dump_skip = 0;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
static NOINLINE int next(priv_dumper_t *dumper)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
|
|
|
for (;;) {
|
2017-07-14 19:48:16 +05:30
|
|
|
const char *fname = *dumper->argv;
|
2017-07-14 19:33:43 +05:30
|
|
|
|
|
|
|
if (fname) {
|
|
|
|
dumper->argv++;
|
2017-07-14 19:59:30 +05:30
|
|
|
if (NOT_LONE_DASH(fname)) {
|
|
|
|
if (!freopen(fname, "r", stdin)) {
|
|
|
|
bb_simple_perror_msg(fname);
|
|
|
|
dumper->exitval = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
} else {
|
2008-07-16 16:30:16 +05:30
|
|
|
if (dumper->next__done)
|
2010-02-06 18:23:21 +05:30
|
|
|
return 0; /* no next file */
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2017-07-14 19:48:16 +05:30
|
|
|
dumper->next__done = 1;
|
2008-07-16 16:30:16 +05:30
|
|
|
if (dumper->pub.dump_skip)
|
2017-07-14 19:48:16 +05:30
|
|
|
do_skip(dumper, fname ? fname : "stdin");
|
|
|
|
if (dumper->pub.dump_skip == 0)
|
2006-11-27 22:19:31 +05:30
|
|
|
return 1;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
static unsigned char *get(priv_dumper_t *dumper)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2006-07-01 18:38:46 +05:30
|
|
|
int n;
|
2001-11-02 17:09:46 +05:30
|
|
|
int need, nread;
|
2008-07-16 16:30:16 +05:30
|
|
|
int blocksize = dumper->blocksize;
|
2001-11-02 17:09:46 +05:30
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
if (!dumper->get__curp) {
|
|
|
|
dumper->address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
|
|
|
|
dumper->get__curp = xmalloc(blocksize);
|
2008-07-29 05:30:14 +05:30
|
|
|
dumper->get__savp = xzalloc(blocksize); /* need to be initialized */
|
2001-11-02 17:09:46 +05:30
|
|
|
} else {
|
2008-07-29 05:30:14 +05:30
|
|
|
unsigned char *tmp = dumper->get__curp;
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->get__curp = dumper->get__savp;
|
2008-07-29 05:30:14 +05:30
|
|
|
dumper->get__savp = tmp;
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->savaddress += blocksize;
|
|
|
|
dumper->address = dumper->savaddress;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
need = blocksize;
|
|
|
|
nread = 0;
|
|
|
|
while (1) {
|
2001-11-02 17:09:46 +05:30
|
|
|
/*
|
|
|
|
* if read the right number of bytes, or at EOF for one file,
|
|
|
|
* and no other files are available, zero-pad the rest of the
|
|
|
|
* block and set the end flag.
|
|
|
|
*/
|
2008-07-16 16:30:16 +05:30
|
|
|
if (!dumper->pub.dump_length || (dumper->get__ateof && !next(dumper))) {
|
|
|
|
if (need == blocksize) {
|
2006-11-27 22:19:55 +05:30
|
|
|
return NULL;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2018-07-03 19:57:54 +05:30
|
|
|
if (dumper->pub.dump_vflag != ALL /* not "show all"? */
|
|
|
|
&& dumper->pub.dump_vflag != FIRST /* not first line? */
|
|
|
|
&& memcmp(dumper->get__curp, dumper->get__savp, nread) == 0 /* same data? */
|
|
|
|
) {
|
2008-07-16 16:30:16 +05:30
|
|
|
if (dumper->pub.dump_vflag != DUP) {
|
2006-11-27 22:19:55 +05:30
|
|
|
puts("*");
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2006-11-27 22:19:55 +05:30
|
|
|
return NULL;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
memset(dumper->get__curp + nread, 0, need);
|
|
|
|
dumper->eaddress = dumper->address + nread;
|
|
|
|
return dumper->get__curp;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
n = fread(dumper->get__curp + nread, sizeof(unsigned char),
|
|
|
|
dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin);
|
2018-07-03 19:57:54 +05:30
|
|
|
if (n == 0) {
|
2001-11-02 17:09:46 +05:30
|
|
|
if (ferror(stdin)) {
|
2008-07-16 16:30:16 +05:30
|
|
|
bb_simple_perror_msg(dumper->argv[-1]);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->get__ateof = 1;
|
2001-11-02 17:09:46 +05:30
|
|
|
continue;
|
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->get__ateof = 0;
|
|
|
|
if (dumper->pub.dump_length != -1) {
|
|
|
|
dumper->pub.dump_length -= n;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2007-06-21 18:13:45 +05:30
|
|
|
need -= n;
|
2018-07-03 19:57:54 +05:30
|
|
|
if (need == 0) {
|
|
|
|
if (dumper->pub.dump_vflag == ALL /* "show all"? */
|
|
|
|
|| dumper->pub.dump_vflag == FIRST /* first line? */
|
|
|
|
|| memcmp(dumper->get__curp, dumper->get__savp, blocksize) != 0 /* not same data? */
|
2008-07-16 12:52:14 +05:30
|
|
|
) {
|
2008-07-16 16:30:16 +05:30
|
|
|
if (dumper->pub.dump_vflag == DUP || dumper->pub.dump_vflag == FIRST) {
|
|
|
|
dumper->pub.dump_vflag = WAIT;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
return dumper->get__curp;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
if (dumper->pub.dump_vflag == WAIT) {
|
2006-11-27 22:19:55 +05:30
|
|
|
puts("*");
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->pub.dump_vflag = DUP;
|
|
|
|
dumper->savaddress += blocksize;
|
|
|
|
dumper->address = dumper->savaddress;
|
|
|
|
need = blocksize;
|
2001-11-02 17:09:46 +05:30
|
|
|
nread = 0;
|
|
|
|
} else {
|
|
|
|
nread += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-16 12:52:14 +05:30
|
|
|
static void bpad(PR *pr)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2006-06-28 20:06:50 +05:30
|
|
|
char *p1, *p2;
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* remove all conversion flags; '-' is the only one valid
|
|
|
|
* with %s, and it's not useful here.
|
|
|
|
*/
|
|
|
|
pr->flags = F_BPAD;
|
|
|
|
*pr->cchar = 's';
|
2008-07-16 12:52:14 +05:30
|
|
|
for (p1 = pr->fmt; *p1 != '%'; ++p1)
|
|
|
|
continue;
|
2006-06-28 20:06:50 +05:30
|
|
|
for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
|
2008-07-16 12:52:14 +05:30
|
|
|
if (pr->nospace)
|
|
|
|
pr->nospace--;
|
|
|
|
while ((*p2++ = *p1++) != 0)
|
|
|
|
continue;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
2007-08-13 02:28:27 +05:30
|
|
|
static const char conv_str[] ALIGN1 =
|
2016-08-26 23:44:31 +05:30
|
|
|
"\0" "\\""0""\0"
|
|
|
|
"\007""\\""a""\0" /* \a */
|
|
|
|
"\b" "\\""b""\0"
|
|
|
|
"\f" "\\""f""\0"
|
|
|
|
"\n" "\\""n""\0"
|
|
|
|
"\r" "\\""r""\0"
|
|
|
|
"\t" "\\""t""\0"
|
|
|
|
"\v" "\\""v""\0"
|
2007-07-24 21:24:42 +05:30
|
|
|
;
|
2003-03-19 14:43:01 +05:30
|
|
|
|
2008-07-16 12:52:14 +05:30
|
|
|
static void conv_c(PR *pr, unsigned char *p)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2003-03-19 14:43:01 +05:30
|
|
|
const char *str = conv_str;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (*p == *str) {
|
|
|
|
++str;
|
2016-08-26 23:44:31 +05:30
|
|
|
goto strpr; /* map e.g. '\n' to "\\n" */
|
2003-03-19 14:43:01 +05:30
|
|
|
}
|
|
|
|
str += 4;
|
|
|
|
} while (*str);
|
|
|
|
|
2009-11-18 16:04:43 +05:30
|
|
|
if (isprint_asciionly(*p)) {
|
2001-11-02 17:09:46 +05:30
|
|
|
*pr->cchar = 'c';
|
2008-07-16 12:52:14 +05:30
|
|
|
printf(pr->fmt, *p);
|
2001-11-02 17:09:46 +05:30
|
|
|
} else {
|
2018-04-06 21:56:33 +05:30
|
|
|
char buf[4];
|
|
|
|
/* gcc-8.0.1 needs lots of casts to shut up */
|
|
|
|
sprintf(buf, "%03o", (unsigned)(uint8_t)*p);
|
2003-03-19 14:43:01 +05:30
|
|
|
str = buf;
|
2009-11-18 16:04:43 +05:30
|
|
|
strpr:
|
2001-11-02 17:09:46 +05:30
|
|
|
*pr->cchar = 's';
|
|
|
|
printf(pr->fmt, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-16 12:52:14 +05:30
|
|
|
static void conv_u(PR *pr, unsigned char *p)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2007-08-13 02:28:27 +05:30
|
|
|
static const char list[] ALIGN1 =
|
2003-03-19 14:43:01 +05:30
|
|
|
"nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
|
|
|
|
"bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
|
|
|
|
"dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
|
|
|
|
"can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
/* od used nl, not lf */
|
|
|
|
if (*p <= 0x1f) {
|
|
|
|
*pr->cchar = 's';
|
2004-07-23 07:05:41 +05:30
|
|
|
printf(pr->fmt, list + (4 * (int)*p));
|
2001-11-02 17:09:46 +05:30
|
|
|
} else if (*p == 0x7f) {
|
|
|
|
*pr->cchar = 's';
|
|
|
|
printf(pr->fmt, "del");
|
2009-11-18 16:04:43 +05:30
|
|
|
} else if (*p < 0x7f) { /* isprint() */
|
2001-11-02 17:09:46 +05:30
|
|
|
*pr->cchar = 'c';
|
|
|
|
printf(pr->fmt, *p);
|
|
|
|
} else {
|
|
|
|
*pr->cchar = 'x';
|
2002-08-23 00:11:20 +05:30
|
|
|
printf(pr->fmt, (int) *p);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
static void display(priv_dumper_t* dumper)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2006-07-01 18:38:46 +05:30
|
|
|
FS *fs;
|
|
|
|
FU *fu;
|
|
|
|
PR *pr;
|
|
|
|
int cnt;
|
2008-07-16 16:30:16 +05:30
|
|
|
unsigned char *bp, *savebp;
|
2003-03-19 14:43:01 +05:30
|
|
|
off_t saveaddress;
|
2008-07-16 16:30:16 +05:30
|
|
|
unsigned char savech = '\0';
|
2001-11-02 17:09:46 +05:30
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
while ((bp = get(dumper)) != NULL) {
|
|
|
|
fs = dumper->pub.fshead;
|
|
|
|
savebp = bp;
|
|
|
|
saveaddress = dumper->address;
|
|
|
|
for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) {
|
2002-08-23 00:11:20 +05:30
|
|
|
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
2001-11-02 17:09:46 +05:30
|
|
|
if (fu->flags & F_IGNORE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (cnt = fu->reps; cnt; --cnt) {
|
2008-07-16 16:30:16 +05:30
|
|
|
for (pr = fu->nextpr; pr; dumper->address += pr->bcnt,
|
|
|
|
bp += pr->bcnt, pr = pr->nextpr) {
|
|
|
|
if (dumper->eaddress && dumper->address >= dumper->eaddress
|
|
|
|
&& !(pr->flags & (F_TEXT | F_BPAD))
|
|
|
|
) {
|
2001-11-02 17:09:46 +05:30
|
|
|
bpad(pr);
|
|
|
|
}
|
2002-08-23 00:11:20 +05:30
|
|
|
if (cnt == 1 && pr->nospace) {
|
2001-11-02 17:09:46 +05:30
|
|
|
savech = *pr->nospace;
|
|
|
|
*pr->nospace = '\0';
|
2002-08-23 00:11:20 +05:30
|
|
|
}
|
|
|
|
/* PRINT; */
|
|
|
|
switch (pr->flags) {
|
|
|
|
case F_ADDRESS:
|
2008-07-16 16:30:16 +05:30
|
|
|
printf(pr->fmt, (unsigned) dumper->address);
|
2002-08-23 00:11:20 +05:30
|
|
|
break;
|
|
|
|
case F_BPAD:
|
|
|
|
printf(pr->fmt, "");
|
|
|
|
break;
|
|
|
|
case F_C:
|
|
|
|
conv_c(pr, bp);
|
|
|
|
break;
|
|
|
|
case F_CHAR:
|
|
|
|
printf(pr->fmt, *bp);
|
|
|
|
break;
|
2008-07-16 16:30:16 +05:30
|
|
|
case F_DBL: {
|
2002-08-23 00:11:20 +05:30
|
|
|
double dval;
|
|
|
|
float fval;
|
|
|
|
|
|
|
|
switch (pr->bcnt) {
|
|
|
|
case 4:
|
2008-11-17 03:51:23 +05:30
|
|
|
memcpy(&fval, bp, sizeof(fval));
|
2002-08-23 00:11:20 +05:30
|
|
|
printf(pr->fmt, fval);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2002-08-23 00:11:20 +05:30
|
|
|
case 8:
|
2008-11-17 03:51:23 +05:30
|
|
|
memcpy(&dval, bp, sizeof(dval));
|
2002-08-23 00:11:20 +05:30
|
|
|
printf(pr->fmt, dval);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
|
|
|
}
|
2002-08-23 00:11:20 +05:30
|
|
|
break;
|
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
case F_INT: {
|
2002-08-23 00:11:20 +05:30
|
|
|
int ival;
|
|
|
|
short sval;
|
|
|
|
|
|
|
|
switch (pr->bcnt) {
|
|
|
|
case 1:
|
|
|
|
printf(pr->fmt, (int) *bp);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2002-08-23 00:11:20 +05:30
|
|
|
case 2:
|
2008-11-17 03:51:23 +05:30
|
|
|
memcpy(&sval, bp, sizeof(sval));
|
2002-08-23 00:11:20 +05:30
|
|
|
printf(pr->fmt, (int) sval);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2002-08-23 00:11:20 +05:30
|
|
|
case 4:
|
2008-11-17 03:51:23 +05:30
|
|
|
memcpy(&ival, bp, sizeof(ival));
|
2002-08-23 00:11:20 +05:30
|
|
|
printf(pr->fmt, ival);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2002-08-23 00:11:20 +05:30
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case F_P:
|
2009-11-18 16:04:43 +05:30
|
|
|
printf(pr->fmt, isprint_asciionly(*bp) ? *bp : '.');
|
2002-08-23 00:11:20 +05:30
|
|
|
break;
|
|
|
|
case F_STR:
|
|
|
|
printf(pr->fmt, (char *) bp);
|
|
|
|
break;
|
|
|
|
case F_TEXT:
|
|
|
|
printf(pr->fmt);
|
|
|
|
break;
|
|
|
|
case F_U:
|
|
|
|
conv_u(pr, bp);
|
|
|
|
break;
|
2008-07-16 16:30:16 +05:30
|
|
|
case F_UINT: {
|
2008-07-16 12:52:14 +05:30
|
|
|
unsigned ival;
|
2004-01-31 04:22:27 +05:30
|
|
|
unsigned short sval;
|
2002-08-23 00:11:20 +05:30
|
|
|
|
|
|
|
switch (pr->bcnt) {
|
|
|
|
case 1:
|
2008-07-16 12:52:14 +05:30
|
|
|
printf(pr->fmt, (unsigned) *bp);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2002-08-23 00:11:20 +05:30
|
|
|
case 2:
|
2008-11-17 03:51:23 +05:30
|
|
|
memcpy(&sval, bp, sizeof(sval));
|
2008-07-16 12:52:14 +05:30
|
|
|
printf(pr->fmt, (unsigned) sval);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2002-08-23 00:11:20 +05:30
|
|
|
case 4:
|
2008-11-17 03:51:23 +05:30
|
|
|
memcpy(&ival, bp, sizeof(ival));
|
2002-08-23 00:11:20 +05:30
|
|
|
printf(pr->fmt, ival);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
|
|
|
}
|
2002-08-23 00:11:20 +05:30
|
|
|
break;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2002-08-23 00:11:20 +05:30
|
|
|
}
|
|
|
|
if (cnt == 1 && pr->nospace) {
|
2001-11-02 17:09:46 +05:30
|
|
|
*pr->nospace = savech;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
if (dumper->endfu) {
|
2001-11-02 17:09:46 +05:30
|
|
|
/*
|
2008-07-16 16:30:16 +05:30
|
|
|
* if eaddress not set, error or file size was multiple
|
|
|
|
* of blocksize, and no partial block ever found.
|
2001-11-02 17:09:46 +05:30
|
|
|
*/
|
2008-07-16 16:30:16 +05:30
|
|
|
if (!dumper->eaddress) {
|
|
|
|
if (!dumper->address) {
|
2001-11-02 17:09:46 +05:30
|
|
|
return;
|
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->eaddress = dumper->address;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) {
|
2002-08-23 00:11:20 +05:30
|
|
|
switch (pr->flags) {
|
2001-11-02 17:09:46 +05:30
|
|
|
case F_ADDRESS:
|
2008-07-16 16:30:16 +05:30
|
|
|
printf(pr->fmt, (unsigned) dumper->eaddress);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
|
|
|
case F_TEXT:
|
2008-07-16 12:52:14 +05:30
|
|
|
printf(pr->fmt);
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
#define dumper ((priv_dumper_t*)pub_dumper)
|
|
|
|
int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2006-07-01 18:38:46 +05:30
|
|
|
FS *tfs;
|
2008-07-16 16:30:16 +05:30
|
|
|
int blocksize;
|
2001-11-02 17:09:46 +05:30
|
|
|
|
2017-07-14 19:33:43 +05:30
|
|
|
/* figure out the data block size */
|
2008-07-16 16:30:16 +05:30
|
|
|
blocksize = 0;
|
|
|
|
tfs = dumper->pub.fshead;
|
|
|
|
while (tfs) {
|
2003-03-19 14:43:01 +05:30
|
|
|
tfs->bcnt = bb_dump_size(tfs);
|
2008-07-16 16:30:16 +05:30
|
|
|
if (blocksize < tfs->bcnt) {
|
|
|
|
blocksize = tfs->bcnt;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
tfs = tfs->nextfs;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->blocksize = blocksize;
|
|
|
|
|
2001-11-02 17:09:46 +05:30
|
|
|
/* rewrite the rules, do syntax checking */
|
2008-07-16 16:30:16 +05:30
|
|
|
for (tfs = dumper->pub.fshead; tfs; tfs = tfs->nextfs) {
|
|
|
|
rewrite(dumper, tfs);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
dumper->argv = argv;
|
|
|
|
display(dumper);
|
2001-11-02 17:09:46 +05:30
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
return dumper->exitval;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
|
2001-11-02 17:09:46 +05:30
|
|
|
{
|
2006-06-19 01:50:07 +05:30
|
|
|
const char *p;
|
2001-11-02 17:09:46 +05:30
|
|
|
FS *tfs;
|
2008-07-16 16:30:16 +05:30
|
|
|
FU *tfu, **nextfupp;
|
2003-03-19 14:43:01 +05:30
|
|
|
const char *savep;
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
/* start new linked list of format units */
|
2006-06-19 01:50:07 +05:30
|
|
|
tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
|
2008-07-16 16:30:16 +05:30
|
|
|
if (!dumper->pub.fshead) {
|
|
|
|
dumper->pub.fshead = tfs;
|
2001-11-02 17:09:46 +05:30
|
|
|
} else {
|
2008-07-16 16:30:16 +05:30
|
|
|
FS *fslast = dumper->pub.fshead;
|
|
|
|
while (fslast->nextfs)
|
|
|
|
fslast = fslast->nextfs;
|
|
|
|
fslast->nextfs = tfs;
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2008-07-16 16:30:16 +05:30
|
|
|
nextfupp = &tfs->nextfu;
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
/* take the format string and break it up into format units */
|
2008-08-24 04:45:48 +05:30
|
|
|
p = fmt;
|
|
|
|
for (;;) {
|
2006-06-19 01:50:07 +05:30
|
|
|
p = skip_whitespace(p);
|
2011-11-18 07:17:35 +05:30
|
|
|
if (*p == '\0') {
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate a new format unit and link it in */
|
|
|
|
/* NOSTRICT */
|
2008-03-17 14:35:21 +05:30
|
|
|
/* DBU:[dave@cray.com] zalloc so that forward pointers start out NULL */
|
2006-06-19 01:50:07 +05:30
|
|
|
tfu = xzalloc(sizeof(FU));
|
2008-07-16 16:30:16 +05:30
|
|
|
*nextfupp = tfu;
|
|
|
|
nextfupp = &tfu->nextfu;
|
2001-11-02 17:09:46 +05:30
|
|
|
tfu->reps = 1;
|
|
|
|
|
|
|
|
/* if leading digit, repetition count */
|
|
|
|
if (isdigit(*p)) {
|
2008-07-16 12:52:14 +05:30
|
|
|
for (savep = p; isdigit(*p); ++p)
|
|
|
|
continue;
|
2001-11-02 17:09:46 +05:30
|
|
|
if (!isspace(*p) && *p != '/') {
|
2003-03-19 14:43:01 +05:30
|
|
|
bb_error_msg_and_die("bad format {%s}", fmt);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
/* may overwrite either white space or slash */
|
|
|
|
tfu->reps = atoi(savep);
|
|
|
|
tfu->flags = F_SETREP;
|
2008-07-16 16:30:16 +05:30
|
|
|
/* skip trailing white space */
|
2006-06-19 01:50:07 +05:30
|
|
|
p = skip_whitespace(++p);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
2008-07-16 16:30:16 +05:30
|
|
|
/* skip slash and trailing white space */
|
2001-11-02 17:09:46 +05:30
|
|
|
if (*p == '/') {
|
2011-11-18 07:17:35 +05:30
|
|
|
p = skip_whitespace(p + 1);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* byte count */
|
|
|
|
if (isdigit(*p)) {
|
2006-12-26 08:21:29 +05:30
|
|
|
// TODO: use bb_strtou
|
|
|
|
savep = p;
|
2008-07-16 12:52:14 +05:30
|
|
|
while (isdigit(*++p))
|
|
|
|
continue;
|
2001-11-02 17:09:46 +05:30
|
|
|
if (!isspace(*p)) {
|
2003-03-19 14:43:01 +05:30
|
|
|
bb_error_msg_and_die("bad format {%s}", fmt);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
2017-01-25 20:51:00 +05:30
|
|
|
// Above check prohibits formats such as '/1"%02x"' - it requires space after 1.
|
|
|
|
// Other than this, formats can be pretty much jammed together:
|
|
|
|
// "%07_ax:"8/2 "%04x|""\n"
|
|
|
|
// but this space is required. The check *can* be removed, but
|
|
|
|
// keeping it to stay compat with util-linux hexdump.
|
2001-11-02 17:09:46 +05:30
|
|
|
tfu->bcnt = atoi(savep);
|
2008-07-16 16:30:16 +05:30
|
|
|
/* skip trailing white space */
|
2011-11-18 07:17:35 +05:30
|
|
|
p = skip_whitespace(p + 1);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* format */
|
|
|
|
if (*p != '"') {
|
2003-03-19 14:43:01 +05:30
|
|
|
bb_error_msg_and_die("bad format {%s}", fmt);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
for (savep = ++p; *p != '"';) {
|
2011-11-18 07:17:35 +05:30
|
|
|
if (*p++ == '\0') {
|
2003-03-19 14:43:01 +05:30
|
|
|
bb_error_msg_and_die("bad format {%s}", fmt);
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
}
|
2008-07-16 12:52:14 +05:30
|
|
|
tfu->fmt = xstrndup(savep, p - savep);
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
/* alphabetic escape sequences have to be done in place */
|
2016-08-26 23:44:31 +05:30
|
|
|
strcpy_and_process_escape_sequences(tfu->fmt, tfu->fmt);
|
|
|
|
/* unknown mappings are not changed: "\z" -> '\\' 'z' */
|
|
|
|
/* trailing backslash, if any, is preserved */
|
|
|
|
#if 0
|
|
|
|
char *p1;
|
|
|
|
char *p2;
|
|
|
|
p1 = tfu->fmt;
|
2001-11-02 17:09:46 +05:30
|
|
|
for (p2 = p1;; ++p1, ++p2) {
|
2016-08-26 23:44:31 +05:30
|
|
|
*p2 = *p1;
|
|
|
|
if (*p1 == '\0')
|
2001-11-02 17:09:46 +05:30
|
|
|
break;
|
2016-08-26 23:44:31 +05:30
|
|
|
|
2001-11-02 17:09:46 +05:30
|
|
|
if (*p1 == '\\') {
|
2016-08-26 23:44:31 +05:30
|
|
|
const char *cs;
|
|
|
|
|
|
|
|
p1++;
|
2003-03-19 14:43:01 +05:30
|
|
|
*p2 = *p1;
|
2016-08-26 23:44:31 +05:30
|
|
|
if (*p1 == '\0') {
|
|
|
|
/* "...\" trailing backslash. Eaten. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cs = conv_str + 4; /* skip NUL element */
|
2003-03-19 14:43:01 +05:30
|
|
|
do {
|
2016-08-26 23:44:31 +05:30
|
|
|
/* map e.g. "\n" -> '\n' */
|
2003-03-19 14:43:01 +05:30
|
|
|
if (*p1 == cs[2]) {
|
|
|
|
*p2 = cs[0];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cs += 4;
|
|
|
|
} while (*cs);
|
2016-08-26 23:44:31 +05:30
|
|
|
/* unknown mappings remove bkslash: "\z" -> 'z' */
|
2001-11-02 17:09:46 +05:30
|
|
|
}
|
|
|
|
}
|
2016-08-26 23:44:31 +05:30
|
|
|
#endif
|
2001-11-02 17:09:46 +05:30
|
|
|
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
2002-08-23 00:11:20 +05:30
|
|
|
|
2001-11-02 17:09:46 +05:30
|
|
|
/*
|
|
|
|
* Copyright (c) 1989 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2002-06-24 03:55:24 +05:30
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
2001-11-02 17:09:46 +05:30
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
2017-08-02 17:56:33 +05:30
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
|
2001-11-02 17:09:46 +05:30
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|