dd: fix skip= parse error (spotted by Dirk Clemens <develop@cle-mens.de>)

This commit is contained in:
Denis Vlasenko 2007-04-19 20:08:19 +00:00
parent 9ace613406
commit d1801a4430
2 changed files with 92 additions and 27 deletions

View File

@ -58,7 +58,7 @@ static bool write_and_stats(int fd, const void *buf, size_t len, size_t obs,
return 1; return 1;
if (n == obs) if (n == obs)
G.out_full++; G.out_full++;
else if (n > 0) else if (n) /* > 0 */
G.out_part++; G.out_part++;
return 0; return 0;
} }
@ -73,10 +73,10 @@ int dd_main(int argc, char **argv);
int dd_main(int argc, char **argv) int dd_main(int argc, char **argv)
{ {
enum { enum {
sync_flag = 1 << 0, SYNC_FLAG = 1 << 0,
noerror = 1 << 1, NOERROR = 1 << 1,
trunc_flag = 1 << 2, TRUNC_FLAG = 1 << 2,
twobufs_flag = 1 << 3, TWOBUFS_FLAG = 1 << 3,
}; };
static const char * const keywords[] = { static const char * const keywords[] = {
"bs=", "count=", "seek=", "skip=", "if=", "of=", "bs=", "count=", "seek=", "skip=", "if=", "of=",
@ -98,10 +98,10 @@ int dd_main(int argc, char **argv)
OP_conv, OP_conv,
OP_conv_notrunc, OP_conv_notrunc,
OP_conv_sync, OP_conv_sync,
OP_conv_noerror, OP_conv_NOERROR,
#endif #endif
}; };
int flags = trunc_flag; int flags = TRUNC_FLAG;
size_t oc = 0, ibs = 512, obs = 512; size_t oc = 0, ibs = 512, obs = 512;
ssize_t n, w; ssize_t n, w;
off_t seek = 0, skip = 0, count = OFF_T_MAX; off_t seek = 0, skip = 0, count = OFF_T_MAX;
@ -152,23 +152,23 @@ int dd_main(int argc, char **argv)
while (1) { while (1) {
/* find ',', replace them with nil so we can use arg for /* find ',', replace them with nil so we can use arg for
* index_in_str_array without copying. * index_in_str_array without copying.
* We rely on arg being non-null, else strstr would fault. * We rely on arg being non-null, else strchr would fault.
*/ */
key = strstr(arg, ","); key = strchr(arg, ',');
if (key) if (key)
*key = '\0'; *key = '\0';
what = index_in_str_array(keywords, arg) + 1; what = index_in_str_array(keywords, arg) + 1;
if (what < OP_conv_notrunc) if (what < OP_conv_notrunc)
bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv"); bb_error_msg_and_die(bb_msg_invalid_arg, arg, "conv");
if (what == OP_conv_notrunc) if (what == OP_conv_notrunc)
flags &= ~trunc_flag; flags &= ~TRUNC_FLAG;
if (what == OP_conv_sync) if (what == OP_conv_sync)
flags |= sync_flag; flags |= SYNC_FLAG;
if (what == OP_conv_noerror) if (what == OP_conv_NOERROR)
flags |= noerror; flags |= NOERROR;
if (!key) /* no ',' left, so this was the last specifier */ if (!key) /* no ',' left, so this was the last specifier */
break; break;
arg += key - arg + 1; /* skip this keyword plus ',' */ arg = key + 1; /* skip this keyword and ',' */
} }
continue; continue;
} }
@ -186,7 +186,7 @@ int dd_main(int argc, char **argv)
seek = XATOU_SFX(arg, dd_suffixes); seek = XATOU_SFX(arg, dd_suffixes);
continue; continue;
} }
if (what == skip) { if (what == OP_skip) {
skip = XATOU_SFX(arg, dd_suffixes); skip = XATOU_SFX(arg, dd_suffixes);
continue; continue;
} }
@ -200,7 +200,7 @@ int dd_main(int argc, char **argv)
//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
ibuf = obuf = xmalloc(ibs); ibuf = obuf = xmalloc(ibs);
if (ibs != obs) { if (ibs != obs) {
flags |= twobufs_flag; flags |= TWOBUFS_FLAG;
obuf = xmalloc(obs); obuf = xmalloc(obs);
} }
if (infile != NULL) if (infile != NULL)
@ -212,12 +212,12 @@ int dd_main(int argc, char **argv)
if (outfile != NULL) { if (outfile != NULL) {
int oflag = O_WRONLY | O_CREAT; int oflag = O_WRONLY | O_CREAT;
if (!seek && (flags & trunc_flag)) if (!seek && (flags & TRUNC_FLAG))
oflag |= O_TRUNC; oflag |= O_TRUNC;
ofd = xopen(outfile, oflag); ofd = xopen(outfile, oflag);
if (seek && (flags & trunc_flag)) { if (seek && (flags & TRUNC_FLAG)) {
if (ftruncate(ofd, seek * obs) < 0) { if (ftruncate(ofd, seek * obs) < 0) {
struct stat st; struct stat st;
@ -247,13 +247,13 @@ int dd_main(int argc, char **argv)
} }
while (G.in_full + G.in_part != count) { while (G.in_full + G.in_part != count) {
if (flags & noerror) /* Pre-zero the buffer when for noerror */ if (flags & NOERROR) /* Pre-zero the buffer when for NOERROR */
memset(ibuf, '\0', ibs); memset(ibuf, '\0', ibs);
n = safe_read(ifd, ibuf, ibs); n = safe_read(ifd, ibuf, ibs);
if (n == 0) if (n == 0)
break; break;
if (n < 0) { if (n < 0) {
if (flags & noerror) { if (flags & NOERROR) {
n = ibs; n = ibs;
bb_perror_msg("%s", infile); bb_perror_msg("%s", infile);
} else } else
@ -263,12 +263,12 @@ int dd_main(int argc, char **argv)
G.in_full++; G.in_full++;
else { else {
G.in_part++; G.in_part++;
if (flags & sync_flag) { if (flags & SYNC_FLAG) {
memset(ibuf + n, '\0', ibs - n); memset(ibuf + n, '\0', ibs - n);
n = ibs; n = ibs;
} }
} }
if (flags & twobufs_flag) { if (flags & TWOBUFS_FLAG) {
char *tmp = ibuf; char *tmp = ibuf;
while (n) { while (n) {
size_t d = obs - oc; size_t d = obs - oc;
@ -285,9 +285,8 @@ int dd_main(int argc, char **argv)
oc = 0; oc = 0;
} }
} }
} else } else if (write_and_stats(ofd, ibuf, n, obs, outfile))
if (write_and_stats(ofd, ibuf, n, obs, outfile)) goto out_status;
goto out_status;
} }
if (ENABLE_FEATURE_DD_IBS_OBS && oc) { if (ENABLE_FEATURE_DD_IBS_OBS && oc) {

View File

@ -2,8 +2,12 @@ strace of "sleep 1 | sleep 2" being run from interactive bash 3.0
Synopsis: Synopsis:
open /dev/tty [, if fails, open ttyname(0)]; close /* helps re-establish ctty */
get current signal mask get current signal mask
install default handlers for GHLD QUIT TERM TCGETS on fd# 0
TCGETS on fd# 2 /* NB: if returns ENOTTY (2>/dev/null), sh seems to disable job control,
does not show prompt, but still executes cmds from fd# 0 */
install default handlers for CHLD QUIT TERM
install common handler for HUP INT ILL TRAP ABRT FPE BUS SEGV SYS PIPE ALRM TERM XCPU XFSZ VTALRM USR1 USR2 install common handler for HUP INT ILL TRAP ABRT FPE BUS SEGV SYS PIPE ALRM TERM XCPU XFSZ VTALRM USR1 USR2
ignore QUIT ignore QUIT
install handler for INT install handler for INT
@ -34,11 +38,73 @@ get our pprocess group
signal followed by a SIGCONT signal will be sent to each process signal followed by a SIGCONT signal will be sent to each process
in the newly-orphaned process group. in the newly-orphaned process group.
... ...
dup stderr to fd# 255
move ourself to our own process group
block CHLD TSTP TTIN TTOU
set tty's (255, stderr's) foreground process group to our group
allow all signals
mark 255 CLOEXEC
set CHLD handler
get signal mask
get fd#0 flags
get signal mask
set INT handler
block CHLD TSTP TTIN TTOU
set fd #255 foreground process group to our group
allow all signals
set INT handler
block all signals
allow all signals
block INT
allow all signals
lotsa sigactions: set INT,ALRM,WINCH handlers, ignore TERM,QUIT,TSTP,TTOU,TTIN
block all signals
allow all signals
block all signals
allow all signals
block all signals
allow all signals
read "sleep 1 | sleep 2\n"
block INT
TCSETSW on fd# 0
allow all signals
lotsa sigactions: set INT,ALRM,WINCH handlers, ignore TERM,QUIT,TSTP,TTOU,TTIN
block CHLD
pipe([4, 5]) /* oops seems I lost another pipe() in editing... */
fork child #1
put child in it's own process group
block only CHLD
close(5)
block only INT CHLD
fork child #2
put child in the same process group as first one
block only CHLD
close(4)
block only CHLD
block only CHLD TSTP TTIN TTOU
set fd# 255 foreground process group to first child's one
block only CHLD
block only CHLD
block only CHLD
wait4 for children to die or stop - first child exits
wait4 for children to die or stop - second child exits
block CHLD TSTP TTIN TTOU
set fd# 255 foreground process group to our own one
block only CHLD
block only CHLD
block nothing
--- SIGCHLD (Child exited) @ 0 (0) ---
wait for it - no child (already waited for)
sigreturn()
read signal mask
lotsa sigactions...
read next command
execve("/bin/sh", ["sh"], [/* 34 vars */]) = 0 execve("/bin/sh", ["sh"], [/* 34 vars */]) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(2, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
rt_sigaction(SIGCHLD, {SIG_DFL}, {SIG_DFL}, 8) = 0 rt_sigaction(SIGCHLD, {SIG_DFL}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0 rt_sigaction(SIGQUIT, {SIG_DFL}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL}, {SIG_DFL}, 8) = 0 rt_sigaction(SIGTERM, {SIG_DFL}, {SIG_DFL}, 8) = 0