186d7f5d3SJohn Marino#!/bin/sh 286d7f5d3SJohn Marino# Create a temporary directory, sort of like mktemp -d does. 386d7f5d3SJohn Marino 486d7f5d3SJohn Marino# Copyright (C) 2007 Red Hat, Inc. All rights reserved. 586d7f5d3SJohn Marino# 686d7f5d3SJohn Marino# This copyrighted material is made available to anyone wishing to use, 786d7f5d3SJohn Marino# modify, copy, or redistribute it subject to the terms and conditions 886d7f5d3SJohn Marino# of the GNU General Public License v.2. 986d7f5d3SJohn Marino# 1086d7f5d3SJohn Marino# You should have received a copy of the GNU General Public License 1186d7f5d3SJohn Marino# along with this program; if not, write to the Free Software Foundation, 1286d7f5d3SJohn Marino# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1386d7f5d3SJohn Marino 1486d7f5d3SJohn Marino# Written by Jim Meyering. 1586d7f5d3SJohn Marino 1686d7f5d3SJohn Marino# Usage: mkdtemp /tmp phoey.XXXXXXXXXX 1786d7f5d3SJohn Marino 1886d7f5d3SJohn Marino# First, try to use the mktemp program. 1986d7f5d3SJohn Marino# Failing that, we'll roll our own mktemp-like function: 2086d7f5d3SJohn Marino# - try to get random bytes from /dev/urandom 2186d7f5d3SJohn Marino# - failing that, generate output from a combination of quickly-varying 2286d7f5d3SJohn Marino# sources and gzip. Ignore non-varying gzip header, and extract 2386d7f5d3SJohn Marino# "random" bits from there. 2486d7f5d3SJohn Marino# - given those bits, map to file-name bytes using tr, and try to create 2586d7f5d3SJohn Marino# the desired directory. 2686d7f5d3SJohn Marino# - make only $MAX_TRIES attempts 2786d7f5d3SJohn Marino 2886d7f5d3SJohn MarinoME=$(basename "$0") 2986d7f5d3SJohn Marinodie() { echo >&2 "$ME: $@"; exit 1; } 3086d7f5d3SJohn Marino 3186d7f5d3SJohn MarinoMAX_TRIES=4 3286d7f5d3SJohn Marino 3386d7f5d3SJohn Marinorand_bytes() 3486d7f5d3SJohn Marino{ 3586d7f5d3SJohn Marino n=$1 3686d7f5d3SJohn Marino 3786d7f5d3SJohn Marino chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 3886d7f5d3SJohn Marino 3986d7f5d3SJohn Marino dev_rand=/dev/urandom 4086d7f5d3SJohn Marino if test -r "$dev_rand"; then 4186d7f5d3SJohn Marino # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194. 4286d7f5d3SJohn Marino head -c$n "$dev_rand" | tr -c $chars 01234567$chars$chars$chars 4386d7f5d3SJohn Marino return 4486d7f5d3SJohn Marino fi 4586d7f5d3SJohn Marino 4686d7f5d3SJohn Marino cmds='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n' 4786d7f5d3SJohn Marino data=$( (eval "$cmds") 2>&1 | gzip ) 4886d7f5d3SJohn Marino 4986d7f5d3SJohn Marino n_plus_50=$(expr $n + 50) 5086d7f5d3SJohn Marino 5186d7f5d3SJohn Marino # Ensure that $data has length at least 50+$n 5286d7f5d3SJohn Marino while :; do 5386d7f5d3SJohn Marino len=$(echo "$data"|wc -c) 5486d7f5d3SJohn Marino test $n_plus_50 -le $len && break; 5586d7f5d3SJohn Marino data=$( (echo "$data"; eval "$cmds") 2>&1 | gzip ) 5686d7f5d3SJohn Marino done 5786d7f5d3SJohn Marino 5886d7f5d3SJohn Marino echo "$data" \ 5986d7f5d3SJohn Marino | dd bs=1 skip=50 count=$n 2>/dev/null \ 6086d7f5d3SJohn Marino | tr -c $chars 01234567$chars$chars$chars 6186d7f5d3SJohn Marino} 6286d7f5d3SJohn Marino 6386d7f5d3SJohn Marinomkdtemp() 6486d7f5d3SJohn Marino{ 6586d7f5d3SJohn Marino case $# in 6686d7f5d3SJohn Marino 2);; 6786d7f5d3SJohn Marino *) die "Usage: $ME DIR TEMPLATE";; 6886d7f5d3SJohn Marino esac 6986d7f5d3SJohn Marino 7086d7f5d3SJohn Marino destdir=$1 7186d7f5d3SJohn Marino template=$2 7286d7f5d3SJohn Marino 7386d7f5d3SJohn Marino case $template in 7486d7f5d3SJohn Marino *XXXX) ;; 7586d7f5d3SJohn Marino *) die "invalid template: $template (must have a suffix of at least 4 X's)";; 7686d7f5d3SJohn Marino esac 7786d7f5d3SJohn Marino 7886d7f5d3SJohn Marino fail=0 7986d7f5d3SJohn Marino 8086d7f5d3SJohn Marino # First, try to use mktemp. 8186d7f5d3SJohn Marino d=$(env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null) \ 8286d7f5d3SJohn Marino || fail=1 8386d7f5d3SJohn Marino 8486d7f5d3SJohn Marino # The resulting name must be in the specified directory. 8586d7f5d3SJohn Marino case $d in "$destdir"*);; *) fail=1;; esac 8686d7f5d3SJohn Marino 8786d7f5d3SJohn Marino # It must have created the directory. 8886d7f5d3SJohn Marino test -d "$d" || fail=1 8986d7f5d3SJohn Marino 9086d7f5d3SJohn Marino # It must have 0700 permissions. 9186d7f5d3SJohn Marino perms=$(ls -dgo "$d" 2>/dev/null) || fail=1 9286d7f5d3SJohn Marino case $perms in drwx------*) ;; *) fail=1;; esac 9386d7f5d3SJohn Marino 9486d7f5d3SJohn Marino test $fail = 0 && { 9586d7f5d3SJohn Marino echo "$d" 9686d7f5d3SJohn Marino return 9786d7f5d3SJohn Marino } 9886d7f5d3SJohn Marino 9986d7f5d3SJohn Marino # If we reach this point, we'll have to create a directory manually. 10086d7f5d3SJohn Marino 10186d7f5d3SJohn Marino # Get a copy of the template without its suffix of X's. 10286d7f5d3SJohn Marino base_template=$(echo "$template"|sed 's/XX*$//') 10386d7f5d3SJohn Marino 10486d7f5d3SJohn Marino # Calculate how many X's we've just removed. 10586d7f5d3SJohn Marino nx=$(expr length "$template" - length "$base_template") 10686d7f5d3SJohn Marino 10786d7f5d3SJohn Marino err= 10886d7f5d3SJohn Marino i=1 10986d7f5d3SJohn Marino while :; do 11086d7f5d3SJohn Marino X=$(rand_bytes $nx) 11186d7f5d3SJohn Marino candidate_dir="$destdir/$base_template$X" 11286d7f5d3SJohn Marino err=$(mkdir -m 0700 "$candidate_dir" 2>&1) \ 11386d7f5d3SJohn Marino && { echo "$candidate_dir"; return; } 11486d7f5d3SJohn Marino test $MAX_TRIES -le $i && break; 11586d7f5d3SJohn Marino i=$(expr $i + 1) 11686d7f5d3SJohn Marino done 11786d7f5d3SJohn Marino die "$err" 11886d7f5d3SJohn Marino} 11986d7f5d3SJohn Marino 12086d7f5d3SJohn Marinomkdtemp "$@" 121