lock_acquire: Refactor function to set the timeout manually and to avoid the sleep of 0,25s when the timeout value is zero.
lock_exists: Provides an easier to check if a lock exists
Signed-off-by: Jonatan Schlag jonatan.schlag@ipfire.org --- src/functions/functions.device | 2 +- src/functions/functions.lock | 37 +++++++++++++++++++++++++++---------- src/udev/network-hotplug-rename | 2 +- 3 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/src/functions/functions.device b/src/functions/functions.device index fc88fec..09848e2 100644 --- a/src/functions/functions.device +++ b/src/functions/functions.device @@ -910,7 +910,7 @@ device_auto_configure_smp_affinity() {
local device=${1}
- if lock_acquire "smp-affinity"; then + if lock_acquire "smp-affinity" 60; then device_set_smp_affinity ${device} auto
lock_release "smp-affinity" diff --git a/src/functions/functions.lock b/src/functions/functions.lock index fac86bd..d9c3acf 100644 --- a/src/functions/functions.lock +++ b/src/functions/functions.lock @@ -29,30 +29,47 @@ __lock_path() { fi }
-lock_acquire() { +lock_exists() { local name=${1} assert isset name
local lockfile=$(__lock_path ${name})
+ if [ -e "${lockfile}" ]; then + return ${EXIT_TRUE} + else + return ${EXIT_FALSE} + fi +} + +lock_acquire() { + local name=${1} + assert isset name + # timeout value in seconds - local timeout=120 + local timeout=${2} + + if ! isset timeout; then + timeout=0 + fi + + local lockfile=$(__lock_path ${name}) + timeout=$(( ${timeout} * 4 ))
log DEBUG "Acquiring lock '${name}'"
- local free="false" - while [ ${timeout} -gt 0 ]; do - if [ ! -e "${lockfile}" ]; then - free="true" - break - fi - + # Wait until lock is available + while [ ${timeout} -gt 0 ] && [ -e "${lockfile}" ]; do timeout=$(( ${timeout} - 1 )) sleep 0.25 done
- assert ${free} "Could not acquire lock '${name}'" + # If another lock still exists, we return an error + if [ -e "${lockfile}" ]; then + error "Could not acquire lock '${name}'" + return ${EXIT_ERROR} + fi
# Write out pid to the lockfile and make sure that # nobody else can access it. diff --git a/src/udev/network-hotplug-rename b/src/udev/network-hotplug-rename index c56c70d..2d474ef 100644 --- a/src/udev/network-hotplug-rename +++ b/src/udev/network-hotplug-rename @@ -45,7 +45,7 @@ log DEBUG "Called for interface '${INTERFACE}'." device_exists ${INTERFACE} || exit ${EXIT_ERROR}
# Acquiring lock for this operation. -lock_acquire ${LOCKFILE} +lock_acquire ${LOCKFILE} 120
# Check if the device is already in use and # prevent the script to touch it in any way.
Signed-off-by: Jonatan Schlag jonatan.schlag@ipfire.org --- Makefile.am | 1 + src/functions/functions.description | 185 ++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 src/functions/functions.description
diff --git a/Makefile.am b/Makefile.am index 108e7a7..61c520c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -114,6 +114,7 @@ dist_network_SCRIPTS = \ src/functions/functions.constants \ src/functions/functions.constants-firewall \ src/functions/functions.db \ + src/functions/functions.description \ src/functions/functions.device \ src/functions/functions.dhclient \ src/functions/functions.dhcpd \ diff --git a/src/functions/functions.description b/src/functions/functions.description new file mode 100644 index 0000000..0db8ede --- /dev/null +++ b/src/functions/functions.description @@ -0,0 +1,185 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2017 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +description_format_filename() { + # Format the filename of a description file for a given zone or port + local type=${1} + local name=${2} + + case ${type} in + zone) + echo "$(zone_dir ${name})/description" + ;; + port) + echo "$(port_dir ${name})/description" + ;; + esac +} + +description_touch_file() { + # If the description file does not exist + # and we have no directory with the given name this function creates the file + local type=${1} + local name=${2} + + local file=$(description_format_filename ${type} ${name}) + + # We use the -e switch here because we want to touch + # when also no directory with this name exist + if ! [ -e ${file} ]; then + touch ${file} + fi + +} +description_title_read() { + # This function reads the title out of a given description file + local file=${1} + assert isset file + + [ -r "${file}" ] || return ${EXIT_ERROR} + + local title + read -r title < ${file} + echo ${title} +} + +description_edit() { + # This function provides a higher level interface special for description files of the editor function. + local type=${1} + local name=${2} + + description_touch_file ${type} ${name} + + local file=$(description_format_filename ${type} ${name}) + editor ${file} "description_check" +} + +description_print() { + # This function prints a given description file. + local type=${1} + local name=${2} + + local file=$(description_format_filename ${type} ${name}) + + if [ ! -r "${file}" ] || [ ! -f "${file}" ]; then + warning "${file} is not readable" + return ${EXIT_ERROR} + fi + + local title=$(description_title_read ${file}) + + cli_headline 1 "Description" + cli_space + cli_print 2 "${title}" + cli_space + + # True if we are in the first line + local first_line=true + + # True if we get from the second line on, only whitespace or empty lines + local front_white=true + + # How many blank lines did we get + local white_counter=0 + + while read line; do + if ${first_line}; then + # We are in the first line and pass they so first_line is now false + first_line=false + continue + fi + # Check if the line is blank or contain only whitespace + if ${front_white} && [[ "${line}" =~ ^(|[[:space:]]+)$ ]]; then + # The we do not print them + continue + else + # we have found after the second line which is not blank or contain only white space so + # front_white is false. Now ew print empyt line but only if they are follewd by a non empty line. + front_white=false + if [[ "${line}" == "" ]] || [[ "${line}" =~ ^[[:space:]]$ ]]; then + # If the line is blank or contain only white space we increase the counter. + (( white_counter++ )) + else + # The line is not blank so we print all blank lines till now and print the current line after. + if [ ${white_counter} -gt 0 ]; then + for (( i = 1; i <= ${white_counter}; i += 1 )); do + cli_space + done + + # The counter is now zero, because the lines were printed. + white_counter=0 + fi + cli_print 2 "${line}" + fi + fi + done < ${file} + + cli_space +} + +description_cli() { + # Function for the command line interface + local type=${1} + local name=${2} + local action=${3} + shift 3 + + case ${action} in + show) + description_print ${type} ${name} ${@} + ;; + edit) + description_edit ${type} ${name} ${@} + ;; + *) + error "Invalid argument: ${action}" + ;; + esac + +} + +description_check_title() { + # Checks if the title is too long and if so prints a warning + assert [ $# -eq 1 ] + + local title=${1} + local title_length=40 + + # Have to be shorter then ${title_length} + if [ ${#title} -gt ${title_length} ]; then + warning "Title '${title}' is to long. Only titles with ${title_length} or less chracters are allowed" + return ${EXIT_ERROR} + fi + + return ${EXIT_OK} +} + +description_check() { + # Check if a description file satisfy our needs + assert [ $# -eq 1 ] + + local file=${1} + local title=$(description_title_read ${file}) + + description_check_title "${title}" + + return ${EXIT_OK} +}
Signed-off-by: Jonatan Schlag jonatan.schlag@ipfire.org --- Makefile.am | 1 + src/functions/functions.editor | 149 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/functions/functions.editor
diff --git a/Makefile.am b/Makefile.am index 61c520c..32e7166 100644 --- a/Makefile.am +++ b/Makefile.am @@ -121,6 +121,7 @@ dist_network_SCRIPTS = \ src/functions/functions.distro \ src/functions/functions.dns \ src/functions/functions.dummy \ + src/functions/functions.editor \ src/functions/functions.ethernet \ src/functions/functions.firewall \ src/functions/functions.firewall-policy \ diff --git a/src/functions/functions.editor b/src/functions/functions.editor new file mode 100644 index 0000000..f362a6f --- /dev/null +++ b/src/functions/functions.editor @@ -0,0 +1,149 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2017 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +editor_cleanup() { + # Cleanup after a file was edited + assert [ $# -eq 2 ] + + local file=${1} + local temp_file=${2} + + lock_release "${file}.lock" + rm -f ${temp_file} +} + +editor_find_best() { + # Open a file with the best available editor + assert [ $# -eq 1 ] + + local file=${1} + local ret + + for editor in ${EDITOR} vim vi; do + ${editor} "${file}" + ret=${?} + + case "${ret}" in + ${EXIT_OK}) + return ${EXIT_OK} + ;; + + ${EXIT_COMMAND_NOT_FOUND}) + continue + ;; + + *) + return ${ret} + ;; + esac + done + + error "Unable to find a working editor" + + return ${EXIT_COMMAND_NOT_FOUND} +} + +editor() { + # This function open a file for editing and take care of all preperation and postprocessing + assert [ $# -ge 1 ] + + local file=${1} + if [ ! -f ${file} ] || [ ! -w ${file} ]; then + error "${file} is not valid file or is not writeable" + return ${EXIT_ERROR} + fi + + local check_func=${2} + + # check if the file is locked + if lock_exists "${file}.lock"; then + error "Cannot edit ${file} because it is locked" + return ${EXIT_ERROR} + fi + + # lock the file + if ! lock_acquire "${file}.lock"; then + error "Cannot lock file ${file}" + return ${EXIT_ERROR} + fi + + # create a temporary file + local temp_file=$(mktemp) + + if ! [ -f "${temp_file}" ]; then + error "Cannot create temporary file" + fi + + # copy the content into this temporary file + cp -f "${file}" "${temp_file}" + + # edit the file + if ! editor_find_best "${temp_file}"; then + error "Could not edit ${file}" + # cleanup + editor_cleanup "${file}" "${temp_file}" + fi + + # run the check if we have one + if isset check_func && ! editor_check "${check_func}" "${temp_file}"; then + return ${EXIT_ERROR} + fi + + # copy the changes back + cp -f "${temp_file}" "${file}" + + # cleanup + editor_cleanup "${file}" "${temp_file}" + +} + +editor_check() { + # Execute the check function to make sure that the changes does not break anything + local check_func="${1}" + shift + + # Execute the check function + "${check_func}" $@ + local ret="${?}" + + case "${ret}" in + # OK + ${EXIT_OK}|${EXIT_TRUE}) + log DEBUG "Check succeeded" + return ${EXIT_TRUE} + ;; + + # Error + ${EXIT_ERROR}|${EXIT_FALSE}) + log CRITICAL "Check failed" + return ${EXIT_FALSE} + ;; + + # Command not found + ${EXIT_COMMAND_NOT_FOUND}) + log CRITICAL "Check function '${check_func}' was not found" + return ${EXIT_FALSE} + ;; + esac + + log CRITICAL "Unhandled exit code for '${check_func}': ${ret}" + return ${EXIT_ERROR} +}