Anonymous | Login | 2024-12-04 06:03 UTC |
Main | My View | View Issues | Change Log | Docs |
Viewing Issue Simple Details [ Jump to Notes ] | [ Issue History ] [ Print ] | ||||||
ID | Category | Severity | Type | Date Submitted | Last Update | ||
0000802 | [1003.1(2013)/Issue7+TC1] Shell and Utilities | Objection | Enhancement Request | 2013-11-21 20:00 | 2024-06-11 09:02 | ||
Reporter | eblake | View Status | public | ||||
Assigned To | |||||||
Priority | normal | Resolution | Accepted | ||||
Status | Closed | ||||||
Name | Eric Blake | ||||||
Organization | Red Hat | ||||||
User Reference | ebb.rm | ||||||
Section | rm | ||||||
Page Number | 3161 | ||||||
Line Number | 105667 | ||||||
Interp Status | --- | ||||||
Final Accepted Text | |||||||
Summary | 0000802: Add 'rm -d' | ||||||
Description |
Both BSD and GNU rm provide an extension option '-d' that makes rm behave as if it uses remove() instead of unlink() to remove its argument, making it possible to use rm to safely remove empty directories without risking recursion if the directory is not empty. While it is true that the standard provides rmdir for removing an empty directory without recursion, the burden is currently on the user to determine whether a name is a directory or not, which leads to a time-of-check-to-time-of-use race between discovering a file's type and then using either rm or rmdir on that file. Of course, if someone else is racing a recursive deletion process by filling directories to be non-empty, by replacing directories with files, or replacing files with directories, the entire attempt to empty out the directory is likely to fail anyways, so the race isn't that much to worry about. Still, it seems like it is worth standardizing 'rm -d'. Side note: On the GNU Coreutils list (http://debbugs.gnu.org/15926), [^] Linda Walsh raised an interesting observation that there is no clean way using just POSIX interfaces to attempt empty out the contents of a directory while leaving the directory itself intact, while still having a safety valve of not emptying beyond a mount point. An initial short attempt looks something like: rm -r * .[!.] .?* by using globs to cover all possible names, but that would produce spurious error messages about files not existing if not all the globs get expanded; using 'rm -rf' to silence the spurious error messages may also silence real errors. Using globs also potentially falls foul of maximum command line length. Furthermore, rm has no way to limit recursion to a single device (GNU rm has an extension --one-file-system that behaves similar to find's -xdev, but that's outside of POSIX). Something like: find . -xdev -depth ! -name . \( \( -type d -exec rmdir {} \; \) -o -exec rm {} \; \) works in the absence of races, but is inefficient at one process per deletion; it's also a lot of typing. Something like: find . ! -name . -prune -exec rm -r {} + benefits from fewer processes and no races between find learning a file's type and choosing which command to execute, but has no safety valves of stopping recursion across device boundaries (again, rm has no -xdev counterpart). Meanwhile, with this proposal, using: find . -xdev -depth ! -name . -exec rm -d {} + is a fairly short way to achieve the goal. She also proposed the syntax 'rm -rF .' as the way to recurse through the contents of '.' rather than short-circuiting due to the current rule [line 105670] that an rm argument ending with a basename of '.' be entirely skipped; but such a proposal belongs in a different bug report, and would need existing practice, whereas 'rm -d' already has existing practice. |
||||||
Desired Action |
At XCU page 3161 line 105667 [rm SYNOPSIS], change:to:
At line 105679 [DESCRIPTION 2.a.], change: to:
After line 105693 [DESCRIPTION 2.d.], add a step:
At line 105694 [DESCRIPTION 3.], change: to:
At line 105699 [DESCRIPTION 4.], change: to:
At line 105713 [OPTIONS], insert a new paragraph:
At line 105781 [EXAMPLES], change: to:
After line 105784 [EXAMPLES], add a new paragraph:
After line 105825 [RATIONALE], add a paragraph:
|
||||||
Tags | issue8 | ||||||
Attached Files | |||||||
|
Relationships | ||||||
|
Notes | |
(0002120) rhansen (manager) 2014-01-30 18:26 |
I may have spotted a bug in this change with regard to interactive prompting (the behavior might be intentional, not a bug): Consider this sequence of events: $ mkdir /tmp/foo $ chmod 500 /tmp/foo $ rm -ir /tmp/foo With the above, the following steps are taken in rm: 1. the file exists, so continue to step 2 2. the file is of type directory, so continue to step 2.a. 2.a. the -r option is specified, so continue to step 2.b. 2.b. the -f option is not specified, the permissions of /tmp/foo do not permit writing, and the -i option is specified, so prompt the user. Assume the response is affirmative, so continue to step 2.c. 2.c. there are no entries in /tmp/foo other than . and .. so continue to step 2.d. 2.d. the -i option is specified, so prompt the user. Assume the response is affirmative, so continue to step 2.e. 2.e. continue to step 4. 4. remove("/tmp/foo") Note that the user is prompted twice: once due to lack of write permission and once due to -i. (This double-prompting also happens in Issue7+TC2 without the bug #802 change applied.) Contrast the above behavior with the behavior in this sequence of events: $ mkdir /tmp/foo $ chmod 500 /tmp/foo $ rm -id /tmp/foo 1. the file exists, so continue to step 2 2. the file is of type directory, so continue to step 2.a. 2.a. neither -R nor -r are specified but -d is specified so continue to step 3 3. the -f option is not specified, the permissions of the file do not permit writing, and the -i option is specified, so prompt the user. Assume the response is affirmative, so continue to step 4. 4. remove("/tmp/foo") Note that the user is prompted only once. What is the intended/desired behavior? Is it correct as-is? Should the 'rm -id' case prompt the user twice to match the behavior of 'rm -ir'? Or is it a bug in the spec that the 'rm -ir' case prompts twice? (Both rm from GNU coreutils and rm from NetBSD only prompt once in the 'rm -ir' case.) |
(0002121) shware_systems (reporter) 2014-01-31 00:42 |
I read it the same way as you describe, but the wording could be clearer that the first case is so a directory marked read only isn't even examined for empty or has files, which I think is the intent, and the second prompt is for removal of an emptied directory, or one that was already empty. Those implementations may be checking if no subdir entries are present before the first prompt, though it doesn't seem they should as that's more part of Step 2.c., and just issuing the one prompt to combine 2.b. and 2.d. If the prompt used has both 'file is read only' and 'there are no entries' in some form I'd think that could be considered a benign extension. I read it as the intent is two prompts should be given because there may be multiple subdirs removed and the initial entry into dir "a" of a path "/tmp/foo/a/b/c/d/e" may have many intermediate "Remove .../e/file1 ?", .../e/file2, etc. prompts before getting back to the point where "a" now empty and is a candidate for removal. I think 2.d. should have the qualifier it's not required if any file in a subdir was explicitly skipped, because then it's already known the rmdir() will fail so asking superfluous. Strictly, it seems 2.b. should have "This directory <file> read only, Skip Y/N?" as a prompt, and 2.d. something like "Remove empty directory <file> Y/N?" in some fashion. Step 2.b. with -i specified could be also construed as "<file> is a directory, Skip Y/N?" whether <file> read-only or read-write, and the read-only prompt version happens just when -i not specified but stdin is a terminal. It's missing a comma somewhere to disambiguate those two possibilities, it looks. I'd consider it a bug in how they did it if a preemptive check for files has a side effect of modifying the last access time stamp and the operator says to skip it. The stat() call is required to flush pending time stamp changes, but I don't see it as expected to queue a new access time change if it succeeds. An opendir() call is left more as implementation-defined if that sort of change will occur, so a check using it might have that side effect and shouldn't. |
(0002122) geoffclare (manager) 2014-02-06 11:08 |
Solaris and HP-UX both behave as described in the standard for the rm -ir case in Note: 0002120. Solaris makes a clear distinction between the two prompts: $ rm -ir /tmp/foo rm: examine files in directory /tmp/foo (yes/no)? y rm: remove /tmp/foo (yes/no)? y $ The first prompt is asking whether to recurse into the directory; the second is asking whether to remove the directory itself. HP-UX also has different prompts, although they are both more cryptic: $ rm -ir /tmp/foo directory /tmp/foo: ? (y/n) y /tmp/foo: ? (y/n) y $ So it looks like the double prompting requirement for rm -ir is intentional. For rm -id it makes sense that there is only one prompt as there is no recursion to ask about. |
(0002123) eblake (manager) 2014-02-06 16:14 edited on: 2014-02-06 16:20 |
FreeBSD behavior: $ cd /tmp $ mkdir foo $ touch foo/bar $ chmod 500 foo $ rm -ir foo remove foo? y remove foo/bar? y rm: foo/bar: Permission denied rm: foo: Directory not empty $ chmod 700 foo $ rm foo/bar chmod 500 foo $ rm -ir foo remove foo? y $ mkdir foo $ touch foo/bar $ rm -ir foo remove foo? n $ rm -ir foo remove foo? y remove foo/bar? y $ So FreeBSD optimizes and only prompts once for an empty directory, and in the non-empty case only asks once for a directory - which is a bug, because all other implementations allow you to descend into a directory, remove all contents, but then answer no to removing the directory itself. |
(0002131) shware_systems (reporter) 2014-02-06 22:07 |
Issue raised in note #2120 moved to bug #819 as separate TC2 concern. |
Mantis 1.1.6[^] Copyright © 2000 - 2008 Mantis Group |