add tools/chkmoddeps
authorSimon Schubert <corecode@dragonflybsd.org>
Tue, 8 Sep 2009 09:40:17 +0000 (11:40 +0200)
committerSimon Schubert <corecode@dragonflybsd.org>
Tue, 8 Sep 2009 09:40:17 +0000 (11:40 +0200)
chkmoddeps is a tool to check for unsatisfied module dependencies.
invoke with pathnames to be searched for kernel and modules.

tools/tools/chkmoddeps/chkdeps.rb [new file with mode: 0755]
tools/tools/chkmoddeps/pmoddeps.gdb [new file with mode: 0755]

diff --git a/tools/tools/chkmoddeps/chkdeps.rb b/tools/tools/chkmoddeps/chkdeps.rb
new file mode 100755 (executable)
index 0000000..931055d
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/env ruby
+
+require 'find'
+require 'open3'
+
+verbose = false
+
+pmoddeps = File.join(File.dirname(__FILE__), 'pmoddeps.gdb')
+
+provides = {}
+depends = {}
+
+Find.find(*ARGV) do |path|
+  next if not FileTest.file?(path)
+  next if not (path.end_with?('.ko') or ['kernel', 'kernel.debug'].include?(File.basename(path)))
+
+  mv = {}
+  md = {}
+
+  Open3.popen3(pmoddeps + ' ' + path) do |pin, pout, perr|
+    pin.close
+    pout.each do |line|
+      f = line.split
+      case f[0]
+      when 'module'
+        # ignore?
+      when 'version'
+        mv[f[1]] = f[2].to_i
+      when 'depend'
+        md[f[1]] = f[2..-1].map{|e| e.to_i}
+      end
+    end
+  end
+
+  modname = File.basename(path)
+
+  provides[modname] = mv
+  depends[modname] = md
+end
+
+kernel = provides.select{|pmn, pd| pmn.start_with?('kernel')}
+
+depends.each do |modname, md|
+  md.each do |depname, vers|
+    minv, pref, maxv = vers
+
+    chk = proc do |h|
+      not h.select{|pn, pv| pn == depname and pv >= minv and pv <= maxv}.empty?
+    end
+
+    defm = []
+    # try module itself
+    defm << [modname, provides[modname]]
+    # try kernel
+    defm += kernel
+    # try module depend name
+    defm << [depname + '.ko', provides[depname + '.ko']]
+
+    defm.reject!{|e, v| not v}
+    match = defm.select{|mn, k| chk.call(k)}
+    if not match.empty?
+      puts "#{modname} depend #{depname} found in #{match[0][0]}" if verbose
+      next
+    end
+
+    # else not found in the right place
+
+    match = provides.select do |pmn, pd|
+      chk.call(pd)
+    end
+
+    if match.empty?
+      $stderr.puts "#{modname} depend #{depname} #{minv} #{pref} #{maxv} not found"
+    else
+      match.each do |m|
+        $stderr.puts "#{modname} depend #{depname} found in #{m[0]} instead"
+      end
+    end
+  end
+end
diff --git a/tools/tools/chkmoddeps/pmoddeps.gdb b/tools/tools/chkmoddeps/pmoddeps.gdb
new file mode 100755 (executable)
index 0000000..b7bac0d
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env gdb -batch -x
+
+set $start = (struct mod_metadata **)&__start_set_modmetadata_set
+set $end = (struct mod_metadata **)&__stop_set_modmetadata_set
+
+set $p = $start - 1
+while $p + 1 < $end
+       set $p = $p + 1
+       set $d = *$p
+
+       if $d->md_type == 2
+               printf "module %s\n", $d->md_cval
+       end
+       if $d->md_type == 1
+               set $dp = (struct mod_depend *)$d->md_data
+
+               printf "depend %s %d %d %d\n", $d->md_cval, \
+                       $dp->md_ver_minimum, \
+                       $dp->md_ver_preferred, \
+                       $dp->md_ver_maximum
+       end
+       if $d->md_type == 3
+               set $dv = (struct mod_version *)$d->md_data
+
+               printf "version %s %d\n", $d->md_cval, $dv->mv_version
+       end
+end