This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2goserver. commit ab860507f6c2062b9864ebac05bd83079cf36671 Author: Mihai Moldovan <ionic@ionic.de> Date: Thu Jan 4 03:04:50 2018 +0100 x2goserver/lib: new script x2gogetfreeport, consists of duplicated functionality in x2gostartagent. Cherry-picked from release/4.0.1.x branch. --- debian/changelog | 2 + x2goserver/lib/x2gogetfreeport | 169 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/debian/changelog b/debian/changelog index 2a280e2..bf9de4c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -295,6 +295,8 @@ x2goserver (4.0.1.23-0x2go1) UNRELEASED; urgency=medium substitution. - x2goserver/bin/x2gostartagent: some shells do not handle quotes in pattern substitutions gracefully. Remove them. + - x2goserver/lib: new script x2gogetfreeport, consists of duplicated + functionality in x2gostartagent. * x2goserver.spec: - RPMify x2goserver-xsession description. - Remove qt4 stuff, we're not using the framework here. diff --git a/x2goserver/lib/x2gogetfreeport b/x2goserver/lib/x2gogetfreeport new file mode 100755 index 0000000..2f91297 --- /dev/null +++ b/x2goserver/lib/x2gogetfreeport @@ -0,0 +1,169 @@ +#!/bin/bash + +# Copyright (C) 2017-2018 X2Go Project - https://wiki.x2go.org +# +# 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 2 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, write to the +# Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +# Get first free port. +# Takes a command for ss, the port type, a start andan end port +# as parameters. +# If an ss command is not given, a default of "ss" is assumed. +# If the port type is not given, a default of "lowlevel" is assumed. +# If the start port is not given, a default of 1 is assumed. +# If the end port is not given, a default of 65535 is assumed. +# Valid values for the port type are "lowlevel" and "display". +# Prints the first free port value on success, or the initial start +# port number on failure. +# Returns 0 on success or non-0 on failure. +typeset ss="${1:-"ss"}" +typeset type="${2:-"lowlevel"}" +typeset start="${3:-"1"}" +typeset end="${4:-"65535"}" + +# Check parameter sanity. +typeset empty_regex='^[[:space:]]*$' +if [[ -z "${ss}" ]] || [[ "${ss}" =~ ${empty_regex} ]]; then + exit "1" +fi +typeset -i start_i="${start}" +typeset -i end_i="${end}" +if [[ -z "${start}" ]] || [[ "${start}" != "${start_i}" ]] || [[ "${start}" -ne "${start_i}" ]]; then + exit "2" +fi +if [[ -z "${end}" ]] || [[ "${end}" != "${end_i}" ]] || [[ "${end}" -ne "${end_i}" ]]; then + exit "3" +fi +[[ "${type}" != 'lowlevel' ]] && [[ "${type}" != 'display' ]] && exit "4" + + +# Skip unnecessary work. +if [[ "${type}" = 'display' ]]; then + typeset -a used_displays + typeset -a used_displays_work + used_displays=() + used_displays_work=() + # What this does is very unobvious, so here's how that works: + # The -d parameter with an empty string as its argument makes + # the read utility process a "line" until the first such delimiter + # is found. Since an empty string in C is terminated by a NULL + # character, the delimiter will be set to this NULL character. + # Hence, assuming that the input string does not contain any + # NULL characters, the whole input string will be treated as + # one big line. + # Then, normal word splitting kicks in and the -a flag tells + # read to put all words into elements of the provided array + # variable. + IFS="${IFS}|" read -r -d '' -a used_displays_work < <("${X2GO_LIB_PATH}/x2gogetdisplays" "${current_host_name}") + + # Filter out any empty or invalid values. + typeset -i item_i='0' + typeset item='' + for item in "${used_displays_work[@]}"; do + item_i="${item}" + + [[ -n "${item}" ]] && [[ "${item}" -eq "${item_i}" ]] && [[ "${item}" = "${item_i}" ]] && used_displays+=( "${item}" ) + done +fi + +# Same algorithm again for the system ports in use, but we cannot really +# use a function to duplicate code less since arrays and functions don't +# mix well in bash. + +# Get all used in system ports from X2Go database and ss output +typeset -a used_ports +typeset -a used_ports_work +used_ports=() +used_ports_work=() +IFS="${IFS}|" read -r -d '' -a used_ports_work < <("${X2GO_LIB_PATH}/x2gogetports" "${current_host_name}"; + "${ss}" -nt -all | awk ' + { + n = split ($0, lines, "\n"); + for (i = 1; i <= n; ++i) { + split (lines[i], words, " "); + delim = split (words[4], ports, ":"); + if (delim > 1) { + printf ("\n%d\n", ports[delim]) + } + } + }') + +# Filter out any empty or invalid values. +item_i='0' +item='' +for item in "${used_ports_work[@]}"; do + item_i="${item}" + + [[ -n "${item}" ]] && [[ "${item}" -eq "${item_i}" ]] && [[ "${item}" = "${item_i}" ]] && used_ports+=( "${item}" ) +done + +typeset -i ret_port="${start}" +typeset -i ret='1' +typeset -i work_port='0' +typeset -i stop_port='65535' +[[ "${type}" = 'display' ]] && stop_port="$((stop_port - 6000))" +# Find the next free port number. +for ((work_port = start; i <= stop_port; ++work_port)); do + typeset -i i="0" + typeset -i value_found="0" + + if [[ "${type}" = 'display' ]]; then + for ((i = 0; i < ${#used_displays[@]}; ++i)); do + if [[ "${used_displays[i]}" = "${work_port}" ]]; then + # We need to continue with the next port number, + # this one is taken. + value_found="1" + break + fi + done + + # Check if such a socket is already in use system-wide. + if "${ss}" -lxs 2>"/dev/null" | grep -Eqs "(@|)/tmp/.X11-unix/X${work_port}(|-lock) " >"/dev/null"; then + continue + fi + fi + + # Port number taken? Continue with the next one. + [[ "${value_found}" -ne "0" ]] && continue + + # Check raw port number. Either to make sure that the corresponding + # raw port for the DISPLAY port found is still free, or also in the + # general case. + typeset -i map_port="${work_port}" + [[ "${type}" = 'display' ]] && map_port="$((map_port + 6000))" + for ((i = 0; i < ${#used_ports[@]}; ++i)); do + if [[ "${used_ports[i]}" = "${map_port}" ]]; then + value_found="1" + break + fi + done + + # Port number taken? Continue with the next one. + [[ "${value_found}" -ne "0" ]] && continue + + # If the port is a well-known one, don't block it. + grep -qs "${work_port}" "/etc/services" &>"/dev/null" && continue + + # Searched the array and got nothing? Great, grab that port number! + ret_port="${work_port}" + ret='0' + break +done + +# At this point, ${ret} and ${ret_port} should be set up correctly. +# Either to the first free port value if one has been found (and ${ret} +# to zero) or to the start port value (and ${ret} to one.) +printf '%d\n' "${ret_port}" +exit "${ret}" -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2goserver.git