1*86d7f5d3SJohn Marino#!/bin/sh 2*86d7f5d3SJohn Marino# Create a temporary directory, sort of like mktemp -d does. 3*86d7f5d3SJohn Marino 4*86d7f5d3SJohn Marino# Copyright (C) 2007 Red Hat, Inc. All rights reserved. 5*86d7f5d3SJohn Marino# 6*86d7f5d3SJohn Marino# This copyrighted material is made available to anyone wishing to use, 7*86d7f5d3SJohn Marino# modify, copy, or redistribute it subject to the terms and conditions 8*86d7f5d3SJohn Marino# of the GNU General Public License v.2. 9*86d7f5d3SJohn Marino# 10*86d7f5d3SJohn Marino# You should have received a copy of the GNU General Public License 11*86d7f5d3SJohn Marino# along with this program; if not, write to the Free Software Foundation, 12*86d7f5d3SJohn Marino# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 13*86d7f5d3SJohn Marino 14*86d7f5d3SJohn Marino# Written by Jim Meyering. 15*86d7f5d3SJohn Marino 16*86d7f5d3SJohn Marino# Usage: mkdtemp /tmp phoey.XXXXXXXXXX 17*86d7f5d3SJohn Marino 18*86d7f5d3SJohn Marino# First, try to use the mktemp program. 19*86d7f5d3SJohn Marino# Failing that, we'll roll our own mktemp-like function: 20*86d7f5d3SJohn Marino# - try to get random bytes from /dev/urandom 21*86d7f5d3SJohn Marino# - failing that, generate output from a combination of quickly-varying 22*86d7f5d3SJohn Marino# sources and gzip. Ignore non-varying gzip header, and extract 23*86d7f5d3SJohn Marino# "random" bits from there. 24*86d7f5d3SJohn Marino# - given those bits, map to file-name bytes using tr, and try to create 25*86d7f5d3SJohn Marino# the desired directory. 26*86d7f5d3SJohn Marino# - make only $MAX_TRIES attempts 27*86d7f5d3SJohn Marino 28*86d7f5d3SJohn MarinoME=$(basename "$0") 29*86d7f5d3SJohn Marinodie() { echo >&2 "$ME: $@"; exit 1; } 30*86d7f5d3SJohn Marino 31*86d7f5d3SJohn MarinoMAX_TRIES=4 32*86d7f5d3SJohn Marino 33*86d7f5d3SJohn Marinorand_bytes() 34*86d7f5d3SJohn Marino{ 35*86d7f5d3SJohn Marino n=$1 36*86d7f5d3SJohn Marino 37*86d7f5d3SJohn Marino chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 38*86d7f5d3SJohn Marino 39*86d7f5d3SJohn Marino dev_rand=/dev/urandom 40*86d7f5d3SJohn Marino if test -r "$dev_rand"; then 41*86d7f5d3SJohn Marino # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194. 42*86d7f5d3SJohn Marino head -c$n "$dev_rand" | tr -c $chars 01234567$chars$chars$chars 43*86d7f5d3SJohn Marino return 44*86d7f5d3SJohn Marino fi 45*86d7f5d3SJohn Marino 46*86d7f5d3SJohn Marino cmds='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n' 47*86d7f5d3SJohn Marino data=$( (eval "$cmds") 2>&1 | gzip ) 48*86d7f5d3SJohn Marino 49*86d7f5d3SJohn Marino n_plus_50=$(expr $n + 50) 50*86d7f5d3SJohn Marino 51*86d7f5d3SJohn Marino # Ensure that $data has length at least 50+$n 52*86d7f5d3SJohn Marino while :; do 53*86d7f5d3SJohn Marino len=$(echo "$data"|wc -c) 54*86d7f5d3SJohn Marino test $n_plus_50 -le $len && break; 55*86d7f5d3SJohn Marino data=$( (echo "$data"; eval "$cmds") 2>&1 | gzip ) 56*86d7f5d3SJohn Marino done 57*86d7f5d3SJohn Marino 58*86d7f5d3SJohn Marino echo "$data" \ 59*86d7f5d3SJohn Marino | dd bs=1 skip=50 count=$n 2>/dev/null \ 60*86d7f5d3SJohn Marino | tr -c $chars 01234567$chars$chars$chars 61*86d7f5d3SJohn Marino} 62*86d7f5d3SJohn Marino 63*86d7f5d3SJohn Marinomkdtemp() 64*86d7f5d3SJohn Marino{ 65*86d7f5d3SJohn Marino case $# in 66*86d7f5d3SJohn Marino 2);; 67*86d7f5d3SJohn Marino *) die "Usage: $ME DIR TEMPLATE";; 68*86d7f5d3SJohn Marino esac 69*86d7f5d3SJohn Marino 70*86d7f5d3SJohn Marino destdir=$1 71*86d7f5d3SJohn Marino template=$2 72*86d7f5d3SJohn Marino 73*86d7f5d3SJohn Marino case $template in 74*86d7f5d3SJohn Marino *XXXX) ;; 75*86d7f5d3SJohn Marino *) die "invalid template: $template (must have a suffix of at least 4 X's)";; 76*86d7f5d3SJohn Marino esac 77*86d7f5d3SJohn Marino 78*86d7f5d3SJohn Marino fail=0 79*86d7f5d3SJohn Marino 80*86d7f5d3SJohn Marino # First, try to use mktemp. 81*86d7f5d3SJohn Marino d=$(env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null) \ 82*86d7f5d3SJohn Marino || fail=1 83*86d7f5d3SJohn Marino 84*86d7f5d3SJohn Marino # The resulting name must be in the specified directory. 85*86d7f5d3SJohn Marino case $d in "$destdir"*);; *) fail=1;; esac 86*86d7f5d3SJohn Marino 87*86d7f5d3SJohn Marino # It must have created the directory. 88*86d7f5d3SJohn Marino test -d "$d" || fail=1 89*86d7f5d3SJohn Marino 90*86d7f5d3SJohn Marino # It must have 0700 permissions. 91*86d7f5d3SJohn Marino perms=$(ls -dgo "$d" 2>/dev/null) || fail=1 92*86d7f5d3SJohn Marino case $perms in drwx------*) ;; *) fail=1;; esac 93*86d7f5d3SJohn Marino 94*86d7f5d3SJohn Marino test $fail = 0 && { 95*86d7f5d3SJohn Marino echo "$d" 96*86d7f5d3SJohn Marino return 97*86d7f5d3SJohn Marino } 98*86d7f5d3SJohn Marino 99*86d7f5d3SJohn Marino # If we reach this point, we'll have to create a directory manually. 100*86d7f5d3SJohn Marino 101*86d7f5d3SJohn Marino # Get a copy of the template without its suffix of X's. 102*86d7f5d3SJohn Marino base_template=$(echo "$template"|sed 's/XX*$//') 103*86d7f5d3SJohn Marino 104*86d7f5d3SJohn Marino # Calculate how many X's we've just removed. 105*86d7f5d3SJohn Marino nx=$(expr length "$template" - length "$base_template") 106*86d7f5d3SJohn Marino 107*86d7f5d3SJohn Marino err= 108*86d7f5d3SJohn Marino i=1 109*86d7f5d3SJohn Marino while :; do 110*86d7f5d3SJohn Marino X=$(rand_bytes $nx) 111*86d7f5d3SJohn Marino candidate_dir="$destdir/$base_template$X" 112*86d7f5d3SJohn Marino err=$(mkdir -m 0700 "$candidate_dir" 2>&1) \ 113*86d7f5d3SJohn Marino && { echo "$candidate_dir"; return; } 114*86d7f5d3SJohn Marino test $MAX_TRIES -le $i && break; 115*86d7f5d3SJohn Marino i=$(expr $i + 1) 116*86d7f5d3SJohn Marino done 117*86d7f5d3SJohn Marino die "$err" 118*86d7f5d3SJohn Marino} 119*86d7f5d3SJohn Marino 120*86d7f5d3SJohn Marinomkdtemp "$@" 121