mknbi-set 7.3KB

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