-
Notifications
You must be signed in to change notification settings - Fork 0
/
makedev
executable file
·269 lines (244 loc) · 6.99 KB
/
makedev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#!/bin/bash --norc
set -e
set -u
srcdir=$(dirname "$(readlink -f "$0")")
quiet=false
function usage {
if ! $quiet; then
echo "This script runs \"serverprog\" to start an NBD server locally and attaches it to a"
echo " device file. serverprog should be an incantation of nbdcpp_main; see the ramdisk and"
echo " loopback examples provided."
echo "Usage: $0 OPTIONS serverprog [serverprog_options...]"
echo " serverprog must be a compiled executable which calls nbdcpp_main"
echo " and accepts the remaining options."
echo "OPTIONS are [-f] [-q] [-l logfile] [-d /dev/nbdX] [-k killer] [-u socketfile]:"
echo " -f: run the server in the foreground (default: runs as a daemon in the background)"
echo " -q: suppress all output except for the device name"
echo " -l logfile: append server messages to the given file."
echo " By default, a temp file is used unless -f is specified."
echo " -d device: Use the specified nbd device (default: find the first unused nbd device)"
echo " -k killer: create a script with this filaname that can cleanly disconnect the device"
echo " (will be created with a default name unless running with -f)"
echo " -u socketfile: specify local filename for the unix socket (default: create a temp file)"
fi
[[ $# -eq 1 ]] && exit $1
}
sockfile=""
templog=true
daemonize=true
devfile=""
killfile=""
# process initial options
while [[ $# -ge 1 ]]; do
if [[ $1 = '-f' ]]; then
daemonize=false
elif [[ $1 = '-q' ]]; then
quiet=true
elif [[ $1 = '-l' ]]; then
[[ $# -ge 2 && ! $2 =~ ^- ]] || usage 1
logfile=$(readlink -f "$2")
templog=false
shift
elif [[ $1 = '-d' ]]; then
[[ $# -ge 2 && ! $2 =~ ^- ]] || usage 1
[[ $2 =~ / ]] && devfile=$(readlink -f "$2") || devfile="/dev/$2"
shift
elif [[ $1 = '-k' ]]; then
[[ $# -ge 2 && ! $2 =~ ^- ]] || usage 1
killfile=$(readlink -f "$2")
shift
elif [[ $1 = '-u' ]]; then
[[ $# -ge 2 && ! $2 =~ ^- ]] || usage 1
sockfile=$(readlink -f "$2")
shift
else
break
fi
shift
done
[[ $# -ge 1 ]] || usage 1
[[ $1 =~ ^- ]] && usage 1
# get the name of the server program
server=$(readlink -f "$1")
[[ -x $server ]] || usage 1
shift
# check if we need sudo
[[ $(id -u) -eq 0 ]] && getroot="" || getroot="sudo"
# check that nbd module is loaded
if ! grep -q '^nbd ' /proc/modules; then
# nbd module not yet loaded
$quiet || echo "loading nbd module..."
if ! $getroot modprobe nbd; then
if ! $quiet; then
echo "ERROR: could not load nbd module"
echo "Are you running a recent Linux kernel with the modprobe command?"
echo "Perhaps you need to install the kmod package?"
fi
exit 2
fi
fi
# find the nbd-client executable
# first try the normal path
if ! nbdc=$(which nbd-client); then
gotit=false
# next try a few other likely paths
for dir in "/usr/local/sbin" "/usr/sbin" "/sbin"; do
nbdc="$dir/nbd-client"
if [[ -x $nbdc ]]; then
gotit=true
break
fi
done
if ! $gotit; then
# try sudo which as a last resort
if ! nbdc=$($getroot which nbd-client); then
if ! $quiet; then
echo "ERROR: no nbd-client program found"
echo "Perhaps you need to install the nbd-client package?"
exit 2
fi
fi
fi
fi
# automatically determine device file, if necessary
if [[ -z $devfile ]]; then
i=0
while true; do
devfile="/dev/nbd$i"
# break if device doesn't exist or if it's not already in use
if [[ ! -e $devfile ]] || ! "$nbdc" -c "$devfile" >/dev/null; then
break
fi
: $(( i++ ))
done
fi
if [[ ! -e $devfile ]]; then
$quiet || echo "ERROR: device $devfile does not exist; unable to proceed"
exit 3
fi
# make a killfile name if necessary
if [[ -z $killfile ]]; then
if $daemonize; then
# user-friendly name
killfile="stop-$(basename "$devfile")"
else
killfile=$(mktemp --tmpdir nbdkill.XXXXXXXXXX.sh)
rm -f "$killfile"
fi
fi
if [[ -e $killfile ]]; then
if ! $quiet; then
read -n1 -p "Kill script $killfile already exists. Delete it? [Y/n] " yn
[[ -z $yn || $yn =~ [yY] ]] || exit 1
fi
fi
if ! touch "$killfile"; then
$quiet || echo "Error: cannot write kill script $killfile"
exit 3
fi
# create temp file for log if necessary
if $templog; then
if $daemonize; then
logfile=$(mktemp --tmpdir nbdlog.XXXXXXXXXX.txt)
else
$quiet && logfile="" || logfile=/dev/stderr
templog=false
fi
else
if ! touch "$logfile"; then
$quiet || echo "ERROR: need write access to log file $logfile"
rm -f "$killfile"
exit 3
fi
fi
# create temp file for socket if necessary
if [[ -z $sockfile ]]; then
sockfile=$(mktemp --tmpdir nbdsock.XXXXXXXXXX)
elif [[ -e $sockfile ]]; then
if ! $quiet; then
read -n1 -p "Socket file $sockfile already exists. Delete it? [Y/n] " yn
[[ -z $yn || $yn =~ [yY] ]] || exit 1
fi
if ! touch "$sockfile"; then
$quiet || echo "ERROR: need write access to socket file $sockfile"
rm -f "$killfile"
$templog && rm -f "$logfile"
exit 3
fi
fi
# now remove the socket file to avoid error message when server starts
rm -f "$sockfile"
# start the actual server process and save its pid and blocksize
if ! sinfo=($("$server" "$@" -q -u "$sockfile" ${logfile:+-l "$logfile"} -d))
then
$quiet || echo "ERROR starting the server (see above)"
rm -f "$killfile"
$templog && rm -f "$logfile"
rm -f "$sockfile"
exit 4
fi
# create the kill script
exec 4>"$killfile"
cat >&4 <<EOF
#!/usr/bin/env bash
quiet=$quiet
# check running as root
if [[ \$(id -u) -ne 0 ]]; then
\$quiet || echo "Must be run as root; attempting sudo..."
sudo "\$0"
exit \$?
fi
devfile="$devfile"
server_pid="${sinfo[0]}"
sockfile="$sockfile"
EOF
$templog && echo "logfile=\"$logfile\"" >&4
cat >&4 <<EOF
\$quiet || echo "Disconnecting the nbd device..."
nbd-client -d "\$devfile" >/dev/null
\$quiet || echo "Stopping the server..."
kill -INT \$server_pid
wait \$server_pid 2>/dev/null
\$quiet || echo "Cleaning up files..."
rm -f "\$sockfile"
EOF
$templog && echo "rm -f \"\$logfile\"" >&4
cat >&4 <<EOF
rm -f "$(readlink -f "$killfile")" # self-destruct
\$quiet || echo "The nbd server has been successfully stopped."
EOF
exec 4>&-
chmod +x "$killfile"
# wait until the server is listening
while [[ ! -e $sockfile ]]; do
sleep 0.1
done
# connect to the server using nbd-client
$getroot nbd-client -Nx -block-size "${sinfo[1]}" -u "$sockfile" "$devfile" >/dev/null 2>&1
if $daemonize; then
if $quiet; then
echo "$devfile"
else
echo "The device is ready at $devfile"
echo "Log message are stored in $logfile"
echo "Run the script $killfile to close."
fi
exit 0
else
if $quiet; then
trap ':' SIGINT
echo "$devfile"
else
trap 'echo "Caught SIGINT - beginning shutdown"' SIGINT
echo "Device is running on $devfile"
echo "Hit Ctrl-C (or send SIGINT to pid $$) to close the device"
fi
set +e
sleep inf &
sleeper=$!
wait $sleeper 2>/dev/null
kill $sleeper
wait $sleeper 2>/dev/null
$getroot "$killfile"
exit 0
fi