.
authorJim Meyering <jim@meyering.net>
Sun, 2 Oct 1994 22:10:57 +0000 (22:10 +0000)
committerJim Meyering <jim@meyering.net>
Sun, 2 Oct 1994 22:10:57 +0000 (22:10 +0000)
src/sort.c
src/tr.c

index eb34c32..ae28518 100644 (file)
    The author may be reached (Email) at the address mike@gnu.ai.mit.edu,
    or (US mail) as Mike Haertel c/o Free Software Foundation. */
 
-#ifdef HAVE_CONFIG_H
-#if defined (CONFIG_BROKETS)
-/* We use <config.h> instead of "config.h" so that a compilation
-   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
-   (which it would do because it found this file in $srcdir).  */
 #include <config.h>
-#else
-#include "config.h"
-#endif
-#endif
 
 /* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
@@ -38,6 +29,7 @@
 #include <stdio.h>
 #include "system.h"
 #include "long-options.h"
+#include "safe-stat.h"
 
 #ifdef _POSIX_VERSION
 #include <limits.h>
@@ -1732,32 +1724,61 @@ main (argc, argv)
 
   if (strcmp (outfile, "-"))
     {
-      for (i = 0; i < nfiles; ++i)
-       if (!strcmp (outfile, files[i]))
-         break;
-      if (i == nfiles)
-       ofp = xfopen (outfile, "w");
-      else
+      struct stat outstat;
+      if (SAFE_STAT (outfile, &outstat) == 0)
        {
-         char buf[8192];
-         FILE *fp = xfopen (outfile, "r");
-         int cc;
-
-         tmp = tempname ();
-         ofp = xfopen (tmp, "w");
-         while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
-           xfwrite (buf, 1, cc, ofp);
-         if (ferror (fp))
+         /* The following code prevents a race condition when
+            people use the brain dead shell programming idiom:
+                 cat file | sort -o file
+            This feature is provided for historical compatibility,
+            but we strongly discourage ever relying on this in
+            new shell programs. */
+
+         /* Temporarily copy each input file that might be another name
+            for the output file.  When in doubt (e.g. a pipe), copy.  */
+         for (i = 0; i < nfiles; ++i)
            {
-             error (0, errno, "%s", outfile);
-             cleanup ();
-             exit (2);
+             char buf[8192];
+             FILE *fp;
+             int cc;
+
+             if (S_ISREG (outstat.st_mode) && strcmp (outfile, files[i]))
+               {
+                 struct stat instat;
+                 if ((strcmp (files[i], "-")
+                      ? SAFE_STAT (files[i], &instat)
+                      : fstat (fileno (stdin), &instat)) != 0)
+                   {
+                     error (0, errno, "%s", files[i]);
+                     cleanup ();
+                     exit (2);
+                   }
+                 if (S_ISREG (instat.st_mode)
+                     && (instat.st_ino != outstat.st_ino
+                         || instat.st_dev != outstat.st_dev))
+                   {
+                     /* We know the files are distinct.  */
+                     continue;
+                   }
+               }
+
+             fp = xfopen (files[i], "r");
+             tmp = tempname ();
+             ofp = xfopen (tmp, "w");
+             while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
+               xfwrite (buf, 1, cc, ofp);
+             if (ferror (fp))
+               {
+                 error (0, errno, "%s", files[i]);
+                 cleanup ();
+                 exit (2);
+               }
+             xfclose (ofp);
+             xfclose (fp);
+             files[i] = tmp;
            }
-         xfclose (ofp);
-         xfclose (fp);
-         files[i] = tmp;
-         ofp = xfopen (outfile, "w");
        }
+      ofp = xfopen (outfile, "w");
     }
   else
     ofp = stdout;
index e34eae1..7e1f3a2 100644 (file)
--- a/src/tr.c
+++ b/src/tr.c
@@ -343,7 +343,7 @@ Usage: %s [OPTION]... SET1 [SET2]\n\
 SETs are specified as strings of characters.  Most represent\n\
 themselves.  Here are the special writings:\n\
 \n\
-  \\NNN            character with octal value NNN (1 to 3 digits)\n\
+  \\NNN            character with octal value NNN (1 to 3 octal digits)\n\
   \\\\              backslash\n\
   \\a              audible BEL\n\
   \\b              backspace\n\
@@ -1798,6 +1798,9 @@ deleting and squeezing repeats");
 without squeezing repeats");
     }
 
+  if (squeeze_repeats && non_option_args == 0)
+    error (1, 0, "at least one string must be given when squeezing repeats");
+
   spec_init (s1);
   if (parse_str ((unsigned char *) argv[optind], s1))
     exit (1);