[alt.sources] Generic Installation Script in Perl

mccarrol@topaz.rutgers.edu (Mark C. Carroll <MC>) (10/16/89)

This script allows you to quickly create a description of how a
software package should be installed. It's written in Perl, which
is not a standard part of Unix, but should be. If you don't have Perl
on your machine, get it. You'll never hack a shellscript again.

<MC>

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	Install
#	README
#	install.man
# This archive created: Sun Oct 15 14:17:35 1989
cat << SHAR_EOF > Install
#!/pub/local/bin/perl
# Generic Install Script in Perl
# Written by Mark C. Carroll
# version 1: completed Oct 15, 1989
%Install=();
$verbose="no";

# Beginning of Parameter Setting Code.
@stuff=("graph3d1.sh","graph3d2.sh","bs");
$names=&PackNames(@stuff);
do SetGroupParams("3d","3d","mccarrol","studsys",0644,0755,@stuff);

# Beginning of standard code. Do not change after this line.
# First, make sure the person installing is root:
die "Install: you must be root to Install\n" unless ("$>" eq "0");
local ($group);

# Then, install each filegroup
foreach $group ( @InstallNames ) {
   print "Install : installing $group\n";
   &InstallGroup($group);
}

sub PackNames {
# pack names into a string of the form "name:name:name"
   local (@namearray)=@_;
   local ($namestring);

   $namestring=join(':',@namearray);
   return $namestring;
}


sub SetGroupParams {
   local ($groupname,$grouploc,$groupowner,$groupgroup,$filemode,$dirmode,@files)=@_;
   local ($uid,$gid,$filelist);
   $uid=&GetUid($groupowner);
   $gid=&GetGid($groupgroup);
   $Install{$groupname,"owner"} = $uid;
   $Install{$groupname,"group"} = $gid;
   $Install{$groupname,"location"} = $grouploc;
   $Install{$groupname,"filemode"} = $filemode;
   $Install{$groupname,"dirmode"} = $dirmode;
   $filelist=&PackNames(@files);
   $Install{$groupname,"files"} = $filelist;   
   push(@InstallNames,$groupname);
}

sub GetUid {
  local ($user)=@_;
  local ($login,$pass,$uid);
  open(pass,'/etc/passwd') || die "Install: Can't get uids\n";
  while (<pass>) {
    ($login,$pass,$uid)=split(/:/);
    if ($login eq $user) {
      close pass;
      return $uid;
    }
  }
  close pass;
  die "Install; can't find uid of $user\n";
}

sub GetGid {
   local ($group)=@_;
   local ($name,$i,$gid);

   open(groups,"/etc/group") || die "Install; can't open group files\n";
   while (<groups>) {
      ($name,$i,$gid)=split(/:/);
      if ($name eq $group) {
         close groups;
         return $gid;
      }
   }
   close groups;
   die "Install; can't find group id of $group\n";
}


sub InstallGroup {
   local ($filegroup)=@_;

   local (@files)=split(/:/,$Install{$filegroup,"files"});
   local ($owner)=($Install{$filegroup,"owner"});
   local ($group)=($Install{$filegroup,"group"});
   local ($location)=($Install{$filegroup,"location"});
   local ($fmode)=($Install{$filegroup,"filemode"});
   local ($dmode)=($Install{$filegroup,"dirmode"});
   if ("$verbose" eq "yes") {
      print "Installation Information on $filegroup:\n";
      print "   Owner: $owner\n";
      print "   Group: $group\n";
      print "   Destination: $location\n";
      print "   File mode: $fmode\n";
      print "   Dir mode: $dmode\n";
      print "   Files:\n";
      foreach $f ( @files ) { print "      $f\n"; }
   }
   unless  ( -e $location ) {
      print "Directory $location does not exist. Should I create it? ";
      $shouldi=<STDIN>;
      die "Install: installation directory $location does not exist\n" 
         unless ($shouldi =~ /[Yy]/) ;
      mkdir($location,$dmode);
      chown $owner,$group,$location;
   }
   @fullfiles=();
   foreach $f ( @files ) {
      $fullname = $location . "/" . $f;
      if ( -e $f ) {
         system("cp $f $location");
         push(@fullfiles,$fullname);
      } 
      else {
         print "Install: file $f in group $filegroup not found\n";
      }
   }
   chown $owner,$group,@fullfiles;
   chmod $fmode,@fullfiles;
}

SHAR_EOF
cat << SHAR_EOF > README
This is a quick hack that I thought might be useful to some other
folks out there.

My job here at Rutgers is putting together a library of free software
for the Pyramid Users Group. The Pyramid operating system has two
"universes", System V, and Berkeley. When I get a package for the
library, I like to be able to have the sources set up identically in
the Berkeley and System V universes, with the exception of a single
line in the Makefile. This was impossible, because System V's install
command is not compatible with the Berkeley install. So, I wanted to
put together some way of having a common script that would work under
both berkeley, and sysv. I started with a shell script. But that ends up
horribly ugly, and the amount of work to customize it to each package is
monstrous. So then, I moved on to writing a make-like program in C/yacc/lex.
Writing in C is just a dreadful overkill. Then, I discovered Perl. After
I realized perl could do this, I sat down and wrote this entire program in
less than 2 hours, included the time I wasted because I was missing a bug-fix.

The man page stinks, mainly because I don't know nroff. (I'm a LaTeX
weenie) It was created by trying to get the gist of man from reading
the system manpages. It's sufficient, I hope, but it's really pretty
lousy. If anyone feels like fixing it up, send me a copy of it!

I'm giving it away in the hopes that it might actually be useful to
someone else. You can hereby do anything you want with it. I release
it to the Public Domain. I'd appreciate it if you leave my name on the
code if you use it, but you aren't obligated to.

	Mark C. Carroll <MC>
 	mccarrol@topaz.rutgers.edu { ...!rutgers!mccarrol }
	Rutgers University LCSR, Student Systems Programmer
	October 15, 1989

SHAR_EOF
cat << SHAR_EOF > install.man
.TH Install Rutgers

\fBInstall\fR - generic perl installation script

.SH SYNOPSIS
.nf
.B Install

.fi
.SH DESCRIPTION
\fBInstall\fR is a generic script for installing software packages. 

\fBInstall\fR scripts consist of 2 portions: the user header, and the actual
installation code. The header consists of lines of the form:

&SetGroupParams(groupname,location,owner,group,filemode,dirmode,files);

groupname is the name of the type of files being installed: ie bin.

location is the name of the directory the files must be installed in.

owner and group are the username, and usergroup that will own the
installed files.

filemode is the octal protection mode of the files being installed.
This must have a leading zero.

dirmode is the octal protection mode of the directory to be created. If
the directory already exists, its modes will not be changed.

files is the list of files to be installed.

.SH OPTIONS

The only option currently present in \fBInstall\fR is $verbose. To get
full information on each file group as it processes, insert the line

$verbose="yes";

in the beginning of the script.

.SH EXAMPLE

&SetGroupParams("bin","/usr/local/bin","root","bin",0755,0755,"Install");
&SetGroupParams("man","/usr/man/manl","root","bin",0644,0755,"Install.l");
&SetGroupParams("stuff","/pub/src/Install","root","bin",0644,0755,"Install","Install.l");

These lines would install "Install" in /usr/local/bin, owned
by root, group bin, with protection mode 755; Install.l
in /usr/man/manl, owned by root, group bin, mode 644; both
Install, and Install.l in "/pub/src/Install", creating the directory
"pub/src/Install" with mode 755.

.SH AUTHOR
Mark C. Carroll

.SH BUGS
Nun. I don't make misstaks.

.SH FEATURES
Ugly "syntax". I'd like to eventually have a clean make-like syntax for
Install. It's also not as flexible as I'd like. And it's very clearly
a quick hack. But it works.
SHAR_EOF
#	End of shell archive
exit 0
-- 
\ Mark Craig Carroll: <MC>     \ "Man may trust man, but we'll never \
 \ mccarrol@topaz.rutgers.edu   \  have a truly sane world until men  \
  \ ...!rutgers!mccarrol         \  learn to trust mankind"            \
   \ carroll@zodiac.bitnet        \     -Michael Moorcock               \