diff --git a/usr.bin/cmp/cmp.1 b/usr.bin/cmp/cmp.1 index 5a56802bd22e..3e616bbe806e 100644 --- a/usr.bin/cmp/cmp.1 +++ b/usr.bin/cmp/cmp.1 @@ -1,210 +1,213 @@ .\" Copyright (c) 1987, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by .\" the Institute of Electrical and Electronics Engineers, Inc. .\" .\" 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. .\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" 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. .\" .\" @(#)cmp.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" .Dd September 23, 2021 .Dt CMP 1 .Os .Sh NAME .Nm cmp .Nd compare two files .Sh SYNOPSIS .Nm .Op Fl l | s | x -.Op Fl hz +.Op Fl bhz .Op Fl -ignore-initial Ns Cm = Ns Ar num1 Ns Op :num2 .Op Fl -bytes Ns Cm = Ns Ar num .Ar file1 file2 .Op Ar skip1 Op Ar skip2 .Sh DESCRIPTION The .Nm utility compares two files of any type and writes the results to the standard output. By default, .Nm is silent if the files are the same; if they differ, the byte and line number at which the first difference occurred is reported. .Pp Bytes and lines are numbered beginning with one. .Pp The following options are available: .Bl -tag -width indent +.It Fl b , Fl -print-bytes +Print each byte when a difference is found. .It Fl h Do not follow symbolic links. .It Fl i Ar num1 Ns Oo :num2 Oc , Fl -ignore-initial= Ns Ar num1 Ns Op :num2 Skip .Ar num1 bytes from .Ar file1 , and optionally skip .Ar num2 bytes from .Ar file2 . If .Ar num2 is not specified, then .Ar num1 is applied for both .Ar file1 and .Ar file2 . .It Fl l , Fl -verbose Print the byte number (decimal) and the differing byte values (octal) for each difference. .It Fl n Ar num , Fl -bytes= Ns num Only compare up to .Ar num bytes. .It Fl s , Fl -silent , Fl -quiet Print nothing for differing files; return exit status only. .It Fl x Like .Fl l but prints in hexadecimal and using zero as index for the first byte in the files. .It Fl z For regular files compare file sizes first, and fail the comparison if they are not equal. .El .Pp The optional arguments .Ar skip1 and .Ar skip2 are the byte offsets from the beginning of .Ar file1 and .Ar file2 , respectively, where the comparison will begin. The offset is decimal by default, but may be expressed as a hexadecimal or octal value by preceding it with a leading ``0x'' or ``0''. .Pp .Ar skip1 and .Ar skip2 may also be specified with SI size suffixes. .Sh EXIT STATUS The .Nm utility exits with one of the following values: .Bl -tag -width 4n .It 0 The files are identical. .It 1 The files are different; this includes the case where one file is identical to the first part of the other. In the latter case, if the .Fl s option has not been specified, .Nm writes to standard error that EOF was reached in the shorter file (before any differences were found). .It >1 An error occurred. .El .Sh EXAMPLES Assuming a file named .Pa example.txt with the following contents: .Bd -literal -offset indent a b c .Ed .Pp Compare stdin with .Pa example.txt : .Bd -literal -offset indent $ echo -e "a\\nb\\nc" | cmp - example.txt .Ed .Pp Same as above but introducing a change in the third byte of stdin. Show the byte number (decimal) and differing byte (octal): .Bd -literal -offset indent $ echo -e "a\\nR\\nc" | cmp -l - example.txt 3 122 142 .Ed .Pp Compare file sizes of .Pa example.txt and .Pa /boot/loader.conf and return 1 if they are not equal. Note that .Fl z can only be used with regular files: .Bd -literal -offset indent $ cmp -z example.txt /boot/loader.conf example.txt /boot/loader.conf differ: size .Ed .Pp Compare stdin with .Pa example.txt omitting the first 4 bytes from stdin and the first 2 bytes from .Pa example.txt : .Bd -literal -offset indent $ echo -e "a\\nR\\nb\\nc" | cmp - example.txt 4 2 .Ed .Sh SEE ALSO .Xr diff 1 , .Xr diff3 1 .Sh STANDARDS The .Nm utility is expected to be .St -p1003.2 compatible. The +.Fl b , .Fl h , .Fl i , .Fl n , .Fl x , and .Fl z options are extensions to the standard. .Ar skip1 and .Ar skip2 arguments are extensions to the standard. .Sh HISTORY A .Nm command appeared in .At v1 . .Sh BUGS The phrase .Dq SI size suffixes above refers to the traditional power of two convention, as described in .Xr expand_number 3 . diff --git a/usr.bin/cmp/cmp.c b/usr.bin/cmp/cmp.c index 256cef8a0c31..98ae96c73375 100644 --- a/usr.bin/cmp/cmp.c +++ b/usr.bin/cmp/cmp.c @@ -1,261 +1,265 @@ /* * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1987, 1990, 1993, 1994 * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1987, 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)cmp.c 8.3 (Berkeley) 4/2/94"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "extern.h" -bool lflag, sflag, xflag, zflag; +bool bflag, lflag, sflag, xflag, zflag; static const struct option long_opts[] = { + {"print-bytes", no_argument, NULL, 'b'}, {"ignore-initial", required_argument, NULL, 'i'}, {"verbose", no_argument, NULL, 'l'}, {"bytes", required_argument, NULL, 'n'}, {"silent", no_argument, NULL, 's'}, {"quiet", no_argument, NULL, 's'}, {NULL, no_argument, NULL, 0} }; static void usage(void); static bool parse_iskipspec(char *spec, off_t *skip1, off_t *skip2) { char *colon; colon = strchr(spec, ':'); if (colon != NULL) *colon++ = '\0'; if (expand_number(spec, skip1) < 0) return (false); if (colon != NULL) return (expand_number(colon, skip2) == 0); *skip2 = *skip1; return (true); } int main(int argc, char *argv[]) { struct stat sb1, sb2; off_t skip1, skip2, limit; int ch, fd1, fd2, oflag; bool special; const char *file1, *file2; skip1 = skip2 = 0; oflag = O_RDONLY; - while ((ch = getopt_long(argc, argv, "+hi:ln:sxz", long_opts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, "+bhi:ln:sxz", long_opts, NULL)) != -1) switch (ch) { + case 'b': /* Print bytes */ + bflag = true; + break; case 'h': /* Don't follow symlinks */ oflag |= O_NOFOLLOW; break; case 'i': if (!parse_iskipspec(optarg, &skip1, &skip2)) { fprintf(stderr, "Invalid --ignore-initial: %s\n", optarg); usage(); } break; case 'l': /* print all differences */ lflag = true; break; case 'n': /* Limit */ if (expand_number(optarg, &limit) < 0 || limit < 0) { fprintf(stderr, "Invalid --bytes: %s\n", optarg); usage(); } break; case 's': /* silent run */ sflag = true; break; case 'x': /* hex output */ lflag = true; xflag = true; break; case 'z': /* compare size first */ zflag = true; break; case '?': default: usage(); } argv += optind; argc -= optind; if (lflag && sflag) errx(ERR_EXIT, "specifying -s with -l or -x is not permitted"); if (argc < 2 || argc > 4) usage(); /* Don't limit rights on stdin since it may be one of the inputs. */ if (caph_limit_stream(STDOUT_FILENO, CAPH_WRITE | CAPH_IGNORE_EBADF)) err(ERR_EXIT, "unable to limit rights on stdout"); if (caph_limit_stream(STDERR_FILENO, CAPH_WRITE | CAPH_IGNORE_EBADF)) err(ERR_EXIT, "unable to limit rights on stderr"); /* Backward compatibility -- handle "-" meaning stdin. */ special = false; if (strcmp(file1 = argv[0], "-") == 0) { special = true; fd1 = STDIN_FILENO; file1 = "stdin"; } else if ((fd1 = open(file1, oflag, 0)) < 0 && errno != EMLINK) { if (!sflag) err(ERR_EXIT, "%s", file1); else exit(ERR_EXIT); } if (strcmp(file2 = argv[1], "-") == 0) { if (special) errx(ERR_EXIT, "standard input may only be specified once"); special = true; fd2 = STDIN_FILENO; file2 = "stdin"; } else if ((fd2 = open(file2, oflag, 0)) < 0 && errno != EMLINK) { if (!sflag) err(ERR_EXIT, "%s", file2); else exit(ERR_EXIT); } if (argc > 2 && expand_number(argv[2], &skip1) < 0) { fprintf(stderr, "Invalid skip1: %s\n", argv[2]); usage(); } if (argc == 4 && expand_number(argv[3], &skip2) < 0) { fprintf(stderr, "Invalid skip2: %s\n", argv[3]); usage(); } if (sflag && skip1 == 0 && skip2 == 0) zflag = true; if (fd1 == -1) { if (fd2 == -1) { c_link(file1, skip1, file2, skip2, limit); exit(0); } else if (!sflag) errx(ERR_EXIT, "%s: Not a symbolic link", file2); else exit(ERR_EXIT); } else if (fd2 == -1) { if (!sflag) errx(ERR_EXIT, "%s: Not a symbolic link", file1); else exit(ERR_EXIT); } /* FD rights are limited in c_special() and c_regular(). */ caph_cache_catpages(); if (!special) { if (fstat(fd1, &sb1)) { if (!sflag) err(ERR_EXIT, "%s", file1); else exit(ERR_EXIT); } if (!S_ISREG(sb1.st_mode)) special = true; else { if (fstat(fd2, &sb2)) { if (!sflag) err(ERR_EXIT, "%s", file2); else exit(ERR_EXIT); } if (!S_ISREG(sb2.st_mode)) special = true; } } if (special) 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); } c_regular(fd1, file1, skip1, sb1.st_size, fd2, file2, skip2, sb2.st_size, limit); } exit(0); } static void usage(void) { (void)fprintf(stderr, "usage: cmp [-l | -s | -x] [-hz] file1 file2 [skip1 [skip2]]\n"); exit(ERR_EXIT); } diff --git a/usr.bin/cmp/extern.h b/usr.bin/cmp/extern.h index 803319a50ca4..d98daf424995 100644 --- a/usr.bin/cmp/extern.h +++ b/usr.bin/cmp/extern.h @@ -1,48 +1,48 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993, 1994 * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * 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. * * @(#)extern.h 8.3 (Berkeley) 4/2/94 * * $FreeBSD$ * */ #define OK_EXIT 0 #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, off_t, off_t); void c_special(int, const char *, off_t, int, const char *, off_t, off_t); -void diffmsg(const char *, const char *, off_t, off_t); +void diffmsg(const char *, const char *, off_t, off_t, int, int); void eofmsg(const char *); -extern bool lflag, sflag, xflag, zflag; +extern bool bflag, lflag, sflag, xflag, zflag; diff --git a/usr.bin/cmp/link.c b/usr.bin/cmp/link.c index f0b4482a5792..e01a5911faf7 100644 --- a/usr.bin/cmp/link.c +++ b/usr.bin/cmp/link.c @@ -1,98 +1,102 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005 Brian Somers * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "extern.h" void c_link(const char *file1, off_t skip1, const char *file2, off_t skip2, off_t limit) { char buf1[PATH_MAX], *p1; char buf2[PATH_MAX], *p2; int dfound, len1, len2; off_t byte; u_char ch; if ((len1 = readlink(file1, buf1, sizeof(buf1) - 1)) < 0) { if (!sflag) err(ERR_EXIT, "%s", file1); else exit(ERR_EXIT); } if ((len2 = readlink(file2, buf2, sizeof(buf2) - 1)) < 0) { if (!sflag) err(ERR_EXIT, "%s", file2); else exit(ERR_EXIT); } if (skip1 > len1) skip1 = len1; buf1[len1] = '\0'; if (skip2 > len2) skip2 = len2; buf2[len2] = '\0'; dfound = 0; byte = 1; for (p1 = buf1 + skip1, p2 = buf2 + skip2; *p1 && *p2 && (limit == 0 || byte <= limit); p1++, p2++) { if ((ch = *p1) != *p2) { if (xflag) { dfound = 1; (void)printf("%08llx %02x %02x\n", (long long)byte - 1, ch, *p2); } else if (lflag) { dfound = 1; - (void)printf("%6lld %3o %3o\n", - (long long)byte, ch, *p2); + 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 - diffmsg(file1, file2, byte, 1); + diffmsg(file1, file2, byte, 1, ch, *p2); /* NOTREACHED */ } byte++; } if (*p1 || *p2) eofmsg (*p1 ? file2 : file1); if (dfound) exit(DIFF_EXIT); } diff --git a/usr.bin/cmp/misc.c b/usr.bin/cmp/misc.c index 1e84f0d7a527..1dba34d28792 100644 --- a/usr.bin/cmp/misc.c +++ b/usr.bin/cmp/misc.c @@ -1,65 +1,75 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993, 1994 * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * 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. */ #if 0 #ifndef lint static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "extern.h" void 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) +diffmsg(const char *file1, const char *file2, off_t byte, off_t line, + int b1, int b2) { - if (!sflag) + if (sflag) + goto out; + + 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); + } else { (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 a60398620282..d270aeeac396 100644 --- a/usr.bin/cmp/regular.c +++ b/usr.bin/cmp/regular.c @@ -1,185 +1,189 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993, 1994 * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * 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. */ #if 0 #ifndef lint static char sccsid[] = "@(#)regular.c 8.3 (Berkeley) 4/2/94"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "extern.h" static u_char *remmap(u_char *, int, off_t); static void segv_handler(int); #define MMAP_CHUNK (8*1024*1024) #define ROUNDPAGE(i) ((i) & ~pagemask) void 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) { struct sigaction act, oact; cap_rights_t rights; u_char ch, *p1, *p2, *m1, *m2, *e1, *e2; off_t byte, length, line; off_t pagemask, off1, off2; size_t pagesize; int dfound; if (skip1 > len1) eofmsg(file1); len1 -= skip1; if (skip2 > len2) eofmsg(file2); len2 -= skip2; if (sflag && len1 != len2) exit(DIFF_EXIT); pagesize = getpagesize(); pagemask = (off_t)pagesize - 1; off1 = ROUNDPAGE(skip1); off2 = ROUNDPAGE(skip2); length = MIN(len1, len2); if (limit > 0) length = MIN(length, limit); if ((m1 = remmap(NULL, fd1, off1)) == NULL) { c_special(fd1, file1, skip1, fd2, file2, skip2, limit); return; } if ((m2 = remmap(NULL, fd2, off2)) == NULL) { munmap(m1, MMAP_CHUNK); c_special(fd1, file1, skip1, fd2, file2, skip2, limit); return; } if (caph_rights_limit(fd1, cap_rights_init(&rights, CAP_MMAP_R)) < 0) err(1, "unable to limit rights for %s", file1); if (caph_rights_limit(fd2, cap_rights_init(&rights, CAP_MMAP_R)) < 0) err(1, "unable to limit rights for %s", file2); if (caph_enter() < 0) err(ERR_EXIT, "unable to enter capability mode"); sigemptyset(&act.sa_mask); act.sa_flags = SA_NODEFER; act.sa_handler = segv_handler; if (sigaction(SIGSEGV, &act, &oact)) err(ERR_EXIT, "sigaction()"); dfound = 0; e1 = m1 + MMAP_CHUNK; e2 = m2 + MMAP_CHUNK; p1 = m1 + (skip1 - off1); p2 = m2 + (skip2 - off2); for (byte = line = 1; length--; ++byte) { if ((ch = *p1) != *p2) { if (xflag) { dfound = 1; (void)printf("%08llx %02x %02x\n", (long long)byte - 1, ch, *p2); } else if (lflag) { dfound = 1; - (void)printf("%6lld %3o %3o\n", - (long long)byte, ch, *p2); + 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 - diffmsg(file1, file2, byte, line); + diffmsg(file1, file2, byte, line, ch, *p2); /* NOTREACHED */ } if (ch == '\n') ++line; if (++p1 == e1) { off1 += MMAP_CHUNK; if ((p1 = m1 = remmap(m1, fd1, off1)) == NULL) { munmap(m2, MMAP_CHUNK); err(ERR_EXIT, "remmap %s", file1); } e1 = m1 + MMAP_CHUNK; } if (++p2 == e2) { off2 += MMAP_CHUNK; if ((p2 = m2 = remmap(m2, fd2, off2)) == NULL) { munmap(m1, MMAP_CHUNK); err(ERR_EXIT, "remmap %s", file2); } e2 = m2 + MMAP_CHUNK; } } munmap(m1, MMAP_CHUNK); munmap(m2, MMAP_CHUNK); if (sigaction(SIGSEGV, &oact, NULL)) err(ERR_EXIT, "sigaction()"); if (len1 != len2) eofmsg (len1 > len2 ? file2 : file1); if (dfound) exit(DIFF_EXIT); } static u_char * remmap(u_char *mem, int fd, off_t offset) { if (mem != NULL) munmap(mem, MMAP_CHUNK); mem = mmap(NULL, MMAP_CHUNK, PROT_READ, MAP_SHARED, fd, offset); if (mem == MAP_FAILED) return (NULL); madvise(mem, MMAP_CHUNK, MADV_SEQUENTIAL); return (mem); } static void segv_handler(int sig __unused) { static const char msg[] = "cmp: Input/output error (caught SIGSEGV)\n"; write(STDERR_FILENO, msg, sizeof(msg)); _exit(EXIT_FAILURE); } diff --git a/usr.bin/cmp/special.c b/usr.bin/cmp/special.c index 25f755f6e70a..c206a317c0ef 100644 --- a/usr.bin/cmp/special.c +++ b/usr.bin/cmp/special.c @@ -1,116 +1,121 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993, 1994 * 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * 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. */ #if 0 #ifndef lint static char sccsid[] = "@(#)special.c 8.3 (Berkeley) 4/2/94"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "extern.h" void c_special(int fd1, const char *file1, off_t skip1, int fd2, const char *file2, off_t skip2, off_t limit) { int ch1, ch2; off_t byte, line; FILE *fp1, *fp2; int dfound; if (caph_limit_stream(fd1, CAPH_READ) < 0) err(ERR_EXIT, "caph_limit_stream(%s)", file1); if (caph_limit_stream(fd2, CAPH_READ) < 0) err(ERR_EXIT, "caph_limit_stream(%s)", file2); if (caph_enter() < 0) err(ERR_EXIT, "unable to enter capability mode"); if ((fp1 = fdopen(fd1, "r")) == NULL) err(ERR_EXIT, "%s", file1); if ((fp2 = fdopen(fd2, "r")) == NULL) err(ERR_EXIT, "%s", file2); dfound = 0; while (skip1--) if (getc(fp1) == EOF) goto eof; while (skip2--) if (getc(fp2) == EOF) goto eof; for (byte = line = 1; limit == 0 || byte <= limit; ++byte) { ch1 = getc(fp1); ch2 = getc(fp2); if (ch1 == EOF || ch2 == EOF) break; if (ch1 != ch2) { if (xflag) { dfound = 1; (void)printf("%08llx %02x %02x\n", (long long)byte - 1, ch1, ch2); } else if (lflag) { dfound = 1; - (void)printf("%6lld %3o %3o\n", - (long long)byte, ch1, ch2); + if (bflag) + (void)printf("%6lld %3o %c %3o %c\n", + (long long)byte, ch1, ch1, ch2, + ch2); + else + (void)printf("%6lld %3o %3o\n", + (long long)byte, ch1, ch2); } else { - diffmsg(file1, file2, byte, line); + diffmsg(file1, file2, byte, line, ch1, ch2); /* NOTREACHED */ } } if (ch1 == '\n') ++line; } eof: if (ferror(fp1)) err(ERR_EXIT, "%s", file1); if (ferror(fp2)) err(ERR_EXIT, "%s", file2); if (feof(fp1)) { if (!feof(fp2)) eofmsg(file1); } else if (feof(fp2)) eofmsg(file2); fclose(fp2); fclose(fp1); if (dfound) exit(DIFF_EXIT); } diff --git a/usr.bin/cmp/tests/Makefile b/usr.bin/cmp/tests/Makefile index 087f32f4185f..99469ba42243 100644 --- a/usr.bin/cmp/tests/Makefile +++ b/usr.bin/cmp/tests/Makefile @@ -1,10 +1,15 @@ # $FreeBSD$ .include +PACKAGE= tests + ATF_TESTS_SH+= cmp_test2 NETBSD_ATF_TESTS_SH= cmp_test +${PACKAGE}FILES+= b_flag.out +${PACKAGE}FILES+= bl_flag.out + .include .include diff --git a/usr.bin/cmp/tests/b_flag.out b/usr.bin/cmp/tests/b_flag.out new file mode 100644 index 000000000000..bb3d288716b0 --- /dev/null +++ b/usr.bin/cmp/tests/b_flag.out @@ -0,0 +1 @@ +a b differ: char 3, line 1 is 143 c 144 d diff --git a/usr.bin/cmp/tests/bl_flag.out b/usr.bin/cmp/tests/bl_flag.out new file mode 100644 index 000000000000..8ec9007d7ed3 --- /dev/null +++ b/usr.bin/cmp/tests/bl_flag.out @@ -0,0 +1 @@ + 3 143 c 144 d diff --git a/usr.bin/cmp/tests/cmp_test2.sh b/usr.bin/cmp/tests/cmp_test2.sh index 893ee59076c3..c264827646ca 100755 --- a/usr.bin/cmp/tests/cmp_test2.sh +++ b/usr.bin/cmp/tests/cmp_test2.sh @@ -1,128 +1,145 @@ # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2017 Alan Somers # # 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. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND 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 FOUNDATION 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. # # $FreeBSD$ atf_test_case special special_head() { atf_set "descr" "Test cmp(1)'s handling of non-regular files" } special_body() { echo 0123456789abcdef > a echo 0123456789abcdeg > b atf_check -s exit:0 -o empty -e empty -x "cat a | cmp a -" atf_check -s exit:0 -o empty -e empty -x "cat a | cmp - a" atf_check -s exit:1 -o not-empty -e empty -x "cat b | cmp a -" atf_check -s exit:1 -o not-empty -e empty -x "cat b | cmp - a" atf_check -s exit:0 -o empty -e empty -x "cmp a a <&-" } atf_test_case symlink symlink_head() { atf_set "descr" "Test cmp(1)'s handling of symlinks" } symlink_body() { echo 0123456789abcdef > a echo 0123456789abcdeg > b ln -s a a.lnk ln -s b b.lnk ln -s a a2.lnk cp a adup ln -s adup adup.lnk atf_check -s exit:0 cmp a a.lnk atf_check -s exit:0 cmp a.lnk a atf_check -s not-exit:0 -o ignore cmp a b.lnk atf_check -s not-exit:0 -o ignore cmp b.lnk a atf_check -s not-exit:0 -o ignore -e ignore cmp -h a a.lnk atf_check -s not-exit:0 -o ignore -e ignore cmp -h a.lnk a atf_check -s exit:0 cmp -h a.lnk a2.lnk atf_check -s not-exit:0 -o ignore -e ignore cmp -h a.lnk adup.lnk } atf_test_case pr252542 pr252542_head() { atf_set "descr" "Test cmp(1) -s with file offset skips" } pr252542_body() { echo -n '1234567890' > a echo -n 'abc567890' > b echo -n 'xbc567890' > c atf_check -s exit:0 cmp -s a b 4 3 atf_check -s exit:0 cmp -i 4:3 -s a b atf_check -s exit:0 cmp -i 1 -s b c atf_check -s exit:1 -o ignore cmp -z a b 4 3 atf_check -s exit:1 -o ignore cmp -i 4:3 -z a b atf_check -s exit:1 -o ignore cmp -i 1 -z a b } atf_test_case skipsuff skipsuff_head() { atf_set "descr" "Test cmp(1) accepting SI suffixes on skips" } skipsuff_body() { jot -nb a -s '' 1028 > a jot -nb b -s '' 1024 > b jot -nb a -s '' 4 >> b atf_check -s exit:1 -o ignore cmp -s a b atf_check -s exit:0 cmp -s a b 1k 1k } atf_test_case limit limit_head() { atf_set "descr" "Test cmp(1) -n (limit)" } limit_body() { echo -n "aaaabbbb" > a echo -n "aaaaxxxx" > b atf_check -s exit:1 -o ignore cmp -s a b atf_check -s exit:0 cmp -sn 4 a b atf_check -s exit:0 cmp -sn 3 a b atf_check -s exit:1 -o ignore cmp -sn 5 a b # Test special, too. The implementation for link is effectively # identical. atf_check -s exit:0 -e empty -x "cat a | cmp -sn 4 b -" atf_check -s exit:0 -e empty -x "cat a | cmp -sn 3 b -" atf_check -s exit:1 -o ignore -x "cat a | cmp -sn 5 b -" } +atf_test_case bflag +bflag_head() +{ + atf_set "descr" "Test cmp(1) -b (print bytes)" +} +bflag_body() +{ + echo -n "abcd" > a + echo -n "abdd" > b + + atf_check -s exit:1 -o file:$(atf_get_srcdir)/b_flag.out \ + cmp -b a b + atf_check -s exit:1 -o file:$(atf_get_srcdir)/bl_flag.out \ + cmp -bl a b +} + atf_init_test_cases() { atf_add_test_case special atf_add_test_case symlink atf_add_test_case pr252542 atf_add_test_case skipsuff atf_add_test_case limit + atf_add_test_case bflag }