# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # Common utilities for shell programs that manipulate devices and the # connection manager, including "modem" and "connectivity" # Prints an error message to stderr. error() { echo "ERROR: $@" >/dev/stderr } # Prints an error message to stderr and exits with a status code 1. error_exit() { error "$@" exit 1 } # Generates a small snippet of code to take a single argument out of our # parameter list, and complain (and exit) if it's not present. Used in other # places like: $(needarg foo), which binds foo to $1. needarg() { # We need to echo eval here because the part of bash that understands # variable assignments has already run by the time we substitute in the # text of $(needarg foo) - i.e., bash will try to execute 'foo="$1"' as # a *command*, which it isn't. The eval forces bash to reparse the code # before executing it. echo eval "$1=\"\$1\"; [ -z \"\$$1\" ] && echo 'Missing argument: $1' && usage; shift" } # Generates a small snippet of code to take a matching flag argument # and value out of our parameter list if present. If not, assign the # default value to $1. # Used in other places like: $(arg_or_default foo bar) # which binds foo to "bar", unless $1 is "-foo" in which case foo is # bound to $2. arg_or_default() { echo eval "[ x\"\$1\" = x\"-$1\" ] && $1=\"\$2\" && shift 2; [ -z \"\$$1\" ] && $1=\"$2\"" } # Generates a small snippet of code to take a single argument out of our # parameter list. If it's not present, prompt the user and accept a # blank input as if the users chose the default specified as $2. arg_or_prompt() { echo eval "$1=\"\$1\"; [ -n \"\$$1\" ] && shift ; [ -z \"\$$1\" ] && read -p \"$1 [$2]: \" $1 ; [ -z \"\$$1\" ] && $1=\"$2\";" } # Requires a key in a csv list of key value pairs # $1 - comma separated list of keys and values # $2 - required key # If the key is not found in the argument list, then prompt the user # for a value for key, and return $key,$value appended to $1 require() { local value local args=$1 local key=$2 if [ -z "$args" -o -n "${args##*$2*}" ] ; then read -p "$key: " value if [ -n "$args" ] ; then args="$args," fi args="$args$key,$value" fi echo "$args" } # Removes the indexes output by the --fixed option of dbus-send stripindexes() { sed -e 's/^\/[[:digit:]]\+\///' -e 's/[^[:space:]]*/\0:/' -e 's/^/ /' } # Prints values for dbus-send --fixed output lines whose keys match # the first argument. Call it with 'Key' and it will take input like # /4/Key/0 value value # /5/SomethingElse/0 something else # and write # value value extract_dbus_match() { local argument=$1 sed -r -n -e "s_^/[[:digit:]]+/$argument/\S+\s+__p" } # Invokes a DBus method on a DBus object. dbus_call() { local dest="$1" local object="$2" local method="$3" shift 3 dbus-send --system --print-reply --fixed --dest="${dest}" \ "${object}" "${method}" "$@" } # Gets a DBus property of an interface of a DBus object. dbus_property() { local dest="$1" local object="$2" local interface="$3" local property="$4" dbus_call "${dest}" "${object}" org.freedesktop.DBus.Properties.Get \ "string:${interface}" "string:${property}" } # Gets all DBus properties of an interface of a DBus object. dbus_properties() { local dest="$1" local object="$2" local interface="$3" dbus_call "${dest}" "${object}" org.freedesktop.DBus.Properties.GetAll \ "string:${interface}" } # Unpacks output by the --fixed option of dbus-send into key-value pairs. # # e.g. The following code # # echo " # /0 value1 # /1 value2 # " | unpack_tuple key1 key2 # # will output # # key1: value1 # key2: value2 # unpack_tuple() { local cmd='sed' local argidx=0 while test $# != 0; do # Grab a variable name local varname=$1 shift # Generate an expression that turns the current index into that # variable name, and append it. cmd="$cmd -e s/^\\/${argidx}/$varname:/" argidx=$((argidx+1)) done $cmd } # Formats dictionary output by the --fixed option of dbus-send into # key-value pairs. # # e.g. The following code # # echo " # /0/key1 value1 # /1/key2/0 value2a # /1/key2/1 value2b # " | format_dbus_dict # # will output # # key1: value1 # key2: value2a, value2b # format_dbus_dict() { awk 'BEGIN { entry_pattern = "/([0-9]+)/([^ /]+)(/[0-9]+)?" num_entries = 0 } $0 ~ entry_pattern { entry_value = substr($0, length($1) + 2) split($1, entry_tokens, "/") entry_index = entry_tokens[2] if (entry_keys[entry_index] == "") { entry_indices[num_entries++] = entry_index entry_keys[entry_index] = entry_tokens[3] entry_values[entry_index] = entry_value } else { entry_values[entry_index] = entry_values[entry_index] ", " entry_value } } END { for (i = 0; i < num_entries; ++i) { entry_index = entry_indices[i] print entry_keys[entry_index] ": " entry_values[entry_index] } }' } # Indents non-empty lines with two spaces per indent level. indent() { local level="$1" local space [ -n "${level}" ] || level=1 space=$(printf "%${level}s%${level}s" ' ' ' ') sed -E "s/^(.+)/${space}\1/" }