diff --git a/usr.bin/sdiff/sdiff.c b/usr.bin/sdiff/sdiff.c --- a/usr.bin/sdiff/sdiff.c +++ b/usr.bin/sdiff/sdiff.c @@ -51,7 +51,7 @@ static void enqueue(char *, char, char *); static char *mktmpcpy(const char *); static int istextfile(FILE *); -static void binexec(char *, char *, char *) __dead2; +static int bindiff(FILE *, char *, FILE *, char *); static void freediff(struct diffline *); static void int_usage(void); static int parsecmd(FILE *, FILE *, FILE *); @@ -209,12 +209,11 @@ { FILE *diffpipe=NULL, *file1, *file2; size_t diffargc = 0, wflag = WIDTH; - int ch, fd[2] = {-1}, status; - pid_t pid=0; + int ch, fd[2], i, ret, status; + pid_t pid; const char *outfile = NULL; char **diffargv, *diffprog = diff_path, *filename1, *filename2, *tmp1, *tmp2, *s1, *s2; - int i; char I_arg[] = "-I"; char speed_lf[] = "--speed-large-files"; @@ -353,6 +352,15 @@ filename2 = tmp2; } + if ((file1 = fopen(filename1, "r")) == NULL) + err(2, "could not open %s", filename1); + if ((file2 = fopen(filename2, "r")) == NULL) + err(2, "could not open %s", filename2); + if (!istextfile(file1) || !istextfile(file2)) { + ret = bindiff(file1, filename1, file2, filename2); + goto done; + } + diffargv[diffargc++] = filename1; diffargv[diffargc++] = filename2; /* Add NULL to end of array to indicate end of array. */ @@ -393,26 +401,6 @@ if ((diffpipe = fdopen(fd[0], "r")) == NULL) err(2, "could not open diff pipe"); - if ((file1 = fopen(filename1, "r")) == NULL) - err(2, "could not open %s", filename1); - if ((file2 = fopen(filename2, "r")) == NULL) - err(2, "could not open %s", filename2); - if (!istextfile(file1) || !istextfile(file2)) { - /* Close open files and pipe, delete temps */ - fclose(file1); - fclose(file2); - if (diffpipe != NULL) - fclose(diffpipe); - if (tmp1) - if (unlink(tmp1)) - warn("Error deleting %s.", tmp1); - if (tmp2) - if (unlink(tmp2)) - warn("Error deleting %s.", tmp2); - free(tmp1); - free(tmp2); - binexec(diffprog, filename1, filename2); - } /* Line numbers start at one. */ file1ln = file2ln = 1; @@ -424,20 +412,10 @@ /* Wait for diff to exit. */ if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) || WEXITSTATUS(status) >= 2) - err(2, "diff exited abnormally."); + errx(2, "diff exited abnormally"); + ret = WEXITSTATUS(status); - /* Delete and free unneeded temporary files. */ - if (tmp1) - if (unlink(tmp1)) - warn("Error deleting %s.", tmp1); - if (tmp2) - if (unlink(tmp2)) - warn("Error deleting %s.", tmp2); - free(tmp1); - free(tmp2); - filename1 = filename2 = tmp1 = tmp2 = NULL; - - /* No more diffs, so print common lines. */ + /* No more diffs, so enqueue common lines. */ if (lflag) while ((s1 = xfgets(file1))) enqueue(s1, ' ', NULL); @@ -455,23 +433,52 @@ /* Process unmodified lines. */ processq(); +done: + /* Delete and free unneeded temporary files. */ + if (tmp1 != NULL) { + if (unlink(tmp1) != 0) + warn("failed to delete %s", tmp1); + free(tmp1); + } + if (tmp2 != NULL) { + if (unlink(tmp2) != 0) + warn("failed to delete %s", tmp2); + free(tmp2); + } + /* Return diff exit status. */ - return (WEXITSTATUS(status)); + return (ret); } /* - * When sdiff detects a binary file as input, executes them with - * diff to maintain the same behavior as GNU sdiff with binary input. + * When sdiff detects a binary file as input. */ -static void -binexec(char *diffprog, char *f1, char *f2) +static int +bindiff(FILE *f1, char *fn1, FILE *f2, char *fn2) { - - char *args[] = {diffprog, f1, f2, (char *) 0}; - execv(diffprog, args); - - /* If execv() fails, sdiff's execution will continue below. */ - errx(1, "could not execute diff process"); + int ch1, ch2; + + flockfile(f1); + flockfile(f2); + do { + ch1 = getc_unlocked(f1); + ch2 = getc_unlocked(f2); + } while (ch1 != EOF && ch2 != EOF && ch1 == ch2); + funlockfile(f2); + funlockfile(f1); + if (ferror(f1)) { + warn("%s", fn1); + return (2); + } + if (ferror(f2)) { + warn("%s", fn2); + return (2); + } + if (ch1 != EOF || ch2 != EOF) { + printf("Binary files %s and %s differ\n", fn1, fn2); + return (1); + } + return (0); } /*