#!/system/bin/sh # Driver Manager v2 - Kernel Module (.ko) Manager # Load, unload, and manage kernel modules MODDIR=${MODDIR:-/data/adb/modules/driver-manager} . "$MODDIR/scripts/core.sh" log_init "$LOGDIR/ko.log" MODULESDIR="$MODDIR/modules" AUTOLOAD="$CONFIGDIR/autoload.conf" KERNEL_VER=$(uname -r 2>/dev/null) # --- List available .ko files and their status --- list_modules() { echo '{"modules":[' local first=true # List .ko files in our modules directory for ko in "$MODULESDIR"/*.ko; do [ -f "$ko" ] || continue local name=$(basename "$ko" .ko) local modname=$(modinfo -F name "$ko" 2>/dev/null || echo "$name") local desc=$(modinfo -F description "$ko" 2>/dev/null || echo "") local ver=$(modinfo -F version "$ko" 2>/dev/null || echo "") local author=$(modinfo -F author "$ko" 2>/dev/null || echo "") local depends=$(modinfo -F depends "$ko" 2>/dev/null || echo "") local vermagic=$(modinfo -F vermagic "$ko" 2>/dev/null || echo "") local sz=$(file_size "$ko") # Check if loaded local loaded="false" lsmod 2>/dev/null | grep -q "^${modname} " && loaded="true" # Check if in autoload local autoload="false" grep -qx "$name.ko" "$AUTOLOAD" 2>/dev/null && autoload="true" # Check kernel version compatibility local compatible="unknown" if [ -n "$vermagic" ]; then local mod_kver=$(echo "$vermagic" | awk '{print $1}') [ "$mod_kver" = "$KERNEL_VER" ] && compatible="true" || compatible="false" fi [ "$first" = true ] && first=false || echo "," cat << ENTRY { "filename": "$(basename "$ko")", "name": "$modname", "description": "$desc", "version": "$ver", "author": "$author", "depends": "$depends", "vermagic": "$vermagic", "size": $sz, "loaded": $loaded, "autoload": $autoload, "compatible": $compatible } ENTRY done echo ']}' } # --- Load a kernel module --- load_module() { local ko="$1" local params="$2" # Accept either filename or path if [ ! -f "$ko" ]; then ko="$MODULESDIR/$ko" fi if [ ! -f "$ko" ]; then echo '{"status": "error", "message": "Module file not found"}' return 1 fi local name=$(basename "$ko" .ko) local modname=$(modinfo -F name "$ko" 2>/dev/null || echo "$name") # Check if already loaded if lsmod 2>/dev/null | grep -q "^${modname} "; then echo "{\"status\": \"already_loaded\", \"module\": \"$modname\"}" return 0 fi # Check kernel version local vermagic=$(modinfo -F vermagic "$ko" 2>/dev/null) if [ -n "$vermagic" ]; then local mod_kver=$(echo "$vermagic" | awk '{print $1}') if [ "$mod_kver" != "$KERNEL_VER" ]; then log_error "Kernel mismatch: module=$mod_kver running=$KERNEL_VER" echo "{\"status\": \"error\", \"message\": \"Kernel version mismatch: module built for $mod_kver, running $KERNEL_VER\"}" return 1 fi fi # Load dependencies first local depends=$(modinfo -F depends "$ko" 2>/dev/null) if [ -n "$depends" ]; then local IFS=',' for dep in $depends; do if ! lsmod 2>/dev/null | grep -q "^${dep} "; then local dep_ko="$MODULESDIR/${dep}.ko" if [ -f "$dep_ko" ]; then log "Loading dependency: $dep" insmod "$dep_ko" 2>> "$LOGDIR/ko.log" else log "Dependency $dep not in modules dir, trying modprobe" modprobe "$dep" 2>> "$LOGDIR/ko.log" fi fi done fi # Load the module log "Loading module: $ko $params" local output output=$(insmod "$ko" $params 2>&1) if [ $? -eq 0 ]; then log "Loaded: $modname" # Capture relevant dmesg local dmesg_out=$(dmesg | tail -5 2>/dev/null) echo "{\"status\": \"ok\", \"module\": \"$modname\", \"dmesg\": \"$(echo "$dmesg_out" | tr '\n' '|' | sed 's/"/\\"/g')\"}" else log_error "Failed to load $modname: $output" echo "{\"status\": \"error\", \"module\": \"$modname\", \"message\": \"$(echo "$output" | tr '\n' ' ' | sed 's/"/\\"/g')\"}" return 1 fi } # --- Unload a kernel module --- unload_module() { local name="$1" name=$(echo "$name" | sed 's/\.ko$//') if ! lsmod 2>/dev/null | grep -q "^${name} "; then echo "{\"status\": \"not_loaded\", \"module\": \"$name\"}" return 0 fi log "Unloading module: $name" local output output=$(rmmod "$name" 2>&1) if [ $? -eq 0 ]; then log "Unloaded: $name" echo "{\"status\": \"ok\", \"module\": \"$name\"}" else log_error "Failed to unload $name: $output" echo "{\"status\": \"error\", \"module\": \"$name\", \"message\": \"$(echo "$output" | tr '\n' ' ' | sed 's/"/\\"/g')\"}" return 1 fi } # --- Unload all managed modules --- unload_all() { log "Unloading all managed modules" for ko in "$MODULESDIR"/*.ko; do [ -f "$ko" ] || continue local name=$(basename "$ko" .ko) local modname=$(modinfo -F name "$ko" 2>/dev/null || echo "$name") if lsmod 2>/dev/null | grep -q "^${modname} "; then rmmod "$modname" 2>/dev/null log "Unloaded: $modname" fi done echo '{"status": "ok"}' } # --- Get detailed info for a module --- info_module() { local ko="$1" if [ ! -f "$ko" ]; then ko="$MODULESDIR/$ko" fi [ ! -f "$ko" ] && { echo '{"error": "not found"}'; return 1; } modinfo "$ko" 2>/dev/null } # --- Toggle autoload for a module --- set_autoload() { local ko_filename="$1" local enabled="$2" if [ "$enabled" = "true" ] || [ "$enabled" = "1" ]; then if ! grep -qx "$ko_filename" "$AUTOLOAD" 2>/dev/null; then echo "$ko_filename" >> "$AUTOLOAD" log "Autoload enabled: $ko_filename" fi echo "{\"status\": \"ok\", \"autoload\": true, \"module\": \"$ko_filename\"}" else sed -i "/^${ko_filename}$/d" "$AUTOLOAD" 2>/dev/null log "Autoload disabled: $ko_filename" echo "{\"status\": \"ok\", \"autoload\": false, \"module\": \"$ko_filename\"}" fi } # --- Load all autoload modules --- autoload_modules() { [ ! -f "$AUTOLOAD" ] && return 0 log "Loading autoload modules" while IFS= read -r ko; do [ -z "$ko" ] && continue [ "${ko#\#}" != "$ko" ] && continue local kofile="$MODULESDIR/$ko" if [ -f "$kofile" ]; then load_module "$kofile" >/dev/null 2>&1 else log_error "Autoload module not found: $ko" fi done < "$AUTOLOAD" } # --- Main --- case "$1" in list) list_modules ;; load) load_module "$2" "$3" ;; unload) unload_module "$2" ;; unload_all) unload_all ;; info) info_module "$2" ;; autoload) autoload_modules ;; set_autoload) set_autoload "$2" "$3" ;; *) echo "Usage: ko_manager.sh {list|load|unload|unload_all|info|autoload|set_autoload} [args]" ;; esac