]> git.ipfire.org Git - people/ms/network.git/blame - src/functions/functions.util
ipsec: Make sure strongswan is started when it should be
[people/ms/network.git] / src / functions / functions.util
CommitLineData
1848564d
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2010 Michael Tremer & Christian Schmidt #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
97cb552e 22# A simple print statement
1c6a4e30 23print() {
acc9efd5
MT
24 local fmt=${1}; shift
25
40e3553f 26 printf -- "${fmt}\n" "$@"
97cb552e
MT
27}
28
67baa452
MT
29print_indent() {
30 local i=${1}
31 shift
32
33 while (( i-- )); do
34 printf "\t"
35 done
36
37 print "%s" "$@"
38}
39
cb965348
MT
40# The args() function takes a number of arguments like
41# var1="abc d" var2="abc" var3="abcd e"
42# and splits them into several arguments, devided by newline
1c6a4e30 43args() {
cb965348
MT
44 echo "$@" | xargs printf "%s\n"
45}
46
1c6a4e30 47unquote() {
04854c77
MT
48 local var="$@"
49
50 if [ "${var:0:1}" = "\"" ]; then
51 var=${var:1}
52 fi
53
54 local last=$(( ${#var} - 1 ))
55 if [ ${last} -ge 0 ] && [ "${var:${last}:1}" = "\"" ]; then
56 var=${var:0:${last}}
57 fi
58
59 print "${var}"
60}
61
1c6a4e30 62quote() {
04854c77
MT
63 print "\"%s\"" "$@"
64}
65
1c6a4e30 66strip() {
fe52c5e0
MT
67 local value="$@"
68
69 # remove leading whitespace characters
70 value="${value#"${value%%[![:space:]]*}"}"
71
72 # remove trailing whitespace characters
73 value="${value%"${value##*[![:space:]]}"}"
74
75 print "${value}"
76}
77
1848564d 78# Print a pretty error message
1c6a4e30 79error() {
fcbf6823 80 echo -e " ${CLR_RED_B}ERROR${CLR_RESET} : $@" >&2
1848564d
MT
81}
82
1c6a4e30 83error_log() {
1b7a1578
MT
84 log ERROR "$@"
85}
86
1848564d 87# Print a pretty warn message
1c6a4e30 88warning() {
fcbf6823 89 echo -e " ${CLR_YELLOW_B}WARNING${CLR_RESET}: $@" >&2
1848564d
MT
90}
91
1c6a4e30 92warning_log() {
1b7a1578
MT
93 log WARNING "$@"
94}
95
1848564d 96# Speedup function to avoid a call of the basename binary
1c6a4e30 97basename() {
1848564d
MT
98 echo "${1##*/}"
99}
100
1c6a4e30 101format() {
e5651e17
MT
102 local key=${1}
103 assert isset key
104
105 local format=${2}
106 assert isset format
107
108 shift 2
109
110 printf -v "${key}" "${format}" "$@"
111}
112
d13929d4
MT
113format_time() {
114 local s=${1}
115 local ret m
116
117 local units="s m h"
118
119 local unit
120 for unit in ${units}; do
121 m=$(( ${s} % 60 ))
122 s=$(( ${s} / 60 ))
123
124 if [ ${m} -gt 0 ]; then
125 ret="${m}${unit} ${ret}"
126 fi
127 done
128
129 # Remove whitespace
130 echo ${ret}
131}
132
b383499d
MT
133parse_time() {
134 local ret=0
135
136 local arg
137 for arg in $@; do
138 local unit
139
140 case "${arg}" in
141 *h|*m|*s)
142 # Store unit
143 unit="${arg: -1}"
144
145 # Remove unit
146 arg="${arg:0:-1}"
147 ;;
148 esac
149
150 if ! isinteger arg; then
151 return ${EXIT_ERROR}
152 fi
153
154 # Convert hours and minutes into seconds
155 case "${unit}" in
156 h)
157 arg=$(( ${arg} * 3600 ))
158 ;;
159 m)
160 arg=$(( ${arg} * 60 ))
161 ;;
162 esac
163
164 # Add up everything
165 ret=$(( ${ret} + ${arg} ))
166 done
167
168 print "${ret}"
169}
170
1c6a4e30 171assign() {
b79ad79b
MT
172 local key=${1}
173 assert isset key
174 shift
175
e5651e17 176 format "${key}" "%s" "$@"
b79ad79b
MT
177}
178
1c6a4e30 179fread() {
b79ad79b
MT
180 local file=${1}
181 assert isset file
182
183 [ -r "${file}" ] || return ${EXIT_ERROR}
184
185 print "$(<${file})"
186}
187
1c6a4e30 188fwrite() {
b79ad79b
MT
189 local file=${1}
190 assert isset file
191 shift
192
644d3bb8
MT
193 if ! print "%s" "$@" > ${file} 2>/dev/null; then
194 error "Could not write to file: ${file}"
195 return ${EXIT_ERROR}
196 fi
197
198 return ${EXIT_OK}
199}
200
201fappend() {
202 local file=${1}
203 assert isset file
204 shift
205
e1947a76 206 if [ -e "${file}" ] && [ ! -w "${file}" ]; then
8d4e0d52
MT
207 log ERROR "${file}: No such file"
208 return ${EXIT_ERROR}
209 fi
210
211 print "%s" "$@" >> ${file} 2>/dev/null
b79ad79b
MT
212}
213
e1947a76
MT
214file_exists() {
215 local file=${1}
216
217 [ -e "${file}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
218}
219
220file_is_newer_than() {
221 local file1="${1}"
222 local file2="${2}"
223
224 local age1=$(file_get_age "${file1}")
225 local age2=$(file_get_age "${file2}")
226
227 if [ ${age1} -gt ${age2} ]; then
228 return ${EXIT_TRUE}
229 else
230 return ${EXIT_FALSE}
231 fi
232}
233
234file_get_age() {
235 local file="${1}"
236
237 if [ -e "${file}" ]; then
238 stat --format="%Y" "${file}"
239 return $?
240 fi
241
242 return ${EXIT_ERROR}
243}
244
c041b631
MT
245make_parent_dir() {
246 local path="${1}"
247
248 local dirname="$(dirname "${path}")"
249 mkdir -p "${dirname}"
250}
251
1c6a4e30 252enabled() {
1848564d
MT
253 local param=${1}
254
e726ef8d 255 list_match "${!param}" yes on true 1
1848564d
MT
256}
257
1c6a4e30 258mac_generate() {
fb1416c6
MT
259 local b="$(random 12)"
260
261 # Remove multicast bit
262 # and set address is software assigned
263 local first_byte=$(( 0x${b:0:2} & 0xfe ))
264 first_byte=$(( ${first_byte} | 0x02 ))
1848564d
MT
265
266 local output
fb1416c6 267 printf -v output "%02x" "${first_byte}"
790b7ec9 268
fb1416c6 269 output="${output}:${b:2:2}:${b:4:2}:${b:6:2}:${b:8:2}:${b:10:2}"
1848564d
MT
270
271 # Check if output is valid
fb1416c6 272 assert mac_is_valid "${output}"
1848564d 273
790b7ec9 274 echo "${output}"
1848564d
MT
275}
276
1c6a4e30 277mac_format() {
18b43372 278 local mac=${1}
48bc31eb 279 assert isset mac
18b43372 280
48bc31eb
MT
281 # Remove all colons and make the rest lowercase.
282 mac=${mac//:/}
283 mac=${mac,,}
18b43372 284
48bc31eb 285 local output
18b43372
MT
286 if [ "${#mac}" = "12" ]; then
287 # Add colons (:) to mac address
288 output=${mac:0:2}
289 local i
290 for i in 2 4 6 8 10; do
291 output="${output}:${mac:${i}:2}"
292 done
48bc31eb
MT
293 else
294 output=${mac}
18b43372
MT
295 fi
296
297 assert mac_is_valid ${output}
298
48bc31eb 299 print "${output}"
18b43372
MT
300}
301
1c6a4e30 302mac_is_valid() {
1848564d
MT
303 local mac=${1}
304
305 [[ ${mac} =~ ^([0-9a-f]{2}\:){5}[0-9a-f]{2}$ ]]
306}
307
1c6a4e30 308uuid() {
de543653 309 echo $(</proc/sys/kernel/random/uuid)
1848564d
MT
310}
311
a24cff8f
JS
312abs() {
313 local val=${1}
314
315 if [ ${val} -lt 0 ]; then
316 (( val *= -1 ))
317 fi
318
319 echo ${val}
320}
321
fb1416c6
MT
322rand() {
323 local uuid="$(uuid)"
324 echo "${uuid//-/}"
325}
326
327random() {
328 local length="${1:-8}"
329
330 local random
331 while [ ${#random} -lt ${length} ]; do
332 random="${random}$(rand)"
333 done
334
335 echo "${random:0:${length}}"
336}
337
1c6a4e30 338isset() {
1848564d
MT
339 local var=${1}
340
341 [ -n "${!var}" ]
342}
343
1c6a4e30 344isoneof() {
1848564d
MT
345 local var=${!1}
346 shift
347
e726ef8d 348 list_match "${var}" "$@"
1848564d
MT
349}
350
1c6a4e30 351isbool() {
1848564d
MT
352 local var=${1}
353
ec6afbdd 354 isoneof ${var} 0 1 no yes on off true false
1848564d
MT
355}
356
1c6a4e30 357isinteger() {
1848564d
MT
358 local var=${!1}
359
360 [[ ${var} =~ ^[0-9]+$ ]]
361}
362
1c6a4e30 363ismac() {
1848564d
MT
364 local mac=${!1}
365
366 mac_is_valid ${mac}
367}
368
1c6a4e30 369isipaddress() {
fef4edaf
MT
370 local addr=${!1}
371
372 ip_is_valid ${addr}
373}
374
48a64768
JS
375mtu_is_valid() {
376 local proto=${1}
377 local mtu=${2}
378
379 case ${proto} in
380 ipv4)
381 [ ${mtu} -ge 576 ] && [ ${mtu} -le 9000 ]
382 ;;
383 ipv6)
384 [ ${mtu} -ge 1280 ] && [ ${mtu} -le 9000 ]
385 ;;
386 *)
387 error "${proto} is not a valid proto"
388 return ${EXIT_ERROR}
389 ;;
390 esac
391}
392
1c6a4e30 393backtrace() {
711ffac1
MT
394 local start=1
395
396 echo # Empty line
397 error_log "Backtrace (most recent call in first line):"
398
04608623 399 local i source
711ffac1
MT
400 for i in $(seq ${start} ${#BASH_SOURCE[*]}); do
401 [ -z "${FUNCNAME[${i}]}" ] && continue
6396ccab
MT
402
403 # Print called binary with arguments.
404 if [ "${FUNCNAME[${i}]}" == "main" ]; then
405 local args="$(list_reverse ${BASH_ARGV[*]})"
406 printf -v source "%20s" "$0"
407 error_log " ${source} ${args}"
408 continue
409 fi
711ffac1 410
04608623
MT
411 source=${BASH_SOURCE[$(( ${i} + 1 ))]}
412 error_log " $(printf "%20s" "'${FUNCNAME[${i}]}'") called from ${source:-<shell>}:${BASH_LINENO[${i}]}"
711ffac1
MT
413 done
414}
415
1c6a4e30 416assert() {
1848564d
MT
417 local assertion="$@"
418
419 if ! ${assertion}; then
4c670d7c 420 error_log "Assertion '${assertion}' failed."
711ffac1 421 backtrace
cfbe0802 422 exit ${EXIT_ERROR_ASSERT}
1848564d
MT
423 fi
424
425 return ${EXIT_OK}
426}
cad8bd85 427
b0b2f995
MT
428# This function checks, if the given argument is an assert error
429# exit code. If this is the case, the script will halt immediately.
1c6a4e30 430assert_check_retval() {
b0b2f995
MT
431 local ret=${1}
432
433 if [ ${ret} -eq ${EXIT_ERROR_ASSERT} ]; then
434 exit ${EXIT_ERROR_ASSERT}
435 fi
436
437 return ${ret}
438}
439
2bb20bbd
SS
440# This function executes the given command and inverses the return code
441not() {
442 local command="$@"
443
444 ${command} && return ${EXIT_FALSE} || return ${EXIT_TRUE}
445}
446
1c6a4e30 447exec_cmd() {
711ffac1
MT
448 local cmd=$@
449
450 log DEBUG "Running command: ${cmd}"
451
b816e04b 452 DEBUG=${DEBUG} \
8c63fa13
MT
453 LOG_DISABLE_STDOUT="${LOG_DISABLE_STDOUT}" \
454 LOG_FACILITY="${LOG_FACILITY}" \
b816e04b 455 ${SHELL} ${cmd}
711ffac1
MT
456 local ret=$?
457
458 #log DEBUG "Returned with code '${ret}'"
459
460 if [ ${ret} -eq ${EXIT_ERROR_ASSERT} ]; then
461 error_log "Stopping parent process due to assertion error in child process: ${cmd}"
462 exit ${EXIT_ERROR_ASSERT}
463 fi
464
465 return ${ret}
466}
467
1c6a4e30 468cmd() {
b816e04b
MT
469 local cmd=$@
470
471 log DEBUG "Running command: ${cmd}"
472
11285da0
MT
473 if ! ${cmd}; then
474 local ret=$?
b816e04b 475
11285da0
MT
476 log DEBUG "Returned with code '${ret}'"
477 return ${ret}
478 fi
b816e04b 479
11285da0 480 return ${EXIT_OK}
b816e04b
MT
481}
482
1c6a4e30 483cmd_quiet() {
98146c00 484 cmd $@ &>/dev/null
3efecbb3
MT
485}
486
1c6a4e30 487cmd_exec() {
f80ce052
MT
488 local cmd=$@
489
490 log DEBUG "Exec'ing command: ${cmd}"
491
492 exec ${cmd}
493
494 log ERROR "Could not exec-ute: ${cmd}"
495 exit ${EXIT_ERROR}
496}
497
1c6a4e30 498cmd_not_implemented() {
2181765d
MT
499 assert false "not implemented"
500}
501
de3cecef
MT
502# Runs a command in a clean environment so that no confidential information
503# is leaked to any untrusted commands.
504cmd_clean_environment() {
505 local cmd=$@
506
507 log DEBUG "Running command in a clean environment: ${cmd}"
508 env -i -- ${cmd}
509 local ret=${?}
510
511 log DEBUG "Returned with code '${ret}'"
512 return ${ret}
513}
514
f5ee091e
MT
515# Executes the given command in background
516cmd_background() {
517 cmd_quiet $@ &
518}
519
520# Prints the PID of the process that was started last
521cmd_background_get_pid() {
522 print "${!}"
523}
524
525cmd_background_result() {
526 local pids=$@
527
528 wait ${pids}
529}
530
b8026986 531# Increase security of the read command
1c6a4e30 532read() {
b8026986
MT
533 builtin read -r $@
534}
535
1c6a4e30 536seq() {
3efecbb3
MT
537 if [ $# -eq 2 ]; then
538 eval echo {${1}..${2}}
539 elif [ $# -eq 3 ]; then
540 eval echo {${1}..${3}..${2}}
541 fi
542}
543
de72bd91
MT
544range() {
545 eval echo {0..$(( ${1} - 1 ))}
546}
547
548count() {
549 local i=0
550
551 while read; do
552 ((i++))
553 done
554
555 echo ${i}
556}
557
1c6a4e30 558which() {
76e6cd51
MT
559 type -P $@
560}
561
fe52c5e0 562# Prints the number of seconds since epoch.
1c6a4e30 563timestamp() {
fe52c5e0
MT
564 date -u "+%s"
565}
566
1c6a4e30 567beautify_time() {
d82cf370
MT
568 local value=${1}
569
570 local unit
571 local limit
572 for unit in s m h d w; do
573 case "${unit}" in
574 s|m|h)
575 limit=60
576 ;;
577 d)
578 limit=24
579 ;;
580 w)
581 limit=7
582 ;;
583 esac
584
585 [ ${value} -lt ${limit} ] && break
586
587 value=$(( ${value} / ${limit} ))
588 done
589
590 echo "${value}${unit}"
591}
711ffac1 592
1c6a4e30 593beautify_bytes() {
711ffac1
MT
594 local value=${1}
595
596 local unit
597 local limit=1024
598 for unit in B k M G T; do
599 [ ${value} -lt ${limit} ] && break
600 value=$(( ${value} / ${limit} ))
601 done
602
603 echo "${value}${unit}"
604}
943e3f7e 605
1c6a4e30 606module_load() {
943e3f7e
MT
607 local module=${1}
608
609 if ! grep -q "^${module}" /proc/modules; then
610 log DEBUG "Loading module '${module}'."
611 modprobe ${module}
612 fi
613}
6b3f9c85 614
1c6a4e30 615binary_exists() {
6b3f9c85
MT
616 local binary=${1}
617
618 if [ -n "$(type -p ${binary})" ]; then
619 return ${EXIT_OK}
620 fi
621
622 return ${EXIT_ERROR}
623}
d76f5107 624
1c6a4e30 625function_exists() {
1e6f187e
MT
626 local function="${1}"
627
628 if [ "$(type -t "${function}")" = "function" ]; then
629 return ${EXIT_TRUE}
630 fi
631
632 return ${EXIT_FALSE}
633}
634
1c6a4e30 635process_kill() {
d76f5107
MT
636 local process=${1}
637
638 if ! isinteger process; then
639 process=$(pidof ${process})
640 fi
641
642 local pid
643 local sig
644 for pid in ${process}; do
645 for sig in 15 9; do
646 [ -d "/proc/${pid}" ] || break
647
648 kill -${sig} ${pid}
649 sleep 1
650 done
651 done
652}
feb76eaf 653
1c6a4e30 654dec() {
feb76eaf
MT
655 local hex=${1}
656
657 if [ "${hex:0:2}" != "0x" ]; then
658 hex="0x${hex}"
659 fi
660
661 printf "%d\n" "${hex}"
662}
3a7fef62 663
1c6a4e30 664chr() {
5cf0edf9
MT
665 local char="${1}"
666
667 [ ${char} -lt 256 ] || return ${EXIT_ERROR}
668
669 printf "\\$(( ${char} / 64 * 100 + ${char} % 64 / 8 * 10 + ${char} % 8 ))\n"
670}
671
1c6a4e30 672ord() {
5cf0edf9
MT
673 LC_CTYPE="C" printf "%d\n" "'${1}"
674}
675
1c6a4e30 676hex() {
5cf0edf9
MT
677 printf "%X\n" "${1}"
678}
679
1c6a4e30 680network_is_running() {
3a7fef62
MT
681 # Check, if the network service is running.
682 service_is_active network
683}
f80ce052 684
1c6a4e30 685contains_spaces() {
f80ce052
MT
686 local var="$@"
687
688 # Eliminate spaces.
689 local var2=${var// /}
690
691 if [ ${#var} -ne ${#var2} ]; then
692 return ${EXIT_TRUE}
693 fi
694
695 return ${EXIT_FALSE}
0d645497
MT
696}
697
698string_match() {
699 local match=${1}
700 local string=${2}
701
702 [[ ${string} =~ ${match} ]] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
f80ce052 703}
5cf0edf9 704
1c6a4e30 705string_split() {
5cf0edf9
MT
706 local string="$@"
707
708 local pos=0
709 while [ ${pos} -lt ${#string} ]; do
710 print "${string:${pos}:1}"
711 pos=$(( ${pos} + 1 ))
712 done
713
714 return ${EXIT_OK}
715}
716
1c6a4e30 717string_reverse() {
5cf0edf9
MT
718 local string="$@"
719
720 local output
721 local pos=0
722 while [ ${pos} -lt ${#string} ]; do
723 output="${string:${pos}:1}${output}"
724 pos=$(( ${pos} + 1 ))
725 done
726
727 print "${output}"
728 return ${EXIT_OK}
729}
730
1c6a4e30 731dec2bin() {
5cf0edf9
MT
732 local number="${1}"
733
734 local output
735
736 local i div
737 for i in 7 6 5 4 3 2 1; do
738 div=$(( 2 ** ${i} ))
739
740 if [ $(( ${number} / ${div} )) -eq 1 ]; then
741 output="${output}1"
742 else
743 output="${output}0"
744 fi
745 number="$(( ${number} % ${div} ))"
746 done
747
748 if [ $(( ${number} % 2 )) -eq 1 ]; then
749 output="${output}1"
750 else
751 output="${output}0"
752 fi
753
754 print "${output}"
755}
756
1c6a4e30 757bin2dec() {
5cf0edf9
MT
758 local string="${1}"
759 local number=0
760
761 local pos=0 char
762 while [ ${pos} -lt ${#string} ]; do
763 char="${string:${pos}:1}"
764 pos=$(( ${pos} + 1 ))
765
766 number=$(( ${number} << 1 ))
767
768 case "${char}" in
769 0) ;;
770 1)
771 number=$(( ${number} + 1 ))
772 ;;
773 *)
774 assert false "Invalid character: ${char}"
775 ;;
776 esac
777 done
778
779 print "${number}"
780 return ${EXIT_OK}
781}
782
1c6a4e30 783char2bin() {
5cf0edf9
MT
784 local dec="$(ord "${1}")"
785
786 dec2bin "${dec}"
787}
788
1c6a4e30 789bin2char() {
5cf0edf9
MT
790 local dec="$(bin2dec "$@")"
791
792 chr "${dec}"
793}
794
1c6a4e30 795bin2hex() {
5cf0edf9
MT
796 local dec="$(bin2dec "$@")"
797
798 dec2hex "${dec}"
799}
800
1c6a4e30 801hex2bin() {
5cf0edf9
MT
802 local dec="$(hex2dec "$@")"
803
804 dec2bin "${dec}"
805}
806
1c6a4e30 807hex2dec() {
5cf0edf9
MT
808 local hex="${1}"
809
810 # Prepend 0x if necessary.
811 [ "${hex:0:2}" = "0x" ] || hex="0x${hex}"
812
813 printf "%d\n" "${hex}"
814}
815
1c6a4e30 816dec2hex() {
5cf0edf9
MT
817 printf "%02x\n" "${1}"
818}
a95d16fc 819
10b53c87 820# This function just copy config files
a95d16fc 821copy() {
a95d16fc
JS
822 assert [ $# -eq 2 ]
823
824 local src=${1}
825 local dst=${2}
826
287c2e60
MT
827 # Check if we can read from the source
828 if [ ! -r "${src}" ]; then
829 log ERROR "Cannot read ${src}"
830 return ${EXIT_ERROR}
831 fi
832
a95d16fc 833 # Check if ${dst} is a directory
1fade616 834 if [ -d "${dst}" ]; then
9c802e1d 835 log ERROR "${dst} is a directory"
a95d16fc
JS
836 return ${EXIT_ERROR}
837 fi
838
839 if ! fread "${src}" > "${dst}"; then
840 log ERROR "Could not copy data from ${src} to ${dst}"
841 return ${EXIT_ERROR}
842 fi
843}