-
Notifications
You must be signed in to change notification settings - Fork 0
/
tools.subr
346 lines (291 loc) · 7.96 KB
/
tools.subr
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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
if [ ! "$_CBSD_TOOLS_SUBR" ]; then
_CBSD_TOOLS_SUBR=1
###
#v11.0.12
#return 0 errcode for undefined type
#return 1 errcode for ipv4
#return 2 errcode for ipv6
# fill VHID args when CARP-specific records
# export IWM global variables
iptype() {
local prefix p1 p2 ip
[ -z "${1}" ] && return 0
ip="${1}"
unset VHID IPWVHID
prefix=$( substr --pos=0 --len=4 --str=${ip} )
if [ "${prefix}" = "vhid" ]; then
p1=${ip%%#*} # cut all after '#'
IPWVHID=${ip##*#} # cut all before '#' (ip with mask)
ipwmask "${IPWVHID}" # get IWM
VHID=${p1##*_} # get VHID
. ${tools}
is_number ${VHID} && err 1 "${MAGENTA}Error in iptype: vhid should be number${NORMAL}"
else
# cut network prefix if exist
ipwmask "${1}"
fi
[ -z "${IWM}" ] && return 0
prefix=$( substr --pos=0 --len=4 --str=${IWM} )
if [ "${prefix}" = "vhid" ]; then
IPWVHID=
p1=${IWM%%#*}
IPWVHID=${IWM##*#}
VHID=${p1##*_}
. ${tools}
is_number ${VHID} && err 1 "${MAGENTA}Error in iptype: vhid should be number${NORMAL}"
fi
# Identify type {inet,inet6}.
case "${IWM}" in
*\.*\.*\.*)
echo "${IWM}" |/usr/bin/egrep -q '^([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}$' && return 1
# its not ip
return 0
;;
*:*)
return 2
;;
*) return 0
;;
esac
}
resolvhost()
{
local _host
local proto
if [ "${node_ip6_active}" = "1" ]; then
proto="6"
else
proto="4"
fi
_host=$( ${miscdir}/resolv ${proto} ${1} )
[ $? -eq 0 ] && echo ${_host}
}
# convert string in Xm (mbytes) or Xg (gbytes) to bytes
# example:
# if conv2bytes "1g"; then
# echo $convval
# fi
# return bytes in $convval var
# errcode 1 when error
conv2bytes() {
local _testsize
local _value
[ -z "${1}" ] && return 1
# expand_number in conv2human does't support for float, eg: 1.1G
convval=$( ${miscdir}/conv2human ${1} |/usr/bin/tr '[:upper:]' '[:lower:]' )
[ -z "${convval}" ] && return 1
[ ${convval} -gt 0 ] || return 1
}
# convert bytes to human readable form
# example:
# if conv2human "10000"; then
# echo $convval
# fi
# errcode 1 when not number
conv2human() {
[ -z "${1}" ] && return 1
convval=$( ${miscdir}/conv2human ${1}| /usr/bin/tr '[:upper:]' '[:lower:]' )
return $?
}
# $1 - $4 - ip
# $5 - $8 - mask
# example:
# IFS="."
# ip="192.168.1.55"
# mask="255.255.255.248"
# first_ips_w_mask 192.168.1.55 255.255.255.248
first_ips_w_mask()
{
printf "%d.%d.%d.%d\n" "$(($1 & $5))" "$(($2 & $6))" "$(($3 & $7))" "$(( ($4 & $8) + 1 ))"
}
# print prefix from mask
# example: cdr=$( mask2cdr 255.255.255.248 )
mask2cdr ()
{
# Assumes there's no "255." after a non-255 byte in the mask
local x=${1##*255.}
set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*}
x=${1%%$3*}
echo $(( $2 + (${#x}/4) ))
}
# print mask from prefix
# example: mask=$( cdr2mask 24 )
cdr2mask ()
{
# Number of args to shift, 255..255, first non-255 byte, zeroes
set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
[ $1 -gt 1 ] && shift $1 || shift
echo ${1-0}.${2-0}.${3-0}.${4-0}
}
# for select_jail_by_list
# return 1 when node online
# return 0 when only_local=0 and node is offnline
# or only_online=1 or only_local=1
node_state()
{
[ -z "${nodename}" ] && return 0 # nothing to test
[ ${only_local} -eq 0 ] && return 0 # local only
[ ${only_online_node} -eq 1 ] && return 0 # any nodes
local ip
ip=$( cbsdsql nodes SELECT ip FROM nodelist WHERE nodename=\"${nodename}\" )
[ -z "${ip}" ] && return 0 # nothing to test
if ! check_locktime ${ftmpdir}/shmux_${ip}.lock >/dev/null 2>&1; then
return 1 # Offline
else
return 0 # Online
fi
}
# return $jname as selected jail by id
# -s "is subject for list"
# -a [0|1] show only active (status=on jail): 0, or all: 1
# -r [0|1] select jname from remote node too (1), or only local: 0
# -e emulator ( jls for jail and bls for bhyve ): jls
# -o [0|1] for remove node - show only when node online: 0 (default), or any state: 1
select_jail_by_list()
{
local tmpfile
local _ret _id i=1
local sqldelimer=" "
local emulator="jls"
local only_local=0 # default - local node only
local subject="List of online jails:"
local searchstr
local active="."
local only_online_node=0 # only online node
while getopts "a:r:s:e:o:" opt; do
case "$opt" in
a) active="${OPTARG}" ;;
r) only_local="${OPTARG}" ;;
s) subject="${OPTARG}" ;;
e) emulator="${OPTARG}" ;;
o) only_online_node="${OPTARG}" ;;
esac
shift $(($OPTIND - 1))
done
if [ ${only_local} -eq 0 ]; then
searchstr="env NOCOLOR=1 ${emulator}"
else
searchstr="env NOCOLOR=1 ${emulator}"
. ${nodes}
fi
case "${emulator}" in
j*)
stuff="jails"
;;
b*)
stuff="bhyve"
;;
x*)
stuff="xen"
;;
esac
${ECHO} "${MAGENTA}${subject}${NORMAL}"
tmpfile=$( /usr/bin/mktemp )
/usr/bin/truncate -s0 ${tmpfile}
local my_nodename="${nodename}"
${searchstr} shownode=1 display=jname,status header=0 order=asc | /usr/bin/egrep ${active}$ |while read nodename jname status; do
# continue only when any node status or when node is online (when -r 1)
node_state || continue
[ -z "${nodename}" ] && continue
[ "${nodename}" = "${my_nodename}" ] && nodename="local"
[ -z "${jname}" ] && continue
case "${status}" in
On)
active=1
;;
*)
active=0
;;
esac
echo "${active}:${jname}:${nodename}" >> ${tmpfile}
done
_ret=$( /usr/bin/stat -f "%z" ${tmpfile} 2>/dev/null )
[ "${_ret}" = "0" ] && err 1 "${MAGENTA}No ${stuff} found${NORMAL}"
select_jail ${tmpfile} 2>/dev/null
_ret=$?
case "${_ret}" in
0)
jname=$( /bin/cat ${tmpfile} )
/bin/rm -f ${tmpfile}
;;
1)
/bin/rm -f ${tmpfile}
err 0 "${MAGENTA}Cancel pressed${NORMAL}"
;;
2)
/bin/rm -f ${tmpfile}
err 1 "${MAGENTA}select_jail error${NORMAL}"
;;
esac
remote=2 # for autoremote
}
# libchk for testing dependency of cbsd and updatesql. Exit when stuff is broken
test_sql_stuff()
{
local _files="/usr/local/bin/cbsd ${miscdir}/updatesql"
local _i _res
[ -z "${GREP_CMD}" ] && GREP_CMD="grep"
for _i in ${_files}; do
[ ! -f "${_i}" ] && continue
_res=$( /usr/bin/ldd ${_i} 2>/dev/null|${GREP_CMD} " not found " )
if [ -n "${_res}" ]; then
echo "WARNING: ${_i} is broken:"
echo "${_res}"
echo "Please rebuild sources and try again"
exit 1
fi
done
}
# prepare jail hier for executing command inside jail
# when jail is not running
# e.g for offline modification (pkg, helpers and so on... )
# $jname, $path variable must be initialized
prepare_offline_jail()
{
mountbase -o "" -p "" -d "" -c "" -s ""
[ -f "${mount_fstab}" ] && /usr/local/bin/cbsd mountfstab jroot=${path} fstab=${mount_fstab} jname="${jname}"
[ -f "${mount_fstab}.local" ] && /usr/local/bin/cbsd mountfstab jroot=${path} fstab=${mount_fstab}.local jname="${jname}"
/sbin/mount -t devfs devfs ${path}/dev
makeresolv jname=${jname}
trap "${TRAP} /usr/local/bin/cbsd jcleanup jname=$jname" HUP INT ABRT BUS TERM EXIT
}
# MAC random generator
# $1 - OUI (Organizationally Unique Identifier) or MFG (Manufacturing/vendor's code), e.g: "02:ff:f0"
# $2 - how many mac generated, by default - 1
# mac=$( mac_gen 02:ff:f0 2 )
#
# TODO
# make possible to OUI dynamically size: 02:ff or 02:ff:f0:01 or 02:ff:f0:01:01
# and generate only missing parts
mac_gen() {
local OUI="${1}"
local num
[ -z "${2}" ] && num=1
[ -z "${OUI}" ] && return 1
for i in $( /usr/bin/seq 1 ${num} ); do
echo -n $OUI; /bin/dd bs=1 count=3 if=/dev/random 2>/dev/null | /usr/bin/hexdump -v -e '/1 ":%02x"'
echo
done
}
# return $jail_list variable if jname is mask for multiple jail's
# $emulator must be filled
jname_is_multiple()
{
jail_list=
# We accept jname with wildcard '*' e.g.: jail*, *vnet*
# jail as mask?
local is_mask=0
local jail_pref=$( substr --pos=0 --len=1 --str=${jname} )
if [ "${jail_pref}" = "*" ]; then
is_mask=1
else
strpos --str="${jname}" --search="*"
is_mask=$?
fi
if [ ${is_mask} -ne 0 ]; then
jail_mask=$( echo ${jname} |/usr/bin/tr "*" "%" )
jail_list=$( cbsdsql local SELECT jname FROM jails WHERE emulator = \"${emulator}\" AND jname LIKE \"${jail_mask}\" | /usr/bin/xargs )
fi
}
###
fi