A NOTE has been added to this issue. 
====================================================================== 
http://austingroupbugs.net/view.php?id=1016 
====================================================================== 
Reported By:                izabera
Assigned To:                
====================================================================== 
Project:                    1003.1(2013)/Issue7+TC1
Issue ID:                   1016
Category:                   Shell and Utilities
Type:                       Enhancement Request
Severity:                   Editorial
Priority:                   normal
Status:                     New
Name:                       Isabella 
Organization:               --- 
User Reference:             --- 
Section:                    2.7.2 
Page Number:               
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_02

Line Number:                last paragraph 
Interp Status:              --- 
Final Accepted Text:         
====================================================================== 
Date Submitted:             2015-12-28 13:52 UTC
Last Modified:              2016-11-10 17:33 UTC
====================================================================== 
Summary:                    race condition with set -C
====================================================================== 

---------------------------------------------------------------------- 
 (0003485) rhansen (manager) - 2016-11-10 17:33
 http://austingroupbugs.net/view.php?id=1016#c3485 
---------------------------------------------------------------------- 
We discussed this during the 2016-11-03 and 2016-11-10 teleconferences and
came up with the following revised version of the wording from
http://austingroupbugs.net/view.php?id=1016#c3481:

<b>Option 1: encourage O_NOCLOBBER</b>

On page 2361 line 75337 section 2.7.2, change:
<blockquote>Output redirection using the '>' format shall fail if the
<i>noclobber</i> option is set (see the description of <i>set</i>
-<b>C</b>) and the file named by the expansion of <i>word</i> exists and is
a regular file.  Otherwise, redirection using the '>' or ">|" formats shall
cause the file whose name results from the expansion of <i>word</i> to be
created and opened for output on the designated file descriptor, or
standard output if none is specified. If the file does not exist, it shall
be created; otherwise, it shall be truncated to be an empty file after
being opened.</blockquote>
to:
<blockquote>Output redirection using the '>' format shall fail if the
<i>noclobber</i> option is set (see the description of <i>set</i>
-<b>C</b>) and the file named by the expansion of <i>word</i> exists and is
either a regular file or a symbolic link that resolves to a regular file;
it may also fail if the file is a symbolic link that does not resolve to an
existing file.  The check for existence, file creation, and open operations
shall be performed atomically as is done by the <i>open</i>() function as
defined in the System Interfaces volume of POSIX.1-2008 when the O_CREAT
and O_EXCL flags are set, except that if the file exists and is a symbolic
link, the open operation need not fail with [EEXIST] unless the symbolic
link resolves to an existing regular file.  Performing these operations
atomically ensures that the creation of lock files and unique (often
temporary) files is reliable.  The check for the type of the file need not
be performed atomically with the check for existence, file creation, and
open operations.  If not, there is a potential race condition that may
result in a misleading shell diagnostic message when redirection fails. 
See [xref to rationale] for more details.

In all other cases (<i>noclobber</i> not set, redirection using '>' does
not fail for the reasons stated above, or redirection using the ">|"
format), output redirection shall cause the file whose name results from
the expansion of <i>word</i> to be opened for output on the designated file
descriptor, or standard output if none is specified.  If the file does not
exist, it shall be created as an empty file; otherwise, it shall be opened
as if the <i>open</i>() function was called with the O_TRUNC flag
set.</blockquote>

Cross-volume change to XBD ...

On page 241 line 8132 section <fcntl.h> change FUTURE DIRECTIONS from:
<blockquote>None.</blockquote>
to:
<blockquote>A future version of this standard may add an O_NOCLOBBER file
creation flag - see the FUTURE DIRECTIONS section for [xref to
open()].</blockquote>

Cross-volume change to XSH ...

On page 1416 line 47098 section open() change FUTURE DIRECTIONS from:
<blockquote>None.</blockquote>
to:
<blockquote>A future version of this standard may add an O_NOCLOBBER flag,
specified as follows, for use by shells when the <i>noclobber</i> option is
set (see [xref to XRAT C.2.7.2]):

O_NOCLOBBER
<blockquote>If O_CREAT and O_NOCLOBBER are set, <i>open</i>() shall fail if
the file exists and is either a regular file or a symbolic link that
resolves to a regular file.  The check for the existence and type of the
file and the creation of the file if it does not exist shall be atomic with
respect to other threads executing <i>open</i>() naming the same filename
in the same directory with O_NOCLOBBER and O_CREAT set or with O_EXCL and
O_CREAT set.  If O_NOCLOBBER and O_CREAT are set, and the file exists and
is either a non-regular file or a symbolic link that resolves to a
non-regular file, the file shall be opened as if neither flag was set.  If
O_NOCLOBBER and O_CREAT are set, and <i>path</i> names a symbolic link that
does not resolve to an existing file, an empty file shall be created such
that <i>path</i> resolves to the newly created file.  If O_NOCLOBBER is set
and O_CREAT is not set, the result is undefined.</blockquote>

Cross-volume change to XRAT ...

On page 3736 line 128235 section C.2.7.2, change:
<blockquote>There is no additional rationale provided for this
section.</blockquote>
to:
<blockquote>Earlier versions of this standard did not require redirection
using '>' when <i>noclobber</i> is set to perform the file creation step as
an atomic operation.  Historical shells just called <i>stat</i>() to check
if a regular file existed and then called <i>creat</i>().  The operation
thus involved a race condition which meant that it could not be used for
reliable creation of lock files.  Many shell implementations improved on
this by using <i>open</i>() with the O_CREAT and O_EXCL flags set as one
step in a multi-step process which still meant that an existing non-regular
file (for example <b>/dev/null</b>, <b>/dev/tty</b>, or a FIFO) was opened
successfully.  However, the methods employed still involved a race
condition and could produce misleading diagnostics if there is concurrent
creation or removal of files.

An ideal solution would be an O_NOCLOBBER flag for <i>open</i>() which the
shell could use in order to perform the entire operation atomically, and
implementations are encouraged to adopt this solution, adding the flag as
described in the FUTURE DIRECTIONS sections of [xref to XSH open()], and
using it in the implementation's POSIX shell and in other shells.  Authors
of portable shells should make use of <tt>#ifdef O_NOCLOBBER</tt> so that
it is used on implementations that provide it.

If O_NOCLOBBER is not used, shells can use one of the following
methods:<ol>
<li>The "stat first" method.<ul>
<li>a. Call <i>stat</i>() and if the file exists and is a regular file, the
redirection fails.  Otherwise:</li>
<li>b. Call <i>open</i>() without O_CREAT or O_TRUNC to open an existing
file.  If the open succeeds, use <i>fstat</i>() to check whether the opened
file is a regular file.  If it is, close it and fail the redirection.  If
it is a non-regular file, the redirection succeeds.  Otherwise:</li>
<li>c. Call <i>open</i>() with O_CREAT|O_EXCL.  The redirection succeeds or
fails depending on whether the open succeeds or fails.</li></ul></li>
<li>The "exclusive create first" method.<ul>
<li>a. Call <i>open</i>() with O_CREAT|O_EXCL.  If the open succeeds, the
redirection succeeds.  If the open fails with [EMFILE] or [ENFILE], use
<i>stat</i>() to check whether a regular file exists; if it does, fail the
redirection. Otherwise:</li>
<li>b. Call <i>open</i>() without O_CREAT or O_TRUNC to open an existing
file.  If the open succeeds, use <i>fstat</i>() to check whether the opened
file is a regular file.  If it is, close it and fail the redirection.  If
it is a non-regular file, the redirection succeeds.  If the second open
fails, the redirection fails with a diagnostic based on the <i>errno</i>
value set by the first open.</li></ul>
(A minor variation of this method could also be used whereby step 2.b is
only done if the <i>open</i>() in step 2.a fails with [EEXIST].)</li></ol>

Method 1 is in widespread use.  Method 2 has not been observed exactly as
described, although an implementation which omits the <i>stat</i>() in step
2.a has been observed.  Without the <i>stat</i>(), this method has a
problem in that if a regular file exists but the <i>open</i>() fails with
[EMFILE] or [ENFILE] instead of [EEXIST] (which is to be expected if those
conditions exist, because detecting [EEXIST] is more expensive), then the
shell will give an incorrect diagnostic.  (Reporting that no file
descriptors are available implies that a non-regular file exists, because
the shell tried to open the file and it is not supposed to open an existing
regular file.) 

A variant of method 1 which omits the initial <i>stat</i>() call has also
been observed; this has the same problem with [EMFILE] and [ENFILE].  With
the <i>stat</i>(), this misleading diagnostic can also happen, but only if
a regular file is created in the timing window between steps 1.a and 1.b,
which makes it an allowed case.  (The standard allows a misleading
diagnostic when there is concurrent creation or removal of files.)

Both methods have cases where a misleading diagnostic is given when a
non-regular file is concurrently created or removed.  With method 1 it
occurs if no file exists at steps 1.a and 1.b, and a non-regular file is
created before step 1.c.  With method 2 it occurs if a non-regular file
exists at step 2.a and is removed before step 2.b. (In both cases, the
diagnostic misleadingly implies that a regular file exists).

Both methods differ from historical shell behavior in that the redirection
fails if there is an existing symbolic link whose target does not exist,
instead of the link's target being created as a regular file.  The standard
developers consider this to be of less importance than ensuring that the
creation of lock files is reliable.</blockquote>


<b>Option 2: require O_NOCLOBBER</b>

On page 2361 line 75337 section 2.7.2, change:
<blockquote>Output redirection using the '>' format shall fail if the
<i>noclobber</i> option is set (see the description of <i>set</i>
-<b>C</b>) and the file named by the expansion of <i>word</i> exists and is
a regular file.  Otherwise, redirection using the '>' or ">|" formats shall
cause the file whose name results from the expansion of <i>word</i> to be
created and opened for output on the designated file descriptor, or
standard output if none is specified. If the file does not exist, it shall
be created; otherwise, it shall be truncated to be an empty file after
being opened.</blockquote>
to:
<blockquote>Output redirection using the '>' format shall fail if the
<i>noclobber</i> option is set (see the description of <i>set</i>
-<b>C</b>) and the file named by the expansion of <i>word</i> exists and is
either a regular file or a symbolic link that resolves to a regular file. 
The check for the existence and type of the file and the creation of the
file if it does not exist shall be performed as a single atomic operation,
as if the <i>open</i>() function as defined in the System Interfaces volume
of POSIX.1-2008 was called with the O_CREAT and O_NOCLOBBER flags set. 
Performing the operation atomically ensures that creation of lock files and
unique (often temporary) files using '>' with <i>noclobber</i> set is
reliable.

In all other cases (<i>noclobber</i> not set, redirection using '>' does
not fail for the reasons stated above, or redirection using the ">|"
format), output redirection shall cause the file whose name results from
the expansion of <i>word</i> to be opened for output on the designated file
descriptor, or standard output if none is specified.  If the file does not
exist, it shall be created as an empty file; otherwise, it shall be opened
as if the <i>open</i>() function was called with the O_TRUNC flag
set.</blockquote>

Cross-volume change to XBD ...

On page 239 line 8036 section <fcntl.h> add:
<blockquote>O_NOCLOBBER Prevent existing regular files from being
overwritten.</blockquote>

Cross-volume changes to XSH ...

On page 1409 line 46805 section open(), change:
<blockquote>... naming the same filename in the same directory with O_EXCL
and O_CREAT set.</blockquote>
to:
<blockquote>... naming the same filename in the same directory with O_EXCL
and O_CREAT set or with O_NOCLOBBER and O_CREAT set.</blockquote>

On page 1409 line 46809 section open(), add:
<blockquote>O_NOCLOBBER
<blockquote>If O_CREAT and O_NOCLOBBER are set, <i>open</i>() shall fail if
the file exists and is either a regular file or a symbolic link that
resolves to a regular file.  The check for the existence and type of the
file and the creation of the file if it does not exist shall be atomic with
respect to other threads executing <i>open</i>() naming the same filename
in the same directory with O_NOCLOBBER and O_CREAT set or with O_EXCL and
O_CREAT set.  If O_NOCLOBBER and O_CREAT are set, and the file exists and
is either a non-regular file or a symbolic link that resolves to a
non-regular file, the file shall be opened as if neither flag was set.  If
O_NOCLOBBER and O_CREAT are set, and <i>path</i> names a symbolic link that
does not resolve to an existing file, an empty file shall be created such
that <i>path</i> resolves to the newly created file.  If O_NOCLOBBER is set
and O_CREAT is not set, the result is undefined.</blockquote>
</blockquote>

Cross-volume change to XRAT ...

On page 3736 line 128235 section C.2.7.2, change:
<blockquote>There is no additional rationale provided for this
section.</blockquote>
to:
<blockquote>Earlier versions of this standard did not require redirection
using '>' when <i>noclobber</i> is set to open the file as if by calling
<i>open</i>() with the O_CREAT and O_NOCLOBBER flags set.  Historical
shells just called <i>stat</i>() to check if a regular file existed and
then called <i>creat</i>().  The operation thus involved a race condition
which meant that it could not be used for reliable creation of lock files. 
Many shell implementations improved on this by using <i>open</i>() with the
O_CREAT and O_EXCL flags set as one step in a multi-step process which
still meant that an existing non-regular file (for example
<b>/dev/null</b>, <b>/dev/tty</b>, or a FIFO) was opened successfully. 
However, the methods employed still involved a race condition and could
produce misleading diagnostics if there is concurrent creation or removal
of files.  They also differed from historical shell behavior in that the
redirection failed if there is an existing symbolic link whose target does
not exist, instead of the link's target being created as a regular file. 
The ideal solution is to use the O_NOCLOBBER flag for <i>open</i>(), which
this standard now requires.</blockquote> 

Issue History 
Date Modified    Username       Field                    Change               
====================================================================== 
2015-12-28 13:52 izabera        New Issue                                    
2015-12-28 13:52 izabera        Name                      => Isabella        
2015-12-28 13:52 izabera        Organization              => ---             
2015-12-28 13:52 izabera        User Reference            => ---             
2015-12-28 13:52 izabera        Section                   => 2.7.2           
2015-12-28 13:52 izabera        Page Number               =>
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_02
2015-12-28 13:52 izabera        Line Number               => last paragraph  
2015-12-31 05:58 shware_systems Note Added: 0002990                          
2015-12-31 12:52 jilles         Note Added: 0002991                          
2015-12-31 14:21 shware_systems Note Added: 0002992                          
2015-12-31 17:05 nick           Interp Status             => ---             
2015-12-31 17:05 nick           Note Added: 0002993                          
2015-12-31 17:05 nick           Description Updated                          
2016-10-20 16:40 geoffclare     Note Added: 0003446                          
2016-10-31 16:23 geoffclare     Note Added: 0003481                          
2016-10-31 16:28 geoffclare     Note Edited: 0003481                         
2016-10-31 16:33 geoffclare     Note Edited: 0003481                         
2016-11-10 17:33 rhansen        Note Added: 0003485                          
======================================================================


Reply via email to