[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: temp file suffixes: mktemp DWIM

From: Eric Blake
Subject: Re: temp file suffixes: mktemp DWIM
Date: Tue, 3 Nov 2009 18:02:53 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Eric Blake <ebb9 <at> byu.net> writes:

> Now that glibc 2.11 has mkostemps, and I'm working on adding that to gnulib, 
> would be nice to expose the idea of an explicit suffix to temporary file 
> names.  But rather than require the user to count how long their suffix is, I 
> imagine it would make more sense to give mktemp(1) some do-what-I-mean 

Before I do that, how about documenting what mktemp currently does.  The 
proposed patch documents the current behavior, although it probably needs some 
tweaks (and corresponding tweaks in mktemp.c) based this email.

mktemp --help is not very obvious that --tmpdir is implied if no TEMPLATE is 

Right now, 'mktemp --help' claims that --tmpdir and -p are distinct, but the 
code says they are almost the same (they both set use_dest_dir=true and 
dest_dir_arg=optarg).  The only difference is that --tmpdir has an optional 
argument, while -p has a mandatory argument, so dest_dir_arg can be NULL if you 
use --tmpdir but not if you use -p.

By the way, the optional argument to --subdir has some interesting effects, 
because we are not consistent on whether we check optarg for being the empty 

mkdir --subdir="$dir"
 => if $dir is empty, try $TMPDIR; if that is empty, use /tmp
mkdir --subdir="$dir" -t
 => if $TMPDIR is empty, use $dir; if that is empty, use .

In other words, the only thing that I can see -t doing is whether we first 
check $TMPDIR or the argument to -p/--tmpdir, and restricts us from using 
subdirectories in the template (is this restriction really necessary)?  It 
doesn't even print a deprecation warning or have a FIXME date with proposed 
removal.  So, what if we just undeprecate -t (by adding a long option), and 
document/implement things as follows:

  -p DIR, --tmpdir[=DIR]
                   interpret TEMPLATE relative to DIR.  If DIR is empty
                     or not supplied, use $TMPDIR if set, else /tmp
  -t, --favor-tmpdir
                   with -p, favor $TMPDIR over the DIR argument; otherwise
                     use $TMPDIR or /tmp instead of current directory

TEMPLATE may contain slashes, but intermediate directories must exist.
If -p or -t is specified, TEMPLATE must not be absolute.

Also, is there a cleanup hole?  For most code paths, an exit status of 1 means 
that the temporary file could not be created.  But consider:

mktemp >/dev/full

This currently gives exit status 1, because the atexit() handler recognizes 
failure to print the file name to stdout, but leaves the temporary file 
around.  Should we go ahead and manually flush/close stdout, rather than 
relying on close_stdout, so that we can then remove the just-created file if we 
detect write failure?  That way, if we fail to inform the user what just got 
created, we are at least avoiding littering their file system with a random 

Fortunately, 'mktemp >&-' does not make the mistake of printing the just-
created file as the contents of that file, since we close the fd returned by 
mkstemp before printing anything.

At any rate, here's the proposed documentation patch:

From: Eric Blake <address@hidden>
Date: Tue, 3 Nov 2009 10:47:42 -0700
Subject: [PATCH] doc: document mktemp

* doc/coreutils.texi (mktemp invocation): New node.
 doc/coreutils.texi |  144 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 142 insertions(+), 2 deletions(-)

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index ec5bcfb..1fd1bec 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -31,7 +31,6 @@
 @c FIXME: the following need documentation
 @c * [: (coreutils)[ invocation.                   File/string tests.
 @c * pinky: (coreutils)pinky invocation.           FIXME.
address@hidden * mktemp: (coreutils)mktemp invocation.         FIXME.

 @dircategory Individual utilities
@@ -80,6 +79,7 @@
 * mkdir: (coreutils)mkdir invocation.           Create directories.
 * mkfifo: (coreutils)mkfifo invocation.         Create FIFOs (named pipes).
 * mknod: (coreutils)mknod invocation.           Create special files.
+* mktemp: (coreutils)mktemp invocation.         Create temporary files.
 * mv: (coreutils)mv invocation.                 Rename files.
 * nice: (coreutils)nice invocation.             Modify niceness.
 * nl: (coreutils)nl invocation.                 Number lines and write files.
@@ -193,7 +193,7 @@ Top
 * Printing text::                echo printf yes
 * Conditions::                   false true test expr
 * Redirection::                  tee
-* File name manipulation::       dirname basename pathchk
+* File name manipulation::       dirname basename pathchk mktemp
 * Working context::              pwd stty printenv tty
 * User information::             id logname whoami groups users who
 * System context::               date arch uname hostname hostid uptime
@@ -378,6 +378,7 @@ Top
 * basename invocation::          Strip directory and suffix from a file name
 * dirname invocation::           Strip non-directory suffix from a file name
 * pathchk invocation::           Check file name validity and portability
+* mktemp invocation::            Create temporary file or directory

 Working context

@@ -11876,6 +11877,7 @@ File name manipulation
 * basename invocation::         Strip directory and suffix from a file name.
 * dirname invocation::          Strip non-directory suffix from a file name.
 * pathchk invocation::          Check file name validity and portability.
+* mktemp invocation::           Create temporary file or directory.
 @end menu

@@ -12050,6 +12052,144 @@ pathchk invocation
 1 otherwise.
 @end display

address@hidden mktemp invocation
address@hidden @command{mktemp}: Create temporary file or directory
address@hidden mktemp
address@hidden file names, creating temporary
address@hidden directory, creating temporary
address@hidden temporary files and directories
address@hidden manages the creation of temporary files and
+directories.  Synopsis:
+mktemp address@hidden@dots{} address@hidden
address@hidden example
+Safely create a temporary file or directory based on @var{template},
+and print its name.  If given, @var{template} must end in at least
+three consecutive @samp{X}.  If omitted, the template
address@hidden is used, and option @option{--tmpdir} is
+When creating a file, the resulting file has read and write
+permissions for the current user, but no permissions for the group or
+others; these permissions are reduced if the current umask is more
+Here are some examples (although note that if you repeat them, you
+will most likely get different file names):
address@hidden @bullet
+Create a temporary file in the current directory.
+$ mktemp file.XXXX
address@hidden example
+Create a secure fifo relative to the user's choice of @env{TMPDIR},
+but falling back to the current directory rather than @file{/tmp}.
+Note that @command{mktemp} does not create fifos, but can create a
+secure directory in which the fifo can live.  Exit the shell if the
+directory or fifo could not be created.
+$ dir=$(mktemp -p "address@hidden:address@hidden" -d dir-XXXX) || exit 1
+$ fifo=$dir/fifo
+$ mkfifo "$fifo" || @{ rmdir $dir; exit 1; @}
address@hidden example
+Create and use a temporary file if possible, but ignore failure.  The
+file will reside in the directory named by @env{TMPDIR}, if specified,
+or else in @file{/tmp}.
+$ file=$(mktemp -q) && @{
+>   # Safe to use $file only within this block
+>   echo ... > $file
+>   rm $file
+> @}
address@hidden example
+Act as a semi-random character generator (it is not fully random,
+since it is impacted by the contents of the current directory).  To
+avoid security holes, do not use the resulting names to create a file.
+$ mktemp -u XXX
+$ mktemp -u XXX
address@hidden example
address@hidden itemize
+The program accepts the following options.  Also see @ref{Common options}.
address@hidden @samp
address@hidden -d
address@hidden --directory
address@hidden -d
address@hidden --directory
+Create a directory rather than a file.  The directory will have read,
+write, and execute permissions for the current user, but no
+permissions for the group or others; these permissions are reduced if
+the current umask is more restrictive.
address@hidden -q
address@hidden --quiet
address@hidden -q
address@hidden --quiet
+Suppress diagnostics about failure to create a file or directory.  The
+exit status will still reflect whether a file was created.
address@hidden -u
address@hidden --dry-run
address@hidden -u
address@hidden --dry-run
+Generate a temporary name that does not name an existing file, without
+changing the file system contents.  Using the output of this command
+to create a new file is inherently unsafe, as there is a window of
+time between generating the name and using it where another process
+can create an object by the same name.
address@hidden -p @var{dir}
address@hidden address@hidden
address@hidden -p
address@hidden --tempdir
+Treat @var{template} relative to the directory @var{dir}.  If
address@hidden is not specified (only possible with the long option
address@hidden) or is the empty string, use the value of
address@hidden if available, otherwise use @samp{/tmp}.  If this is
+specified, @var{template} must not be absolute.  However,
address@hidden can still contain slashes, although intermediate
+directories must already exist.
address@hidden -t
address@hidden -t
+Treat @var{template} as a single file relative to the value of
address@hidden if available, or to the directory specified by
address@hidden, otherwise to @samp{/tmp}.  @var{template} must not
+contain slashes.  This option is deprecated; the use of @option{-p}
+without @option{-t} offers better defaults (by favoring the command
+line over @env{TMPDIR}) and more flexibility (by allowing intermediate
address@hidden table
address@hidden exit status of @command{mktemp}
+Exit status:
+0 if the file was created,
+1 otherwise.
address@hidden display

 @node Working context
 @chapter Working context

reply via email to

[Prev in Thread] Current Thread [Next in Thread]