Subject: [PATCH] rm: fail on duplicate input if force not enabled

From: Łukasz Sroka <[email-masked]>
Date: Sat, 21 Jan 2023 14:05:25 +0100

When the input files contain duplicates, then the rm fails. Because
    duplicates occur most often when the * is used and the shell unwraps it.
    There is a very common scenario when a user accidentally enters space
    after a filename, or enters space instead of forward slash.
    Example:

      rm prefix_ *

    The user intended to remove all files with a `prefix_` but removed all
    of the files in cwd.
    The program quits immediately when a duplicate is detected, to prevent
    pressing `y` because user expected a prompt regarding removing multiple
    files.
    The force option disables this function to enable scripts to work
    without modifying them.

```
diff --git a/src/rm.c b/src/rm.c
index 354e2b0df..e4f9949f0 100644
--- a/src/rm.c
+++ b/src/rm.c
@@ -123,6 +123,16 @@ diagnose_leading_hyphen (int argc, char **argv)
     }
 }

+static bool
+find_duplicates (int n_files, char **files)
+{
+  for (int l = 0; l < n_files-1; l++)
+    for (int r = l+1; r < n_files; r++)
+      if (strcmp(files[l], files[r]) == 0)
+          return true;
+  return false;
+}
+
 void
 usage (int status)
 {
@@ -211,6 +221,7 @@ main (int argc, char **argv)
   bool preserve_root = true;
   struct rm_options x;
   bool prompt_once = false;
+  bool force_rm = false;
   int c;

   initialize_main (&argc, &argv);
@@ -238,6 +249,7 @@ main (int argc, char **argv)
           x.interactive = RMI_NEVER;
           x.ignore_missing_files = true;
           prompt_once = false;
+          force_rm = true;
           break;

         case 'i':
@@ -352,6 +364,17 @@ main (int argc, char **argv)
   uintmax_t n_files = argc - optind;
   char **file =  argv + optind;

+  if (!force_rm && find_duplicates(n_files, file))
+    {
+      /* Because usually when the input files are duplicated it means
that the user
+         sumbitted both a directory and an * as separate arguments,
probably by accident */
+      fprintf (stderr,
+               "%s: input contains duplicates, most likely you've put "
+               "both * and a file from the same directory.\n",
+               program_name);
+      return EXIT_FAILURE;
+    }
+
   if (prompt_once && (x.recursive || 3 < n_files))
     {
       fprintf (stderr,
```