1#
2# (c) Jan Gehring <jan.gehring@gmail.com>
3#
4# vim: set ts=2 sw=2 tw=0:
5# vim: set expandtab:
6
7=head1 NAME
8
9Rex::Commands::Kernel - Load/Unload Kernel Modules
10
11=head1 DESCRIPTION
12
13With this module you can load and unload kernel modules.
14
15Version <= 1.0: All these functions will not be reported.
16
17All these functions are not idempotent.
18
19=head1 SYNOPSIS
20
21 kmod load => "ipmi_si";
22
23 kmod unload => "ipmi_si";
24
25=head1 EXPORTED FUNCTIONS
26
27=cut
28
29package Rex::Commands::Kernel;
30
31use 5.010001;
32use strict;
33use warnings;
34
35our $VERSION = '1.13.4'; # VERSION
36
37use Rex::Logger;
38use Rex::Helper::Run;
39use Rex::Commands::Gather;
40
41use Data::Dumper;
42
43require Rex::Exporter;
44
45use base qw(Rex::Exporter);
46use vars qw(@EXPORT);
47
48@EXPORT = qw(kmod);
49
50=head2 kmod($action => $module)
51
52This function loads or unloads a kernel module.
53
54 task "load", sub {
55   kmod load => "ipmi_si";
56 };
57
58 task "unload", sub {
59   kmod unload => "ipmi_si";
60 };
61
62If you're using NetBSD or OpenBSD you have to specify the complete path and, if needed the entry function.
63
64 task "load", sub {
65   kmod load => "/usr/lkm/ntfs.o";
66   kmod load => "/path/to/module.o", entry => "entry_function";
67 };
68
69=cut
70
71sub kmod {
72  my ( $action, $module, @rest ) = @_;
73
74  my $options = {@_};
75
76  my $os = get_operating_system();
77
78  my $load_command   = "modprobe";
79  my $unload_command = "rmmod";
80
81  if ( $os eq "FreeBSD" ) {
82    $load_command   = "kldload";
83    $unload_command = "kldunload";
84  }
85  elsif ( $os eq "NetBSD" || $os eq "OpenBSD" ) {
86    $load_command   = "modload";
87    $unload_command = "modunload";
88
89    if ( $options->{"entry"} ) {
90      $load_command .= " -e " . $options->{"entry"};
91    }
92  }
93  elsif ( $os eq "SunOS" ) {
94    $load_command = "modload -p ";
95
96    if ( $options->{"exec_file"} ) {
97      $load_command .= " -e " . $options->{"exec_file"} . " ";
98    }
99
100    $unload_command = sub {
101      my @mod_split = split( /\//, $module );
102      my $mod       = $mod_split[-1];
103
104      my ($mod_id) = map { /^\s*(\d+)\s+.*$mod/ } i_run "modinfo";
105      my $cmd = "modunload -i $mod_id";
106
107      if ( $options->{"exec_file"} ) {
108        $cmd .= " -e " . $options->{"exec_file"};
109      }
110
111      return $cmd;
112    };
113  }
114  elsif ( $os eq "OpenWrt" ) {
115    $load_command = "insmod";
116  }
117
118  if ( $action eq "load" ) {
119    Rex::Logger::debug("Loading Kernel Module: $module");
120    i_run "$load_command $module", fail_ok => 1;
121    unless ( $? == 0 ) {
122      Rex::Logger::info( "Error loading Kernel Module: $module", "warn" );
123      die("Error loading Kernel Module: $module");
124    }
125    else {
126      Rex::Logger::debug("Kernel Module $module loaded.");
127    }
128  }
129  elsif ( $action eq "unload" ) {
130    Rex::Logger::debug("Unloading Kernel Module: $module");
131    my $unload_command_str = $unload_command;
132    if ( ref($unload_command) eq "CODE" ) {
133      $unload_command_str = &$unload_command();
134    }
135
136    i_run "$unload_command_str $module", fail_ok => 1;
137    unless ( $? == 0 ) {
138      Rex::Logger::info( "Error unloading Kernel Module: $module", "warn" );
139      die("Error unloading Kernel Module: $module");
140    }
141    else {
142      Rex::Logger::debug("Kernel Module $module unloaded.");
143    }
144  }
145  else {
146    Rex::Logger::info("Unknown action $action");
147    die("Unknown action $action");
148  }
149}
150
1511;
152