| #!/bin/bash |
| |
| # Copyright (c) 2010 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. |
| |
| IFCONFIG=/sbin/ifconfig |
| LSUSB=/usr/sbin/lsusb |
| LSPCI=/usr/sbin/lspci |
| IW=/usr/sbin/iw |
| ARP=/sbin/arp |
| ARPING=/sbin/arping |
| HTPDATE=/usr/sbin/htpdate |
| anonymize_macs=${ANONYMIZE_MACS-yes} |
| default_run=yes |
| |
| test_host=www.google.com |
| fail_count=0 |
| declare -A fn_entry |
| |
| # Annotate function entry. |
| fn_enter () { |
| local fn=${1} |
| fn_entry[${fn}]=1 |
| echo "Entering $*" |
| } |
| |
| # Annotate function entry. Also, return non-zero if function has |
| # been called more than once |
| fn_enter_once () { |
| local fn=${1} |
| [ -n "${fn_entry[${fn}]}" ] && return 1 |
| fn_enter "$@" |
| } |
| |
| # Output pass/fail reports |
| pass () { |
| echo "PASS: $*" |
| } |
| fail () { |
| echo "FAIL: $*" |
| fail_count=$[fail_count+1] |
| } |
| |
| # Create a unique filename -- this is a "non secure" implementation (we would |
| # have used mktemp if that was the concern), but instead we want to create an |
| # easy way to tell which file is more recent. Also, make a symlink to the most |
| # recent file |
| unique_file () { |
| local out_template=$1 |
| out_file=$(echo "${out_template}" | \ |
| sed -e 's/\*/'$(date +'%Y-%m-%d.%H:%M:%S')'/') |
| link_file=$(echo "${out_template}" | sed -e 's/\*/latest/') |
| rm -f ${out_file} ${link_file} |
| ln -s $(basename $out_file) ${link_file} |
| echo $out_file |
| } |
| |
| # Split a dotted decimal string |
| do_address_parts () { |
| (IFS=" ."; echo $1) |
| } |
| |
| # Perform a mask (binary "&") between two dotted-decimal strings |
| do_netmask () { |
| local -a ip=($(do_address_parts $1)) |
| local -a mask=($(do_address_parts $2)) |
| local -a ret |
| for part in ${!ip[@]}; do |
| ret+=($[ip[part] & mask[part]]) |
| done |
| (IFS=.; echo "${ret[*]}") |
| } |
| |
| # Search an entry from the routing table, given the destination IP address |
| # @ip: Destination IP address |
| # @route_flags: Search for this value in the "Flags" column |
| # @part: Column from the netstat output to return |
| get_route () { |
| local ip=$1 |
| local route_flags=$2 |
| shift ; shift |
| netstat -nr | while read line; do |
| local -a netstat=(${line}) |
| if [ ${netstat[3]} = "${route_flags}" -a \ |
| $(do_netmask ${ip} ${netstat[2]}) = ${netstat[0]} ] ; then |
| for part in $*; do |
| echo ${netstat[${part}]} |
| done |
| return 0 |
| fi |
| done |
| return 1 |
| } |
| |
| # Return the interface through which traffic to given neigbor IP should go |
| get_if_route () { |
| get_route $1 U 7 |
| } |
| |
| # Return the gateway IP to which traffic to given remote IP should be forwarded |
| get_gw_route () { |
| get_route $1 UG 1 7 |
| } |
| |
| # Trace down a symbolic link until we reach a dead-end (or a real file) |
| get_tracelink () { |
| local file=$1 |
| local link_count=0 |
| while [ -h ${file} -o -e ${file} ] ; do |
| ls -ld ${file} |
| new_file=$(readlink -f ${file}) |
| [ "${new_file}" = "${file}" ] && return |
| if [ ${link_count} -ge 10 ] ; then |
| fail "Gave up after ${link_count} steps" |
| return |
| fi |
| link_count=$[link_count + 1] |
| file=${new_file} |
| done |
| fail "${file} does not exist" |
| } |
| |
| # Return the IP addresses of the currently configured nameservers |
| get_nameservers () { |
| awk '/^nameserver/ {print $2}' /etc/resolv.conf |
| } |
| |
| # Return list of interface names |
| get_iflist () { |
| ls /sys/class/net/ | egrep -v '^(lo|sit)' |
| } |
| |
| # Return the interface name that has the default route |
| get_default_if () { |
| route -n | awk '/^0.0.0.0/ { print $2; exit 0 }' |
| } |
| |
| # Return IP address of a given network interface |
| get_if_addr () { |
| ifc=$1 |
| ${IFCONFIG} ${ifc} | grep "inet addr" | sed -e 's/.*addr://; s/ .*//' |
| } |
| |
| # Super-gross method for looking up IP address of a given hostname |
| get_host_addr () { |
| # TODO(pstew): super gross -- but there's no host/dig/nslookup/dnsquery |
| local host=$1 |
| ping -c1 ${host} | head -1 | awk -v FS='[()]' '{print $2}' |
| } |
| |
| # Find a the device name of a device given the driver's name |
| get_class_driver () { |
| local find_pat=$1 |
| local find_driver=$2 |
| for device in /sys/class/${find_pat}*; do |
| local driver=$(basename $(readlink ${device}/device/driver)) |
| if [ "${driver}" = "${find_driver}" ] ; then |
| echo $(basename ${device}) |
| return 0 |
| fi |
| done |
| } |
| |
| # The "status" command can't be run as non-root, so we fake it here |
| get_status () { |
| pid=$(pgrep ${1}) |
| if [ -n "${pid}" ] ; then |
| pass "${1} is running, pid ${pid}" |
| else |
| fail "${1} is stopped" |
| fi |
| } |
| |
| # Anonymize MAC addresses so they are not transmitted |
| mac_anonymize () { |
| if [ "${anonymize_macs}" != "yes" ]; then |
| cat |
| return |
| fi |
| sed -e \ |
| 's/\([0-9A-Fa-f][0-9A-Fa-f]\):\([0-9A-Fa-f][0-9A-Fa-f]\):\([0-9A-Fa-f][0-9A-Fa-f]\):[0-9A-Fa-f][0-9A-Fa-f]:[0-9A-Fa-f][0-9A-Fa-f]:[0-9A-Fa-f][0-9A-Fa-f]/\1:\2:\3:##:##:##/' \ |
| -e 's/\([^0-9a-fA-F][0-9a-fA-F]\{8,11\}\)[0-9a-fA-F]\{4\}$/\1####/' \ |
| -e 's/\([^0-9a-fA-F][0-9a-fA-F]\{8\}\)[0-9a-fA-F]\{4\}\([^0-9a-fA-F]\)/\1####\2/' \ |
| -e 's/\(\/[0-9a-fA-F]\{8\}\)[0-9a-fA-F]\{4\}\([^0-9a-fA-F]\)/\1####\2/' \ |
| -e 's/\(\/.*Passphrase \).*/\1[removed]/' \ |
| -e 's/\(\/.*PSK \).*/\1[removed]/' \ |
| -e 's/\(\/.*Password \).*/\1[removed]/' \ |
| -e 's/\(UUID: \).*/\1[removed]/' |
| } |
| |
| # Read the logs |
| tail_logs () { |
| files=$(for f in /var/log/messages{.2,.1,} ; do |
| [ -f ${f} ] && echo ${f}; |
| done) |
| if [ -n "$*" ] ; then |
| tail $* ${files} | mac_anonymize |
| else |
| cat ${files} | mac_anonymize |
| fi |
| } |
| |
| # List all ethernet devices and their unique manufacturer strings |
| get_device_list () { |
| fn_enter_once ${FUNCNAME} || return |
| echo "Device list:" |
| for ifc in $(get_iflist); do |
| dir=$(readlink -f /sys/class/net/${ifc}/device) |
| driver=$(basename $(readlink ${dir}/driver)) |
| if expr ${dir} : '.*usb' > /dev/null; then |
| type=usb |
| vendor=$(cat < ${dir}/../idVendor) |
| device=$(cat ${dir}/../idProduct) |
| elif expr ${dir} : '.*pci' > /dev/null; then |
| type=pci |
| vendor=$(sed -e 's/0x//' < ${dir}/vendor) |
| device=$(sed -e 's/0x//' < ${dir}/device) |
| else |
| type=unknown |
| fi |
| echo -e "${ifc}\t${type}:${device}:${vendor}\t${driver}" |
| done |
| } |
| |
| # List all USB and PCI devices |
| diag_devs () { |
| fn_enter_once ${FUNCNAME} || return |
| ${LSUSB} |
| ${LSPCI} |
| } |
| |
| # Check whether we are in sync with the time server |
| diag_date () { |
| local host=$1 |
| fn_enter ${FUNCNAME} $* |
| echo "Local time of day: $(date)" |
| date_error=$(${HTPDATE} -q ${host} 2>&1 >/dev/null) |
| offset=$(${HTPDATE} -q ${host} 2>&1 | awk -v 'FS=[. ]' '{print $2}') |
| if [ -n "${date_error}" ]; then |
| fail "Unable to get date via htpdate from ${host}: ${date_error}" |
| elif [ "${offset}" = time ] ; then |
| pass "Time appears to be correct" |
| elif [ ${offset} -lt -3600 -o ${offset} -gt 3600 ] ; then |
| fail "Time offset = ${offset}" |
| else |
| pass "Time offset is small (${offset})" |
| fi |
| } |
| |
| # Try to detect IP address collisions |
| diag_ip_collision () { |
| fn_enter ${FUNCNAME} $* |
| local ifc=$1 |
| ip=$(get_if_addr ${ifc}) |
| if [ -z "${ip}" ]; then |
| fail "${ifc} does not have IP address" |
| return 1 |
| fi |
| if ${ARPING} -c 3 -I ${ifc} -D ${ip}; then |
| fail "IP Address Collision Detected!" |
| return 1 |
| fi |
| return 0 |
| } |
| |
| # Make sure we have an ARP table entry for $ip through $ifc |
| diag_arp () { |
| fn_enter ${FUNCNAME} $* |
| local ip=$1 |
| local ifc=$2 |
| |
| if [ -n "${ip}" ] ; then |
| arp=$(${ARP} -an | awk '/('${ip}').*'${ifc}'$/ { print $4 }') |
| if [ -z "${arp}" ]; then |
| fail "Arp table does not contain entry for ${ip}" |
| elif [ "${arp}" = "<incomplete>" ] ; then |
| fail "Can't arp for ${ip}" |
| diag_ip_collision ${ifc} |
| else |
| pass "ARP for ${ip} is ${arp}" | mac_anonymize |
| fi |
| fi |
| |
| fn_enter_once ${FUNCNAME}_table && ${ARP} -an | mac_anonymize |
| |
| return 1 |
| } |
| |
| # Make sure we have a route to each host |
| diag_route () { |
| fn_enter ${FUNCNAME} $* |
| failures=0 |
| for ip in $*; do |
| ifinfo=$(get_if_route ${ip}) |
| gwinfo=$(get_gw_route ${ip}) |
| if [ -n "${ifinfo}" ]; then |
| diag_arp ${ip} ${ifinfo} || failures=$[failures + 1] |
| elif [ -n "${gwinfo}" ]; then |
| diag_arp ${gwinfo} || failures=$[failures + 1] |
| else |
| fail "No route to host ${ip}" |
| diag_ifall || failures=$[failures + 1] |
| fi |
| done |
| |
| fn_enter_once ${FUNCNAME}_table && netstat -nr |
| |
| return ${failures} |
| } |
| |
| # Figure whether we have IP connectivity to each host |
| diag_ping () { |
| fn_enter ${FUNCNAME} $* |
| local failures=0 |
| for ip in $*; do |
| if ping -c 3 ${ip} | grep -q '0 received'; then |
| fail "Ping to ${ip} failed" |
| if diag_route ${ip}; then |
| fail "We were able to reach the router but we cannot get packets to" |
| fail "any machines on the other side. The problem is probably with" |
| fail "the router configuration or connectivity and not this system." |
| else |
| fail "We were successfully able to join the network, but we cannot" |
| fail "seem to reach the router right now. This is either a link" |
| fail "level issue or the router is down." |
| fi |
| failures=$[failures + 1] |
| else |
| pass "address ${ip}: ping OK" |
| fi |
| done |
| |
| return ${failures} |
| } |
| |
| # Report the last DHCP interaction for a given network interface |
| diag_dhcp () { |
| fn_enter_once ${FUNCNAME} || return |
| local ifc=$1 |
| shift |
| |
| local -a dhcp_event=($(tail_logs $* | \ |
| grep "dhcpcd.*event.*on interface ${ifc}" | \ |
| sed -e 's/^\([^ ]*\).*event \([A-Z]*\).*/\1 \2/' | tail -1)) |
| |
| last_dhcpcd_event_time=${dhcp_event[0]} |
| last_dhcpcd_event_type=${dhcp_event[1]} |
| case ${last_dhcpcd_event_type} in |
| RENEW|BOUND|REBOOT) |
| pass "${ifc}: last dhcp event was successful:" \ |
| "${last_dhcpcd_event_type} at ${last_dhcpcd_event_time}" |
| ;; |
| *) |
| fail "${ifc}: last dhcp event was" \ |
| "${last_dhcpd_event_type} at ${last_dhcpcd_event_time}" |
| fail "This could be a link-level connectivity problem" |
| ;; |
| esac |
| } |
| |
| # Perform diagnostics on an 802.11 interface |
| diag_link_wifi () { |
| fn_enter ${FUNCNAME} $* |
| ifc=$1 |
| |
| echo -n "${ifc}: " |
| ${IW} dev ${ifc} link |
| ${IW} dev ${ifc} station dump |
| ${IW} dev ${ifc} survey dump |
| |
| last_connect=$(grep -n "${ifc}: connect SSID" /var/log/messages{.1,}) |
| if [ -z "${last_connect}" ] ; then |
| fail "${ifc}: no recent 802.11 connection attempts" |
| return 1 |
| fi |
| |
| local -a lastconn_info=($(IFS=" :"; echo ${last_connect})) |
| file=${lastconn_info[0]} |
| line=${lastconn_info[1]} |
| size=$(wc -l ${file} | awk '{print $1}') |
| tail=$[size - line + 1] |
| state_changes=$(tail -${tail} ${file} | grep 'state change') |
| last_state_change=$(grep 'state change' ${file} | tail -1 | \ |
| sed -e 's/.*state change //') |
| echo "${ifc}: last flimflam state change: ${last_state_change}" |
| if echo "${state_changes}" | grep -q ' -> COMPLETED'; then |
| pass "${ifc}: last connection attempt appears successful" |
| return 0 |
| elif echo "${state_changes}" | \ |
| grep -q '4WAY_HANDSHAKE -> DISCONNECTED'; then |
| fail "${ifc}: It appears that the wrong WPA PSK was used" |
| fi |
| |
| echo "wpa_supplicant network blocks:" |
| wpa_cli list_networks |
| |
| diag_dhcp ${ifc} -${tail} ${file} |
| } |
| |
| # Print out WiFi debugging info |
| diag_wifi () { |
| for dir in /sys/kernel/debug/ieee80211/phy*/ath9k; do |
| [ -d "${dir}" ] && head -1000 ${dir}/{dma,interrupt,recv,xmit,samples} | \ |
| mac_anonymize |
| done |
| for ifc in $(get_iflist); do |
| if is_wifi ${ifc} ; then |
| echo "iw dev ${ifc} survey dump:" |
| ${IW} dev ${ifc} survey dump | mac_anonymize |
| echo "iw dev ${ifc} station dump:" |
| ${IW} dev ${ifc} station dump | mac_anonymize |
| echo "iw dev ${ifc} scan dump:" |
| ${IW} dev ${ifc} scan dump | mac_anonymize | grep -v SSID |
| echo "iw dev ${ifc} link:" |
| ${IW} dev ${ifc} link | mac_anonymize | grep -v SSID |
| fi |
| done |
| } |
| |
| # Perform diagnostics on a WAN interface |
| diag_link_cellular () { |
| fn_enter ${FUNCNAME} $* |
| diag_cellular_dbus |
| diag_devs |
| qcdev=$(get_class_driver tty/ttyUSB qcserial) |
| if [ -n "${qcdev}" ] ; then |
| echo "QCSerial device is ${qcdev}" |
| fi |
| tail_logs | grep "QDL unable" | tail -3 |
| } |
| |
| diag_link_wired () { |
| fn_enter ${FUNCNAME} $* |
| # No tests yet |
| return 0 |
| } |
| |
| # Tests to check to see if this is a modem. Very abstract adaptation |
| # from flimflam's tests |
| is_modem () { |
| local ifc=$1 |
| driver=$(basename $(readlink /sys/class/net/${ifc}/device/driver)) |
| # Whitelist certain device types |
| [ "${driver}" = "QCUSBNet2k" ] && return 0 |
| |
| # See if there is a TTY device that is associated the same USB device |
| dev_root=$(readlink -f /sys/class/net/${ifc}/device) |
| if expr "${dev_root}" : '.*usb' > /dev/null; then |
| local -a tty_devs=($(echo $(dirname ${dev_root})/*/*/tty)) |
| [ -e "${tty_devs[0]}" ] && return 0 |
| fi |
| |
| return 1 |
| } |
| |
| is_wifi () { |
| local ifc=$1 |
| if expr ${ifc} : wlan > /dev/null || \ |
| [ -e /sys/class/net/${ifc}/phy80211 ] ; then |
| return 0 |
| fi |
| return 1 |
| } |
| |
| # Perform type-specific link diagnostics on a network interface |
| diag_link () { |
| fn_enter ${FUNCNAME} $* |
| ifc=$1 |
| |
| if [ "$(cat /sys/class/net/${ifc}/carrier)" -eq 1 ]; then |
| pass "${ifc}: link detected" |
| else |
| pass "${ifc}: link not detected" |
| fi |
| |
| if is_wifi ${ifc} ; then |
| diag_link_wifi ${ifc} |
| elif is_modem ${ifc}; then |
| diag_link_cellular ${ifc} |
| else |
| diag_link_wired ${ifc} |
| fi |
| |
| echo "Last 10 kernel messages for ${ifc}:" |
| tail_logs | grep "kernel:.*${ifc}" | tail -10 |
| } |
| |
| diag_linkall () { |
| for ifc in $(get_iflist); do |
| diag_link ${ifc} |
| done |
| } |
| |
| # Perform generic diagonostics on a network interface |
| diag_if () { |
| fn_enter ${FUNCNAME} $* |
| ifc=$1 |
| config=$(${IFCONFIG} ${ifc}) |
| ret=0 |
| ${IFCONFIG} ${ifc} | mac_anonymize |
| if ! echo "${config}" | grep -q ' UP '; then |
| fail "${ifc} is not listed as up" |
| ret=1 |
| elif ! echo "${config}" | grep -q ' RUNNING '; then |
| fail "${ifc} is not listed as running" |
| ret=1 |
| fi |
| |
| addr=$(get_if_addr ${ifc}) |
| if [ -n "${addr}" ]; then |
| pass "${ifc} assigned IP address ${addr}" |
| diag_dhcp ${ifc} |
| else |
| fail "${ifc} is not assigned an IP address" |
| ret=1 |
| fi |
| diag_link ${ifc} |
| return ${ret} |
| } |
| |
| # Query interface status on all network interfaces, and return an error if |
| # none of them appear to be up |
| diag_ifall () { |
| fn_enter_once ${FUNCNAME} || return |
| |
| local good_ifs=0 |
| for ifc in $(get_iflist); do |
| diag_if ${ifc} && good_ifs=$[good_ifs + 1] |
| done |
| if [ ${good_ifs} -eq 0 ] ; then |
| fail "No good interfaces found. You are not connected to a network." |
| get_status flimflam |
| get_status wpa_supplicant |
| get_status cromo |
| return 1 |
| fi |
| diag_flimflam |
| return 0 |
| } |
| |
| # Diagnose nameserver connectivity |
| diag_nameservers () { |
| fn_enter_once ${FUNCNAME} || return |
| nameservers=$(get_nameservers) |
| if [ -z "${nameservers}" ] ; then |
| fail "No nameservers -- this is either a network failure or net misconfig" |
| get_tracelink /etc/resolv.conf |
| diag_ifall |
| else |
| echo "Testing connectivity to nameservers" |
| if diag_ping $(get_nameservers); then |
| fail "We can reach the nameservers but were not able to resolve hostnames" |
| fail "You may be behind a captive portar or there may be a DNS" |
| fail "configuration problem" |
| fi |
| fi |
| } |
| |
| # See if we can connect to a given host |
| diag_connectivity () { |
| fn_enter_once ${FUNCNAME} $* || exit 0 |
| local host=$1 |
| local ip=$(get_host_addr $host) |
| if [ -z "${ip}" ] ; then |
| fail "Could not lookup host ${host}" |
| diag_nameservers |
| return 1 |
| fi |
| |
| if diag_ping ${ip}; then |
| fail "We were able to ping ${host} but were not able to connect to it." |
| fail "This probably means that you are behind a portal or (unlikely)" |
| fail "${host} is encountering technical difficulties" |
| fi |
| } |
| |
| # Get information from flimflam about its state over D-Bus. |
| diag_flimflam_dbus () { |
| fn_enter_once ${FUNCNAME} $* |
| local ff="org.chromium.flimflam" |
| if [ -z "$1" ] ; then |
| echo "Flimflam Manager:" |
| dbus-send --fixed --system --dest="${ff}" --print-reply / \ |
| ${ff}.Manager.GetProperties | mac_anonymize |
| # For each Service defined on the Manager, list its properties |
| diag_flimflam_dbus Manager Service |
| # For each Device defined in the Manager, list its properties |
| diag_flimflam_dbus Manager Device |
| else |
| local parent=$1 |
| local child=$2 |
| local parent_path=${3-/} |
| for path in $(dbus-send --fixed --system --dest="${ff}" --print-reply \ |
| ${parent_path} ${ff}.${parent}.GetProperties | \ |
| awk '/^\/[0-9]*\/'${child}'s\// { print $2 }'); do |
| echo "${child} ${path}" | mac_anonymize |
| dbus-send --fixed --system --dest="${ff}" --print-reply ${path} \ |
| ${ff}.${child}.GetProperties | mac_anonymize |
| if [ "${child}" = Device ] ; then |
| # For each Network defined in each Device, list its properties |
| diag_flimflam_dbus Device Network ${path} |
| fi |
| done |
| fi |
| } |
| |
| # Get information from ModemManager about its state over D-Bus |
| diag_cellular_dbus () { |
| fn_enter ${FUNCNAME} $* |
| dbus-send --fixed --system --print-reply --dest=org.chromium.ModemManager \ |
| /org/chromium/ModemManager \ |
| org.freedesktop.ModemManager.EnumerateDevices || \ |
| fail "Could not contact ModemManager!" |
| } |
| |
| # Probe process status of flimflam and its process descendants |
| diag_flimflam () { |
| fn_enter_once ${FUNCNAME} || return |
| local status=$(get_status flimflam) |
| echo "${status}" |
| if ! echo ${status} | fgrep -q 'running'; then |
| return |
| fi |
| local pid=$(echo ${status} | awk '{print $4}') |
| ps jx | awk '/^ *'${pid}'/ {print $10,$11,$12}' | sort | uniq -c |
| echo "Listing of /var/run/flimflam" |
| ls -al /var/run/flimflam |
| diag_flimflam_dbus |
| } |
| |
| # Try to connect to a host |
| diag_webget () { |
| local host=${1} |
| echo "Trying to contact ${host} ... " |
| curl -s https://${host}/ > /dev/null |
| local err=$? |
| |
| case ${err} in |
| 0) |
| pass "We can get to https://www.google.com/ just fine" |
| ;; |
| |
| 6) |
| # DNS resolution error |
| fail "Got DNS resolution error -- trying to debug nameservers" |
| diag_nameservers |
| ;; |
| |
| 7) |
| # Failed to connect to host |
| fail "Got connection error -- trying to debug connection to host" |
| diag_connectivity ${host} |
| ;; |
| |
| 28) |
| # Operation timed out |
| fail "Operation timed out during connection to ${host}" |
| diag_connectivity ${host} |
| diag_ifall |
| ;; |
| |
| 35) |
| # SSL connect error. The SSL handshaking failed |
| fail "SSL connect error. The SSL handshaking failed" |
| diag_connectivity ${host} |
| diag_ifall |
| ;; |
| |
| 60) |
| # Peer certificate cannot be authenticated with known CA certificates |
| fail "Peer cert not authenticated -- probably a hotspot!" |
| ;; |
| |
| *) |
| fail "Encountered unhandled curl error ${err}" |
| ;; |
| esac |
| if [ ${err} -ne 0 ] ; then |
| get_device_list |
| diag_flimflam |
| fi |
| return $err |
| } |
| |
| # Do standard run of tests |
| diag_run () { |
| local host=$1 |
| diag_webget ${host} |
| diag_date ${host} |
| } |
| |
| usage () { |
| echo "Usage: $0 [--date|--flimflam|--link|--show-macs|--wifi|--help] <host>" |
| echo " --date: Diagnose time-of-day" |
| echo " --flimflam: Diagnose flimflam status" |
| echo " --interface: Diagnose interface status" |
| echo " --link: Diagnose all network links" |
| echo " --show-macs: Display full MAC addresses" |
| echo " --wifi: Display driver-specific debugging information" |
| echo " --help: Display this message" |
| echo " <host> Hustname to perform web access test on" |
| } |
| |
| main () { |
| if [ $# -gt 0 ]; then |
| default_run=yes |
| for param in $@; do |
| case $param in |
| --date) |
| default_run=no |
| diag_date ${test_host} |
| ;; |
| --flimflam) |
| default_run=no |
| diag_flimflam |
| ;; |
| --interface) |
| default_run=no |
| diag_ifall |
| ;; |
| --link) |
| default_run=no |
| diag_linkall |
| ;; |
| --no-log) |
| : # Handled below before starting main |
| ;; |
| --show-macs) |
| anonymize_macs=no |
| ;; |
| --wifi) |
| default_run=no |
| diag_wifi |
| ;; |
| --help|-help|-h|-*) |
| usage |
| exit 0 |
| ;; |
| *) |
| test_host=$param |
| ;; |
| esac |
| done |
| if [ "${default_run}" = "no" ] ; then |
| exit ${fail_count} |
| fi |
| fi |
| diag_run ${test_host} |
| } |
| |
| if [ -d /home/${USER}/user/Downloads ] && \ |
| ! expr "$*" : '.*--no-log' >/dev/null; then |
| # Log this output to somewhere the user can upload from |
| main $@ 2>&1 | \ |
| tee $(unique_file /home/${USER}/user/Downloads/network_diagnostics_\*.txt) |
| else |
| main $@ |
| fi |
| |
| exit ${fail_count} |