[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: faster anaconda development cycle?



Okay, I've been meaning to release this for a while, but for some reason 
I've been too lazy to get it out the door.  I've created a perl module 
(sorry for the Python folks -- maybe if I get a chance I'll port this to 
Python at some point) which allows you to create really simple perl 
scripts for modifying various parts of the Red Hat installer including 
boot disks, driver disks, stage1/stage2 images, etc.

I haven't packaged it up properly yet, but I thought it might be useful 
for getting some work done.  I also haven't tested it yet for RH 8.0, but 
if the layout is similar to RH 7.2, you shouldn't have too much of a 
problem mounting various image files.

Here's a quick sample of what it does (from the very terse docs):

# How to use this module:
#
#   Modifying a Red Hat boot disk
#
#      my $img = new RedHat::BootImage "boot.img";
#
#      $img->mount_image();
#      $img->add_file( "my_ks_file.cfg", "ks.cfg" );
#      $img->mount_initrd();
#      $img->add_file( "my_new_loader", "/sbin/loader" );
#      $img->mount_cgz();
#      $img->add_file( "my_new_driver.o", "2.4.9-34BOOT/driver.o" );
#      $img->umount_cgz();
#      $img->umount_initrd();
#      $img->umount_image();
#
#   Modifying a stage2 image
#
#      my $img = new RedHat::BootImage "stage2.img";
#
#      $img->mount_cramfs();
#      $img->add_file( "*.py", "/usr/lib/anaconda" );
#      $img->mount_cgz();
#      $img->add_file( "my_new_driver.o", "2.4.9-34BOOT/driver.o" );
#      $img->umount_cgz();
#      $img->umount_cramfs();
#
#   Modifying a driver disk
#
#      my $img = new RedHat::BootImage "driverdsk.img";
#      $img->mount_image();
#      $img->add_file( "my_pcitable", "pcitable" );
#      $img->mount_cgz();
#      $img->add_file( "my_new_driver.o", "2.4.9-34BOOT/driver.o" );
#      $img->umount_cgz();
#      $img->umount_image();

Hopefully some people find it useful.

--Patrick.



On Wed, 15 Jan 2003, Masoud Sharbiani wrote:

> Hello,
> I've been doing anaconda development (for a custom-distro installer 
> project) since anaconda-7.1 days. In order to speed up creating images, 
> I used to mount -o loop stage2.img to somewhere, erase the .pyc file to 
> be changed and copy over the new .py file just to see whether my 
> change/new screen layout/functionality works or not. Then when I was 
> satisfied with the results (which could get more than 10 changes to set 
> of files to get something right) I'd rebuild anaconda and make them 
> nfs/ftp available to our testers.
> Recently I got the task to port the whole set of changes to anaconda-8. 
> I've found that anaconda-8 (and installer images on the install cdrom, 
> especially stage2.img) is now using cramfs (compressed ramfs) instead of 
> the good-old ext2. therefore, while able to examine the .py files on the 
> stage2.img, I can't change them and test the results and because of 
> this, I have to rebuild the installer on every change/syntax error fix 
> and such, with takes 8-10 minutes on my workstation.
> Is there a faster approach (other than buying the latest and fastest 
> processor/workstation) to decrease this time?
> thanks in advance,
> Masoud
> 
> 
> 
> 
> _______________________________________________
> Anaconda-devel-list mailing list
> Anaconda-devel-list redhat com
> https://listman.redhat.com/mailman/listinfo/anaconda-devel-list
> 
> 
> 
package RedHat::BootImage;

#############################################################################
# RedHat::BootImage.pm
# by Patrick Devine (patrickd vmware com)
# for VMware Inc. (c) 2002, 2003
# 2002.04.23
#
# Version 0.2.0
#
# This module is covered under Perl's Artistic License.
#
# USE AT YOUR OWN RISK
#
# About this module:
# 
# This is the first stab at creating a module which will allow simple access
# to various parts of the Red Hat installer.  It works fairly well right now
# for modifying boot floppies, the initial ram disk, the stage2 image and
# kernel module bundles.
#
# It still needs some work though..  it's biggest weakness is a lack of a
# destructor method for cleaning up after itself.  Ideally this would pop
# through the mount stack and unmount, re-compress, etc. all of the
# previously mounted image files.  MAKE CERTAIN THAT YOU UMOUNT YOUR IMAGES
# OR YOUR IMAGE FILE PROBABLY WILL NOT WORK.
#
# Things left to do:
#
#    - Some perldoc documentation
#    - Destructor method for cleaning up after itself
#    - Need to delete temp files/directories after we create them
#
# How to use this module:
#
#   Modifying a Red Hat boot disk
#
#      my $img = new RedHat::BootImage "boot.img";
#
#      $img->mount_image();
#      $img->add_file( "my_ks_file.cfg", "ks.cfg" );
#      $img->mount_initrd();
#      $img->add_file( "my_new_loader", "/sbin/loader" );
#      $img->mount_cgz();
#      $img->add_file( "my_new_driver.o", "2.4.9-34BOOT/driver.o" );
#      $img->umount_cgz();
#      $img->umount_initrd();
#      $img->umount_image();
#
#   Modifying a stage2 image
#
#      my $img = new RedHat::BootImage "stage2.img";
#
#      $img->mount_cramfs();
#      $img->add_file( "*.py", "/usr/lib/anaconda" );
#      $img->mount_cgz();
#      $img->add_file( "my_new_driver.o", "2.4.9-34BOOT/driver.o" );
#      $img->umount_cgz();
#      $img->umount_cramfs();
#
#   Modifying a driver disk
#
#      my $img = new RedHat::BootImage "driverdsk.img";
#      $img->mount_image();
#      $img->add_file( "my_pcitable", "pcitable" );
#      $img->mount_cgz();
#      $img->add_file( "my_new_driver.o", "2.4.9-34BOOT/driver.o" );
#      $img->umount_cgz();
#      $img->umount_image();
#
# Please send comments/suggestions/criticism/bugs to patrickd vmware com 
#
#


$LOOP_NUM = 10;

sub new {
  my $proto	= shift;
  my $file	= shift;

  my $class	= ref( $proto ) || $proto;
  my $self	= {};

  $self->{image_file}	= $file;
  $self->{verbose}	= 1;

  bless( $self );

  $self;
}

#############################################################################
# Method:	mount_image
# Description:	mount any image which we can read from or write to.  usually
#		used for manipulating ms-dos floppy disks
# Date:		2002.04.23

sub mount_image {
  my $self	= shift;
  my $file	= shift || $self->{image_file};

  print "Mounting $file\n"
    if $self->{verbose};

  return
    unless -e $file;

  #
  # find a place to mount the image
  #

  my $mount	= '';

  for( my $cnt = 0; $cnt < $LOOP_NUM; $cnt++ ) {

    $mount = "/mnt/loop$cnt";

    mkdir $mount
      unless -d $mount;

    #
    # this should be eval'd and return an error if it breaks
    #

    if( !check_if_dir_mounted( $mount )) {
      `mount -oloop $file $mount`;
      push @{ $self->{mount_point} }, $mount;
      last;
    }
  }

  $mount;

}

#############################################################################

sub umount_image {
  my $self	= shift;
  my $mount	= shift;

  $mount = pop @{ $self->{mount_point} }
    unless $mount;

  print "Unmounting $mount\n"
    if $self->{verbose};

  `umount $mount`;

  1;

}

#############################################################################
# Method:	mount_cramfs
# Description:	logically mount a cramfs partition so that we can do work
#		inside of it.  Usually this is Red Hat's stage2.img file.
# Date:		2002.05.07

sub mount_cramfs {
  my $self	= shift;
  my $file	= shift || $self->{image_file} || 'stage2.img';

  my $tmp_target	= find_temp_file_name( 'cramfs' );

  print "Mounting cramfs target $tmp_target\n"
    if $self->{verbose};

  #
  # mount our cramfs image and copy its contents to a temporary
  # directory where we can edit it directly
  #

  my $target	= $self->mount_image( $file );

  `cp -a $target $tmp_target`;

  $self->umount_image();

  push @{ $self->{cramfs_file} }, [ $file, $tmp_target ];
  push @{ $self->{mount_point} }, $tmp_target;

  1;

}

#############################################################################
# Method:	umount_cramfs
# Description:	unmount and restore a cramfs file system

sub umount_cramfs {
  my $self	= shift;

  my $target		= '';
  my $tmp_target	= '';

  ( $target, $tmp_target ) = @{ pop @{ $self->{cramfs_file} }};

  print "Unmounting cramfs target $tmp_target\n"
    if $self->{verbose};

  `mkcramfs $tmp_target $target`; 

  pop @{ $self->{mount_point} };

  1;

}

#############################################################################
# Method:	mount_initrd
# Description:	logically mount an initial ram disk so that we can change
#		around files inside of it.
# Date:		2002.04.23

sub mount_initrd {
  my $self	= shift;
  my $file	= shift || 'initrd.img';

  my $target		= '';
  my $tmp_target	= '';

  #
  # determine our target file from the last mount point
  # (if there was one)
  # 

  my @mounts	= @{ $self->{mount_point} };

  if( @mounts ) {
    if( -e $mounts[$#mounts] . "/$file" ) {
      $target	= $mounts[$#mounts] . "/$file";
    } elsif( -e $mounts[$#mounts] . "/modules/$file" ) {
      $target	= $mounts[$#mounts] . "/modules/$file";
    } else {
      return 0;
    }
  } else {
    $target	= $file;
  }

  return 0
    unless -e $target;

  my $tmp_target	= find_temp_file_name( 'initrd' );
  `zcat $target > $tmp_target`;

  #
  # save our targets for later and mount the image
  #

  push @{ $self->{initrd_file} }, [ $target, $tmp_target ];

  $self->mount_image( $tmp_target );

  1;

}

#############################################################################

sub umount_initrd {
  my $self	= shift;

  my $target		= '';
  my $tmp_target	= '';

  ( $target, $tmp_target ) = @{ pop @{ $self->{initrd_file} }};

  $self->umount_image();

  `gzip -9 -c $tmp_target > $target`; 
  
  1;

}

#############################################################################
# Method:	mount_cgz
# Description:	logically mount a cpio'd + gzipped file.  Red Hat does this
#		to store kernel modules inside the initial ram disk.
# Date:		2002.05.01

sub mount_cgz {
  my $self	= shift;
  my $file	= shift || 'modules/modules.cgz';

  my $target		= '';
  my $tmp_target	= '';

  #
  # determine our target file from the last mount point
  # (if there was one)
  # 

  my @mounts	= @{ $self->{mount_point} };

  if( @mounts ) {
    $target	= $mounts[$#mounts] . "/$file";
  } else {
    $target	= $file;
  }

  return 0
    unless -e $target;

  $tmp_target = find_temp_file_name( 'modules' ); 
  mkdir $tmp_target;

  `cd $tmp_target && zcat $target | cpio -id`;

  #
  # save our targets for later and mount the image
  #

  push @{ $self->{cpio_dir} }, [ $target, $tmp_target ];
  push @{ $self->{mount_point} }, $tmp_target;

  1;

}

#############################################################################

sub umount_cgz {
  my $self	= shift;

  my $target		= '';
  my $tmp_target	= '';

  return 0
    unless $self->{cpio_dir};

  ( $target, $tmp_target ) = @{ pop @{ $self->{cpio_dir} }};

  `cd $tmp_target && find | cpio -o -H crc | gzip -9 > $target`;

  pop @{ $self->{mount_point} };
  
  1;
  

}

#############################################################################
# Method:	add_file
# Description:	copies a file to the last logically mounted device
# Date:		2002.05.01

sub add_file {
  my $self	= shift;
  my $file	= shift;
  my $target	= shift;

  $target =~ s# ^ / ##x;

#  return 0
#    unless -e $file;

  my @mounts	= @{ $self->{mount_point} };

  if( @mounts ) {
    $target	= $mounts[$#mounts] . "/$target";
  } else {
    $target	= $target;
  }

  print "Copying $file to $target\n"
    if $self->{verbose};

  `cp $file $target`;

}

#############################################################################
# Method:	remove_file
# Description:	removes a file to the last logically mounted device
# Date:		2002.05.01

sub remove_file {
  my $self	= shift;
  my $file	= shift;

  $file =~ s# ^ / ##x;

  my @mounts	= @{ $self->{mount_point} };

  if( @mounts ) {
    $target	= $mounts[$#mounts] . "/$file";
  } else {
    $target	= $file;
  }

  unlink $target;

}

#############################################################################
# Function:	check_if_dir_mounted
# Description:	Read through /proc/mounts and see if a directory
#		is currently mounted
# Date:		2002.05.07

sub check_if_dir_mounted {
  my $file	= shift;

  my @dirs = _read_file( '/proc/mounts' );

  for( @dirs ) {
    my( $target, $dest, $fs, $attr ) = split /\s/;
    return 1
      if $dest eq $file;
  }

  0;

}

#############################################################################
# Function:	find_temp_file_name
# Description:	Find a filename/directory in /tmp that we can use for
#		doing some work in
# Date:		2002.05.01

sub find_temp_file_name {
  my $file	= shift;
  my $random	= shift || 10000;

  my $num	= 0;
  my $target	= '';

  #
  # create a name for the initrd file and uncompress it into
  #

  while( 1 ) {
    $num	= int( rand( $random )) + 1;
    $target	= "/tmp/$file-$num";
    last
      unless -e $target;
  }

  $target;

}

#############################################################################
# Function:	_read_file
# Date:		2002.04.23

sub _read_file {
  my $file	= shift;

  return ''
    unless -e $file;

  open IN, $file;
  my @data = <IN>;
  close IN;

  @data;

}


1;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]