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