-
Notifications
You must be signed in to change notification settings - Fork 1
/
caen
executable file
·236 lines (210 loc) · 8.54 KB
/
caen
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
#!/bin/bash
CAEN_SCRIPT_VER=v0.7.0
# Shell settings to improve safety
set -fu -o pipefail
# Source any global or workspace configuration options. This must happen first
# so users can't break private vars. If HOME is unset program will crash. But
# HOME var is part of POSIX compatability, so not our problem
if [ -f "${HOME}/.caen.conf" ]; then
source "${HOME}/.caen.conf"
fi
if [ -f "$(pwd)/.caen.conf" ]; then
source "$(pwd)/.caen.conf"
fi
# Define our help message, docker flags, and env vars
CAEN_ARGS=${CAEN_ARGS:=" "}
CAEN_REPO_NAME=${CAEN_REPO_NAME:=ghcr.io/derickson2402/dockerized-caen}
CAEN_URL='https://github.com/derickson2402/Dockerized-CAEN'
CAEN_VERSION=${CAEN_VERSION:=latest}
CAEN_USER=${CAEN_USER:="$(id -u):$(id -g)"}
CAEN_DEFAULT_ARGS="--rm -i --name caen-${RANDOM:=1} -e TERM=${TERM:=linux} --user ${CAEN_USER}"
CAEN_WORKING_DIR="-v '$(pwd):/code'"
HOST_OS=unknown
HOST_DOCKER_READY=false
CAEN_LATEST_VERSION=${CAEN_SCRIPT_VER}
# NOTE: there is a space at the end to force newline printing
MESSAGE_HELP=$(cat << EOF
Helper script for Dockerized-CAEN. To use, run the following:
caen [program] [args]
For example, running the following would run Valgrind on an
executable called 'program.exe' with a '--flag' and input from a file:
caen valgrind program.exe --flag < input.txt
You can specify a specific version of the container to run with the
\$CAEN_VERSION environment variable like so:
CAEN_VERSION=dev caen valgrind
For more help, check me out on GitHub:
${CAEN_URL}
EOF
)
MESSAGE_OS_ERROR=$(cat << EOF
Hold up! This script is only supported for macOS. See GitHub for more help:
${CAEN_URL}
EOF
)
# Make sure a tmp file exists for us to store the last update check date in
[[ -f /tmp/caen-last-update-check ]] || touch /tmp/caen-last-update-check
CAEN_SCRIPT_LAST_UPDATE=$(cat /tmp/caen-last-update-check)
# Get OS information and verify we are on macOS
function identifyOS() {
if [[ "$OSTYPE" == "darwin"* ]]; then
HOST_OS=mac
else
echo -e "$MESSAGE_OS_ERROR" && exit 1
fi
}
# Check for updates if we have an internet connection. Polls GitHub for latest
# release tag and compares it to script version. Uses CAEN_SCRIPT_LAST_UPDATE
# to limit update frequency, as checking introduces ~1s delay
function checkForUpdates() {
# Update only once daily
if [[ ${CAEN_SCRIPT_LAST_UPDATE} == $(date +%y-%m-%d) ]]; then
return;
fi
# Check for internet connectivity before polling GitHub
if ( wget -q --spider ${CAEN_URL} ); then
CAEN_LATEST_VERSION=$(wget -qO- \
"https://api.github.com/repos/derickson2402/dockerized-caen/releases/latest" \
| grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [[ -z ${CAEN_LATEST_VERSION} ]]; then
echo -e "Hold up! Could not find latest version of script from GitHub, but you appear"
echo -e "to be connected to the internet. Check your internet and try again, or go to"
echo -e "GitHub for more help:"
echo -e "\n ${CAEN_URL}\n"
exit 1
elif [[ ${CAEN_VERSION} != "latest" ]]; then
# Can't check for script updates on special versions, just pull the newest container
echo -e "Heads up! There may be an update available for version ${CAEN_VERSION}."
echo -e "Run the following to get the latest version"
echo -e "\n sudo caen update\n"
elif [[ ${CAEN_SCRIPT_VER} != ${CAEN_LATEST_VERSION} ]]; then
echo -e "Heads up! There is an update available from ${CAEN_SCRIPT_VER} to ${CAEN_LATEST_VERSION}."
echo -e "To update, run the following:"
echo -e "\n sudo caen update\n"
fi
echo "$(date +%y-%m-%d)" > /tmp/caen-last-update-check
fi
}
# Make sure that Docker Engine is installed and running. Provide installation
# URL if not installed, or call host machine to launch daemon if not on
function checkDocker() {
if ( ! command -v docker &> /dev/null ); then
echo -e "Hold up! Docker is not installed on your computer!"
echo -e "You can download and install it here:"
echo -e "\n https://docs.docker.com/desktop/mac/install/\n"
return
fi
if ( ! docker ps &> /dev/null ); then
echo -e "Waking up Moby the Whale..."
open /Applications/Docker.app
# Docker takes up to about 1m to boot, need to wait for it
sleep 10
declare -i counter=0
while ( ! docker stats --no-stream &> /dev/null ); do
if [[ $((${counter} % 15)) == 0 ]]; then
echo -e "Waiting for Moby the Whale to wake up..."
fi
(( counter += 1 ))
sleep 1
if [[ counter -gt 60 ]]; then
echo -e "Couldn't wake up Moby :("
echo -e "Maybe try restarting Docker manually?"
exit 1
fi
done
echo "Hi Moby!"
fi
# All checks have passed, Docker is ready to go
HOST_DOCKER_READY=true
}
# Update the docker container environment and then update the wrapper script.
# This will delete the current script file and replace it
function updateCAEN() {
if [[ $(whoami) != "root" ]]; then
echo -e "Hold up! You can only run an update as root!"
echo -e "Try running with sudo:"
echo -e "\n sudo caen update\n"
exit 1
fi
# Check for internet connection
if ( wget -q --spider ${CAEN_URL} ); then
if [[ ${HOST_DOCKER_READY} == "true" ]]; then
echo "Updating container environment..."
docker pull ${CAEN_REPO_NAME}:${CAEN_VERSION}
else
echo "Cannot update container environment, Docker not responding."
fi
echo "Updating wrapper script..."
echo '#!/bin/bash' > /tmp/caen-update.sh
chmod +x /tmp/caen-update.sh
echo "/bin/bash -c 'wget -q https://raw.githubusercontent.com/derickson2402/Dockerized-CAEN/main/caen -O /usr/local/bin/caen && chmod +x /usr/local/bin/caen'" >> /tmp/caen-update.sh
/tmp/caen-update.sh && rm -f /tmp/caen-update.sh && echo "Done!" && exit
else
echo -e "Hold up! Could not reach github.com! Check your internet connection and"
echo -e "try again."
exit 1
fi
}
# Poll the Docker daemon for the current container version, and print it along
# with the script version
function getVersion() {
if [[ ${HOST_DOCKER_READY} == "true" ]]; then
CONT_SHA=$(docker image ls -q ${CAEN_REPO_NAME}:${CAEN_VERSION})
CONT_VER=$(docker image inspect --format '{{json .}}' "$CONT_SHA" |
perl -nle 'print $& while m{"org.opencontainers.image.version":"\K[^"]+}g')
fi
echo -e "Dockerized-CAEN"
echo -e "Script version: ${CAEN_SCRIPT_VER}"
echo -e "Container version: ${CONT_VER:=unknown}"
exit
}
# Process the CLI args, set default vars, and check what program should be run.
# This lets us give help/version info, and prompt the user for commands that
# require elevated permissions
function checkArgs() {
case $1 in
help)
echo -e "$MESSAGE_HELP"
exit
;;
version)
getVersion
;;
update)
updateCAEN
;;
perf)
if [[ ${HOST_DOCKER_READY} != "true" ]]; then
exit 1
fi
echo -e "Heads up! Perf requires elevated Docker privileges to run. This is"
echo -e "dangerous, so you should only do this with code that you trust!\n"
echo -e "Hit [Ctrl+c] to cancel, or enter to continue"
read </dev/tty
CAEN_DEFAULT_ARGS="$CAEN_DEFAULT_ARGS --privileged"
;;
esac
}
# Execute the given program and its args using the CAEN container
function main() {
# Prep our host environment. Make sure to check for updates first in case
# there is a script bug, so user is more likely to fix their issue
checkForUpdates
identifyOS
if [ $# -eq 0 ]; then
echo -e "$MESSAGE_HELP" && exit
fi
checkDocker
checkArgs $1
# Check for stdin, allowing for file redirection to the container
if [[ ${HOST_DOCKER_READY} != "true" ]]; then
exit 1
fi
if [ ! -t 0 ]; then
eval -- docker run "${CAEN_DEFAULT_ARGS}" "${CAEN_ARGS}" "${CAEN_WORKING_DIR}" "${CAEN_REPO_NAME}":"${CAEN_VERSION}" "$@" < /dev/stdin
else
CAEN_DEFAULT_ARGS="${CAEN_DEFAULT_ARGS} -t"
eval -- docker run "$CAEN_DEFAULT_ARGS" "${CAEN_ARGS}" "${CAEN_WORKING_DIR}" "${CAEN_REPO_NAME}":"${CAEN_VERSION}" "$@"
fi
}
# Bash driver, actually calls all functions
main "$@"; exit