meta-digi/meta-digi-dey/recipes-digi/sysinfo/sysinfo/sysinfo

662 lines
19 KiB
Bash
Executable File

#!/bin/sh
#===============================================================================
#
# sysinfo
#
# Copyright (C) 2016-2026 by Digi International Inc.
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published by
# the Free Software Foundation.
#
#
# !Description: System information gather script
#
#===============================================================================
FW_PRINTENV="$(which fw_printenv)"
QRENCODE="$(which qrencode)"
WESTON_IMAGE="$(which weston-image)"
FBSPLASH="$(which fbsplash)"
QR_PREFIX="50000000-01;A"
QR_TEMP_FILES=""
QR_VIEWER_PID=""
usage() {
echo "Usage:"
echo " sysinfo"
echo " sysinfo --qr_display"
}
add_temp_file() {
QR_TEMP_FILES="${QR_TEMP_FILES} $1"
}
cleanup_temp_files() {
for f in ${QR_TEMP_FILES}; do
[ -n "${f}" ] && rm -f "${f}"
done
}
# Compose the compact payload encoded in the QR from runtime device data.
get_qr_payload() {
QR_MACADDR=""
if [ -x "${FW_PRINTENV}" ]; then
QR_MACADDR="$("${FW_PRINTENV}" -n "ethaddr" 2>/dev/null | tr -d ':')"
fi
if [ -z "${QR_MACADDR}" ]; then
echo "Error: unable to read 'ethaddr' from fw_printenv" >&2
return 1
fi
QR_SERIAL="$(cat /proc/device-tree/serial-number 2>/dev/null | tr -d '\0')"
if [ -z "${QR_SERIAL}" ]; then
echo "Error: unable to read 'serial-number' from /proc/device-tree" >&2
return 1
fi
QR_DRM_IC="$(cat /proc/device-tree/digi,drm-ic 2>/dev/null | tr -d '\0')"
printf "%s;%s;MAC%s%s\n" "${QR_PREFIX}" "${QR_SERIAL}" "${QR_MACADDR}" "${QR_DRM_IC:+;${QR_DRM_IC}}"
}
get_framebuffer_device() {
if [ -e "/dev/fb0" ]; then
echo "/dev/fb0"
return 0
fi
ls /dev/fb* 2>/dev/null | grep -m 1 '^/dev/fb'
}
get_framebuffer_size() {
FB_DEVICE="$1"
FB_NAME="$(basename "${FB_DEVICE}")"
FB_SIZE_PATH="/sys/class/graphics/${FB_NAME}/virtual_size"
if [ -r "${FB_SIZE_PATH}" ]; then
tr ',' ' ' < "${FB_SIZE_PATH}"
return 0
fi
return 1
}
is_weston_running() {
pidof weston >/dev/null 2>&1
}
wait_for_keypress() {
if [ ! -t 0 ]; then
return 0
fi
echo "Press any key to close the QR code"
old_stty="$(stty -g 2>/dev/null)" || return 0
stty -echo -icanon min 1 time 0 2>/dev/null || return 0
dd bs=1 count=1 >/dev/null 2>&1
stty "${old_stty}" 2>/dev/null || true
}
print_qr() {
if [ ! -x "${QRENCODE}" ]; then
echo "Error: qrencode is not installed" >&2
return 1
fi
QR_SERIAL="$(cat /proc/device-tree/serial-number 2>/dev/null | tr -d '\0')"
QR_MACADDR=""
if [ -x "${FW_PRINTENV}" ]; then
QR_MACADDR="$("${FW_PRINTENV}" -n "ethaddr" 2>/dev/null | tr -d ':')"
fi
QR_DRM_IC="$(cat /proc/device-tree/digi,drm-ic 2>/dev/null | tr -d '\0')"
QR_PAYLOAD="$(get_qr_payload)" || return 1
echo "MAC Address: ${QR_MACADDR}"
echo "Serial Number: ${QR_SERIAL}"
if [ -n "${QR_DRM_IC}" ]; then
echo "Device Default Password: ${QR_DRM_IC}"
fi
printf "%s" "${QR_PAYLOAD}" | "${QRENCODE}" -t ANSIUTF8
echo ""
echo "This QR code is used to provision the device in Digi Remote Manager."
}
# PNG output is used by the Wayland/Weston path.
generate_qr_png() {
QR_PAYLOAD="$(get_qr_payload)" || return 1
QR_PNG_PATH="/tmp/sysinfo-qr.png"
"${QRENCODE}" -o "${QR_PNG_PATH}" -s 8 -m 2 "${QR_PAYLOAD}" || return 1
echo "${QR_PNG_PATH}"
}
# fbsplash only accepts raw PPM images, so convert qrencode ASCII output into
# a binary P6 image and generate a small ini file to center it on screen.
generate_qr_ppm() {
FB_DEVICE="$1"
QR_PAYLOAD="$(get_qr_payload)" || return 1
QR_ASCII_PATH="/tmp/sysinfo-qr.txt"
QR_MATRIX_PATH="/tmp/sysinfo-qr.matrix"
QR_PPM_PATH="/tmp/sysinfo-qr.ppm"
QR_INI_PATH="/tmp/sysinfo-qr.ini"
FB_SIZE="$(get_framebuffer_size "${FB_DEVICE}")"
add_temp_file "${QR_ASCII_PATH}"
add_temp_file "${QR_MATRIX_PATH}"
add_temp_file "${QR_PPM_PATH}"
add_temp_file "${QR_INI_PATH}"
if [ -n "${FB_SIZE}" ]; then
FB_WIDTH="$(echo "${FB_SIZE}" | awk '{print $1}')"
FB_HEIGHT="$(echo "${FB_SIZE}" | awk '{print $2}')"
fi
"${QRENCODE}" -t ASCII -o "${QR_ASCII_PATH}" "${QR_PAYLOAD}" || return 1
awk '
BEGIN {
height = 0
width = 0
}
{
line = $0
if (length(line) > width) {
width = length(line)
}
lines[++height] = line
}
END {
if (height == 0) {
exit 1
}
# qrencode ASCII uses double-width horizontal cells. Collapse each pair
# into a single logical QR module encoded as 1/0.
module_width = int((width + 1) / 2)
print module_width, height
for (y = 1; y <= height; y++) {
line = lines[y]
while (length(line) < module_width * 2) {
line = line " "
}
row = ""
for (x = 1; x <= module_width * 2; x += 2) {
pair = substr(line, x, 2)
row = row (index(pair, "#") ? "1" : "0")
}
print row
}
}
' "${QR_ASCII_PATH}" > "${QR_MATRIX_PATH}" || return 1
IFS=' ' read -r QR_WIDTH QR_HEIGHT < "${QR_MATRIX_PATH}" || return 1
QR_SCALE=4
IMG_WIDTH=$((QR_WIDTH * QR_SCALE))
IMG_HEIGHT=$((QR_HEIGHT * QR_SCALE))
IMG_LEFT=0
IMG_TOP=0
if [ -n "${FB_WIDTH}" ] && [ "${FB_WIDTH}" -gt "${IMG_WIDTH}" ] 2>/dev/null; then
IMG_LEFT=$(((FB_WIDTH - IMG_WIDTH) / 2))
fi
if [ -n "${FB_HEIGHT}" ] && [ "${FB_HEIGHT}" -gt "${IMG_HEIGHT}" ] 2>/dev/null; then
IMG_TOP=$(((FB_HEIGHT - IMG_HEIGHT) / 2))
fi
{
echo "BAR_LEFT=0"
echo "BAR_TOP=0"
echo "BAR_WIDTH=0"
echo "BAR_HEIGHT=0"
echo "BAR_R=0"
echo "BAR_G=0"
echo "BAR_B=0"
echo "IMG_LEFT=${IMG_LEFT}"
echo "IMG_TOP=${IMG_TOP}"
} > "${QR_INI_PATH}" || return 1
printf 'P6\n%s %s\n255\n' "${IMG_WIDTH}" "${IMG_HEIGHT}" > "${QR_PPM_PATH}" || return 1
awk -v scale="${QR_SCALE}" -v width="${QR_WIDTH}" '
NR == 1 { next }
{
row = $0
# Expand each logical QR module into a scale x scale pixel block.
for (repeat_y = 0; repeat_y < scale; repeat_y++) {
for (i = 1; i <= width; i++) {
pixel = substr(row, i, 1)
color = (pixel == "1") ? 0 : 255
for (repeat_x = 0; repeat_x < scale; repeat_x++) {
printf "%c%c%c", color, color, color
}
}
}
}
' "${QR_MATRIX_PATH}" >> "${QR_PPM_PATH}" || return 1
echo "${QR_PPM_PATH}"
}
# On graphical images, rely on Weston to render the PNG in a proper window.
display_qr_wayland() {
if [ -x "${WESTON_IMAGE}" ] && [ -n "${WAYLAND_DISPLAY}" ] && is_weston_running; then
QR_PNG_PATH="$(generate_qr_png)" || return 1
"${WESTON_IMAGE}" "${QR_PNG_PATH}" >/dev/null 2>/dev/null &
QR_VIEWER_PID=$!
return 0
fi
return 1
}
# Select the most suitable display backend for the current runtime.
display_qr() {
FB_DEVICE="$(get_framebuffer_device)"
if [ -n "${SYSINFO_QR_DISPLAY_HOOK}" ] && [ -x "${SYSINFO_QR_DISPLAY_HOOK}" ]; then
QR_PNG_PATH="$(generate_qr_png)" || return 1
"${SYSINFO_QR_DISPLAY_HOOK}" "${QR_PNG_PATH}"
return $?
fi
display_qr_wayland && return 0
if [ -x "${FBSPLASH}" ] && [ -n "${FB_DEVICE}" ]; then
QR_PPM_PATH="$(generate_qr_ppm "${FB_DEVICE}")" || return 1
QR_INI_PATH="/tmp/sysinfo-qr.ini"
echo "Framebuffer device: ${FB_DEVICE}"
"${FBSPLASH}" -s "${QR_PPM_PATH}" -d "${FB_DEVICE}" -i "${QR_INI_PATH}" -c
return $?
fi
echo "Error: no display backend available" >&2
echo "Detected framebuffer: ${FB_DEVICE:-[NONE]}" >&2
echo "Set SYSINFO_QR_DISPLAY_HOOK or use Weston/fbsplash-capable images" >&2
return 1
}
trap cleanup_temp_files EXIT INT TERM
make_report(){
echo "--------------------------------------"
echo "- -"
echo "- Uptime -"
echo "- -"
echo "--------------------------------------"
echo ""
uptime
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Firmware version -"
echo "- -"
echo "--------------------------------------"
echo ""
sed -n 's/^firmware \(.*\)/\1/p' < /etc/sw-versions
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Kernel version -"
echo "- -"
echo "--------------------------------------"
echo ""
uname -a
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- OS release -"
echo "- -"
echo "--------------------------------------"
echo ""
if [ -f "/etc/os-release" ]; then
cat /etc/os-release
else
echo "[NOT FOUND] /etc/os-release"
fi
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Build configurations -"
echo "- -"
echo "--------------------------------------"
echo ""
if [ -f "/etc/buildinfo" ]; then
cat /etc/buildinfo
else
echo "[NOT FOUND] /etc/buildinfo"
fi
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- U-boot saved environment -"
echo "- -"
echo "--------------------------------------"
echo ""
if [ -x "${FW_PRINTENV}" ]; then
${FW_PRINTENV}
else
echo "[NOT FOUND] fw_printenv"
fi
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Linux boot log -"
echo "- -"
echo "--------------------------------------"
echo ""
dmesg
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Log files from /var/log -"
echo "- -"
echo "--------------------------------------"
echo ""
for f in $(find /var/log/ -name "*.log"); do
echo "${f} FILE";
echo "---------------------------------------";
cat ${f};
printf "\n\n"
done
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- /var/log/messages -"
echo "- -"
echo "--------------------------------------"
echo ""
if [ -f "/var/log/messages" ]; then
cat /var/log/messages
else
echo "[NOT FOUND] /var/log/messages"
fi
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Linux kernel configuration -"
echo "- -"
echo "--------------------------------------"
echo ""
if [ -f "/proc/config.gz" ]; then
zcat /proc/config.gz
else
echo "[NOT FOUND] /proc/config.gz"
fi
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Memory consumption -"
echo "- -"
echo "--------------------------------------"
echo ""
free
printf "\n"
cat /proc/meminfo
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Running processes -"
echo "- -"
echo "--------------------------------------"
echo ""
ps -l
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Mounts -"
echo "- -"
echo "--------------------------------------"
echo ""
mount
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Opened ports -"
echo "- -"
echo "--------------------------------------"
echo ""
netstat -n -a -p
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Routes -"
echo "- -"
echo "--------------------------------------"
echo ""
route -n
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- Network configuration -"
echo "- -"
echo "--------------------------------------"
echo ""
ifconfig -a
printf "\n"
ip link show
printf "\n"
echo "--------------------------------------"
echo "- -"
echo "- Wireless configuration -"
echo "- -"
echo "--------------------------------------"
echo ""
wpa_supplicant -v 2>/dev/null
echo ""
if [ -f "/etc/wpa_supplicant.conf" ]; then
echo "wpa_supplicant.conf:"
cat "/etc/wpa_supplicant.conf"
else
echo "[NOT FOUND] /etc/wpa_supplicant.conf"
fi
echo ""
if [ -f "/etc/wpa_supplicant_p2p.conf" ]; then
echo "wpa_supplicant_p2p.conf:"
cat "/etc/wpa_supplicant_p2p.conf"
else
echo "[NOT FOUND] /etc/wpa_supplicant_p2p.conf"
fi
echo ""
hostapd -v 2>&1
echo ""
if [ -f "/etc/hostapd.conf" ]; then
echo "hostapd.conf:"
cat "/etc/hostapd.conf"
else
echo "[NOT FOUND] hostapd.conf"
fi
echo ""
if [ -f "/etc/hostapd_wlan0.conf" ]; then
echo "hostapd_wlan0.conf:"
cat "/etc/hostapd_wlan0.conf"
else
echo "[NOT FOUND] /etc/hostapd_wlan0.conf"
fi
echo ""
if [ -f "/etc/hostapd_wlan1.conf" ]; then
echo "hostapd_wlan1.conf:"
cat "/etc/hostapd_wlan1.conf"
else
echo "[NOT FOUND] /etc/hostapd_wlan1.conf"
fi
printf "\n\n"
echo "--------------------------------------"
echo "- -"
echo "- OTP values -"
echo "- -"
echo "--------------------------------------"
echo ""
if grep -qs '\<digi,ccimx8x\>' /proc/device-tree/compatible; then
OTP_PATH="/sys/devices/platform/scu/scu\:imx8qx-ocotp/imx-scu-ocotp0"
else
OTP_PATH="/sys/bus/nvmem/devices/imx-ocotp0"
fi
if [ -e ${OTP_PATH}/nvmem ]; then
echo "${OTP_PATH}:"
hexdump -C -v ${OTP_PATH}/nvmem
echo ""
fi
echo "--------------------------------------"
echo "- -"
echo "- TrustFence -"
echo "- -"
echo "--------------------------------------"
echo ""
if grep -qs '\<digi,ccimx8\(x\|m\)\>' /proc/device-tree/compatible; then
if [ -f "/proc/device-tree/digi,tf-closed" ]; then
echo "Security status: [CLOSED]"
elif [ -f "/proc/device-tree/digi,tf-open" ]; then
echo "Security status: [OPEN]"
fi
else
if [ -e ${OTP_PATH}/nvmem ]; then
# Check SEC_CONFIG on OCOTP_CFG5 (ADDR=6) bit 1.
SEC_CONFIG_WORD=$(dd if=${OTP_PATH}/nvmem of=/dev/stdout bs=4 skip=6 count=1 status=none | hexdump -n 4 -v -e '1/4 "0x%08x\n"')
if [ "$((${SEC_CONFIG_WORD} & 0x2))" != "0" ]; then
echo "Security status: [CLOSED]"
else
echo "Security status: [OPEN]"
fi
else
echo "Security status: [UNKNOWN]"
fi
fi
if [ -f "/proc/device-tree/digi,uboot-env,encrypted" ]; then
echo "U-Boot environment is encrypted"
else
echo "U-Boot environment is NOT encrypted"
fi
echo "-------------End of report------------"
}
DISTRO="$(sed -ne 's,DISTRO = \(.*\)$,\1,g;T;p' /etc/buildinfo)"
DEY_VERSION="$(sed -ne 's,DISTRO_VERSION = \(.*\)$,\1,g;T;p' /etc/buildinfo)"
UBOOT_VERSION="$(cat /proc/device-tree/digi,uboot,version 2>/dev/null | tr -d '\0')"
if [ -z "${UBOOT_VERSION}" ]; then
UBOOT_PARTITION="/dev/mmcblk0boot0"
[ -c "/dev/mtd0" ] && UBOOT_PARTITION="/dev/mtd0"
UBOOT_VERSION="$(strings ${UBOOT_PARTITION} | grep -m 1 dub | cut -d' ' -f2)"
fi
MACHINE="$(cat /proc/device-tree/compatible | tr '\0' '\t' | cut -f 1)"
if grep -qs 'DVK' /proc/device-tree/model; then
BOARD_TYPE="DVK"
else
BOARD_TYPE="SBC"
fi
BOARD_VARIANT="$(cat /proc/device-tree/digi,hwid,variant | tr -d '\0')"
BOARD_SN="$(cat /proc/device-tree/digi,hwid,sn | tr -d '\0')"
BOARD_VERSION="$(cat /proc/device-tree/digi,carrierboard,version | tr -d '\0')"
[ -e "/proc/device-tree/digi,carrierboard,id" ] && BOARD_ID="$(cat /proc/device-tree/digi,carrierboard,id | tr -d '\0')"
[ -e "/proc/device-tree/cpus/rev" ] && SOC_REV="$(cat /proc/device-tree/cpus/rev | tr -d '\0')"
if grep -qs '\<digi,ccimx6ul\>' /proc/device-tree/compatible; then
MCA_NODE="/sys/bus/i2c/devices/0-007e"
elif grep -qs '\<digi,ccimx8\(x\|m\)\>' /proc/device-tree/compatible; then
MCA_NODE="/sys/bus/i2c/devices/0-0063"
elif grep -qs '\<digi,ccimx95\>' /proc/device-tree/compatible; then
MCA_NODE="/sys/bus/i2c/devices/7-0020"
fi
if [ -d "$MCA_NODE" ]; then
MCA_HW_VERSION=$(cat ${MCA_NODE}/hw_version 2>/dev/null | tr -d '\0') || MCA_HW_VERSION="??"
MCA_FW_VERSION=$(cat ${MCA_NODE}/fw_version 2>/dev/null | tr -d '\0') || MCA_FW_VERSION="??"
MCA_VERSION="HW_VERSION=${MCA_HW_VERSION} FW_VERSION=${MCA_FW_VERSION}"
fi
IOEXP_NODE="/sys/bus/i2c/devices/0-006e"
if [ -d "$IOEXP_NODE" ]; then
IOEXP_HW_VERSION=$(cat ${IOEXP_NODE}/hw_version 2>/dev/null | tr -d '\0') || IOEXP_HW_VERSION="??"
IOEXP_FW_VERSION=$(cat ${IOEXP_NODE}/fw_version 2>/dev/null | tr -d '\0') || IOEXP_FW_VERSION="??"
IOEXP_VERSION="HW_VERSION=${IOEXP_HW_VERSION} FW_VERSION=${IOEXP_FW_VERSION}"
fi
DATE="$(date "+%Y%m%d%H%M%S")"
REPORT_PATH="/tmp/sysinfo-${DEY_VERSION}-${BOARD_SN}-${DATE}"
DISPLAY_QR="0"
while [ $# -gt 0 ]; do
case "$1" in
--qr_display)
DISPLAY_QR="1"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Error: unknown argument '$1'" >&2
usage >&2
exit 1
;;
esac
done
print_qr || exit $?
(
echo "-------------------------------------"
echo "- -"
echo "- ENVIRONMENT TABLE -"
echo "- -"
echo "-------------------------------------"
echo ""
echo "|||:Component|:Version"
DUT_HEADER="SN-${BOARD_SN}, ${MACHINE} ${BOARD_VARIANT} ${BOARD_TYPE}v${BOARD_VERSION}"
if [ -n "${BOARD_ID}" ]; then
DUT_HEADER="${DUT_HEADER} board_ID=${BOARD_ID}"
fi
if [ -n "${SOC_REV}" ]; then
DUT_HEADER="${DUT_HEADER} SOC_REV=${SOC_REV}"
fi
echo "|| DUT | ${DUT_HEADER}"
echo "|| U-Boot | ${UBOOT_VERSION}"
echo "|| Firmware version | $(sed -n 's/^firmware \(.*\)/\1/p' < /etc/sw-versions)"
echo "|| DEY version | ${DISTRO}-${DEY_VERSION}-$(cat /etc/version)"
echo "|| Kernel | $(uname -a)"
echo "|| meta-digi | $(sed -ne '/^meta-digi-dey/s,.*= \(.*\)$,\1,g;T;p' /etc/buildinfo)"
[ -n "${MCA_VERSION}" ] && echo "|| MCA | ${MCA_VERSION}"
[ -n "${IOEXP_VERSION}" ] && echo "|| I/O Expander | ${IOEXP_VERSION}"
printf "\n\n"
) | tee "${REPORT_PATH}.txt"
make_report >> "${REPORT_PATH}.txt"
tar -zhcf "${REPORT_PATH}.tar.gz" -C $(dirname ${REPORT_PATH}) $(basename "${REPORT_PATH}.txt") /proc/device-tree 2> /dev/null
echo "Report generated in ${REPORT_PATH}.tar.gz"
rm -rf "${REPORT_PATH}.txt"
if [ "${DISPLAY_QR}" = "1" ]; then
display_qr || exit $?
wait_for_keypress
if [ -n "${QR_VIEWER_PID}" ]; then
kill "${QR_VIEWER_PID}" >/dev/null 2>&1 || true
wait "${QR_VIEWER_PID}" 2>/dev/null || true
fi
fi