From ba0ae447ef6da18b0677fe5fb27117cb1d28b30a Mon Sep 17 00:00:00 2001 From: itohy Date: Thu, 17 Feb 2000 03:06:12 +0000 Subject: [PATCH] Fix SIGINFO botch (PR #8868). Continue partial write(2) on signals (xwrite()). Partial read(2) at a few places are also continued (xread()). Add {read,write}_with_restart() hooks for porting on systems which don't restart interrupted read()/write() calls. Reviewed and discussed in tech-kern and tech-userlevel lists. --- bin/pax/ar_io.c | 144 +++++++++++++++++++++++++++++++++++++++++--- bin/pax/buf_subs.c | 10 +-- bin/pax/extern.h | 11 +++- bin/pax/file_subs.c | 8 +-- bin/pax/tables.c | 16 ++--- 5 files changed, 162 insertions(+), 27 deletions(-) diff --git a/bin/pax/ar_io.c b/bin/pax/ar_io.c index 83c504dab350..450614d29fed 100644 --- a/bin/pax/ar_io.c +++ b/bin/pax/ar_io.c @@ -1,4 +1,4 @@ -/* $NetBSD: ar_io.c,v 1.14 1999/10/22 20:59:08 is Exp $ */ +/* $NetBSD: ar_io.c,v 1.15 2000/02/17 03:06:12 itohy Exp $ */ /*- * Copyright (c) 1992 Keith Muller. @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94"; #else -__RCSID("$NetBSD: ar_io.c,v 1.14 1999/10/22 20:59:08 is Exp $"); +__RCSID("$NetBSD: ar_io.c,v 1.15 2000/02/17 03:06:12 itohy Exp $"); #endif #endif /* not lint */ @@ -438,7 +438,7 @@ ar_drain() /* * keep reading until pipe is drained */ - while ((res = read(arfd, drbuf, sizeof(drbuf))) > 0) + while ((res = read_with_restart(arfd, drbuf, sizeof(drbuf))) > 0) ; lstrval = res; } @@ -518,6 +518,132 @@ ar_app_ok() return(-1); } +#ifdef SYS_NO_RESTART +/* + * read_with_restart() + * Equivalent to read() but does retry on signals. + * This function is not needed on 4.2BSD and later. + * Return: + * Number of bytes written. -1 indicates an error. + */ + +#if __STDC__ +int +read_with_restart(int fd, void *buf, int bsz) +#else +int +read_with_restart(fd, buf, bsz) + int fd; + void *buf; + int bsz; +#endif +{ + int r; + + while (((r = read(fd, buf, bsz)) < 0) && errno == EINTR) + ; + + return(r); +} +#endif + +/* + * xread() + * Equivalent to read() but does retry on partial read, which may occur + * on signals. + * Return: + * Number of bytes read. 0 for end of file, -1 for an error. + */ + +#if __STDC__ +int +xread(int fd, void *buf, int bsz) +#else +int +xread(fd, buf, bsz) + int fd; + void *buf; + int bsz; +#endif +{ + char *b = buf; + int nread = 0; + int r; + + do { + if ((r = read_with_restart(fd, b, bsz)) <= 0) + break; + b += r; + bsz -= r; + nread += r; + } while (bsz > 0); + + return(nread ? nread : r); +} + +#ifdef SYS_NO_RESTART +/* + * write_with_restart() + * Equivalent to write() but does retry on signals. + * This function is not needed on 4.2BSD and later. + * Return: + * Number of bytes written. -1 indicates an error. + */ + +#if __STDC__ +int +write_with_restart(int fd, void *buf, int bsz) +#else +int +write_with_restart(fd, buf, bsz) + int fd; + void *buf; + int bsz; +#endif +{ + int r; + + while (((r = write(fd, buf, bsz)) < 0) && errno == EINTR) + ; + + return(r); +} +#endif + +/* + * xwrite() + * Equivalent to write() but does retry on partial write, which may occur + * on signals. + * Return: + * Number of bytes written. -1 indicates an error. + */ + +#if __STDC__ +int +xwrite(int fd, void *buf, int bsz) +#else +int +xwrite(fd, buf, bsz) + int fd; + void *buf; + int bsz; +#endif +{ + char *b = buf; + int written = 0; + int r; + + do { + if ((r = write_with_restart(fd, b, bsz)) <= 0) + break; + b += r; + bsz -= r; + written += r; + } while (bsz > 0); + + return(written ? written : r); +} + /* * ar_read() * read up to a specified number of bytes from the archive into the @@ -550,7 +676,7 @@ ar_read(buf, cnt) */ switch (artyp) { case ISTAPE: - if ((res = read(arfd, buf, cnt)) > 0) { + if ((res = read_with_restart(arfd, buf, cnt)) > 0) { /* * CAUTION: tape systems may not always return the same * sized records so we leave blksz == MAXBLK. The @@ -588,7 +714,7 @@ ar_read(buf, cnt) * and return. Trying to do anything else with them runs the * risk of failure. */ - if ((res = read(arfd, buf, cnt)) > 0) { + if ((res = read_with_restart(arfd, buf, cnt)) > 0) { io_ok = 1; return(res); } @@ -637,7 +763,7 @@ ar_write(buf, bsz) if (lstrval <= 0) return(lstrval); - if ((res = write(arfd, buf, bsz)) == bsz) { + if ((res = xwrite(arfd, buf, bsz)) == bsz) { wr_trail = 1; io_ok = 1; return(bsz); @@ -1064,7 +1190,7 @@ get_phys() * we know we are at file mark when we get back a 0 from * read() */ - while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0) + while ((res = read_with_restart(arfd, scbuf, sizeof(scbuf))) > 0) padsz += res; if (res < 0) { syswarn(1, errno, "Unable to locate tape filemark."); @@ -1093,7 +1219,7 @@ get_phys() syswarn(1, errno, "Unable to backspace over last tape block."); return(-1); } - if ((phyblk = read(arfd, scbuf, sizeof(scbuf))) <= 0) { + if ((phyblk = read_with_restart(arfd, scbuf, sizeof(scbuf))) <= 0) { syswarn(1, errno, "Cannot determine archive tape blocksize."); return(-1); } @@ -1102,7 +1228,7 @@ get_phys() * read foward to the file mark, then back up in front of the filemark * (this is a bit paranoid, but should be safe to do). */ - while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0) + while ((res = read_with_restart(arfd, scbuf, sizeof(scbuf))) > 0) ; if (res < 0) { syswarn(1, errno, "Unable to locate tape filemark."); diff --git a/bin/pax/buf_subs.c b/bin/pax/buf_subs.c index 0aa1938b18d5..6c6fdd7b39c2 100644 --- a/bin/pax/buf_subs.c +++ b/bin/pax/buf_subs.c @@ -1,4 +1,4 @@ -/* $NetBSD: buf_subs.c,v 1.11 1999/10/22 10:43:11 mrg Exp $ */ +/* $NetBSD: buf_subs.c,v 1.12 2000/02/17 03:06:13 itohy Exp $ */ /*- * Copyright (c) 1992 Keith Muller. @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)buf_subs.c 8.2 (Berkeley) 4/18/94"; #else -__RCSID("$NetBSD: buf_subs.c,v 1.11 1999/10/22 10:43:11 mrg Exp $"); +__RCSID("$NetBSD: buf_subs.c,v 1.12 2000/02/17 03:06:13 itohy Exp $"); #endif #endif /* not lint */ @@ -699,7 +699,7 @@ wr_rdfile(arcn, ifd, left) return(-1); } cnt = MIN(cnt, size); - if ((res = read(ifd, bufpt, cnt)) <= 0) + if ((res = read_with_restart(ifd, bufpt, cnt)) <= 0) break; size -= res; bufpt += res; @@ -884,10 +884,10 @@ cp_file(arcn, fd1, fd2) * read the source file and copy to destination file until EOF */ for(;;) { - if ((cnt = read(fd1, buf, blksz)) <= 0) + if ((cnt = read_with_restart(fd1, buf, blksz)) <= 0) break; if (no_hole) - res = write(fd2, buf, cnt); + res = xwrite(fd2, buf, cnt); else res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm); if (res != cnt) diff --git a/bin/pax/extern.h b/bin/pax/extern.h index 742a0b0f4c3f..889959f4d811 100644 --- a/bin/pax/extern.h +++ b/bin/pax/extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: extern.h,v 1.20 1999/11/01 01:35:58 mrg Exp $ */ +/* $NetBSD: extern.h,v 1.21 2000/02/17 03:06:13 itohy Exp $ */ /*- * Copyright (c) 1992 Keith Muller. @@ -57,6 +57,15 @@ void ar_close __P((void)); void ar_drain __P((void)); int ar_set_wr __P((void)); int ar_app_ok __P((void)); +#ifdef SYS_NO_RESTART +int read_with_restart __P((int, void *, int)); +int write_with_restart __P((int, void *, int)); +#else +#define read_with_restart read +#define write_with_restart write +#endif +int xread __P((int, void *, int)); +int xwrite __P((int, void *, int)); int ar_read __P((char *, int)); int ar_write __P((char *, int)); int ar_rdsync __P((void)); diff --git a/bin/pax/file_subs.c b/bin/pax/file_subs.c index 4f89b42691fe..4f9ac38be670 100644 --- a/bin/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -1,4 +1,4 @@ -/* $NetBSD: file_subs.c,v 1.15 1999/11/07 15:48:24 mycroft Exp $ */ +/* $NetBSD: file_subs.c,v 1.16 2000/02/17 03:06:13 itohy Exp $ */ /*- * Copyright (c) 1992 Keith Muller. @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93"; #else -__RCSID("$NetBSD: file_subs.c,v 1.15 1999/11/07 15:48:24 mycroft Exp $"); +__RCSID("$NetBSD: file_subs.c,v 1.16 2000/02/17 03:06:13 itohy Exp $"); #endif #endif /* not lint */ @@ -948,7 +948,7 @@ file_write(fd, str, cnt, rem, isempt, sz, name) } strncpy(gnu_hack_string, st, wcnt); gnu_hack_string[wcnt] = 0; - } else if (write(fd, st, wcnt) != wcnt) { + } else if (xwrite(fd, st, wcnt) != wcnt) { syswarn(1, errno, "Failed write to file %s", name); return(-1); } @@ -992,7 +992,7 @@ file_flush(fd, fname, isempt) return; } - if (write(fd, blnk, 1) < 0) + if (write_with_restart(fd, blnk, 1) < 0) syswarn(1, errno, "Failed write to file %s", fname); return; } diff --git a/bin/pax/tables.c b/bin/pax/tables.c index 91924d6a1b34..e671b3182558 100644 --- a/bin/pax/tables.c +++ b/bin/pax/tables.c @@ -1,4 +1,4 @@ -/* $NetBSD: tables.c,v 1.10 1999/11/01 01:35:59 mrg Exp $ */ +/* $NetBSD: tables.c,v 1.11 2000/02/17 03:06:13 itohy Exp $ */ /*- * Copyright (c) 1992 Keith Muller. @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93"; #else -__RCSID("$NetBSD: tables.c,v 1.10 1999/11/01 01:35:59 mrg Exp $"); +__RCSID("$NetBSD: tables.c,v 1.11 2000/02/17 03:06:13 itohy Exp $"); #endif #endif /* not lint */ @@ -446,7 +446,7 @@ chk_ftime(arcn) "Failed ftime table seek"); return(-1); } - if (read(ffd, ckname, namelen) != namelen) { + if (xread(ffd, ckname, namelen) != namelen) { syswarn(1, errno, "Failed ftime table read"); return(-1); @@ -492,7 +492,7 @@ chk_ftime(arcn) * offset. add the file to the head of the hash chain */ if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) { - if (write(ffd, arcn->name, namelen) == namelen) { + if (xwrite(ffd, arcn->name, namelen) == namelen) { pt->mtime = arcn->sb.st_mtime; pt->namelen = namelen; pt->fow = ftab[indx]; @@ -1288,8 +1288,8 @@ add_dir(name, nlen, psb, frc_mode) dblk.atime = psb->st_atime; dblk.fflags = psb->st_flags; dblk.frc_mode = frc_mode; - if ((write(dirfd, name, dblk.nlen) == dblk.nlen) && - (write(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { + if ((xwrite(dirfd, name, dblk.nlen) == dblk.nlen) && + (xwrite(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { ++dircnt; return; } @@ -1329,11 +1329,11 @@ proc_dir() */ if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) break; - if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) + if (xread(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; - if (read(dirfd, name, dblk.nlen) != dblk.nlen) + if (xread(dirfd, name, dblk.nlen) != dblk.nlen) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break;