handle SIGPIPE in built-in cat correctly (LP#1532621)

This commit is contained in:
tg 2016-01-20 20:29:48 +00:00
parent 046d8e5b7a
commit 9167be0584
1 changed files with 37 additions and 25 deletions

46
funcs.c
View File

@ -38,7 +38,7 @@
#endif #endif
#endif #endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.291 2016/01/19 23:12:13 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.292 2016/01/20 20:29:48 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -3669,10 +3669,11 @@ c_realpath(const char **wp)
int int
c_cat(const char **wp) c_cat(const char **wp)
{ {
int fd = STDIN_FILENO, rv, eno; int fd = STDIN_FILENO, rv;
ssize_t n, w; ssize_t n, w;
const char *fn = "<stdin>"; const char *fn = "<stdin>";
char *buf, *cp; char *buf, *cp;
int opipe = 0;
#define MKSH_CAT_BUFSIZ 4096 #define MKSH_CAT_BUFSIZ 4096
/* parse options: POSIX demands we support "-u" as no-op */ /* parse options: POSIX demands we support "-u" as no-op */
@ -3694,61 +3695,72 @@ c_cat(const char **wp)
return (1); return (1);
} }
/* catch SIGPIPE */
opipe = block_pipe();
do { do {
if (*wp) { if (*wp) {
fn = *wp++; fn = *wp++;
if (ksh_isdash(fn)) if (ksh_isdash(fn))
fd = STDIN_FILENO; fd = STDIN_FILENO;
else if ((fd = binopen2(fn, O_RDONLY)) < 0) { else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
eno = errno; bi_errorf("%s: %s", fn, cstrerror(errno));
bi_errorf("%s: %s", fn, cstrerror(eno));
rv = 1; rv = 1;
continue; continue;
} }
} }
while (/* CONSTCOND */ 1) { while (/* CONSTCOND */ 1) {
n = blocking_read(fd, (cp = buf), MKSH_CAT_BUFSIZ); if ((n = blocking_read(fd, (cp = buf),
eno = errno; MKSH_CAT_BUFSIZ)) == -1) {
if (errno == EINTR) {
restore_pipe(opipe);
/* give the user a chance to ^C out */ /* give the user a chance to ^C out */
intrcheck(); intrcheck();
if (n == -1) {
if (eno == EINTR) {
/* interrupted, try again */ /* interrupted, try again */
opipe = block_pipe();
continue; continue;
} }
/* an error occured during reading */ /* an error occured during reading */
bi_errorf("%s: %s", fn, cstrerror(eno)); bi_errorf("%s: %s", fn, cstrerror(errno));
rv = 1; rv = 1;
break; break;
} else if (n == 0) } else if (n == 0)
/* end of file reached */ /* end of file reached */
break; break;
while (n) { while (n) {
w = write(STDOUT_FILENO, cp, n); if ((w = write(STDOUT_FILENO, cp, n)) != -1) {
eno = errno; n -= w;
cp += w;
continue;
}
if (errno == EINTR) {
restore_pipe(opipe);
/* give the user a chance to ^C out */ /* give the user a chance to ^C out */
intrcheck(); intrcheck();
if (w == -1) {
if (eno == EINTR)
/* interrupted, try again */ /* interrupted, try again */
opipe = block_pipe();
continue; continue;
}
if (errno == EPIPE) {
/* fake receiving signel */
rv = ksh_sigmask(SIGPIPE);
} else {
/* an error occured during writing */ /* an error occured during writing */
bi_errorf("%s: %s", "<stdout>", bi_errorf("%s: %s", "<stdout>",
cstrerror(eno)); cstrerror(errno));
rv = 1; rv = 1;
}
if (fd != STDIN_FILENO) if (fd != STDIN_FILENO)
close(fd); close(fd);
goto out; goto out;
} }
n -= w;
cp += w;
}
} }
if (fd != STDIN_FILENO) if (fd != STDIN_FILENO)
close(fd); close(fd);
} while (*wp); } while (*wp);
out: out:
restore_pipe(opipe);
free_osfunc(buf); free_osfunc(buf);
return (rv); return (rv);
} }