1#!/usr/bin/perl
2
3# Copyright (c) 2006-2010 by Mauro Carvalho Chehab <mchehab@kernel.org>
4#
5# Licensed under the terms of the GNU GPL License version 2
6
7use strict;
8use File::Find;
9
10my %depend = ();
11my %depend2 = ();
12my %rmlist = ();
13my @nodep;
14my @modlist;
15my @allmodules;
16my %reqmodules;
17my %loaded = ();
18my $i=0;
19
20sub findprog($)
21{
22	foreach(split(/:/, $ENV{PATH}),qw(/sbin /usr/sbin /usr/local/sbin)) {
23		return "$_/$_[0]" if(-x "$_/$_[0]");
24	}
25	die "Can't find needed utility '$_[0]'";
26}
27
28sub parse_dir {
29	my $file = $File::Find::name;
30	my $modinfo = findprog('modinfo');
31
32	if (!($file =~ /[.]ko$/)) {
33		return;
34	}
35
36	my $module = $file;
37	$module =~ s|.*\/([^/]+)\.ko|\1|;
38
39	open IN, "$modinfo $module.ko|" or die "can't run $modinfo $file";
40	while (<IN>) {
41		if (m/depends:\s*(.*)/) {
42			my $deps = $1;
43			$deps =~ s/\n//;
44			$deps =~ s/[,]/ /g;
45			$deps = " $deps ";
46			$depend{$module} = $deps;
47			push @allmodules, $module;
48			$i++;
49		}
50	}
51	close IN;
52}
53
54sub parse_loaded {
55	open IN,  "/proc/modules";
56	while (<IN>) {
57		m/^([\w\d_-]+)/;
58		$loaded{$1}=1;
59	}
60	close IN;
61}
62
63sub cleandep()
64{
65	my $dep;
66
67	while ( my ($k, $v) = each(%depend) ) {
68		my $arg=$v;
69		my $arg2=" ";
70		while (!($arg =~ m/^\s*$/)) {
71			if ($arg =~ m/^ ([^ ]+) /) {
72				my $val=$1;
73				if (exists($depend{$val})) {
74					$arg2="$arg2 $val ";
75				} else {
76					$reqmodules{$val}=1;
77				}
78			}
79			$arg =~ s/^ [^ ]+//;
80			$arg2 =~ s/\s\s+/ /;
81		}
82		$depend2 { $k } = $arg2;
83	}
84
85}
86
87sub rmdep()
88{
89	my $dep;
90
91	while ($dep=pop @nodep) {
92		while ( my ($k, $v) = each(%depend2) ) {
93			if ($v =~ m/\s($dep)\s/) {
94				$v =~ s/\s${dep}\s/ /;
95				$v =~ s/\s${dep}\s/ /;
96				$v =~ s/\s${dep}\s/ /;
97				$depend2 {$k} = $v;
98			}
99		}
100	}
101}
102
103sub orderdep ()
104{
105	my $old;
106	do {
107		$old=$i;
108		while ( my ($key, $value) = each(%depend2) ) {
109			if ($value =~ m/^\s*$/) {
110				push @nodep, $key;
111				push @modlist, $key;
112				$i=$i-1;
113				delete $depend2 {$key};
114			}
115		}
116		rmdep();
117	} until ($old==$i);
118	while ( my ($key, $value) = each(%depend2) ) {
119		printf "ERROR: bad dependencies - $key ($value)\n";
120	}
121}
122
123sub rmmod(@)
124{
125	my $rmmod = findprog('rmmod');
126	my @not;
127	foreach (reverse @_) {
128		s/-/_/g;
129		if (exists ($loaded{$_})) {
130			print "$rmmod $_\n";
131			unshift @not, $_ if (system "$rmmod $_");
132		}
133	}
134	return @not;
135}
136
137sub prepare_cmd()
138{
139	my $ver=qx(uname -r);
140	$ver =~ s/\s+$//;
141	die "Couldn't get kernel version" if (!$ver);
142
143	print "Seeking media drivers at /lib/modules/$ver/kernel/drivers/media/\n";
144	find(\&parse_dir, "/lib/modules/$ver/kernel/drivers/media/");
145	print "Seeking media drivers at /lib/modules/$ver/kernel/drivers/staging/media/\n";
146	find(\&parse_dir, "/lib/modules/$ver/kernel/drivers/staging/media/");
147	printf "found $i modules\n";
148
149	cleandep();
150	orderdep();
151}
152
153prepare_cmd;
154parse_loaded;
155
156my @notunloaded = rmmod(@modlist);
157@notunloaded = rmmod(@notunloaded) if (@notunloaded);
158if (@notunloaded) {
159	print "Couldn't unload: ", join(' ', @notunloaded), "\n";
160}
161