Austin Group Defect Tracker

Aardvark Mark IV

Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000161 [1003.1(2008)/Issue 7] Shell and Utilities Objection Error 2009-10-03 23:17 2013-04-16 13:06
Reporter eblake View Status public  
Assigned To ajosey
Priority normal Resolution Accepted As Marked  
Status Closed  
Name Eric Blake
Organization N/A
User Reference ebb.mkdir
Section mkdir
Page Number 2937
Line Number 96644
Interp Status Approved
Final Accepted Text See Note: 0000247
Summary 0000161: mkdir -p through dangling symlink
Description The description of mkdir -p in terms of a shell script is incorrect in the presence of whitespace in the directory name. In particular, consider:

mkdir -p "$(printf 'a b\n'/c')"

which in practice creates the parent directory with a trailing newline, but which according to the spec effectively recursively calls mkdir(1) with two arguments and no newline, instead of a single argument.

Furthermore, it seems inconsistent that:

ln -s dir dangling
mkdir -p dangling/sub

is required to fail (since it recurses to 'mkdir -p dangling', but that must fail with EEXIST), while

mkdir -p dangling/

is required to succeed (the recursion sees $(dirname dangling/) which is ".", and that exists; next the code has the same effect as mkdir("dangling/") which is required to follow through the symlink per mkdir(2)). (It doesn't help that GNU/Linux mkdir(2) fails with EEXIST when dealing with a symlink with trailing slash, in violation of the standard as written).

Correctly describing the dirname operation in shell without losing a trailing newline gets rather lengthy. Providing a trailing slash to the recursive mkdir call solves the problem of stripping trailing newline. Furthermore, requiring a trailing slash on all intermediate components will give more predictable behavior, where a directory can be created through a dangling symlink.
Desired Action Replace lines 96644-5:

mkdir −p −m $(umask −S),u+wx $(dirname dir) &&
mkdir [−m mode] dir


mkdir −p −m $(umask −S),u+wx \
  "$(dirname "dir" | head -n -1; printf /)" &&
mkdir [−m mode] "dir"
Tags tc1-2008
Attached Files

- Relationships
parent of 0000682Applied Online Pubs html rendition of 'mkdir -p' is missing important text 

-  Notes
eblake (manager)
2009-10-03 23:24

Typo in the Description:

mkdir -p "$(printf 'a b\n'/c')"

should be:

mkdir -p "$(printf 'a b\n/c')"
eblake (manager)
2009-10-03 23:38

The desired action also has a typo; 'head -c -1' was intended instead of 'head -n -1'. But unfortunately, even that is not portable (unlike the counterpart of 'tail -c -1'). For that matter, the only portable means I could find for discarding only the trailing newline involves even more processes, including running the dirname command twice:

mkdir −p −m $(umask −S),u+wx "$(dirname "dir" |
  dd bs=1 count=$(($(dirname "dir" | wc -c) - 1)) 2>/dev/null; echo /)" &&
mkdir [−m mode] "dir"
geoffclare (manager)
2009-10-05 09:59
edited on: 2009-10-09 08:12

Interpretation response
The standard states the requirements for mkdir -p,
and conforming implementations must conform to this. However, concerns
have been raised about this which are being referred to the sponsor.


Notes to the Editor (not part of this interpretation):

Replace the description of -p with:
-p  Create any missing intermediate pathname components.

    For each dir operand that does not name an existing directory,
    before performing the actions described in the DESCRIPTION above
    the mkdir utility shall create any pathname components of the path
    prefix of dir that do not name an existing directory by performing
    actions equivalent to first calling the mkdir() function with the
    following arguments:

      1. A pathname naming the missing pathname component, ending
         with a trailing <slash> character, as the path argument.

      2. The value zero as the mode argument.

    and then calling the chmod() function with the following

      1. The same path argument as in the mkdir() call.

      2. The value (S_IWUSR|S_IXUSR|~filemask)&0777 as the mode argument,
         where filemask is the file mode creation mask of the process
         (see [xref to umask()]).

    Each dir operand that names an existing directory shall be ignored
    without error.

- Issue History
Date Modified Username Field Change
2009-10-03 23:17 eblake New Issue
2009-10-03 23:17 eblake Status New => Under Review
2009-10-03 23:17 eblake Assigned To => ajosey
2009-10-03 23:17 eblake Name => Eric Blake
2009-10-03 23:17 eblake Organization => N/A
2009-10-03 23:17 eblake User Reference => ebb.mkdir
2009-10-03 23:17 eblake Section => mkdir
2009-10-03 23:17 eblake Page Number => 2937
2009-10-03 23:17 eblake Line Number => 96644
2009-10-03 23:24 eblake Note Added: 0000245
2009-10-03 23:38 eblake Note Added: 0000246
2009-10-05 09:59 geoffclare Note Added: 0000247
2009-10-05 10:00 geoffclare Note Edited: 0000247
2009-10-05 10:01 geoffclare Note Edited: 0000247
2009-10-08 16:22 nick Interp Status => Pending
2009-10-08 16:22 nick Final Accepted Text => See Note: 0000247
2009-10-08 16:22 nick Note Added: 0000249
2009-10-08 16:22 nick Status Under Review => Interpretation Required
2009-10-08 16:22 nick Resolution Open => Accepted As Marked
2009-10-08 16:26 nick Note Edited: 0000247
2009-10-08 16:27 nick Note Deleted: 0000249
2009-10-09 08:12 geoffclare Note Edited: 0000247
2009-11-07 07:20 ajosey Interp Status Pending => Proposed
2009-12-08 10:00 ajosey Interp Status Proposed => Approved
2010-09-21 11:25 geoffclare Tag Attached: tc1-2008
2013-04-16 13:06 ajosey Status Interpretation Required => Closed
2013-04-23 17:52 eblake Relationship added parent of 0000682

Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker