#!/bin/sh # Collect a local hardware report for Clawdie live-USB support and future # custom ISO builds. This command never uploads unless explicitly requested. set -u PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" export PATH usage() { cat <<'EOF' Usage: hw-report [--upload-public-probe] [--no-smart] Collect a local hardware diagnostics bundle under /home/clawdie/hw-reports when that home directory exists, otherwise under $HOME/hw-reports. Options: --upload-public-probe Also run hw-probe -all -upload. This submits an anonymous public report to bsd-hardware.info. --no-smart Skip smartctl disk probes. -h, --help Show this help. Recommended live-USB invocation: mdo -u root hw-report EOF } _upload_public_probe="NO" _run_smart="YES" while [ "$#" -gt 0 ]; do case "$1" in --upload-public-probe) _upload_public_probe="YES" ;; --no-smart) _run_smart="NO" ;; -h|--help) usage exit 0 ;; *) echo "ERROR: unknown option: $1" >&2 usage >&2 exit 2 ;; esac shift done if [ "$(id -u)" -ne 0 ]; then echo "WARNING: not running as root; some hardware data will be incomplete." >&2 echo "Recommended: mdo -u root hw-report" >&2 fi _stamp="$(date -u '+%Y%m%dT%H%M%SZ')" _host="$(hostname 2>/dev/null || echo clawdie-live)" _report_name="hw-report-${_host}-${_stamp}" if [ -d /home/clawdie ]; then _base="${CLAWDIE_HW_REPORT_DIR:-/home/clawdie/hw-reports}" else _base="${CLAWDIE_HW_REPORT_DIR:-${HOME:-/root}/hw-reports}" fi _report_dir="${_base}/${_report_name}" _raw_dir="${_report_dir}/raw" _logs_dir="${_report_dir}/logs" mkdir -p "${_raw_dir}" "${_logs_dir}" _log="${_report_dir}/collection.log" : > "${_log}" note() { printf '%s %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*" | tee -a "${_log}" } have() { command -v "$1" >/dev/null 2>&1 } run_capture() { _name="$1" shift _out="${_raw_dir}/${_name}.txt" note "collect ${_name}: $*" { printf '# command: %s\n' "$*" printf '# collected_utc: %s\n\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$@" } > "${_out}" 2>&1 _rc=$? printf '\n# exit_status: %s\n' "${_rc}" >> "${_out}" if [ "${_rc}" -ne 0 ]; then note "WARN ${_name} exited ${_rc}" fi return 0 } run_shell_capture() { _name="$1" _cmd="$2" _out="${_raw_dir}/${_name}.txt" note "collect ${_name}: ${_cmd}" { printf '# command: %s\n' "${_cmd}" printf '# collected_utc: %s\n\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" /bin/sh -c "${_cmd}" } > "${_out}" 2>&1 _rc=$? printf '\n# exit_status: %s\n' "${_rc}" >> "${_out}" if [ "${_rc}" -ne 0 ]; then note "WARN ${_name} exited ${_rc}" fi return 0 } run_if_present() { _cmd="$1" _name="$2" shift 2 if have "${_cmd}"; then run_capture "${_name}" "${_cmd}" "$@" else note "skip ${_name}: ${_cmd} not found" fi } run_shell_if_present() { _cmd="$1" _name="$2" _script="$3" if have "${_cmd}"; then run_shell_capture "${_name}" "${_script}" else note "skip ${_name}: ${_cmd} not found" fi } json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g' } note "start ${_report_name}" cat > "${_report_dir}/README.txt" <<'EOF' Clawdie hardware report bundle This is a local diagnostics bundle for FreeBSD/Clawdie live-USB support and future custom ISO builds. It is not uploaded automatically. Privacy notes: - This bundle may contain hostnames, MAC addresses, disk model/serial strings, USB/PCI IDs, kernel messages, local network interface state, Xorg/SDDM log details, device names, and monitor EDID or serial-like strings. - Review before sharing. - Public hw-probe upload only happens when hw-report is run with --upload-public-probe. EOF run_capture uname-a uname -a run_if_present freebsd-version freebsd-version-kru -kru run_capture hostname hostname run_capture date-utc date -u '+%Y-%m-%dT%H:%M:%SZ' run_if_present uptime uptime run_if_present pciconf pciconf-lv -lv run_if_present pciconf pciconf-lvbce -lvbce run_if_present usbconfig usbconfig run_if_present usbconfig usb-device-desc dump_device_desc run_if_present usbconfig usb-all-desc dump_all_desc run_if_present devinfo devinfo-rv -rv run_if_present dmidecode dmidecode run_if_present service dbus-status dbus onestatus run_if_present service sddm-status sddm onestatus run_if_present kldstat kldstat run_if_present kldstat kldstat-v -v run_if_present dmesg dmesg run_shell_capture dmesg-hardware-filter "dmesg | egrep -i 'drm|kms|amdgpu|i915|radeon|nvidia|firmware|wifi|wlan|iwm|iwlwifi|rtwn|urtwn|run|otus|mt76|usb|uhub|ure|ue[0-9]|realtek|rtl|bluetooth|ubt|bcm|cypress|webcam|video|hid|iichid|hms|hmt|elan|touch|acpi|battery|powerd'" run_shell_capture dmesg-boot "for f in /var/run/dmesg.boot; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture xorg-var-logs "for f in /var/log/Xorg.*.log*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture xorg-user-logs "for f in /home/clawdie/.local/share/xorg/Xorg.*.log*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture xsession-errors "for f in /home/clawdie/.xsession-errors /home/clawdie/.xsession-errors.old; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture var-log-messages "for f in /var/log/messages*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; case \"\$f\" in *.gz) zcat \"\$f\";; *.bz2) bzcat \"\$f\";; *.xz) xzcat \"\$f\";; *.zst) zstdcat \"\$f\";; *) cat \"\$f\";; esac; echo; done" run_shell_capture sddm-log-files "for f in /var/log/sddm.log; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture sddm-config "for f in /usr/local/etc/sddm.conf /usr/local/etc/sddm.conf.d/*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture loader-conf-files "for f in /boot/loader.conf /boot/loader.conf.local; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_if_present kenv kenv run_shell_capture xorg-config-snippets "for f in /usr/local/etc/X11/xorg.conf.d/* /etc/X11/xorg.conf.d/* /usr/local/share/X11/xorg.conf.d/*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_if_present ifconfig ifconfig-a -a run_if_present netstat netstat-rn -rn run_shell_capture resolver-state "ls -l /etc/resolv.conf 2>/dev/null || true; readlink /etc/resolv.conf 2>/dev/null || true; cat /etc/resolv.conf 2>/dev/null || true" run_shell_capture wlan-devices "sysctl net.wlan.devices" run_shell_capture rc-conf-live "grep -E '^(hostname|kld_list|sshd_enable|tailscaled_enable|avahi_daemon_enable|pf_enable|sddm_enable|webcamd_enable|powerdxx_enable|colibri_daemon_enable|clawdie_live_|performance_cx_lowest|economy_cx_lowest|dumpdev_enable)' /etc/rc.conf || true" run_if_present service service-enabled -e run_if_present sysctl sysctl-hw hw run_if_present sysctl sysctl-machdep machdep run_shell_capture sysctl-selected "sysctl hw.acpi hw.dri kern.disks kern.geom net.wlan.devices dev.cpu 2>/dev/null || true" run_shell_capture sysctl-drm-hw-dri "sysctl dev.drm hw.dri 2>/dev/null || true" run_if_present service powerdxx-status powerdxx status run_if_present sysctl snd-default-unit hw.snd.default_unit run_if_present sysctl acpi-acline hw.acpi.acline run_if_present sysctl acpi-cx-lowest hw.acpi.cpu.cx_lowest run_if_present sysctl acpi-video-brightness hw.acpi.video.lcd0.brightness run_shell_capture sysctl-input-stack "sysctl kern.evdev dev.iichid dev.hidbus dev.hms dev.hmt dev.hkbd dev.hconf dev.ig4 dev.psm dev.atkbd dev.uhid hw.psm 2>/dev/null || true" run_if_present service moused-status moused onestatus run_if_present gpart gpart-show show run_if_present geom geom-disk-list disk list run_if_present camcontrol camcontrol-devlist devlist run_if_present nvmecontrol nvmecontrol-devlist devlist run_if_present df df-h -h run_if_present mount mount run_if_present zpool zpool-list list run_if_present zfs zfs-list list if [ "${_run_smart}" = "YES" ] && have smartctl; then _disks="$(sysctl -n kern.disks 2>/dev/null || true)" if [ -n "${_disks}" ]; then for _disk in ${_disks}; do case "${_disk}" in md*|cd*) note "skip smartctl-${_disk}: virtual/removable class" ;; *) run_capture "smartctl-${_disk}" smartctl -a "/dev/${_disk}" ;; esac done else note "skip smartctl: kern.disks empty" fi else note "skip smartctl: disabled or smartctl not found" fi run_if_present lspci lspci-nn -nn run_if_present lsusb lsusb run_if_present lscpu lscpu run_if_present lsblk lsblk run_if_present hwstat hwstat run_shell_if_present usbhid-dump usbhid-dump-version "usbhid-dump --help 2>&1 | head -40" run_if_present cat clawdie-live-gpu-log /var/log/clawdie-live-gpu.log run_if_present cat clawdie-noblank-guard-log /home/clawdie/.clawdie-noblank-guard.log run_if_present cat clawdie-touchpad-guard-log /home/clawdie/.clawdie-touchpad-guard.log run_if_present cat sndstat /dev/sndstat run_if_present mixer mixer-s -s run_if_present v4l2-ctl v4l2-list-devices --list-devices run_shell_capture video-devices "ls -l /dev/video* 2>/dev/null || true" run_shell_capture dri-devices "ls -l /dev/dri /dev/dri/* 2>/dev/null || true" run_shell_capture input-device-nodes "ls -l /dev/input /dev/input/* /dev/uhid* /dev/atp* 2>/dev/null || true" run_if_present xset xset-q q run_shell_if_present xfconf-query xfce4-power-manager "xfconf-query -c xfce4-power-manager -l -v 2>/dev/null || true" run_shell_if_present xfconf-query xfce4-panel "xfconf-query -c xfce4-panel -l -v 2>/dev/null || true" run_shell_if_present xfconf-query xfce4-desktop "xfconf-query -c xfce4-desktop -l -v 2>/dev/null || true" run_shell_if_present xfconf-query xsettings "xfconf-query -c xsettings -l -v 2>/dev/null || true" run_shell_if_present xfconf-query xfce4-pointers "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority xfconf-query -c pointers -l -v 2>/dev/null || xfconf-query -c pointers -l -v 2>/dev/null || true" run_shell_capture xfce-perchannel-xml "for f in /home/clawdie/.config/xfce4/xfconf/xfce-perchannel-xml/*; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture xfce-panel-launchers "find /home/clawdie/.config/xfce4/panel -maxdepth 4 -type f -print -exec sed -n '1,80p' {} \\; 2>/dev/null || true" run_shell_capture icon-theme-dirs "find /usr/local/share/icons -maxdepth 4 -type f \( -name 'icon-theme.cache' -o -name 'clawdie-start.*' \) -print 2>/dev/null || true" run_shell_capture clawdie-iso-assets "find /usr/local/share/clawdie-iso -maxdepth 4 -type f -ls 2>/dev/null || true; for f in /usr/local/share/clawdie-iso/build-manifest.json; do [ -e \"\$f\" ] || continue; echo \"===== \$f =====\"; cat \"\$f\"; echo; done" run_shell_capture colibri-service-state "service colibri_daemon status 2>&1 || true; egrep -n '^(command|command_args|procname)=' /usr/local/etc/rc.d/colibri_daemon 2>/dev/null || true; sysrc -n colibri_daemon_enable 2>/dev/null || true" if [ -f /home/clawdie/.Xauthority ]; then run_shell_if_present xinput xinput-list "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority xinput list 2>/dev/null || true" run_shell_if_present xinput xinput-list-props "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority sh -c 'for id in \$(xinput list --id-only 2>/dev/null); do echo \"===== device \$id =====\"; xinput list-props \"\$id\"; echo; done' || true" run_shell_if_present xrandr xrandr-verbose "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority xrandr --verbose 2>/dev/null || true" run_shell_if_present glxinfo glxinfo-B "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority glxinfo -B 2>/dev/null || true" fi run_shell_if_present libinput libinput-list-devices "libinput list-devices 2>/dev/null || true" run_if_present vulkaninfo vulkaninfo-summary --summary if have vulkaninfo && [ -f /home/clawdie/.Xauthority ]; then run_shell_capture vulkaninfo-summary-display0 "DISPLAY=:0 XAUTHORITY=/home/clawdie/.Xauthority vulkaninfo --summary" fi run_if_present pkg pkg-info info run_if_present pkg pkg-version version run_if_present pkg pkg-audit audit run_if_present hw-probe hw-probe-all -all if [ "${_upload_public_probe}" = "YES" ]; then if have hw-probe; then run_capture hw-probe-all-upload hw-probe -all -upload else note "skip hw-probe public upload: hw-probe not found" fi else note "public hw-probe upload not requested" fi _public_probe_urls="" _public_probe_url="" _upload_output="${_raw_dir}/hw-probe-all-upload.txt" if [ -f "${_upload_output}" ]; then _public_probe_urls="$(grep -Eo 'https?://[^[:space:]<>"'"'"']+' "${_upload_output}" | grep -E 'bsd-hardware\.info|linux-hardware\.org' | sort -u || true)" _public_probe_url="$(printf '%s\n' "${_public_probe_urls}" | sed -n '1p')" fi _freebsd="$(freebsd-version -kru 2>/dev/null | tr '\n' ' ' | sed 's/[[:space:]]*$//')" _gpu="$(pciconf -lv 2>/dev/null | grep -B3 -A4 -E 'VGA|display' | sed -n '1,12p')" _wlan="$(sysctl -n net.wlan.devices 2>/dev/null || true)" _disks="$(sysctl -n kern.disks 2>/dev/null || true)" cat > "${_report_dir}/summary.txt" < "${_report_dir}/summary.json" <> "${_log}" 2>&1; then note "archive ${_archive}" else note "WARN archive failed: ${_archive}" fi if [ -d /home/clawdie ] && id clawdie >/dev/null 2>&1; then chown -R clawdie:clawdie "${_base}" 2>/dev/null || true fi cat <