diff options
36 files changed, 1376 insertions, 182 deletions
diff --git a/krebs/3modules/lass/default.nix b/krebs/3modules/lass/default.nix index c99263fe8..26b0947bb 100644 --- a/krebs/3modules/lass/default.nix +++ b/krebs/3modules/lass/default.nix @@ -9,7 +9,7 @@ with lib; dc = "lass"; #dc = "cac"; nets = rec { internet = { - addrs4 = ["167.88.34.158"]; + addrs4 = ["162.252.241.33"]; aliases = [ "echelon.internet" ]; diff --git a/krebs/3modules/makefu/default.nix b/krebs/3modules/makefu/default.nix index 652527da2..037abbdfd 100644 --- a/krebs/3modules/makefu/default.nix +++ b/krebs/3modules/makefu/default.nix @@ -245,6 +245,8 @@ with lib; extraZones = { "krebsco.de" = '' share.euer IN A ${head nets.internet.addrs4} + mattermost.euer IN A ${head nets.internet.addrs4} + git.euer IN A ${head nets.internet.addrs4} gum IN A ${head nets.internet.addrs4} ''; }; diff --git a/krebs/3modules/mv/default.nix b/krebs/3modules/mv/default.nix index 446caf454..6da2abc85 100644 --- a/krebs/3modules/mv/default.nix +++ b/krebs/3modules/mv/default.nix @@ -13,6 +13,7 @@ with lib; addrs6 = ["42:0:0:0:0:0:111:111"]; aliases = [ "stro.retiolum" + "cgit.stro.retiolum" ]; tinc.pubkey = '' -----BEGIN RSA PUBLIC KEY----- diff --git a/krebs/5pkgs/cacpanel/default.nix b/krebs/5pkgs/cacpanel/default.nix new file mode 100644 index 000000000..3e3e2e1fc --- /dev/null +++ b/krebs/5pkgs/cacpanel/default.nix @@ -0,0 +1,18 @@ +{pkgs, python3Packages, ...}: + +python3Packages.buildPythonPackage rec { + name = "cacpanel-${version}"; + version = "0.2.1"; + + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/source/c/cacpanel/cacpanel-${version}.tar.gz"; + sha256 = "1zaazg5r10kgva32zh4fhpw6l6h51ijkwpa322na0kh4x6f6aqj3"; + }; + + propagatedBuildInputs = with python3Packages; [ + docopt + requests2 + beautifulsoup4 + ]; +} + diff --git a/krebs/5pkgs/drivedroid-gen-repo/default.nix b/krebs/5pkgs/drivedroid-gen-repo/default.nix index 087f97c9a..de8046c4a 100644 --- a/krebs/5pkgs/drivedroid-gen-repo/default.nix +++ b/krebs/5pkgs/drivedroid-gen-repo/default.nix @@ -2,7 +2,7 @@ python3Packages.buildPythonPackage rec { name = "drivedroid-gen-repo-${version}"; - version = "0.4.2"; + version = "0.4.4"; propagatedBuildInputs = with pkgs;[ python3Packages.docopt @@ -10,7 +10,7 @@ python3Packages.buildPythonPackage rec { src = fetchurl { url = "https://pypi.python.org/packages/source/d/drivedroid-gen-repo/drivedroid-gen-repo-${version}.tar.gz"; - sha256 = "1w4dqc9ndyiv5kjh2y8n4p4c280vhqyj8s7y6al2klchcp2ab7q7"; + sha256 = "09p58hzp61r5fp025lak9z52y0aakmaqpi59p9w5xq42dvy2hnvl"; }; meta = { diff --git a/krebs/5pkgs/get/default.nix b/krebs/5pkgs/get/default.nix index d4f5f6b46..9a0192aab 100644 --- a/krebs/5pkgs/get/default.nix +++ b/krebs/5pkgs/get/default.nix @@ -4,7 +4,7 @@ stdenv.mkDerivation { name = "get-1.3.1"; src = fetchgit { - url = http://cgit.cd.retiolum/get; + url = http://cgit.cd.krebsco.de/get; rev = "64c97edd3f9952cd5e703208c46748a035a515bf"; sha256 = "32ca83f4fd86fd3285bef9dcfd0917308086d239189858daceca175de49ff97c"; }; diff --git a/krebs/5pkgs/haskell-overrides/blessings.nix b/krebs/5pkgs/haskell-overrides/blessings.nix index 311458211..741fb5c36 100644 --- a/krebs/5pkgs/haskell-overrides/blessings.nix +++ b/krebs/5pkgs/haskell-overrides/blessings.nix @@ -3,7 +3,7 @@ mkDerivation { pname = "blessings"; version = "1.0.0"; src = fetchgit { - url = http://cgit.cd.retiolum/blessings; + url = http://cgit.cd.krebsco.de/blessings; rev = "25a510dcb38ea9158e9969d56eb66cb1b860ab5f"; sha256 = "b962153e80e51519b52220199d8350b54154833e4bc25a792ecc58898fef3fb2"; }; diff --git a/krebs/5pkgs/haskell-overrides/scanner.nix b/krebs/5pkgs/haskell-overrides/scanner.nix index ebc5cd620..b88b9dbe3 100644 --- a/krebs/5pkgs/haskell-overrides/scanner.nix +++ b/krebs/5pkgs/haskell-overrides/scanner.nix @@ -3,7 +3,7 @@ mkDerivation { pname = "scanner"; version = "1.0.0"; src = fetchgit { - url = http://cgit.cd.retiolum/scanner; + url = http://cgit.cd.krebsco.de/scanner; rev = "7f091a3bc152ad3974a1873b460fa1759bf8dcad"; sha256 = "7d123c227777932039d26fc832b8d32a90f04c0bd6b7e8bcff0a6f49a54e0054"; }; diff --git a/krebs/5pkgs/haskell-overrides/xmonad-stockholm.nix b/krebs/5pkgs/haskell-overrides/xmonad-stockholm.nix index 5c6f068e7..096597808 100644 --- a/krebs/5pkgs/haskell-overrides/xmonad-stockholm.nix +++ b/krebs/5pkgs/haskell-overrides/xmonad-stockholm.nix @@ -5,7 +5,7 @@ mkDerivation { pname = "xmonad-stockholm"; version = "1.0.0"; src = fetchgit { - url = "http://cgit.cd/xmonad-stockholm"; + url = "http://cgit.cd.krebsco.de/xmonad-stockholm"; sha256 = "35dda5d16acc90af94ae2fae10ab5cc2d5b450c3f1ff2e7f515ac53877269abf"; rev = "2dbefe42fc5cfe9093465bf3e22ba8f82feeef6e"; }; diff --git a/krebs/5pkgs/much/default.nix b/krebs/5pkgs/much/default.nix index ba5ab2327..2a9376139 100644 --- a/krebs/5pkgs/much/default.nix +++ b/krebs/5pkgs/much/default.nix @@ -12,7 +12,7 @@ mkDerivation { pname = "much"; version = "1.0.0"; src = fetchgit { - url = "http://cgit.cd.retiolum/much"; + url = "http://cgit.cd.krebsco.de/much"; rev = "045dc986b4de225a927175f81c8ccfdab450202c"; sha256 = "cec175e3dc32ef93029ee5285f6c4042ce11d637945bc8cec02cb6699d06cc13"; }; diff --git a/krebs/5pkgs/push/default.nix b/krebs/5pkgs/push/default.nix index bc5c030a0..13769c747 100644 --- a/krebs/5pkgs/push/default.nix +++ b/krebs/5pkgs/push/default.nix @@ -12,7 +12,7 @@ stdenv.mkDerivation { name = "push-1.1.1"; src = fetchgit { - url = http://cgit.cd.retiolum/push; + url = http://cgit.cd.krebsco.de/push; rev = "ea8b76569c6b226fe148e559477669b095408472"; sha256 = "c305a1515d30603f6ed825d44487e863fdc7d90400620ceaf2c335a3b5d1e221"; }; diff --git a/krebs/Zhosts/stro b/krebs/Zhosts/stro new file mode 100644 index 000000000..cddab5421 --- /dev/null +++ b/krebs/Zhosts/stro @@ -0,0 +1,10 @@ +Subnet = 10.243.111.111/32 +Subnet = 42:0:0:0:0:0:111:111/128 +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEA0vIzLyoetOyi3R7qOh3gjSvUVjPEdqCvd0NEevDCIhhFy0nIbZ/b +vnuk3EUeTb6e384J8fKB4agig0JeR3JjtDvtjy5g9Cdy2nrU71w8wqU0etmv2PTb +FjbCFfeBXn0N3U7gXwjZGCvjAXa1a4jGb4R2iYBYGG3aY4reCN8B8Ah81h+S0oLg +ZJJfaBmWM5vNRFEI5X4CLaVnwtsoZuXIjYStgNn/9Mg/Y6NQS0H0H+HFeyhigAqG +oYGqNar/2QqPU176V/FwrD30F3qJV1uyzuPta7hmdfOxqYjZ/jqdPSRYtlunYYcq +XbH5oYmzO9NEeVWzjdac/DiV2OP8HufoYwIDAQAB +-----END RSA PUBLIC KEY----- diff --git a/lass/3modules/bitlbee.nix b/lass/3modules/bitlbee.nix deleted file mode 100644 index 8ce560146..000000000 --- a/lass/3modules/bitlbee.nix +++ /dev/null @@ -1,153 +0,0 @@ -{ config, lib, pkgs, ... }: - - -let - - inherit (lib) - mkIf - mkOption - types - singleton - ; - - authModeCheck = v: - v == "Open" || - v == "Closed" || - v == "Registered" - ; - - bitlbeeConfig = pkgs.writeText "bitlbee.conf" '' - [settings] - RunMode = Daemon - User = bitlbee - ConfigDir = ${cfg.configDir} - DaemonInterface = ${cfg.interface} - DaemonPort = ${toString cfg.portNumber} - AuthMode = ${cfg.authMode} - ${lib.optionalString (cfg.hostName != "") "HostName = ${cfg.hostName}"} - ${lib.optionalString (cfg.protocols != "") "Protocols = ${cfg.protocols}"} - ${cfg.extraSettings} - - [defaults] - ${cfg.extraDefaults} - ''; - - cfg = config.lass.bitlbee; - - out = { - options.lass.bitlbee = api; - config = mkIf cfg.enable imp; - }; - - api = { - enable = mkOption { - default = false; - description = '' - Whether to run the BitlBee IRC to other chat network gateway. - Running it allows you to access the MSN, Jabber, Yahoo! and ICQ chat - networks via an IRC client. - ''; - }; - - interface = mkOption { - default = "127.0.0.1"; - description = '' - The interface the BitlBee deamon will be listening to. If `127.0.0.1', - only clients on the local host can connect to it; if `0.0.0.0', clients - can access it from any network interface. - ''; - }; - - portNumber = mkOption { - default = 6667; - description = '' - Number of the port BitlBee will be listening to. - ''; - }; - - authMode = mkOption { - default = "Open"; - type = types.addCheck types.str authModeCheck; - description = '' - The following authentication modes are available: - Open -- Accept connections from anyone, use NickServ for user authentication. - Closed -- Require authorization (using the PASS command during login) before allowing the user to connect at all. - Registered -- Only allow registered users to use this server; this disables the register- and the account command until the user identifies himself. - ''; - }; - - hostName = mkOption { - default = ""; - type = types.str; - description = '' - Normally, BitlBee gets a hostname using getsockname(). If you have a nicer - alias for your BitlBee daemon, you can set it here and BitlBee will identify - itself with that name instead. - ''; - }; - - configDir = mkOption { - default = "/var/lib/bitlbee"; - type = types.path; - description = '' - Specify an alternative directory to store all the per-user configuration - files. - ''; - }; - - protocols = mkOption { - default = ""; - type = types.str; - description = '' - This option allows to remove the support of protocol, even if compiled - in. If nothing is given, there are no restrictions. - ''; - }; - - extraSettings = mkOption { - default = ""; - description = '' - Will be inserted in the Settings section of the config file. - ''; - }; - - extraDefaults = mkOption { - default = ""; - description = '' - Will be inserted in the Default section of the config file. - ''; - }; - - bitlbeePkg = mkOption { - default = pkgs.bitlbee; - description = '' - the bitlbee pkg to use. - ''; - }; - }; - - imp = { - users.extraUsers = singleton { - name = "bitlbee"; - uid = config.ids.uids.bitlbee; - description = "BitlBee user"; - home = "/var/lib/bitlbee"; - createHome = true; - }; - - users.extraGroups = singleton { - name = "bitlbee"; - gid = config.ids.gids.bitlbee; - }; - - systemd.services.bitlbee = { - description = "BitlBee IRC to other chat networks gateway"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig.User = "bitlbee"; - serviceConfig.ExecStart = "${cfg.bitlbeePkg}/sbin/bitlbee -F -n -c ${bitlbeeConfig}"; - }; - }; - -in -out diff --git a/lass/3modules/default.nix b/lass/3modules/default.nix index 7c85af3a4..0dcad971c 100644 --- a/lass/3modules/default.nix +++ b/lass/3modules/default.nix @@ -2,7 +2,6 @@ _: { imports = [ ./xresources.nix - ./bitlbee.nix ./folderPerms.nix ./newsbot-js.nix ./per-user.nix diff --git a/lass/3modules/dnsmasq.nix b/lass/3modules/dnsmasq.nix index 99c165479..83a9cb180 100644 --- a/lass/3modules/dnsmasq.nix +++ b/lass/3modules/dnsmasq.nix @@ -25,13 +25,6 @@ let configFile = pkgs.writeText "dnsmasq.conf" cfg.config; imp = { - #users.extraUsers.go = { - # name = "go"; - # uid = 42774411; #genid go - # description = "go url shortener user"; - # home = "/var/lib/go"; - # createHome = true; - #}; systemd.services.dnsmasq = { description = "dnsmasq"; diff --git a/makefu/1systems/gum.nix b/makefu/1systems/gum.nix index 9de07266e..75607aa46 100644 --- a/makefu/1systems/gum.nix +++ b/makefu/1systems/gum.nix @@ -13,15 +13,21 @@ in { ../2configs/fs/single-partition-ext4.nix # ../2configs/iodined.nix ../2configs/git/cgit-retiolum.nix - + ../2configs/mattermost-docker.nix ]; + + + ###### stable krebs.build.target = "root@gum.krebsco.de"; krebs.build.host = config.krebs.hosts.gum; + + # Chat environment.systemPackages = with pkgs;[ weechat bepasty-client-cli + get ]; services.bitlbee.enable = true; @@ -31,7 +37,6 @@ in { boot.kernelModules = [ "kvm-intel" ]; # Network - services.udev.extraRules = '' SUBSYSTEM=="net", ATTR{address}=="c8:0a:a9:c8:ee:dd", NAME="et0" ''; diff --git a/makefu/2configs/base-gui.nix b/makefu/2configs/base-gui.nix index 7b7f85f13..16a5386ca 100644 --- a/makefu/2configs/base-gui.nix +++ b/makefu/2configs/base-gui.nix @@ -10,6 +10,17 @@ # # if this is not enough, check out main-laptop.nix +## TODO: .Xdefaults: +# URxvt*termName: rxvt +# URxvt.scrollBar : false +# URxvt*scrollBar_right: false +# URxvt*borderLess: false +# URxvt.foreground: white +# URxvt.background: black +# URxvt.urgentOnBell: true +# URxvt.visualBell: false +# URxvt.font : xft:Terminus + with lib; let mainUser = config.krebs.build.user.name; diff --git a/makefu/2configs/default.nix b/makefu/2configs/default.nix index 3d9174788..760c70789 100644 --- a/makefu/2configs/default.nix +++ b/makefu/2configs/default.nix @@ -65,6 +65,7 @@ with lib; time.timeZone = "Europe/Berlin"; #nix.maxJobs = 1; + programs.ssh.startAgent = false; services.openssh.enable = true; nix.useChroot = true; diff --git a/makefu/2configs/git/cgit-retiolum.nix b/makefu/2configs/git/cgit-retiolum.nix index e12827697..304d39fcd 100644 --- a/makefu/2configs/git/cgit-retiolum.nix +++ b/makefu/2configs/git/cgit-retiolum.nix @@ -15,6 +15,7 @@ let tinc_graphs = { desc = "Tinc Advanced Graph Generation"; }; + cac = { }; }; priv-repos = mapAttrs make-priv-repo { @@ -23,6 +24,9 @@ let connector-repos = mapAttrs make-priv-repo { connector = { }; + mattermost = { + desc = "Mattermost Docker files"; + }; }; diff --git a/makefu/2configs/mattermost-docker.nix b/makefu/2configs/mattermost-docker.nix new file mode 100644 index 000000000..20a93dff1 --- /dev/null +++ b/makefu/2configs/mattermost-docker.nix @@ -0,0 +1,47 @@ +{config, lib, ...}: + +with lib; +let + sec = toString <secrets>; + ssl_cert = "${sec}/wildcard.krebsco.de.crt"; + ssl_key = "${sec}/wildcard.krebsco.de.key"; +in { + # mattermost docker config and deployment guide: git.euer.krebsco.de + virtualisation.docker.enable = true; + users.extraUsers.${config.krebs.build.user.name}.extraGroups = [ "docker" ]; + krebs.nginx = { + enable = true; + servers.mattermost = { + listen = [ "80" "443 ssl" ]; + server-names = [ "mattermost.euer.krebsco.de" ]; + extraConfig = '' + gzip on; + gzip_buffers 4 32k; + gzip_types text/plain application/x-javascript text/css; + ssl_certificate ${ssl_cert}; + ssl_certificate_key ${ssl_key}; + default_type text/plain; + + if ($scheme = http){ + return 301 https://$server_name$request_uri; + } + + client_max_body_size 4G; + keepalive_timeout 10; + + ''; + locations = [ + (nameValuePair "/" '' + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_redirect off; + proxy_pass http://localhost:8065/; + '') + ]; + }; + }; +} diff --git a/mv/1systems/stro.nix b/mv/1systems/stro.nix index 9edcea007..38d4b4bc6 100644 --- a/mv/1systems/stro.nix +++ b/mv/1systems/stro.nix @@ -12,6 +12,7 @@ with lib; imports = [ ../2configs/hw/x220.nix + ../2configs/git.nix ../2configs/mail-client.nix ../2configs/xserver { @@ -154,7 +155,7 @@ with lib; connectTo = [ "cd" "gum" - "pigstarter" + "wry" ]; }; } @@ -217,6 +218,7 @@ with lib; "sendmail" # for cron ]; + services.bitlbee.enable = true; services.printing.enable = true; services.journald.extraConfig = '' diff --git a/mv/2configs/bash_completion.sh b/mv/2configs/bash_completion.sh new file mode 100644 index 000000000..537484fb9 --- /dev/null +++ b/mv/2configs/bash_completion.sh @@ -0,0 +1,779 @@ + +# Expand variable starting with tilde (~) +# We want to expand ~foo/... to /home/foo/... to avoid problems when +# word-to-complete starting with a tilde is fed to commands and ending up +# quoted instead of expanded. +# Only the first portion of the variable from the tilde up to the first slash +# (~../) is expanded. The remainder of the variable, containing for example +# a dollar sign variable ($) or asterisk (*) is not expanded. +# Example usage: +# +# $ v="~"; __expand_tilde_by_ref v; echo "$v" +# +# Example output: +# +# v output +# -------- ---------------- +# ~ /home/user +# ~foo/bar /home/foo/bar +# ~foo/$HOME /home/foo/$HOME +# ~foo/a b /home/foo/a b +# ~foo/* /home/foo/* +# +# @param $1 Name of variable (not the value of the variable) to expand +__expand_tilde_by_ref() +{ + # Does $1 start with tilde (~)? + if [[ ${!1} == \~* ]]; then + # Does $1 contain slash (/)? + if [[ ${!1} == */* ]]; then + # Yes, $1 contains slash; + # 1: Remove * including and after first slash (/), i.e. "~a/b" + # becomes "~a". Double quotes allow eval. + # 2: Remove * before the first slash (/), i.e. "~a/b" + # becomes "b". Single quotes prevent eval. + # +-----1----+ +---2----+ + eval $1="${!1/%\/*}"/'${!1#*/}' + else + # No, $1 doesn't contain slash + eval $1="${!1}" + fi + fi +} # __expand_tilde_by_ref() + + +# Get the word to complete. +# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases +# where the user is completing in the middle of a word. +# (For example, if the line is "ls foobar", +# and the cursor is here --------> ^ +# @param $1 string Characters out of $COMP_WORDBREAKS which should NOT be +# considered word breaks. This is useful for things like scp where +# we want to return host:path and not only path, so we would pass the +# colon (:) as $1 in this case. +# @param $2 integer Index number of word to return, negatively offset to the +# current word (default is 0, previous is 1), respecting the exclusions +# given at $1. For example, `_get_cword "=:" 1' returns the word left of +# the current word, respecting the exclusions "=:". +# @deprecated Use `_get_comp_words_by_ref cur' instead +# @see _get_comp_words_by_ref() +_get_cword() +{ + local LC_CTYPE=C + local cword words + __reassemble_comp_words_by_ref "$1" words cword + + # return previous word offset by $2 + if [[ ${2//[^0-9]/} ]]; then + printf "%s" "${words[cword-$2]}" + elif [[ "${#words[cword]}" -eq 0 || "$COMP_POINT" == "${#COMP_LINE}" ]]; then + printf "%s" "${words[cword]}" + else + local i + local cur="$COMP_LINE" + local index="$COMP_POINT" + for (( i = 0; i <= cword; ++i )); do + while [[ + # Current word fits in $cur? + "${#cur}" -ge ${#words[i]} && + # $cur doesn't match cword? + "${cur:0:${#words[i]}}" != "${words[i]}" + ]]; do + # Strip first character + cur="${cur:1}" + # Decrease cursor position + ((index--)) + done + + # Does found word matches cword? + if [[ "$i" -lt "$cword" ]]; then + # No, cword lies further; + local old_size="${#cur}" + cur="${cur#${words[i]}}" + local new_size="${#cur}" + index=$(( index - old_size + new_size )) + fi + done + + if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then + # We messed up! At least return the whole word so things + # keep working + printf "%s" "${words[cword]}" + else + printf "%s" "${cur:0:$index}" + fi + fi +} # _get_cword() + + +# Get word previous to the current word. +# This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4 +# will properly return the previous word with respect to any given exclusions to +# COMP_WORDBREAKS. +# @deprecated Use `_get_comp_words_by_ref cur prev' instead +# @see _get_comp_words_by_ref() +# +_get_pword() +{ + if [[ $COMP_CWORD -ge 1 ]]; then + _get_cword "${@:-}" 1 + fi +} + + + +# Complete variables. +# @return True (0) if variables were completed, +# False (> 0) if not. +_variables() +{ + if [[ $cur =~ ^(\$\{?)([A-Za-z0-9_]*)$ ]]; then + [[ $cur == *{* ]] && local suffix=} || local suffix= + COMPREPLY+=( $( compgen -P ${BASH_REMATCH[1]} -S "$suffix" -v -- \ + "${BASH_REMATCH[2]}" ) ) + return 0 + fi + return 1 +} + +# Assign variable one scope above the caller +# Usage: local "$1" && _upvar $1 "value(s)" +# Param: $1 Variable name to assign value to +# Param: $* Value(s) to assign. If multiple values, an array is +# assigned, otherwise a single value is assigned. +# NOTE: For assigning multiple variables, use '_upvars'. Do NOT +# use multiple '_upvar' calls, since one '_upvar' call might +# reassign a variable to be used by another '_upvar' call. +# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference +_upvar() +{ + if unset -v "$1"; then # Unset & validate varname + if (( $# == 2 )); then + eval $1=\"\$2\" # Return single value + else + eval $1=\(\"\${@:2}\"\) # Return array + fi + fi +} + +# Assign variables one scope above the caller +# Usage: local varname [varname ...] && +# _upvars [-v varname value] | [-aN varname [value ...]] ... +# Available OPTIONS: +# -aN Assign next N values to varname as array +# -v Assign single value to varname +# Return: 1 if error occurs +# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference +_upvars() +{ + if ! (( $# )); then + echo "${FUNCNAME[0]}: usage: ${FUNCNAME[0]} [-v varname"\ < |