| #!/bin/sh |
| # Create a temporary directory, much like mktemp -d does. |
| |
| # Copyright (C) 2007-2020 Free Software Foundation, Inc. |
| |
| # This program is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation, either version 3 of the License, or |
| # (at your option) any later version. |
| |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <https://www.gnu.org/licenses/>. |
| |
| # Written by Jim Meyering. |
| |
| # Usage: mktempd /tmp phoey.XXXXXXXXXX |
| |
| # First, try to use the mktemp program. |
| # Failing that, we'll roll our own mktemp-like function: |
| # - try to get random bytes from /dev/urandom |
| # - failing that, generate output from a combination of quickly-varying |
| # sources and gzip. Ignore non-varying gzip header, and extract |
| # "random" bits from there. |
| # - given those bits, map to file-name bytes using tr, and try to create |
| # the desired directory. |
| # - make only $MAX_TRIES attempts |
| |
| ME=`basename "$0"` |
| die() { echo >&2 "$ME: $@"; exit 1; } |
| |
| MAX_TRIES=4 |
| |
| rand_bytes() |
| { |
| n=$1 |
| |
| chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 |
| |
| dev_rand=/dev/urandom |
| if test -r "$dev_rand"; then |
| # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194. |
| dd ibs=$n count=1 if="$dev_rand" 2>/dev/null \ |
| | tr -c $chars 01234567$chars$chars$chars |
| return |
| fi |
| |
| cmds='date; date +%N; free; who -a; w; ps auxww; ps -ef' |
| data=` (eval "$cmds") 2>&1 | gzip ` |
| |
| n_plus_50=`expr $n + 50` |
| |
| # Ensure that $data has length at least 50+$n |
| while :; do |
| len=`echo "$data"|wc -c` |
| test $n_plus_50 -le $len && break; |
| data=` (echo "$data"; eval "$cmds") 2>&1 | gzip ` |
| done |
| |
| echo "$data" \ |
| | dd bs=1 skip=50 count=$n 2>/dev/null \ |
| | tr -c $chars 01234567$chars$chars$chars |
| } |
| |
| mktempd() |
| { |
| case $# in |
| 2);; |
| *) die "Usage: $ME DIR TEMPLATE";; |
| esac |
| |
| destdir=$1 |
| template=$2 |
| |
| # Disallow any trailing slash on specified destdir: |
| # it would subvert the post-mktemp "case"-based destdir test. |
| case $destdir in |
| /) ;; |
| */) die "invalid destination dir: remove trailing slash(es)";; |
| esac |
| |
| case $template in |
| *XXXX) ;; |
| *) die "invalid template: $template (must have a suffix of at least 4 X's)";; |
| esac |
| |
| fail=0 |
| |
| # First, try to use mktemp. |
| d=`env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null` \ |
| || fail=1 |
| |
| # The resulting name must be in the specified directory. |
| case $d in "$destdir"*);; *) fail=1;; esac |
| |
| # It must have created the directory. |
| test -d "$d" || fail=1 |
| |
| # It must have 0700 permissions. Handle sticky "S" bits. |
| perms=`ls -dgo "$d" 2>/dev/null|tr S -` || fail=1 |
| case $perms in drwx------*) ;; *) fail=1;; esac |
| |
| test $fail = 0 && { |
| echo "$d" |
| return |
| } |
| |
| # If we reach this point, we'll have to create a directory manually. |
| |
| # Get a copy of the template without its suffix of X's. |
| base_template=`echo "$template"|sed 's/XX*$//'` |
| |
| # Calculate how many X's we've just removed. |
| template_length=`echo "$template" | wc -c` |
| nx=`echo "$base_template" | wc -c` |
| nx=`expr $template_length - $nx` |
| |
| err= |
| i=1 |
| while :; do |
| X=`rand_bytes $nx` |
| candidate_dir="$destdir/$base_template$X" |
| err=`mkdir -m 0700 "$candidate_dir" 2>&1` \ |
| && { echo "$candidate_dir"; return; } |
| test $MAX_TRIES -le $i && break; |
| i=`expr $i + 1` |
| done |
| die "$err" |
| } |
| |
| mktempd "$@" |