-
Notifications
You must be signed in to change notification settings - Fork 0
/
virt-serial.sh
290 lines (259 loc) · 7.73 KB
/
virt-serial.sh
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
#!/bin/bash
#############################################
#
# Meta data
#
# written by: Andreas Ulm
# created: 2017-01-28
# Description: Script to manage serial ports over
# TCP connections using socat.
#
#############################################
#####################
# #
# default config #
# #
#####################
# define directory for temporary files
TMP="/tmp/virt-serial"
# define directory for log files
LOGDIR="/var/log/virt-serial"
# user allowed to access created com port
COMUSER="root"
# base path for com port
DEVPATH="/dev/virt-serial"
# define colors for output
RED='\e[1;31m'
GREEN='\e[1;32m'
DEF='\e[0m'
#####################
# #
# functions #
# #
#####################
# define usage function
# call of this function results in script exit with given code
function usage() {
echo "$0 [-c config] (-a target|-d target|-h|-l target)"
echo
echo " This script must be run as root"
echo
echo " -a target = activate connection to target"
echo " -c config = use specified configuration file"
echo " -d target = deactivate connection to target"
echo " -l = list active connections"
echo
echo " target = ip-address[:port]"
echo
echo " config may define the following parameters:"
echo " TMP = directory for temporary files"
echo " LOGDIR = directory for log files"
echo " COMUSER = user allowed to access created com port"
echo " DEVPATH = base path for com port"
echo
exit "${1}"
}
# check necessary environment
function checkEnv() {
# check for root permission
if [ $EUID -ne 0 ]; then
echo "${RED}This function of the script has to be run as root.${DEF}" >&2
error=1
fi
# check for socat command
if ! which socat &>/dev/null; then
echo "${RED}Please install 'socat'-command${DEF} (e.g. apt-get install socat, pacman -S socat)" >&2
error=1
fi
echo
[[ ${error} -eq 1 ]] && usage 5
}
# check if connection to given ip-address and port already exists
# if it exists load its configration & return 0
# if it does not exist return 1
function checkCon() {
local ip="${1}"
local port="${2}"
local pidfile="${TMP}/${ip}_${port}.pid"
local conffile="${TMP}/${ip}_${port}.conf"
# exit script if port is missing
if [[ -z "${port}" ]]; then
echo -e "${RED}port is missing${DEF}"
echo
usage 7
fi
if ! [[ "${port}" =~ [0-9][0-9]* ]]; then
echo -e "${RED}port is invalid${DEF}"
echo
usage 7
else
if [[ ${port} < 1 || ${port} > 65534 ]]; then
echo -e "${RED}port is invalid${DEF}"
echo
usage 7
fi
fi
# create tmp directory if missing
[[ -d "${TMP}" ]] || mkdir -p "${TMP}"
# check pidfile for existing process
if [[ -f "${pidfile}" ]]; then
if pgrep -F "${pidfile}" >/dev/null; then
export PID="$(<"${pidfile}")"
[[ -e "${conffile}" ]] && source "${conffile}"
return 0
else
cleanup "${ip}" "${port}"
return 1
fi
else
return 1
fi
}
# delete temporary files
function cleanup() {
local ip="${1}"
local port="${2}"
local pidfile="${TMP}/${ip}_${port}.pid"
local conffile="${TMP}/${ip}_${port}.conf"
local logfile="${LOGDIR}/${ip}_${port}.log"
rm -f "${conffile}" "${pidfile}"
echo "$(date) run cleanup for target ${ip}:${port} initiated by ${SUDO_USER}" >> "${logfile}"
}
# activate connection for given target
function activate() {
ip="${1}"
port="${2}"
if checkCon "${ip}" "${port}"; then
echo -e "${RED}connection for ${ip}:${port} already exists:${DEF}"
echo " PID: ${PID}"
echo " COMPATH: ${COMPATH}"
echo " started at: ${STARTED}"
else
pidfile="${TMP}/${ip}_${port}.pid"
conffile="${TMP}/${ip}_${port}.conf"
logfile="${LOGDIR}/${ip}_${port}.log"
# get amount of running connections
count="$(ls /dev/virt-serial* 2>/dev/null | wc -l)"
let "count++"
# get available connection path
while [[ -e "${DEVPATH}${count}" ]]; do
let "count++"
done
# start com port connection in background
socat -d -d -d pty,link="${DEVPATH}${count}",rawer,user="${COMUSER}",wait-slave tcp:"${ip}":"${port}" &>> "${logfile}" &
echo "$!" > "${pidfile}"
if checkCon "${ip}" "${port}"; then
date="$(date)"
echo "# Started connection at $(date)" > "${conffile}"
echo "STARTED='${date}'" >> "${conffile}"
echo "COMPATH='${DEVPATH}${count}'" >> "${conffile}"
echo -e "${GREEN}Successfully started connection.${DEF}"
echo " PID: ${PID}"
echo " COMPATH: ${DEVPATH}${count}"
echo " started: ${date}"
echo " logfile: ${logfile}"
else
echo -e "${RED}Failed to start connection.${DEF}"
echo "See logfile ${logfile}"
fi
fi
}
# deactivate given connection
function deactivate() {
ip="${1}"
port="${2}"
if checkCon "${ip}" "${port}"; then
if kill "${PID}" &>/dev/null; then
cleanup "${ip}" "${port}"
echo -e "${GREEN}Successfully deactivated connection for target '${ip}:${port}' (${PID})${DEF}"
else
echo -e "${RED}Failed to deactivate connection for target '${ip}:${port}'${DEF}"
fi
else
echo "Connection for target '${ip}:${port}' not found"
fi
}
# find and list all running connections
function list() {
ip="${1}"
port="${2}"
echo "The following connections are currently established:"
if ls "${TMP}"/*.pid &>/dev/null; then
for pidfile in "${TMP}"/*.pid; do
file="${pidfile##*/}"
file="${file%%.pid}"
read ip port <<<"${file//_/ }"
if checkCon "${ip}" "${port}"; then
echo " TARGET: ${ip}:${port}"
echo " PID: ${PID}"
echo " COMPATH: ${COMPATH}"
echo " started: ${STARTED}"
echo " logfile: ${LOGDIR}/${ip}_${port}.log"
fi
done
else
echo " No active connections"
fi
}
#####################
# #
# main script #
# #
#####################
# read all commandline arguments & define action to be run
while getopts ':a:c:d:hl' opt
do
case "${opt}" in
"a")
read ip port <<<"${OPTARG//:/ }"
ACTION="activate"
;;
"c")
config="${OPTARG}"
;;
"d")
read ip port <<<"${OPTARG//:/ }"
ACTION="deactivate"
;;
"h")
usage 0
;;
"l")
ACTION="list"
;;
'?')
echo -e "${RED}unknown option -${OPTARG}${DEF}"
echo
usage 2
;;
':')
echo -e "${RED}-${OPTARG} requires an argument${DEF}"
echo
usage 3
;;
*)
echo -e "${RED}error while parsing given options${DEF}"
echo
usage 1
;;
esac
done
[[ -z "${ACTION}" ]] && usage 0
checkEnv
# allow overwrite of all configuration parameters defined above
[[ -n "${config}" && -e "${config}" ]] && source "${config}"
# restrict access for all created files & directories to root
umask 0027
# create log directory if missing
[[ -d "${LOGDIR}" ]] || mkdir -p "${LOGDIR}"
case "${ACTION}" in
"activate")
activate "${ip}" "${port}"
;;
"deactivate")
deactivate "${ip}" "${port}"
;;
"list")
list
;;
esac