: ########################################################################## # Title : mktemp - create unique file or directory name # Author : Heiner Steven # Date : 2002-10-23 # Requires : # Category : File Utilities # SCCS-Id. : @(#) mktemp 2.2 03/12/19 ########################################################################## # Description # Creates a unique file or directory from a template. For each # process there can be 26 unique names for the same template. # # Caveats # o Calling this script is inherently insecure and prone to errors. # In the time between this script creating a temporary # file/directory and the calling script using it, another process # may have manipulated the file. ########################################################################## PN=`basename "$0"` # Program name VER='2.2' usage () { echo >&2 "$PN - create temporary file name, $VER usage: $PN [-du] templateXXXXXX -d: create a directory instead of a file -u: unsafe mode: remove the file after creating it A template looks like a file name with six trailing 'X's. $PN will replace the 'X's with a character string that can be used to create a unique file name. Only 26 unique file names per process can be created for each unique template. Example: tempfile=\`$PN /tmp/mytmpXXXXXX\` || exit 1" exit 1 } msg () { for msgLine do echo "$PN: $msgLine" >&2 done } fatal () { msg "$@"; exit 1; } set -- `getopt :hdu "$@"` || usage MakeDir=false Unsafe=false while [ $# -gt 0 ] do case "$1" in -d) MakeDir=true;; -u) Unsafe=true;; --) shift; break;; -h) usage;; -*) usage;; *) break;; # First file name esac shift done [ $# -eq 1 ] || usage template=$1; shift case "$template" in *XXXXXX) ;; # valid template *) fatal "invalid template: $template A template must end with 6 'X' characters: XXXXXX";; esac # We will now generate several file names, and check if they # specify already existing files. Basically we have two options: # 1. check if the file already exists, and create it otherwise # 2. try to create it, taking care not to overwrite existing files # # Option 2 is preferred because of the following reasons: # o otherwise we would have to check for existing directory entries (not # just files). The new name could specify an existing file, directory, # link, device driver, ... # o checking for existence of an entry takes time, and somebody # else could create a file of the same name after the check. Example: # process A process B # does XXXXXX exist? # -> no # create XXXXXX # create XXXXXX # -> FAILURE # Enable the "noclobber" option advising the shell not to overwrite # existing files. set -C || fatal "cannot set \"noclobber\" option" # We will append the following suffixes to the file name, if it is # not unique: set -- "" a b c d e f g h i j k l m n o p q r s t u v w x y z while [ $# -gt 0 ] do # Convert our process id to a 6 digit number with leading zeros: pattern=`echo "000000${$}${1}" | sed 's/.*\(......\)$/\1/'` #DEBUG: pattern=`echo "000000${1}" | sed 's/.*\(......\)$/\1/'` shift # Insert the (hopefully unique) pattern into the template tmpname=`echo "$template" | sed "s/XXXXXX$/$pattern/"` if $MakeDir then umask 077 if mkdir "$tmpname" then $Unsafe && rm -rf "$tmpname" echo "$tmpname" exit 0 fi else # Create file in a sub-shell to suppress "cannot create file" # messages. umask 0177 if (> "$tmpname") >/dev/null 2>&1 then $Unsafe && rm -f "$tmpname" echo "$tmpname" exit 0 fi fi done # When we arrive here, no unique file name could be generated: exit 1