[sundance] Add reset completion check
[gpxe.git] / contrib / initrd / mknbi-set
blobe61acac9f9abcb843f3c42b006c4589f0c28e7ab
1 #!/usr/bin/perl -w
3 # $Id$
4 # Maintains set of NBIs based on currently-installed kernels
5 # Network card module sets are taken from /etc/mknbi-set.conf
7 use strict;
8 use vars qw($verbosity);
10 use constant EB_PCI_DEVICE => 1;
12 # Utility function: calculate output id given a kernel file name and
13 # space-separated list of modules
14 sub calc_output_id ($$) {
15 my $kernel = shift;
16 my $moduleset = shift;
17 my $kernel_ver = "";
18 ( $kernel_ver ) = ( $kernel =~ /vmlinuz-(.*)$/ );
19 ( my $output_id = "$moduleset".( $kernel_ver ? ".$kernel_ver" : "" ) ) =~ tr/,/./;
20 return ( $kernel_ver, $output_id );
23 # Utility function: read modules.pcimap-style file
24 # Add modules to modulesets hash, write out dhcpd.conf fragment
25 sub read_config_file ($$$$) {
26 my $configfile = shift;
27 my $modulesets = shift;
28 my $dhcpfh = shift;
29 my $alwaysuse = shift;
31 print "Scanning through $configfile for network modules...\n" if $verbosity >= 1;
32 open CF, $configfile or die "Could not open $configfile: $!\n";
33 chomp ( my $tempmodule = `mktemp /tmp/mknbi-set.XXXXXX` );
34 chomp ( my $cwd = `pwd` ); chdir '/'; # Modprobe searches the current directory...
35 print $dhcpfh " \# Generated from $configfile\n";
36 while (<CF>) {
37 chomp;
38 next if /^[\#;]/ or /^\s*$/;
39 ( my $module, undef, my $vendor, my $device ) = /^(\S+)(\s+(\S+)\s+(\S+))?/ ;
40 $modulesets->{$module} = 1 if $alwaysuse;
41 if ( ! exists $modulesets->{$module} ) {
42 # Check to see if module is a network module
43 # Only do this the first time we encounter a module
44 my @modulepaths = `/sbin/modprobe -l $module.o*` ;
45 chomp ( my $modulepath = $modulepaths[0] );
46 if ( $modulepath ) {
47 if ( $modulepath =~ /.o.gz$/ ) {
48 system ( "zcat $modulepath > $tempmodule" );
49 } else {
50 system ( "cp $modulepath $tempmodule" );
52 $modulesets->{$module} = 0;
53 foreach ( `nm $tempmodule` ) {
54 chomp;
55 $modulesets->{$module} = 1 if /(ether|wlan)/ ;
57 unlink $tempmodule;
58 } else {
59 print STDERR "Cannot locate module $module specified in $configfile\n";
62 if ( $modulesets->{$module} ) {
63 if ( $vendor ) {
64 print "$module ($vendor,$device) listed in $configfile\n" if $verbosity >= 2;
65 printf $dhcpfh ( " if option etherboot.nic-dev-id = %02x:%02x:%02x:%02x:%02x { option etherboot.kmod \"%s\"; }\n",
66 EB_PCI_DEVICE,
67 ( hex($vendor) >> 8 ) & 0xff, hex($vendor) & 0xff,
68 ( hex($device) >> 8 ) & 0xff, hex($device) & 0xff,
69 $module );
70 } else {
71 print "$module (without PCI IDs) listed in $configfile\n" if $verbosity >= 2;
75 close CF;
76 print $dhcpfh "\n";
77 chdir $cwd;
80 my $conffile = '/etc/mknbi-set.conf';
81 my $mkinitrd_net = 'mkinitrd-net';
82 my $mknbi = 'mknbi-linux';
83 my $output_dir = '/var/lib/tftpboot';
84 my $dhcpfile = '/etc/dhcpd.conf.etherboot-pcimap.include';
85 my $use_local;
86 our $verbosity = 1;
87 my $modulesets = {};
88 my $kernel = '';
89 my @kernels = ();
91 my $usage="Usage: $0 [-l|--local] [-q] [-v] [-r|--refresh module[,module...]] [--help]";
93 # Parse command-line options
94 while ( $_ = shift ) {
95 if ( /-l|--local/ ) {
96 $conffile = 'mknbi-set.conf';
97 $mkinitrd_net = './mkinitrd-net';
98 $mknbi = './mknbi-linux --format=nbi --target=linux';
99 $output_dir = 'tftpboot';
100 $dhcpfile = 'tftpboot/dhcpd.conf.etherboot-pcimap.include';
101 $use_local = 1;
102 } elsif ( /-r|--refresh/ ) {
103 my $moduleset = shift;
104 $modulesets->{$moduleset} = 1;
105 } elsif ( /-k|--kernel/ ) {
106 $kernel = shift;
107 } elsif ( /-v|--verbose/ ) {
108 $verbosity++;
109 } elsif ( /-q|--quiet/ ) {
110 $verbosity--;
111 } elsif ( /--help/ ) {
112 die "$usage\n".
113 " -k, --kernel Build NBIs for a particular kernel\n".
114 " -l, --local Run locally from CVS (for developers only)\n".
115 " -r, --refresh Refresh NBI for a particular module\n".
116 " -v, --verbose Be more verbose\n".
117 " -q, --quiet Be less verbose\n";
118 } else {
119 die "$usage\n";
123 # Get set of current kernels
124 if ($kernel) {
125 @kernels = ( $kernel );
126 } else {
127 @kernels = glob('/boot/vmlinuz*');
129 die "Could not find any kernels in /boot\n" unless @kernels;
131 # If modules have been specified via --refresh, do not scan for modules or rewrite the
132 # dhcpd.conf fragment file
133 unless ( %$modulesets ) {
134 # Write dhcpd.conf fragment file
135 open my $dhcpfh, ">$dhcpfile" or die "Could not open $dhcpfile for writing: $!\n";
136 print $dhcpfh "# Etherboot PCI ID -> Linux kernel module mapping file\n";
137 print $dhcpfh "# Generated by mknbi-set on ".(scalar localtime)."\n";
138 print $dhcpfh "#\n";
139 print $dhcpfh "if substring ( option vendor-class-identifier, 0, 9 ) = \"Etherboot\" {\n";
140 print $dhcpfh " if exists etherboot.nic-dev-id {\n";
141 print $dhcpfh " \# Legacy nic-dev-id mechanism: there are some DLink DFE538 cards in circulation that\n";
142 print $dhcpfh " \# predated the change to the new nic-dev-id binary structure\n";
143 print $dhcpfh " if option etherboot.nic-dev-id = \"PCI:1186:1300\" { option etherboot.kmod \"8139too\"; }\n";
144 print $dhcpfh "\n";
146 # Get set of network modules to build NBIs for
147 # Read explicitly-specified module sets from $conffile
148 read_config_file($conffile, $modulesets, $dhcpfh, 1);
149 # Obtain list of all network modules from pcimap file
150 my $pcimap;
151 foreach ( `/sbin/modprobe -c` ) {
152 $pcimap = $1 if /^pcimap.*?=(.*)$/;
154 if ( $pcimap ) {
155 read_config_file($pcimap, $modulesets, $dhcpfh, 0);
156 } else {
157 print STDERR "Could not identify pcimap file\n";
159 # Finish off dhcpd.conf fragment file
160 print $dhcpfh " }\n}\n";
161 close $dhcpfh;
164 # Build initrd and nbi for each kernel-moduleset combination
165 foreach my $moduleset ( sort keys %$modulesets ) {
166 next unless $modulesets->{$moduleset}; # Ignore if value is 0
167 print "Building NBIs for module set $moduleset\n" if $verbosity >= 1;
168 foreach my $kernel ( @kernels ) {
169 ( my $kernel_ver, my $output_id ) = calc_output_id ( $kernel, $moduleset );
170 if ( -l $kernel ) {
171 # Symbolic link; create matching symlink
172 my $real_kernel = readlink ( $kernel );
173 ( my $real_kernel_ver, my $real_output_id ) = calc_output_id ( $real_kernel, $moduleset );
174 print "Symlinking $output_id to $real_output_id\n" if $verbosity >= 2;
175 my $initrd_file = "$output_dir/initrd-$output_id.img";
176 unlink ( $initrd_file ) if -l $initrd_file;
177 system ( "ln -s initrd-$real_output_id.img $initrd_file" ) == 0 or print STDERR "Could not symlink $initrd_file to initrd-$real_output_id.img: $!\n";
178 my $nbi_file = "$output_dir/boot-$output_id.nbi";
179 unlink ( $nbi_file ) if -l $nbi_file;
180 system ( "ln -s boot-$real_output_id.nbi $nbi_file" ) == 0 or print STDERR "Could not symlink $nbi_file to boot-$real_output_id.nbi: $!\n";
181 } else {
182 # Real file: create initrd and nbi
183 print "Creating initrd and nbi for $output_id\n" if $verbosity >= 2;
184 ( my $moduleset_spaces = $moduleset ) =~ tr/,/ /;
185 my $initrd_cmd = "$mkinitrd_net --nolink ".
186 ( $use_local ? "--local " : "" ).
187 ( $kernel_ver ? "--kernel $kernel_ver " : "" ).
188 ( $verbosity >= 2 ? "" : "-q " ).
189 $moduleset_spaces;
190 print "$initrd_cmd\n" if $verbosity >= 3;
191 if ( system ( $initrd_cmd ) == 0 ) {
192 my $mknbi_cmd = "$mknbi $kernel $output_dir/initrd-$output_id.img > $output_dir/boot-$output_id.nbi";
193 print "$mknbi_cmd\n" if $verbosity >= 3;
194 system ( $mknbi_cmd ) == 0 or print STDERR "mknbi failed: $!\n";
195 } else {
196 print STDERR "$initrd_cmd failed: $!\n";