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
0001616 [Issue 8 drafts] Shell and Utilities Editorial Enhancement Request 2022-11-08 23:03 2022-11-09 13:18
Reporter illiliti View Status public  
Assigned To
Priority normal Resolution Open  
Status New   Product Version Draft 2.1
Name Mark Lundblad
Organization
User Reference
Section Shell and Utilities
Page Number -
Line Number -
Final Accepted Text
Summary 0001616: Standardize mktemp utility
Description The current standard has no reliable and convenient utility to create temporary file or directory, despite that low-level interfaces, mkstemp/mkdtemp, are available for this use case. The mktemp(1) utility is a perfect candidate to fill this gap. Its interface is fairly simple and mostly consistent across various implementations, however not without some differences. I evaluated GNU, LSB, NetBSD, FreeBSD, OpenBSD, Illumos, Solaris, sbase, toybox, busybox implementations and here is what I found:

- FreeBSD, NetBSD accept multiple templates. Others do not.
- FreeBSD does not specify -p option. Others do.
- LSB does not specify -d and -p options. Others do.
- FreeBSD, NetBSD accept parameter for -t option. Others do not.
- FreeBSD, NetBSD use -t option to specify prefix. Others use it to explicitly tell mktemp to create temporary file in temporary directory rather than in current directory.
- All have different default value for template.
- All have different requirements regarding how many Xs template should contain, but it seems they all accept six Xs.
- sbase, Illumos, Solaris override -p parameter with TMPDIR value if it is set. Others do not.
- GNU overrides -p parameter with TMPDIR value or /tmp if parameter is empty string. Others do not.
- OpenBSD, Illumos, Solaris(not sure), toybox do not allow '/' in template if -p option is passed. Others do.

Given that, I think mktemp interface is not completely lost and below is my attempt to make it portable.
Desired Action Standardize mktemp utility. Here is the most minimal and portable example:

NAME
     mktemp - create temporary unique file or directory

SYNOPSIS
     mktemp [-dqu] [-p directory] [template]

DESCRIPTION
     mktemp creates a temporary file based on a template as if by calling
     mkstemp(3). If no template is specified, an implementation-defined value
     shall be used instead. If template does not contain exactly six Xs at the
     end, the behavior is unspecified. If template does not contain '/', the file
     shall be created in the current directory. Otherwise, the file shall be
     created by its path. The filename of created temporary file shall be written
     to the standard output.

OPTIONS
     -d Create directory instead of file as if by calling mkdtemp(3).

     -p directory
             Change directory where temporary file will be created. With this
             option, it is unspecified what happens if template contains '/'. If
             TMPDIR is set, it is unspecified whether its value take precedence
             over passed parameter or vice versa. If passed parameter is empty
             string, the behavior is unspecified.

     -q Fail silently if an error occurs.

     -u Operate in unsafe mode. A unique name is generated, but the
             temporary file shall be unlinked before mktemp exits. Use of this
             option is not encouraged.

SEE ALSO
     mkdtemp(3), mkstemp(3)
Tags No tags attached.
Attached Files

- Relationships

-  Notes
(0006038)
steffen (reporter)
2022-11-08 23:30

While i accept it as natural as it is so widely used, please note that POSIX says for pathchk(1):

  The pathchk utility was new for the ISO POSIX-2: 1993 standard. It, along with the set −C(noclobber) option added to the shell, replaces the mktemp, validfnam, and create utilities that appeared in early proposals.

So what you do is

if ( set -C ) >/dev/null 2>&1; then
  set +C
else
  # For heaven's sake auto-redirect on SunOS/Solaris
  if [ -f /usr/xpg4/bin/sh ] && [ -x /usr/xpg4/bin/sh ]; then
    exec /usr/xpg4/bin/sh "${0}" "${@}"
  else
    synopsis 1 'sh(1)ell without "set -C" (for safe temporary file creation)'
  fi
fi

and then

old_umask=`umask`
umask 077
i=1
while :; do
  tmpfile="${tmpdir}/MYNAME-${i}.tmp"
  (
    set -C
    : > "${tmpfile}"
  ) >/dev/null 2>&1 && break
  i=`expr ${i} + 1`
  if [ ${i} -gt ${max} ]; then
    echo >&2 'Cannot create a temporary file within '"${tmpdir}"
    exit ${EX_TEMPFAIL}
  fi
done
trap "exit ${EX_TEMPFAIL}" HUP INT QUIT PIPE TERM
trap "trap \"\" HUP INT QUIT PIPE TERM EXIT; rm -f ${tmpfile}" EXIT
umask ${old_umask}

..after finding a tmpdir and doing some other setup.
(0006041)
illiliti (reporter)
2022-11-09 13:18

Yeah, your example should work, but it is not simple. Look at how simple mktemp is:

tmpfile=$(mktemp)

or directory:

tmpdir=$(mktemp -d)

mktemp is impossible to misuse unlike shell. Plus it is already more-or-less portable and widespread on all open-source systems.

Also unrelated, but it seems that your example does not work with yash when tmpfile is a dangling symlink. Looks like a yash bug. Reported.

- Issue History
Date Modified Username Field Change
2022-11-08 23:03 illiliti New Issue
2022-11-08 23:03 illiliti Name => Mark Lundblad
2022-11-08 23:03 illiliti Section => Shell and Utilities
2022-11-08 23:03 illiliti Page Number => -
2022-11-08 23:03 illiliti Line Number => -
2022-11-08 23:30 steffen Note Added: 0006038
2022-11-09 13:18 illiliti Note Added: 0006041


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