-
Notifications
You must be signed in to change notification settings - Fork 0
/
start_linux.sh.old
executable file
·171 lines (136 loc) · 5.35 KB
/
start_linux.sh.old
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
#!/bin/bash
usage() { echo "USAGE: bash $0 [OPTIONS] [SCRIPT] [SCRIPT2] [...]
OPTIONS:
-h display help
-k --enable-kvm in qemu
-i <imagefile.img> use specified qemu disk image
-o <outfilename> write output of all scripts to the given file
" 1>&2; exit 1; }
IMG="qemu_image.img"
DEFOUTFILE=
USEKVM=
while getopts ":hki:o:" OPT; do
case "$OPT" in
h)
usage
;;
i)
IMG="$OPTARG"
;;
o)
DEFOUTFILE="$OPTARG"
;;
k)
USEKVM="--enable-kvm"
;;
*)
usage
;;
esac
done
shift $(($OPTIND - 1)) # isolate remaining args (which should be script filenames)
[ -f $IMG ] || { echo "ERROR: Qemu disk image does not exist: $IMG"; exit 1; }
for file in "$@"; do
[ -f $file ] || { echo "ERROR: file does not exist: $file"; exit 1; }
done
##### BEGIN RUNNING QEMU IN THE BACKGROUND #####
NAME="qemu-linux"
TS="$(date +%s%N)" # get current time in nanoseconds -- good enough for unique timestamp
NAMEDPIPE="/tmp/$NAME-$TS"
mkfifo "$NAMEDPIPE.in" "$NAMEDPIPE.out" # create I/O pipes
qemu-system-x86_64 \
-kernel linux/arch/x86_64/boot/bzImage \
-hda $IMG \
-append "root=/dev/sda console=ttyS0" \
-no-reboot \
-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
-serial pipe:$NAMEDPIPE \
-display none \
$USEKVM \
2> /dev/null \
&
# start qemu with the named pipe for I/O, and background it, since we need to
# begin watching its output and giving input accordingly using the pipe
##### DEFINE FUNCTIONS TO RUN SCRIPTS AND STORE OUTPUT #####
# print the given command to the input buffer, terminated by a newline character
do_now() {
CMD=$1
echo "now doing $CMD"
printf "$CMD\n" > "$NAMEDPIPE.in"
}
# wait until any of the given strings appear in the output buffer, then return
wait_for() {
BREAK=
while read line; do
for STR in "$@"; do
if [[ "$line" == *"$STR"* ]]; then
BREAK=1
break
fi
done
[ -n "$BREAK" ] && break
done < "$NAMEDPIPE.out"
}
# write from the output buffer to the given file until any of the given strings appear
# does not write the final line containing the found string
write_until() {
OUTFILE=$1
BREAK= # initialize empty BREAK variable
shift # shift arg index by 1
while read outline; do
for STR in "$@"; do # if no further arguments, read indefinitely
if [[ "$outline" == *"$STR"* ]]; then
BREAK=1 # remember to break from the actual read loop
break # break from the inner for loop
fi
done
[ -n "$BREAK" ] && break # break if the BREAK variable has been set
echo "$outline " | sed 's/.*//g' >> $OUTFILE
done < "$NAMEDPIPE.out"
}
# write each line of the given file to the input buffer, terminated by a newline
# then write a blank line
do_script() {
SCRIPTFILE=$1
[ -n "$2" ] && OUTFILE=$2 || OUTFILE="$SCRIPTFILE.output"
# first replace all newlines with semicolons
# then replace all formerly escaped newlines (now \;) with space characters
# then append a space after all semicolons
#CMDSTRING="$(tr '\n' ';' < "$SCRIPTFILE" | sed 's/\\;/ /g;s/;/; /g')"
STARTTIME=$(date +%s%N)
printf "START OF SCRIPT $SCRIPTFILE $(date +%D_%T)\n\n" >> $OUTFILE
# run each command from the script on the VM
while read cmdline; do
#echo "trying to run $cmdline ..."
do_now "$cmdline" # run the command
read OUTLINE < "$NAMEDPIPE.out" # read the line with the command from the output buffer
#echo "$OUTLINE"
echo "$OUTLINE " | sed 's/.*//g' >> $OUTFILE # write the line to the output file
do_now "" # write a newline character so that an empty prompt will be written to the buffer when done
write_until "$OUTFILE" "root@localhost:" ">" # write until the empty prompt or bash next line '>' appears in the buffer
done < $SCRIPTFILE
ENDTIME=$(date +%s%N)
TOTALMS=$(echo "$(($ENDTIME-$STARTTIME))" | sed -r 's/.{6}$//')
printf "\nEND OF SCRIPT $SCRIPTFILE $(date +%D_%T) -- $TOTALMS ms\n\n" >> $OUTFILE
}
##### RUN ALL SCRIPTS WHICH WERE PASSED AS ARGUMENTS AND STORE THEIR OUTPUT #####
# "Debian GNU/Linux 10 localhost" is the last line before the login prompt, which
# is not terminated by a newline character, so does not appear in the pipe yet
wait_for "Debian GNU/Linux 10 localhost"
read < "$NAMEDPIPE.out" # throw away blank line after the above line
do_now "root" # enter root into the login prompt
do_now "" # enter newline into the shell prompt, causing a blank prompt to appear in the output buffer
wait_for "root@localhost:" # wait for the blank prompt to appear in the output buffer
for SCRIPTFILE in "$@"; do
do_script "$SCRIPTFILE" "$DEFOUTFILE"
done
do_now "shutdown now" # tell Linux VM to shut down
# Write until the pipe closes
write_until "shutdown_sequence.txt" # "/dev/null"
# kill the backgrounded qemu process
#kill $(ps -aux | grep qemu-system-x86_64 | grep $NAMEDPIPE | awk '{print $2}')
# there should be a better way to do this using the I/O port via isa-debug-exit
# it also may be the case that the the VM is not yet shut down
rm "$NAMEDPIPE.in" "$NAMEDPIPE.out"