| #!/bin/dash |
| # 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. |
| |
| TRY_BASH=1 |
| if echo "$@" | grep -q -- "--dash"; then |
| TRY_BASH=0 |
| fi |
| |
| # NOTE: This script *almost* works in dash. Unfortunately, dash is missing |
| # the 'history' builtin and readline support is missing from the 'read' |
| # builtin. |
| # |
| # Please test that any changes continue to work in dash by running |
| # '/build/board-name/bin/dash crosh --dash' before checking them in. |
| |
| if type "history" 2>/dev/null | grep -q "shell builtin"; then |
| IS_BASH=1 |
| else |
| IS_BASH=0 |
| fi |
| |
| if [ "$TRY_BASH" = "1" -a "$IS_BASH" != "1" -a -x "/bin/bash" ]; then |
| # Relaunch in bash if we can. |
| exec /bin/bash $0 "$@" |
| fi |
| |
| # |
| # Please keep the help text in alphabetical order! |
| # |
| HELP=' |
| exit |
| Exit crosh. |
| |
| help |
| Display this help. |
| |
| help_advanced |
| Display the help for more advanced commands, mainly used for debugging. |
| |
| ping [-c count] [-i interval] [-n] [-s packetsize] [-W waittime] <destination> |
| Send ICMP ECHO_REQUEST packets to a network host. If <destination> is "gw" |
| then the next hop gateway for the default route is used. |
| |
| ssh [optional args...] |
| Starts the ssh subsystem if invoked without any arguments. |
| "ssh <user> <host>", "ssh <user> <host> <port>", "ssh <user>@<host>", |
| or "ssh <user>@<host> <port>" connect without entering the subsystem. |
| |
| ssh_forget_host |
| Remove a host from the list of known ssh hosts. This command displays |
| a menu of known hosts and prompts for the host to forget. |
| |
| top |
| Run top. |
| ' |
| |
| HELP_ADVANCED=' |
| connectivity |
| Shows connectivity status. "connectivity help" for more details |
| |
| experimental_storage < status | enable | disable > |
| Enable or disable experimental storage features. |
| |
| ff_debug [<tag_expr>] [--help] [--list_valid_tags] [--reset] |
| Add and remove flimflam debugging tags. |
| |
| modem <command> [args...] |
| Interact with the 3G modem. Run "modem help" for detailed help. |
| |
| modem_set_carrier carrier-name |
| Configures the modem for the specified carrier. |
| |
| network_logging <wifi | cellular | ethernet> |
| A function that enables a predefined set of tags useful for |
| debugging the specified device. |
| |
| network_diag [--date] [--flimflam] [--link] [--show-macs] [--wifi] [--help] |
| [--wifi-monitor] <host> |
| A function that performs a suite of network diagnostics. Saves a copy |
| of the output to your download directory. |
| |
| rlz < status | enable | disable > |
| Enable or disable RLZ. |
| |
| route [-n] [-6] |
| Display the routing tables. |
| |
| set_apn [-n <network-id>] [-u <username>] [-p <password>] <apn> |
| Set the APN to use when connecting to the network specified by <network-id>. |
| If <network-id> is not specified, use the network-id of the currently |
| registered network. |
| |
| set_apn -c |
| Clear the APN to be used, so that the default APN will be used instead. |
| |
| set_arpgw <true | false> |
| Turn on extra network state checking to make sure the default gateway |
| is reachable. |
| |
| tpcontrol {status|taptoclick [on|off]|sensitivity [1-5]|set <property> <value>} |
| tpcontrol {syntp [on|off]} |
| Manually adjust advanced touchpad settings. |
| |
| tracepath [-n] <destination>[/port] |
| Trace the path/route to a network host. |
| |
| wpa_debug [<debug_level>] [--help] [--list_valid_level] [--reset] |
| Set wpa_supplicant debugging level. |
| |
| syslog <message> |
| Logs a message to syslog. |
| |
| chaps_debug [start|stop|<log_level>] |
| Sets the chapsd logging level. No arguments will start verbose logging. |
| ' |
| |
| CHROMEOS_INSTALL=/usr/sbin/chromeos-install |
| . "/usr/sbin/chromeos-common.sh" || exit 1 |
| SRC=$(get_block_dev_from_partition_dev $(rootdev -s)) |
| if [ "$(cat /sys/block/${SRC#/dev/}/removable)" == "1" ]; then |
| REMOVABLE=1 |
| fi |
| |
| if [ "$(echo "$@" | grep -- "--usb")" -o "$REMOVABLE" = "1" ]; then |
| . "$(dirname "$0")/crosh-usb" |
| fi |
| |
| # Force dev behavior on dev images. |
| /usr/bin/crossystem "cros_debug?1" |
| DEVMODE=$((!$?)) |
| |
| if [ "$(echo "$@" | grep -- "--dev")" -o "$DEVMODE" = "1" ]; then |
| . "$(dirname "$0")/crosh-dev" |
| fi |
| |
| if [ -e "$(dirname $0)/crosh-workarounds" ]; then |
| . "$(dirname "$0")/crosh-workarounds" |
| fi |
| |
| ctrl_c() { |
| return |
| } |
| |
| trap ctrl_c INT |
| |
| shell_read() { |
| local prompt="$1" |
| shift |
| |
| if [ "$IS_BASH" -eq "1" ]; then |
| # In bash, -e gives readline support. |
| read -p "$prompt" -e $@ |
| else |
| read -p "$prompt" $@ |
| fi |
| } |
| |
| shell_history() { |
| if [ "$IS_BASH" -eq "1" ]; then |
| # In bash, the history builtin can be used to manage readline history |
| history $@ |
| fi |
| } |
| |
| cmd_help() { |
| echo "$HELP" |
| } |
| |
| cmd_help_advanced() { |
| echo "$HELP_ADVANCED" |
| } |
| |
| cmd_exit() { |
| exit |
| } |
| |
| check_dforward() { |
| # Matches a port number between 8000 and 8999. |
| expr "$1" : '^8[0-9][0-9][0-9]$' > /dev/null |
| } |
| |
| check_forward() { |
| # Matches three things, separated by ':': |
| # A port number, between 8000 and 8999; |
| # A hostname |
| # A port number, unrestricted |
| expr "$1" : '^8[0-9][0-9][0-9]:[[:alnum:]][-[:alnum:].]*:[1-9][0-9]*$' \ |
| > /dev/null |
| } |
| |
| check_serveraliveinterval() { |
| # Matches a number of seconds. |
| expr "$1" : '^[0-9][0-9]*$' > /dev/null; |
| } |
| |
| check_keyfile() { |
| # Allow files in /home/chronos/user, /media. Note that we *do* allow .., so |
| # this isn't actually a security barrier, just a molly-guard to keep users |
| # from putting keys in insecure storage. |
| if [ ! -f "$1" -a ! -f "$HOME/Downloads/$1" ]; then |
| return 1; |
| fi |
| if [ ! -r "$1" -a ! -r "$HOME/Downloads/$1" ]; then |
| return 1; |
| fi |
| (expr "$1" : "^$HOME" > /dev/null) || \ |
| (expr "$1" : '^/media/' > /dev/null) || \ |
| (expr "$1" : '^[^/]*$' > /dev/null) |
| } |
| |
| check_ssh_host() { |
| check_hostname "$1" || check_ipv6 "$1"; |
| } |
| |
| cmd_ssh() { |
| local user="" |
| local host="" |
| local port="22" |
| local idfile="" |
| local dforwards="" |
| local forwards="" |
| local nocmd="" |
| local serveraliveinterval="" |
| local line |
| local cmd |
| local params |
| local exit |
| local id=$(uuidgen) |
| |
| local defopts="-e none -F /etc/ssh/ssh_config" |
| |
| if [ ! -z "$1" ]; then |
| # Sets the username, host, and optionally port directly. We accept: |
| # 'user host', 'user host port', 'user@host', or 'user@host port'. |
| local at_pos=$(expr index "$1" '@') |
| if [ $at_pos = 0 ]; then |
| user="$1" |
| host="$2" |
| if [ ! -z "$3" ]; then |
| port="$3" |
| fi |
| else |
| user=$(substr "$1" "0" $(expr "$at_pos" - 1)) |
| host=$(substr "$1" "$at_pos") |
| if [ ! -z "$2" ]; then |
| port="$2" |
| fi |
| fi |
| fi |
| |
| if [ -z "$user" -o -z "$host" ]; then |
| while [ 1 ]; do |
| if ! shell_read "ssh> " line; then |
| echo; |
| exit=1; |
| break |
| fi |
| |
| local space_pos=$(expr index "$line" ' ') |
| if [ $space_pos = 0 ]; then |
| cmd="$line" |
| params="" |
| else |
| cmd=$(substr "$line" "0" "$space_pos") |
| params=$(substr "$line" "$space_pos") |
| fi |
| |
| case "$cmd" in |
| |
| key) |
| if check_keyfile "$params"; then |
| mkdir -p -m 600 "$HOME/.ssh"; |
| trap "rm -f $HOME/.ssh/key-$id" EXIT; |
| (cd "$HOME/Downloads" ; cp -- "$params" "$HOME/.ssh/key-$id") |
| chmod 600 "$HOME/.ssh/key-$id" |
| idfile="-i $HOME/.ssh/key-$id" |
| else |
| echo "File '$params' is not a valid key file. Key files must reside" |
| echo "under /media or $HOME. Key files in the Downloads directory may" |
| echo "be specified with an unqualified name." |
| fi |
| ;; |
| |
| dynamic-forward) |
| if ! check_dforward "$params"; then |
| echo "Invalid forward '$params'." |
| echo "Note that the local port number must be in 8000-8999." |
| else |
| dforwards="$dforwards -D$params" |
| fi |
| ;; |
| |
| forward) |
| if ! check_forward "$params"; then |
| echo "Invalid forward '$params'" |
| echo "Note that the local port number must be in 8000-8999." |
| else |
| forwards="$forwards -L$params" |
| fi |
| ;; |
| |
| nocmd) |
| nocmd="-N" |
| ;; |
| |
| server-alive-interval) |
| if ! check_serveraliveinterval "$params"; then |
| echo "Invalid ServerAliveInterval '$params'." |
| else |
| serveraliveinterval="-oServerAliveInterval=$params" |
| fi |
| ;; |
| |
| port) |
| if ! check_digits "$params"; then |
| echo "Invalid port '$params'" |
| else |
| port="$params" |
| fi |
| ;; |
| |
| user) |
| user="$params" |
| ;; |
| |
| host) |
| host="$params" |
| ;; |
| |
| exit) |
| exit=1 |
| break |
| ;; |
| |
| connect) |
| break |
| ;; |
| |
| *) |
| echo "connect - connect" |
| echo "dynamic-forward port - dynamic socks proxy (-D)" |
| echo "forward port:host:port - static port forward (-L)" |
| echo "help - this" |
| echo "host <hostname> - remote hostname" |
| echo "key <file> - sets private key to use (-i)" |
| echo "nocmd - don't execute command (-N)" |
| echo "port <num> - port on remote host (-p)" |
| echo "server-alive-interval <num> - set ServerAliveInterval option" |
| echo "exit - exit ssh subsystem" |
| echo "user <username> - username on remote host" |
| echo "Note that this program can only bind local ports in the range" |
| echo "8000-8999, inclusive." |
| ;; |
| esac |
| done |
| fi |
| |
| if [ -z "$exit" ]; then |
| if [ -z "$user" ]; then |
| echo "No username given." |
| elif [ -z "$host" ]; then |
| echo "No host given." |
| elif ! check_username "$user"; then |
| echo "Invalid username '$user'" |
| elif ! check_ssh_host "$host"; then |
| echo "Invalid hostname '$host'" |
| else |
| ssh $defopts $idfile $dforwards $forwards $nocmd $serveraliveinterval \ |
| -p "$port" -l "$user" "$host" |
| fi |
| fi |
| |
| if [ -n "$idfile" ]; then |
| rm "$HOME/.ssh/key-$id"; |
| trap - EXIT; |
| fi |
| } |
| |
| cmd_ssh_forget_host() { |
| local known_hosts="$(readlink -f $HOME/.ssh/known_hosts)" |
| |
| # Test that the known_hosts is a regular file and is not 0 length. |
| if [ ! -f "$known_hosts" -o ! -s "$known_hosts" ]; then |
| echo "No known hosts." |
| return |
| fi |
| |
| local count="$(cat "$known_hosts" | wc -l)" |
| |
| # Print an indexed list of the known hosts. |
| echo "Known hosts:" |
| awk '{ print " " NR ") " $1; }' "$known_hosts" |
| |
| local hostno |
| |
| while true; do |
| LINE_="" |
| shell_read "Please select a host to forget [1-$count]: " LINE_ |
| if [ -z "$LINE_" ]; then |
| echo "Aborting." |
| return |
| fi |
| |
| # Extract the numbers from the user input. |
| hostno="$(echo $LINE_ | sed 's/[^[:digit:]]*//g')" |
| |
| # If they typed a number... |
| if [ -n "$hostno" ]; then |
| # And it was in the proper range... |
| if [ $hostno -gt 0 -a $hostno -le $count ]; then |
| # Then we can stop asking for input. |
| break |
| fi |
| fi |
| |
| echo "Invalid selection. Please enter a number between 1 and $count." |
| done |
| |
| local trimmed="$(awk -v I="$hostno" 'NR != I { print }' "$known_hosts")" |
| echo "$trimmed" > "$known_hosts" |
| chmod 644 "$known_hosts" |
| } |
| |
| cmd_swap() { |
| local swap_enable_file="/home/chronos/.swap_enabled" |
| |
| case "$1" in |
| "enable") |
| if [ -z "$2" ]; then |
| # remove file in case root owns it |
| rm -f $swap_enable_file |
| touch $swap_enable_file |
| elif ! echo "$2" | grep -q "^[0-9]*$"; then |
| echo "$2 is not a valid integer literal" |
| cmd_swap usage |
| return 1 |
| elif [ "$2" -ne 500 -a \ |
| "$2" -ne 1000 -a \ |
| "$2" -ne 2000 -a \ |
| "$2" -ne 3000 -a \ |
| "$2" -ne 4500 -a \ |
| "$2" -ne 6000 ]; then |
| echo "invalid size $2. Valid choices: 500, 1000, 2000, 3000, 4500 or 6000" |
| cmd_swap usage |
| return 1 |
| else |
| # remove file in case root owns it |
| rm -f $swap_enable_file |
| echo "$2" >$swap_enable_file |
| fi |
| echo "Swap will be ON at next reboot." |
| echo "You are turning on compressed swap, which is an experimental feature" |
| echo "of Chrome OS. System instability may result. To turn it off, use" |
| echo "the command \"swap disable\"." |
| ;; |
| "disable") |
| rm -f $swap_enable_file |
| echo "Swap will be OFF at next reboot." |
| ;; |
| "status") |
| /sbin/swapon -s |
| ;; |
| *) |
| echo "Usage: swap < status | enable [<optional swap size (MB)>] | disable >" |
| return 1 |
| ;; |
| esac |
| } |
| |
| cmd_experimental_storage() { |
| local enable="" |
| if [ -z "$1" ]; then |
| echo "Usage: experimental_storage < status | enable | disable >" |
| return 1 |
| fi |
| |
| case "$1" in |
| "status") |
| ;; |
| "enable") |
| enable="true" |
| ;; |
| "disable") |
| enable="false" |
| ;; |
| *) |
| echo "Invalid parameter: $1" |
| return 1 |
| ;; |
| esac |
| |
| if [ -z "$enable" ]; then |
| enable=$( dbus-send --system --type=method_call --print-reply \ |
| --dest=org.chromium.CrosDisks /org/chromium/CrosDisks \ |
| org.freedesktop.DBus.Properties.Get string:org.chromium.CrosDisks \ |
| string:ExperimentalFeaturesEnabled 2>/dev/null ) |
| if [ $? -eq 0 ]; then |
| if echo "$enable" | grep -iqs "true"; then |
| echo "Experimental storage features are currently enabled." |
| else |
| echo "Experimental storage features are currently disabled." |
| fi |
| else |
| echo "Could not determine the status of experimental storage features." |
| fi |
| else |
| if dbus-send --system --type=method_call --print-reply \ |
| --dest=org.chromium.CrosDisks /org/chromium/CrosDisks \ |
| org.freedesktop.DBus.Properties.Set \ |
| string:org.chromium.CrosDisks string:ExperimentalFeaturesEnabled \ |
| variant:boolean:${enable} >/dev/null 2>&1; then |
| echo "Experimental storage features have been ${1}d." |
| else |
| echo "Could not $1 experimental storage features." |
| fi |
| fi |
| } |
| |
| cmd_ff_debug(){ |
| /usr/bin/ff_debug "$@" |
| } |
| |
| cmd_wpa_debug(){ |
| /usr/bin/wpa_debug "$@" |
| } |
| |
| cmd_set_arpgw(){ |
| /usr/bin/set_arpgw "$@" |
| } |
| |
| cmd_network_logging(){ |
| if [ -n "$1" ]; then |
| case "$1" in |
| "wifi") |
| echo; /usr/bin/ff_debug service+wifi+inet+device+manager |
| echo; /usr/bin/wpa_debug msgdump |
| echo; /usr/bin/modem set-logging info |
| ;; |
| "cellular") |
| echo; /usr/bin/ff_debug service+cellular+modem+device+manager |
| echo; /usr/bin/wpa_debug info |
| echo; /usr/bin/modem set-logging debug |
| ;; |
| "ethernet") |
| echo; /usr/bin/ff_debug service+ethernet+device+manager |
| echo; /usr/bin/wpa_debug info |
| echo; /usr/bin/modem set-logging info |
| ;; |
| "--help") |
| echo "Usage: network_logging <wifi | cellular | ethernet>" |
| ;; |
| *) |
| echo "Invalid parameter $1" |
| ;; |
| esac |
| else |
| echo "Missing parameter wifi | cellular | ethernet" |
| fi |
| } |
| |
| cmd_network_diag(){ |
| /usr/bin/network_diagnostics "$@" |
| } |
| |
| debugd() { |
| method="$1"; shift |
| dbus-send --system --print-reply --fixed --dest=org.chromium.debugd \ |
| /org/chromium/debugd "org.chromium.debugd.$method" "$@" |
| } |
| |
| cmd_ping() { |
| local option="dict:string:variant:" |
| |
| # NB: use printf to avoid echo interpreting -n |
| while [ "$(printf '%s' "$1" | cut -c1)" = "-" ]; do |
| # Do just enough parsing to filter/map options; we |
| # depend on ping to handle final validation |
| if [ "$1" = "-i" ]; then |
| shift; option="${option}interval,int32:$1," |
| elif [ "$1" = "-c" ]; then |
| shift; option="${option}count,int32:$1," |
| elif [ "$1" = "-W" ]; then |
| shift; option="${option}waittime,int32:$1," |
| elif [ "$1" = "-s" ]; then |
| shift; option="${option}packetsize,int32:$1," |
| elif [ "$1" = "-n" ]; then |
| option="${option}numeric,boolean:true" |
| else |
| echo "Unknown option: $1" |
| return 1 |
| fi |
| |
| shift |
| done |
| |
| if [ -z "$1" ]; then |
| echo "Missing parameter: destination" |
| return 1 |
| fi |
| |
| local dest="$1" |
| if [ "$dest" = "gw" ]; then |
| # Convenient shorthand for the next-hop gateway attached |
| # to the default route; this means if you have a host named |
| # "gw" then you'll need to specify a FQDN or IP address. |
| dest=$(/sbin/route -n | awk '$1 == "0.0.0.0" { print $2; }') |
| if [ -z "$dest" ]; then |
| echo "Cannot determine primary gateway; routing table is:" |
| cmd_route -n |
| return 1 |
| fi |
| fi |
| |
| option=$(echo "$option" | sed 's/,$//') |
| |
| # We want C-c to terminate the running ping so that the UI stays the same. |
| # Therefore, create a fifo to direct the output of the ping to, and have a |
| # subshell read from the fifo and emit to stdout. When the subshell ends (at a |
| # C-c), we stop the ping and clean up the fifo. |
| # no way to mktemp a fifo, so make a dir to hold it instead |
| dir=$(mktemp -d "/tmp/crosh-ping-XXXXXXXXXX") |
| if [ $? -ne 0 ]; then |
| echo "Can't create temporary directory" |
| return 1 |
| fi |
| fifo="${dir}/fifo" |
| if ! mkfifo "$fifo"; then |
| echo "Can't create fifo at $fifo" |
| return 1 |
| fi |
| debugd PingStart "fd:1" "string:$dest" "$option" 2>&1 > "$fifo" & |
| read pid < "$fifo" |
| echo "pid: $pid" |
| (while read line; do echo "$line"; done) < "$fifo" |
| debugd PingStop "string:$pid" |
| if [ $? -ne 0 ]; then |
| echo "Can't stop ping" |
| return 1 |
| fi |
| rm -rf "$dir" |
| } |
| |
| # TODO(dkrahn): Remove once this is the default. crosbug.com/22543 |
| cmd_chaps() { |
| local flag_file="/home/chronos/.disable_chaps" |
| local enabled=1 |
| local changed=0 |
| if [ -r ${flag_file} ]; then |
| enabled=0 |
| fi |
| if [ -z "$1" ]; then |
| if [ ${enabled} -eq 1 ]; then |
| echo "Currently enabled" |
| else |
| echo "Currently disabled" |
| fi |
| return |
| fi |
| if [ "$1" = "on" ]; then |
| if [ $enabled -eq 0 ]; then |
| changed=1; |
| fi |
| rm -f "${flag_file}" |
| else |
| if [ $enabled -eq 1 ]; then |
| changed=1 |
| fi |
| touch "${flag_file}" |
| fi |
| if [ $changed -eq 1 ]; then |
| echo "You must reboot for this to take effect." |
| else |
| echo "No change." |
| fi |
| } |
| |
| cmd_chaps_debug() { |
| local level=${1:--2} |
| if [ "$1" = "stop" ]; then |
| level=0 |
| fi |
| if [ "$1" = "start" ]; then |
| level=-2 |
| fi |
| rm -f /home/chronos/.chaps_debug* |
| if [ "${level}" = "-1" ]; then |
| touch /home/chronos/.chaps_debug_1 |
| elif [ "${level}" = "-2" ]; then |
| touch /home/chronos/.chaps_debug_2 |
| fi |
| /usr/bin/chaps_client --set_log_level=${level} 2> /dev/null |
| if [ $? -eq 0 ]; then |
| echo "Logging level set to ${level}." |
| else |
| echo "Failed to set logging level." |
| fi |
| } |
| |
| cmd_route() { |
| local option="dict:string:variant:" |
| |
| # NB: use printf to avoid echo interpreting -n |
| while [ "$(printf '%s' "$1" | cut -c1)" = "-" ]; do |
| if [ "$1" = "-n" ]; then |
| option="${option}numeric,boolean:true," |
| elif [ "$1" = "-6" ]; then |
| option="${option}v6,boolean:true," |
| else |
| echo "Unknown option: $1" |
| return 1 |
| fi |
| |
| shift |
| done |
| option=$(echo "$option" | sed 's/,$//') |
| |
| debugd GetRoutes "$option" |
| } |
| |
| cmd_tracepath() { |
| local option="dict:string:variant:" |
| |
| # NB: use printf to avoid echo interpreting -n |
| while [ "$(printf '%s' "$1" | cut -c1)" = "-" ]; do |
| if [ "$1" = "-n" ]; then |
| option="${option}numeric,boolean:true," |
| else |
| echo "Unknown option: $1" |
| return 1 |
| fi |
| |
| shift |
| done |
| |
| option=$(echo "$option" | sed 's/,$//') |
| |
| if [ -z "$1" ]; then |
| echo "Missing parameter: destination" |
| return 1 |
| fi |
| |
| # We want C-c to terminate the running tracepath so that the UI stays the same. |
| # Therefore, create a fifo to direct the output of the tracepath to, and have a |
| # subshell read from the fifo and emit to stdout. When the subshell ends (at a |
| # C-c), we stop the tracepath and clean up the fifo. |
| # TODO(ellyjones): factor this (and the similar code in cmd_ping) out somehow |
| # no way to mktemp a fifo, so make a dir to hold it instead |
| dir=$(mktemp -d "/tmp/crosh-tracepath-XXXXXXXXXX") |
| if [ $? -ne 0 ]; then |
| echo "Can't create temporary directory" |
| return 1 |
| fi |
| fifo="${dir}/fifo" |
| if ! mkfifo "$fifo"; then |
| echo "Can't create fifo at $fifo" |
| return 1 |
| fi |
| debugd TracePathStart "fd:1" "string:$1" "$option" 2>&1 > "$fifo" & |
| read pid < "$fifo" |
| echo "pid: $pid" |
| (while read line; do echo "$line"; done) < "$fifo" |
| debugd TracePathStop "string:$pid" |
| if [ $? -ne 0 ]; then |
| echo "Can't stop tracepath" |
| return 1 |
| fi |
| rm -rf "$dir" |
| } |
| |
| cmd_top() { |
| # -s is "secure" mode, which disables kill, renice, and change display/sleep |
| # interval. |
| top -s |
| } |
| |
| cmd_modem() { |
| /usr/bin/modem "$@" |
| } |
| |
| cmd_modem_set_carrier() { |
| /usr/bin/modem set-carrier "$@" |
| } |
| |
| cmd_set_apn() { |
| /usr/bin/set_apn "$@" |
| } |
| |
| cmd_connectivity() { |
| /usr/bin/connectivity "$@" |
| } |
| |
| cmd_autest() { |
| local omaha_url="autest" |
| |
| if [ "$1" = "-scheduled" ]; then |
| # pretend that this is a scheduled check as opposed to an user-initiated |
| # check for testing features that get enabled only on scheduled checks. |
| omaha_url="autest-scheduled" |
| fi |
| |
| echo "Calling update_engine_client with omaha_url = $omaha_url" |
| /usr/bin/update_engine_client --omaha_url $omaha_url |
| } |
| |
| cmd_tpcontrol() { |
| /opt/google/touchpad/tpcontrol "$@" |
| } |
| |
| cmd_try_touch_experiment() { |
| # Test out a new set of Touch parameters briefly, then revert them. |
| # This takes in a single string of hex digits ie ([a-fA-F0-9]*) that |
| # correspond to an ascii string of the form |
| # PARAMETER1 NAME:PARAMETER1 VALUE,PARAMETER2 NAME:PARAMETER2 VALUE,... |
| # The input is encoded as hex to a) eliminate escaping issues for spaces |
| # and b) obfuscate which properties are being changed from the user so they |
| # don't see what they're changing, and have it influence their decision. |
| |
| # First, check and make sure only hex digit characters have been passed in |
| if [ -n "`echo \"$@\" | sed 's/[0-9a-fA-F]//g'`" ]; then |
| return 1 |
| fi |
| |
| # Converting the input from hex to ascii |
| treatment="`echo \"$@\" | sed 's/\(..\)/\\\\u\1/g'`" |
| treatment=`printf "${treatment}\n"` |
| if [ -n "`echo \"${treatment}\" | sed 's/[0-9a-zA-Z :,\.\-]//g'`" ]; then |
| return 1; |
| fi |
| |
| # Get the current system setup and old values so we can restore them |
| device=`/opt/google/touchpad/tpcontrol listdev` |
| old_values="`xinput list-props ${device}`" |
| |
| # Splitting the treatment into property name/value pairs |
| treatment_commands="" |
| reset_commands="" |
| IFS=, |
| for pair in ${treatment}; do |
| name="`echo "${pair}" | cut -d ":" -f1`" |
| new_value="`echo "${pair}" | cut -d ":" -f2`" |
| |
| property_entry=`echo "${old_values}" | grep "${name}" | tr -d "\t"` |
| property_number=`echo "${property_entry}" | sed "s/^.*(\([0-9]*\)).*$/\1/"` |
| old_value=`echo "${property_entry}" | sed "s/^[^:]*:\(.*\)$/\1/"` |
| |
| change_cmd="${property_number}:${new_value}" |
| reset_cmd="${property_number}:${old_value}" |
| |
| treatment_commands="${change_cmd},${treatment_commands}" |
| reset_commands="${reset_cmd},${reset_commands}" |
| done |
| |
| echo "Applying Changes now..." |
| change_properties "${treatment_commands}", "${device}" |
| |
| echo "Press Ctrl+C to return to your original settings." |
| cat |
| |
| echo "Reverting Changes now..." |
| change_properties "${reset_commands}", "${device}" |
| |
| # Checking to make sure everything is back to normal |
| restored_values="`xinput list-props ${device}`" |
| if [ "${old_values}" != "${restored_values}" ]; then |
| echo "ERROR: Some properties may not have been reset correctly!" |
| echo "If your touchpad is misbehaving, you can restore it by logging out" |
| echo "and back in again." |
| fi |
| } |
| |
| change_properties() { |
| # change format: PROPERTY_NUMBER:PROPERTY_VALUE,... |
| cleaned="`echo "$1" | sed "s/,*$//g"`" |
| IFS=, |
| for cmd in ${cleaned}; do |
| property_number="`echo "${cmd}" | cut -d ":" -f1`" |
| property_value="`echo "${cmd}" | cut -d ":" -f2`" |
| xinput set-prop "$2" "${property_number}" "${property_value}" |
| done |
| } |
| |
| cmd_rlz() { |
| local flag_file="$HOME/.rlz_disabled" |
| local enabled=1 |
| local changed=0 |
| if [ -r "${flag_file}" ]; then |
| enabled=0 |
| fi |
| case "$1" in |
| "status") |
| if [ $enabled -eq 1 ]; then |
| echo "Currently enabled" |
| else |
| echo "Currently disabled" |
| fi |
| return |
| ;; |
| |
| "enable") |
| if [ $enabled -eq 0 ]; then |
| changed=1 |
| fi |
| rm -f "${flag_file}" |
| ;; |
| |
| "disable") |
| if [ $enabled -eq 1 ]; then |
| changed=1 |
| fi |
| touch "${flag_file}" |
| ;; |
| |
| *) |
| echo "Usage: rlz < status | enable | disable >" |
| return 1 |
| ;; |
| esac |
| if [ $changed -eq 1 ]; then |
| echo "You must reboot for this to take effect." |
| else |
| echo "No change." |
| fi |
| } |
| |
| cmd_syslog() { |
| logger -t crosh -- "$*" |
| } |
| |
| substr() { |
| local str="$1" |
| local start="$2" |
| local end="$3" |
| |
| if [ "$IS_BASH" = "1" ]; then |
| # NB: use printf to avoid echo interpreting -n |
| if [ -z "$end" ]; then |
| printf '%s\n' ${str:$start} |
| else |
| printf '%s\n' ${str:$start:$end} |
| fi |
| return |
| fi |
| |
| start=$(expr "$start" + 1) |
| |
| if [ ! -z "$end" ]; then |
| end=$(expr "$end" - 1) |
| fi |
| |
| echo "$str" | cut -c${start}-${end} |
| } |
| |
| dispatch() { |
| local line="$1" |
| local command="" |
| local params="" |
| |
| local space_pos=$(expr index "$line" ' ') |
| |
| if [ $space_pos = 0 ]; then |
| command=$line |
| else |
| command=$(substr "$line" "0" "$space_pos") |
| params=$(substr "$line" "$space_pos") |
| fi |
| |
| if ! type "cmd_$command" 2>/dev/null | head -1 | grep -q "function"; then |
| echo "Unknown command: '$command'" |
| else |
| command="cmd_$command" |
| $command $params |
| fi |
| } |
| |
| # Checks that a given string looks like a hostname or IPv4 address (starts |
| # with an alphanumeric and contains only alphanumeric, '.', or '-' |
| # characters). |
| check_hostname() { |
| expr "$1" : '^[[:alnum:]][-[:alnum:].]*$' > /dev/null |
| } |
| |
| # Checks that a given string could plausibly be an IPv6 address |
| # (hexadecimal, ':', and '.' characters only, followed by an optional zone |
| # index consisting of a '%' and a device name). |
| check_ipv6() { |
| echo "$1" | /bin/grep -E -q '^[0-9a-fA-F:.]+(%[a-z0-9]+)?$' |
| } |
| |
| # Checks that a given string starts with an alphanumeric, and contains only |
| # alphanumeric and zero or more of "_:.~%$^\-" |
| check_username() { |
| expr "$1" : '^[[:alnum:]][[:alnum:]_:.~%$^\-]*$' > /dev/null |
| } |
| |
| check_digits() { |
| expr "$1" : '^[[:digit:]]*$' > /dev/null |
| } |
| |
| # Don't allow SIGHUP to terminate crosh. This guarantees that even if the user |
| # closes the crosh window, we make our way back up to the main loop, which gives |
| # cleanup code in command handlers a chance to run. |
| trap '' HUP |
| |
| repl() { |
| echo "Welcome to crosh, type 'help' for a list of commands." |
| if [ "$IS_BASH" != "1" ]; then |
| echo "Sorry, line editing and command history disabled due to" \ |
| "shell limitations." |
| fi |
| |
| while [ 1 ]; do |
| if shell_read "crosh> " LINE_; then |
| if [ ! -z "$LINE_" ]; then |
| shell_history -s "$LINE_" |
| dispatch "$LINE_" |
| fi |
| else |
| echo |
| return 1 |
| fi |
| done |
| } |
| |
| INPUTRC="$(dirname "$0")/inputrc.crosh" |
| HISTFILE="$HOME/.crosh_history" |
| shell_history -r $HISTFILE |
| |
| # Initialize pseudo completion support. |
| if [ "$IS_BASH" = "1" ]; then |
| bind 'TAB:dynamic-complete-history' 2>/dev/null |
| for f in $(declare -F | sed -n '/-f cmd_/s:.*cmd_::p'); do |
| # Do not add duplicates to avoid ballooning history. |
| grep -qs "^${f}$" $HISTFILE || shell_history -s $f |
| done |
| fi |
| |
| repl |
| |
| shell_history -w $HISTFILE |