installwatch.txt

Rob 'Feztaa' Park feztaa at shaw.ca
Wed Jul 31 00:16:59 PDT 2002


Updated installwatch.txt. Big fix here ;)

Thanks.

-- 
Rob 'Feztaa' Park
http://members.shaw.ca/feztaa/
--
Sometimes the best medicine is to stop taking something.
-------------- next part --------------
TITLE:		Using Installwatch as a Package Manager
LFS VERSION:	Any
AUTHOR:		Robert Park <feztaa at shaw.ca>

SYNOPSIS:
	How to keep track of files that are installed on your system when you
	compile something from source, and how to easily remove all of these
	files.

HINT:

Changelog
---------

$Log: installwatch.txt,v $
Revision 1.11  2002/07/31 07:14:50  feztaa
Updated nuke script to version 1.12

Revision 1.10  2002/07/27 01:06:27  feztaa
Updated nuke script to version 1.11

Revision 1.9  2002/06/15 18:03:12  feztaa
Updated nuke script to version 1.9

Revision 1.8  2002/06/09 03:48:40  feztaa
Added second installwatch url, changed some style of code blocks (more
consistent now), added a few notes at the beginning, and reworded a few
things.

Revision 1.7  2002/05/30 01:01:28  feztaa
Updated nuke script to version 1.8.
Also changed location of nuke script from /usr/bin to /usr/sbin,
so that it generally won't be in regular user's $PATH.

Intro
-----

One big problem with LFS is that there is no package management system.  This
means that it is a *HUGE* pain in the butt to uninstall something, since there
is no record of what got installed where, and by what program.

There are lots of other ways to implement "package management" in LFS; but this
is the one that I use ;)

If you're interested, a good friend of mine has written a similar tutorial, but
using ftrace instead:

http://www.linuxjunior.org/cgi-bin/pet/pet.cgi?SUBMIT=Display&id=44

That, coupled with the fact that the ftrace website has been down for as long
as I can remember, was my main inspiration/motivation for writing this ;)

Notes
-----

In an attempt to make this easier to read, all "code blocks" that you should
execute on the commandline start and end with "##--CODE--##". Feel free to copy
that onto the commandline along with the code itself, it won't hurt anything.
Quoted text, such as the output of a program, is prefixed with four spaces.

Also, if you're trying to use this during the early stages of Chapter 6 in the
LFS book, it will fail miserably for you. The reason is that installwatch needs
programs to be dynamically linked for it to work; in Chapter 6, all of your
programs are statically linked. Installwatch *might* work for you near the end
of chapter 6 when most of the static stuff is gone, but I advise not using it
until chapter 6 is finished and you're installing other stuff. I've yet to find
a program that wouldn't install properly with installwatch, just as long as
your stuff is dynamically linked.

Requirements
------------

You'll need to download installwatch, which you can get from one of these
locations:

http://asic-linux.com.mx/~izto/checkinstall/installwatch.html
http://proyectos.glo.org.mx/checkinstall/installwatch.html

If both these sites are down, try this one (but only as a last resort):

http://www.google.ca/search?hl=en&q=installwatch+izto+0.6.3&meta=

I used version 0.6.3 to write this hint, but other versions should work as well
(just as long as their logfiles are in the same format).

Instructions
------------

1. Unpack and compile installwatch. Compilation is done like so:

##--CODE--##
make &&
make install
##--CODE--##

2. Make sure that 'make' is owned by the root group:

##--CODE--##
chgrp root /usr/bin/make
##--CODE--##

I've also heard that installwatch will not work if make is setgid. I'm not sure
if this is true, but you might want to make sure it isn't:

##--CODE--##
chmod -s /usr/bin/make
##--CODE--##

3. Create the /var/install and /var/uninstall directories:

##--CODE--##
mkdir /var/{install,uninstall}
##--CODE--##

The install directory will be where we put installwatch's logfiles, and the
uninstall directory will be where we put the log of what we deleted with the
"nuke" script that I am going to show you next.

4. The nuke script is used to analyse an installwatch logfile and remove the
files that it mentions. This, of course, is used only when you've decided that
you want to uninstall that program ;)

You can download it from http://members.shaw.ca/feztaa/projects/nuke, or you
can execute the following commands (it's long) to create the script.  If you
download it, be sure to save it to /usr/sbin/nuke, and give it 755 (rwxr-wr-w)
permissions. If you don't want to download it, run the this at the command
promp as root:

##--CODE--##
cat <<"EOF" >/usr/sbin/nuke
#!/usr/bin/env perl
# Author: Robert Park <feztaa at shaw.ca>
# License: GNU General Public License

# $Log: installwatch.txt,v $
# Revision 1.11  2002/07/31 07:14:50  feztaa
# Updated nuke script to version 1.12
#
# Revision 1.12  2002/07/31 07:11:43  feztaa
# Fixed major problem with symlinks that point to directories.
#
# Revision 1.11  2002/07/27 00:45:39  feztaa
# Major overhaul; reduced LOC and increased efficiency all around.
#
# Revision 1.10  2002/07/26 19:41:00  feztaa
# Incorporated fixes from Zenith Lau <zenithlau at sniic.com>, fixing
# issues with symlinks.

use strict;

die "You must be root!\n" unless ($< == 0);

# Underline a string by appending with with a newline and hyphens
sub underline
{
  my $str = join("", @_);
  my $chomp = 1;

  $chomp++ while (chomp $str);

  return "$str\n" . ("-" x length $str) . ("\n" x $chomp);
}

# Take an array, and return a string that's been properly commified, 
# ie ("one", "two", "three") becomes "one, two, and three".
sub commify
{
  (@_ == 0) ? ''                                      :
  (@_ == 1) ? $_[0]                                   :
  (@_ == 2) ? join(" and ", @_)                       :
              join(", ", @_[0 .. ($#_-1)], "and $_[-1]");
}

my %opts;
my @args;

foreach my $arg (@ARGV)
{
  ($arg =~ m/^(-r|--report)$/) ? $opts{report} = 1 : push @args, $arg;
}

# Process all the logfiles
foreach my $arg (@args)
{
  $arg =~ s#^.*/##g;
  chomp $arg;

  my $install = "/var/install/" . $arg;
  my $uninstall = "/var/uninstall/" . $arg;

  unless (-f $install)
  {
    print "Can't find $arg\n";
    next;
  }

  open "INSTALL", "<$install" or die "$!\n";

  print "Processing $arg ... ";

  my %files;
  my $error = 0;

  while (<INSTALL>)
  {
    chomp;
    my @fields = split;

    my $action = $fields[1];
    my $file = $action eq "symlink" ? $fields[3] : $fields[2];

    # Don't delete stuff that wasn't created properly; 
    # prevents deletion of /usr or similar.
    if ($fields[-1] eq "#success")
    {
      push @{ $files{$file} }, $action if (-f $file or -l $file or -d $file);
    }
  }

  print "done.\n";

  if ($opts{report})
  {
    # Reporting mode, don't delete anything.
    print underline("Files/Directories installed by $arg\n");

    foreach my $file (sort { length $b <=> length $a } keys %files)
    {
      print "$file:  ", commify (@{ $files{$file} }), "\n";
    }
  }
  else
  {
    # Nuke mode, delete stuff...
    print "Uninstalling $arg ... ";
    
    open "UNINSTALL", ">$uninstall" or die "$!\n";

    select UNINSTALL;

    print underline("Removed Files/Directories");

    foreach my $file (sort { length $b <=> length $a } keys %files)
    {
      if (grep /open|symlink|mkdir/, @{ $files{$file} })
      {
        $! = "";

        print "\n$file";

        # -d returns true for symlinks that point to directories,
        # so this is actually necessary.
        (-l "$file") ? unlink "$file" :
        (-d "$file") ? rmdir "$file"  :
                       unlink "$file";

        if ($!)
        {
          print " -- $!";
          $error++;
        }
      }
    }

    close "INSTALL";
    close "UNINSTALL";
    select STDOUT;

    # Let the user know what happened
    if ($error) 
    { 
      print "$error files/directories could not be removed.\n"; 
    }
    else
    { 
      unlink $install;
      print "successful.\n"; 
    }
  }
}
EOF
chmod 755 /usr/sbin/nuke
##--CODE--##

This script examines the logfile and keeps track of all the files and
directories that were created during the install process, then it removes them.

It will also create a log of what it uninstalled. This logfile will be located
in /var/uninstall and will have the same name as the original logfile in
/var/install. This new logfile will look something like this:

    Removed Files/Directories
    -------------------------
    
    /different/path/to/file -- Permission denied
    /path/to/another/file
    /different/path/to -- Directory not empty
    /path/to/another
    /path/to/file
    /path/to

In this case, /different/path/to/file could not be removed due to permission
problems, and /different/path/to could not be removed because it was not empty
('file' was still there). The other files and directories were deleted
properly.

5. Next, you need to know how to use installwatch when you're compiling your
software. Without this part, you'd have no logfiles in /var/install, and the
nuke script would be thoroughly useless ;)

When you are reading installation instructions for something, and you see "make
install", you'll want to replace that with this:

installwatch -o /var/install/programname-version make install

But, if you're too lazy and don't want to remember all that, create an alias
similar to this one:

##--CODE--##
alias iw='installwatch -o /var/install/$(basename $(pwd))'
##--CODE--##

This will take the name of the current directory, and use that as the logfile
name to use in /var/install. The idea is that the name of the directory you are
compiling source in is descriptive of the software you are compiling. For
example, I compiled XMMS in /usr/src/xmms-1.2.7, and this alias created the
logfile named "/var/install/xmms-1.2.7". You'll want to put this alias into
your bashrc, so that you won't have to recreate the alias every time you start
a new shell.

If you're going to use this alias as-is, then wherever you see "make install"
in the installation instructions for something, you'll have to prefix it with
"iw". For example, instead of the standard "./configure && make && make
install", you'd type this:

##--CODE--##
./configure && make && iw make install
##--CODE--##

You can also use the "iw" alias for anything else that creates or modifies
files that you want to keep track of; it just happens to be most useful with a
"make install" during a compile.

6. In order to use the nuke script, do this:

##--CODE--##
nuke logfilename
##--CODE--##

"logfilename" should be the name of a file that exists in /var/install. You
can't specify an absolute path to a logfilename, they have to be in
/var/install. Also, you can uninstall more than one thing at once, if you want
to:

##--CODE--##
nuke logfilename1 logfilename2 logfilename3
##--CODE--##

Once you have run nuke, go to /var/uninstall and read over the log file for
what you just uninstalled. Make sure nothing failed to delete -- if something
did, you'll want to delete it yourself. Once you are satisfied that the program
is uninstalled, you can delete the logfile from /var/uninstall.

When reading the logfile, if the filename is alone on one line, that means it
was removed successfully. If you see something like "filename -- some words",
that means that it failed to be deleted, and "some words" is the the error
message. Just remember that you don't want to see the two hyphens ;)

There is also a special "reporting mode" in the nuke script. You can use it if
you just want to see what files were created by the install, and what kinds of
things the install did to those files (chown, chmod, etc), without actually
removing the program. The -r option does this, like so:

##--CODE--##
nuke -r logfilename
##--CODE--##

This will produce output something like this:

    Files/Directories installed by foobar-1.0
    -----------------------------------------
    
    /usr/bin/foobar:  open, chown, and chmod
    /etc/foobarrc:  open, chown, and chmod

The End
-------

Congratulations! You now have an extremely easy method of removing software
that was compiled from source!

If you encounter any problems, please let me know. I want to make this as good
as it can possibly be ;)


More information about the hints mailing list