Skip to content

Instantly share code, notes, and snippets.

@weshouman
Last active August 20, 2023 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weshouman/86ff41d714bc95d89977321f34eb0547 to your computer and use it in GitHub Desktop.
Save weshouman/86ff41d714bc95d89977321f34eb0547 to your computer and use it in GitHub Desktop.
Kernel module dependency walker

Those scripts are used to walk the dependencies of the Kernel Modules in Linux.

Usage

One could use any of the following implementation, either on Python or Bash

Note: The python implementation is updated to use a cache, making it instantaneous

Python Script

Use any of the following commands

# Get the direct dependencies of the evdi
./find_modules.py evdi

# Get all the dependencies of the evdi
./find_modules.py --all evdi

# Get the direct dependents of the drm
./find_modules.py --reverse drm

# Get all the dependents of the drm
./find_modules.py --reverse --all drm

Bash Script

Use any of the following commands

# Get the direct dependencies of the evdi
./find_modules.sh evdi dependencies

# Get all the dependencies of the evdi
./find_modules.sh evdi dependencies_all

# Get the direct dependents of the drm
./find_modules.sh drm dependents

# Get all the dependents of the drm
./find_modules.sh drm dependents_all
#!/usr/bin/env python3
import os
import subprocess
import sys
import argparse
def get_modules_dependencies():
modules_list = get_modules_list()
modules_dependencies = {}
for module in modules_list:
dependencies = subprocess.getoutput(f"modinfo -F depends {module} 2>/dev/null")
dep_list = dependencies.split(',')
# transform any empty list from [''] to []
dep_list = [dep.strip() for dep in dep_list if dep.strip() != '']
modules_dependencies[module] = dep_list
return modules_dependencies
def get_modules_list():
output = subprocess.check_output("lsmod", text=True)
modules_list = [line.split()[0] for line in output.splitlines()[1:]]
return modules_list
def find_dependents(module_name, all_modules_dependencies):
dependent_modules = []
for module, dependencies in all_modules_dependencies.items():
if module_name in dependencies:
dependent_modules.append(module)
if not dependent_modules:
pass
#print(f"No modules depend on {module_name}")
else:
for dep_module in dependent_modules:
print(f"- {dep_module}")
def find_dependents_all(module_name, all_modules_dependencies, indent=""):
dependent_modules = []
for module, dependencies in all_modules_dependencies.items():
if module_name in dependencies:
dependent_modules.append(module)
if dependent_modules:
for dep in dependent_modules:
print(f"{indent}- {dep}")
find_dependents_all(dep, all_modules_dependencies, indent + " ")
def find_dependencies(module_name, all_modules_dependencies, indent=""):
dependencies = all_modules_dependencies.get(module_name)
if dependencies:
for dep in dependencies:
print(f"{indent}- {dep}")
def find_all_dependencies(module_name, all_modules_dependencies, indent=""):
dependencies = all_modules_dependencies.get(module_name)
if dependencies:
for dep in dependencies:
print(f"{indent}- {dep}")
find_all_dependencies(dep, all_modules_dependencies, indent + " ")
def main():
parser = argparse.ArgumentParser(description="Find module dependencies.")
parser.add_argument("module_name", help="The name of the module to analyze")
parser.add_argument("--reverse", action="store_true", help="Show reverse dependencies")
parser.add_argument("--all", action="store_true", help="Show all dependencies")
args = parser.parse_args()
module_name = args.module_name
all_modules_dependencies = get_modules_dependencies()
if args.reverse and args.all:
find_dependents_all(module_name, all_modules_dependencies)
if args.reverse:
find_dependents(module_name, all_modules_dependencies)
elif args.all:
find_all_dependencies(module_name, all_modules_dependencies)
else:
find_dependencies(module_name, all_modules_dependencies)
if __name__ == "__main__":
main()
#!/bin/bash
# Check if at least two arguments are provided
if [ $# -lt 2 ]; then
echo "Usage: $0 <module-name> <method>"
echo "Methods: dependents, dependents_all, dependencies, dependencies_all"
exit 1
fi
module_name="$1"
method="$2"
# Get the list of modules that are currently loaded
modules_list=$(lsmod | tail -n +2 | awk '{print $1}')
find_dependents() {
for module in $modules_list; do
dependencies=$(modinfo -F depends $module 2>/dev/null)
if [ -n "$dependencies" ]; then
if echo "$dependencies" | grep -q "\<$module_name\>"; then
dependent_modules+=("$module")
fi
fi
done
if [ ${#dependent_modules[@]} -eq 0 ]; then
echo "No modules depend on $module_name"
else
echo "Modules that depend on $module_name:"
for dep_module in "${dependent_modules[@]}"; do
echo "- $dep_module"
done
fi
}
# Function to find reverse dependencies and display as a tree
find_dependents_all() {
local module="$1"
local indent="$2"
local dependencies=()
for mod in $modules_list; do
dep=$(modinfo -F depends $mod 2>/dev/null | grep -o "\<$module\>")
if [ -n "$dep" ]; then
dependencies+=("$mod")
fi
done
if [ ${#dependencies[@]} -gt 0 ]; then
for dep in "${dependencies[@]}"; do
echo "$indent- $dep"
find_dependents_all "$dep" "$indent "
done
fi
}
# Function to find all dependencies of a module
find_dependencies() {
local module="$1"
local indent="$2"
local dependencies=$(modinfo -F depends $module 2>/dev/null)
if [ -n "$dependencies" ]; then
#echo "$indent$module depends on:"
IFS=',' read -ra dep_array <<< "$dependencies"
for dep in "${dep_array[@]}"; do
echo "$indent- $dep"
done
fi
}
# Function to find all dependencies of a module
find_all_dependencies() {
local module="$1"
local indent="$2"
local dependencies=$(modinfo -F depends $module 2>/dev/null)
if [ -n "$dependencies" ]; then
#echo "$indent$module depends on:"
IFS=',' read -ra dep_array <<< "$dependencies"
for dep in "${dep_array[@]}"; do
echo "$indent- $dep"
find_all_dependencies "$dep" "$indent "
done
fi
}
# Start searching based on the specified method
case "$method" in
"dependents")
find_dependents "$module_name" ""
;;
"dependents_all")
echo "Modules that depend on $module_name:"
find_dependents_all "$module_name" ""
;;
"dependencies")
echo "modules that $module_name depends on:"
find_dependencies "$module_name" ""
;;
"dependencies_all")
echo "All modules that $module_name depends on:"
find_all_dependencies "$module_name" ""
;;
*)
echo "Invalid method specified. Available methods: dependents, dependents_all, dependencies, dependencies_all"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment