The branch main has been updated by des:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=3c37828ee1874754e1c5e96268016113c1e02ba2

commit 3c37828ee1874754e1c5e96268016113c1e02ba2
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2024-10-09 12:08:47 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
CommitDate: 2024-10-09 12:11:43 +0000

    cmp: Check the status of stdout.
    
    POSIX requires us to print an error message and exit non-zero if
    writing to stdout fails.  This can only happen if sflag is unset.
    
    MFC after:      3 days
    Sponsored by:   Klara, Inc.
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D47020
---
 usr.bin/cmp/cmp.c              | 25 +++++++++++++++----------
 usr.bin/cmp/extern.h           |  6 +++---
 usr.bin/cmp/link.c             | 14 ++++++++------
 usr.bin/cmp/misc.c             | 10 +++-------
 usr.bin/cmp/regular.c          | 35 +++++++++++++++++++----------------
 usr.bin/cmp/special.c          | 18 +++++++++++-------
 usr.bin/cmp/tests/cmp_test2.sh | 30 ++++++++++++++++++++++++++++++
 7 files changed, 89 insertions(+), 49 deletions(-)

diff --git a/usr.bin/cmp/cmp.c b/usr.bin/cmp/cmp.c
index 01750aa66da7..746616c0c20b 100644
--- a/usr.bin/cmp/cmp.c
+++ b/usr.bin/cmp/cmp.c
@@ -100,8 +100,9 @@ main(int argc, char *argv[])
        int ch, fd1, fd2, oflag;
        bool special;
        const char *file1, *file2;
+       int ret;
 
-       limit = skip1 = skip2 = 0;
+       limit = skip1 = skip2 = ret = 0;
        oflag = O_RDONLY;
        while ((ch = getopt_long(argc, argv, "+bhi:ln:sxz", long_opts, NULL)) 
!= -1)
                switch (ch) {
@@ -199,8 +200,8 @@ main(int argc, char *argv[])
 
        if (fd1 == -1) {
                if (fd2 == -1) {
-                       c_link(file1, skip1, file2, skip2, limit);
-                       exit(0);
+                       ret = c_link(file1, skip1, file2, skip2, limit);
+                       goto end;
                } else if (!sflag)
                        errx(ERR_EXIT, "%s: Not a symbolic link", file2);
                else
@@ -239,19 +240,23 @@ main(int argc, char *argv[])
 #ifdef SIGINFO
        (void)signal(SIGINFO, siginfo);
 #endif
-       if (special)
-               c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
-       else {
+       if (special) {
+               ret = c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
+       } else {
                if (zflag && sb1.st_size != sb2.st_size) {
                        if (!sflag)
                                (void)printf("%s %s differ: size\n",
                                    file1, file2);
-                       exit(DIFF_EXIT);
+                       ret = DIFF_EXIT;
+               } else {
+                       ret = c_regular(fd1, file1, skip1, sb1.st_size,
+                           fd2, file2, skip2, sb2.st_size, limit);
                }
-               c_regular(fd1, file1, skip1, sb1.st_size,
-                   fd2, file2, skip2, sb2.st_size, limit);
        }
-       exit(0);
+end:
+       if (!sflag && fflush(stdout) != 0)
+               err(ERR_EXIT, "stdout");
+       exit(ret);
 }
 
 static void
diff --git a/usr.bin/cmp/extern.h b/usr.bin/cmp/extern.h
index a7cb1fe5330b..4671b34653fa 100644
--- a/usr.bin/cmp/extern.h
+++ b/usr.bin/cmp/extern.h
@@ -34,10 +34,10 @@
 #define DIFF_EXIT      1
 #define ERR_EXIT       2       /* error exit code */
 
-void   c_link(const char *, off_t, const char *, off_t, off_t);
-void   c_regular(int, const char *, off_t, off_t, int, const char *, off_t,
+int    c_link(const char *, off_t, const char *, off_t, off_t);
+int    c_regular(int, const char *, off_t, off_t, int, const char *, off_t,
            off_t, off_t);
-void   c_special(int, const char *, off_t, int, const char *, off_t, off_t);
+int    c_special(int, const char *, off_t, int, const char *, off_t, off_t);
 void   diffmsg(const char *, const char *, off_t, off_t, int, int);
 void   eofmsg(const char *);
 
diff --git a/usr.bin/cmp/link.c b/usr.bin/cmp/link.c
index a08f4dcf9973..dfa2f957d829 100644
--- a/usr.bin/cmp/link.c
+++ b/usr.bin/cmp/link.c
@@ -37,7 +37,7 @@
 
 #include "extern.h"
 
-void
+int
 c_link(const char *file1, off_t skip1, const char *file2, off_t skip2,
     off_t limit)
 {
@@ -87,15 +87,17 @@ c_link(const char *file1, off_t skip1, const char *file2, 
off_t skip2,
                                else
                                        (void)printf("%6lld %3o %3o\n",
                                            (long long)byte, ch, *p2);
-                       } else
+                       } else {
                                diffmsg(file1, file2, byte, 1, ch, *p2);
-                               /* NOTREACHED */
+                               return (DIFF_EXIT);
+                       }
                }
                byte++;
        }
 
-       if (*p1 || *p2)
+       if (*p1 || *p2) {
                eofmsg (*p1 ? file2 : file1);
-       if (dfound)
-               exit(DIFF_EXIT);
+               return (DIFF_EXIT);
+       }
+       return (dfound ? DIFF_EXIT : 0);
 }
diff --git a/usr.bin/cmp/misc.c b/usr.bin/cmp/misc.c
index 78b431b6f6a9..4abefff31cf9 100644
--- a/usr.bin/cmp/misc.c
+++ b/usr.bin/cmp/misc.c
@@ -43,17 +43,15 @@ eofmsg(const char *file)
 {
        if (!sflag)
                warnx("EOF on %s", file);
-       exit(DIFF_EXIT);
 }
 
 void
 diffmsg(const char *file1, const char *file2, off_t byte, off_t line,
     int b1, int b2)
 {
-       if (sflag)
-               goto out;
-
-       if (bflag) {
+       if (sflag) {
+               /* nothing */
+       } else if (bflag) {
                (void)printf("%s %s differ: char %lld, line %lld is %3o %c %3o 
%c\n",
                    file1, file2, (long long)byte, (long long)line, b1, b1,
                    b2, b2);
@@ -61,6 +59,4 @@ diffmsg(const char *file1, const char *file2, off_t byte, 
off_t line,
                (void)printf("%s %s differ: char %lld, line %lld\n",
                    file1, file2, (long long)byte, (long long)line);
        }
-out:
-       exit(DIFF_EXIT);
 }
diff --git a/usr.bin/cmp/regular.c b/usr.bin/cmp/regular.c
index 9e1db2bd8772..c4407f708e8a 100644
--- a/usr.bin/cmp/regular.c
+++ b/usr.bin/cmp/regular.c
@@ -50,7 +50,7 @@ static void segv_handler(int);
 
 #define ROUNDPAGE(i) ((i) & ~pagemask)
 
-void
+int
 c_regular(int fd1, const char *file1, off_t skip1, off_t len1,
     int fd2, const char *file2, off_t skip2, off_t len2, off_t limit)
 {
@@ -62,15 +62,19 @@ c_regular(int fd1, const char *file1, off_t skip1, off_t 
len1,
        size_t pagesize;
        int dfound;
 
-       if (skip1 > len1)
+       if (skip1 > len1) {
                eofmsg(file1);
+               return (DIFF_EXIT);
+       }
        len1 -= skip1;
-       if (skip2 > len2)
+       if (skip2 > len2) {
                eofmsg(file2);
+               return (DIFF_EXIT);
+       }
        len2 -= skip2;
 
        if (sflag && len1 != len2)
-               exit(DIFF_EXIT);
+               return (DIFF_EXIT);
 
        pagesize = getpagesize();
        pagemask = (off_t)pagesize - 1;
@@ -82,14 +86,12 @@ c_regular(int fd1, const char *file1, off_t skip1, off_t 
len1,
                length = MIN(length, limit);
 
        if ((m1 = remmap(NULL, fd1, off1)) == NULL) {
-               c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
-               return;
+               return (c_special(fd1, file1, skip1, fd2, file2, skip2, limit));
        }
 
        if ((m2 = remmap(NULL, fd2, off2)) == NULL) {
                munmap(m1, MMAP_CHUNK);
-               c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
-               return;
+               return (c_special(fd1, file1, skip1, fd2, file2, skip2, limit));
        }
 
        if (caph_rights_limit(fd1, cap_rights_init(&rights, CAP_MMAP_R)) < 0)
@@ -120,21 +122,21 @@ c_regular(int fd1, const char *file1, off_t skip1, off_t 
len1,
                }
 #endif
                if ((ch = *p1) != *p2) {
+                       dfound = 1;
                        if (xflag) {
-                               dfound = 1;
                                (void)printf("%08llx %02x %02x\n",
                                    (long long)byte - 1, ch, *p2);
                        } else if (lflag) {
-                               dfound = 1;
                                if (bflag)
                                        (void)printf("%6lld %3o %c %3o %c\n",
                                            (long long)byte, ch, ch, *p2, *p2);
                                else
                                        (void)printf("%6lld %3o %3o\n",
                                            (long long)byte, ch, *p2);
-                       } else
+                       } else {
                                diffmsg(file1, file2, byte, line, ch, *p2);
-                               /* NOTREACHED */
+                               return (DIFF_EXIT);
+                       }
                }
                if (ch == '\n')
                        ++line;
@@ -161,10 +163,11 @@ c_regular(int fd1, const char *file1, off_t skip1, off_t 
len1,
        if (sigaction(SIGSEGV, &oact, NULL))
                err(ERR_EXIT, "sigaction()");
 
-       if (len1 != len2)
-               eofmsg (len1 > len2 ? file2 : file1);
-       if (dfound)
-               exit(DIFF_EXIT);
+       if (len1 != len2) {
+               eofmsg(len1 > len2 ? file2 : file1);
+               return (DIFF_EXIT);
+       }
+       return (dfound ? DIFF_EXIT : 0);
 }
 
 static u_char *
diff --git a/usr.bin/cmp/special.c b/usr.bin/cmp/special.c
index 47082eb276ab..e25e82b17047 100644
--- a/usr.bin/cmp/special.c
+++ b/usr.bin/cmp/special.c
@@ -39,7 +39,7 @@
 
 #include "extern.h"
 
-void
+int
 c_special(int fd1, const char *file1, off_t skip1,
     int fd2, const char *file2, off_t skip2, off_t limit)
 {
@@ -98,7 +98,7 @@ c_special(int fd1, const char *file1, off_t skip1,
                                            (long long)byte, ch1, ch2);
                        } else {
                                diffmsg(file1, file2, byte, line, ch1, ch2);
-                               /* NOTREACHED */
+                               return (DIFF_EXIT);
                        }
                }
                if (ch1 == '\n')
@@ -110,13 +110,17 @@ eof:      if (ferror(fp1))
        if (ferror(fp2))
                err(ERR_EXIT, "%s", file2);
        if (feof(fp1)) {
-               if (!feof(fp2))
+               if (!feof(fp2)) {
                        eofmsg(file1);
-       } else
-               if (feof(fp2))
+                       return (DIFF_EXIT);
+               }
+       } else {
+               if (feof(fp2)) {
                        eofmsg(file2);
+                       return (DIFF_EXIT);
+               }
+       }
        fclose(fp2);
        fclose(fp1);
-       if (dfound)
-               exit(DIFF_EXIT);
+       return (dfound ? DIFF_EXIT : 0);
 }
diff --git a/usr.bin/cmp/tests/cmp_test2.sh b/usr.bin/cmp/tests/cmp_test2.sh
index 80d2e663875f..2ec6071851d3 100755
--- a/usr.bin/cmp/tests/cmp_test2.sh
+++ b/usr.bin/cmp/tests/cmp_test2.sh
@@ -133,6 +133,35 @@ bflag_body()
            cmp -bl a b
 }
 
+# Helper for stdout test case
+atf_check_stdout()
+{
+       (
+               trap "" PIPE
+               cmp "$@" 2>stderr
+               echo $? >result
+       ) | true
+       atf_check -o inline:"2\n" cat result
+       atf_check -o match:"stdout" cat stderr
+}
+
+atf_test_case stdout
+stdout_head()
+{
+       atf_set descr "Failure to write to stdout"
+}
+stdout_body()
+{
+       echo a >a
+       echo b >b
+       atf_check_stdout a b
+       atf_check_stdout - b <a
+       atf_check_stdout a - <b
+       ln -s a alnk
+       ln -s b blnk
+       atf_check_stdout -h alnk blnk
+}
+
 atf_init_test_cases()
 {
        atf_add_test_case special
@@ -141,4 +170,5 @@ atf_init_test_cases()
        atf_add_test_case skipsuff
        atf_add_test_case limit
        atf_add_test_case bflag
+       atf_add_test_case stdout
 }

Reply via email to