#!/usr/local/bin/perl 'di '; 'ig00 '; ############################################################################# # # Install and update the automounter... # # David Muir Sharnoff, muir@csi.com, 1-27-92 # # Configurables: # $data_death = 60*60*24*60; # time (seconds) that showmount -e results are chached in /etc/auto.master $autodir = "/auto"; # our replacement for /tmp_mnt... $nfsopts = "rw,bg,intr,hard,noquota"; $ENV{'PATH'} .= ':/usr/etc:/etc'; # # Manual page at bottom, run the entire program though "[nt]roff -man" # # Environments tested: # # perl 4.0 p l19 # # SunOS 4.1.1 # SunOS 4.1.2 (Solaris 1.0.1) # # NFS servers hit: # # Sun's, Apollo's, Decstations, SCO, HPUX # # $Header: /cae780/home/muir/tmp/RCS/autoautomount,v 1.15 1992/03/03 00:04:09 muir Exp muir $ # ############################################################################# ############################################################################# # # Copyright (c) 1992 Comdisco Systems Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the Comdisco Systems Inc. # 4. The name of Comdisco may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COMDISCO SYSTEMS INC ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL COMDISCO SYSTEMS INC BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This copyright notice derrived from material copyrighted by the Regents # of the University of California. # ############################################################################# @oARGV = @ARGV; while (@ARGV) { $_ = shift(@ARGV); if ($_ eq '-silent') { $opt_silent = 1; } elsif ($_ eq '-nosilent') { $opt_silent = 0; } elsif ($_ eq '-autoupdate') { $opt_autoupdate = 1; } elsif ($_ eq '-noautoupdate') { $opt_autoupdate = 0; } elsif ($_ eq '-favor') { $opt_favor = 1; $opt_unfavor = 0; } elsif ($_ eq '-unfavor') { $opt_favor = 0; $opt_unfavor = 1; } elsif ($_ eq '-flush') { $parse_flush = 1; while($ARGV[0] !~ m,^-,) { push(@arg_flush,shift(@ARGV)); } } else { die "Usage: $0 [-silent] [-autoupdate] [-flush [hosts ...]] [-[un]favor]\n"; } } @flush{@arg_flush} = @arg_flush; sub fixquoting { local($cmd,$qq) = @_; local(@a) = split($qq,$cmd.$qq); return $cmd unless $#a > 2; return join($qq,$a[0],join("\\$qq",@a[1..($#a-1)]),$a[$#a]); } chop($hostname = `hostname`); if ($opt_silent || $opt_autoupdate) { $e = "$0"; for $o (@oARGV) { $e .= &fixquoting(" '$o'","'"); } $e .= " -nosilent -noautoupdate >8); if ($status) { print "auto.log ($hostname)...\n" if $opt_silent; system("cat auto.log") if $opt_silent; print "Exit $status\n"; exit($status); } if ($opt_autoupdate) { $e = "csh -xe auto.update >8); if ($status) { print "auto.log ..\n" if $opt_silent; system("cat auto.log") if $opt_silent; print "Exit $status\n"; exit($status); } } exit(0); } chop($cwd = `pwd`); $| = 1; open(SOFT,">auto.soft") || die "could not open auto.soft: $!"; open(FSTAB,">auto.fstab") || die "could not open auto.fstab: $!"; open(MASTER,">auto.master") || die "could not open auto.master: $!"; open(HARD,">auto.hard") || die "could not open auto.hard: $!"; open(INSTALL,">auto.install") || die "could not open auto.install: $!"; open(UPDATE,">auto.update") || die "could not open auto.update: $!"; open(AWKML,">auto.awkml") || die "could not open auto.awkml: $!"; $install = ""; $header = ""; $update = ""; $postheader = ""; open(HOSTS,"/etc/hosts") || die "could not open /etc/hosts: $!"; while() { next if /^#/; next unless /^\d+\.\d+/; chop; split; next if $_[1] eq 'localhost'; next if $_[1] eq 'loghost'; next if $_[1] eq 'mailhost'; next if $_[1] eq $hostname; push(@hosts,$_[1]); $comment{$_[1]} = join(' ',@_[2..$#_]); # print "noting host $_[1]\n"; } open(OFSTAB,"/etc/fstab") || die "could not open /etc/fstab: $!"; while() { next unless /^# auto/; &readfstab($_); } sub readfstab { local($_) = @_; if (/remount\s+(.*)/) { push(@remount,split(' ',$1)); } if (/ignore\s+(.*)/) { push(@ignore,split(' ',$1)); } if (/unfavor\s+(.*)/) { push(@unfavor,split(' ',$1)); } if (/favor\s+(.*)/) { push(@favor,split(' ',$1)); } if (/include\s(.*)/) { if (-e $1) { local(*MFS); open(MFS,$1) || die "open $1: $!"; while() { &readfstab($_); } close(MFS); } } } close(OFSTAB); @ignore{@ignore} = @ignore; @remount{@remount} = @remount; @favor{@favor} = @favor; @unfavor{@unfavor} = @unfavor; open(OFSTAB,"/etc/fstab") || die "could not open /etc/fstab: $!"; while() { if (m,^([A-Za-z_]\S*):(\S+)\s+(\S+)\s+nfs\s+(\S+)\s,) { ($rhost,$rpart,$lpart,$nopt) = ($1,$2,$3,$4); $oldNFSopt{$lpart} = $nopt; unless ($ignore{$rhost} || $ignore{$lpart} || $ignore{"$rhost:$rpart"}) { $unmount{$lpart} = $rhost; next; } } print FSTAB $_; } close(OFSTAB); if ((@arg_flush || !$parse_flush) && open(OMASTER,"/etc/auto.master")) { while() { next unless /^# showmount (\S+) (\S+) (.*)/; ($host,$date,$files) = ($1,$2,$3); next if $flush{$host}; $oldshowdate{$host} = $date; $oldshowfiles{$host} = $files; } } print MASTER </dev/null"; if ($? >> 8) { print "couldn't contact..."; if (($now - $oldshowdate{$host}) < $date_death) { print "using old data..."; @parts = split(' ',$oldshowfiles{$host}); $date = $oldshowdate{$host}; } else { print "\n"; next; } } else { $ok = 0; open(SHOWMOUNT,"showmount -e $host 2>&1|") || die "could not popen showmount -e $host"; for $_ (sort bylength_space ) { if (/RPC/ || /export/) { $ok = 1; } if (/^sh: showmount: not found/) { die $_; } ($part,$who) = m!^(/\S*)\s+(\S+)$!; next unless $part; next unless $who; next unless ($who =~ /\beveryone\b/ || $who =~ /\b$host\b/); $ok = 1; push(@parts,$part); } close(SHOWMOUNT); $date = $now; last unless $ok; } if (@parts) { print MASTER "# showmount $host $date @parts\n"; for $part (@parts) { $unfavor = 0; if ($opt_favor) { $favor = 1; } elsif ($opt_unfavor) { $unfavor = 1; $favor = 0; } elsif (@favor) { $favor = 0; } elsif (@unfavor) { $favor = 1; } else { $favor = 1; } if ($part =~ m,^/+$,) { $spart = ""; } else { $spart = $part; } if ($ignore{$host} || $ignore{"$host:$part"}) { print "ignoring $host:$part..."; next; } if ($remount{$host} && $ignore{"/$host$part"}) { $keep_mounted{"/$host/$part"} = $host; print "ignoring /$host$part..."; next; } $favor = 2 if $favor{$host}; $unfavor = 2 if $unfavor{$host}; $favor = 3 if $favor{"$host:$part"}; $unfavor = 3 if $unfavor{"$host:$part"}; if ($remount{$host}) { $favor = 3 if $favor{"/$host$part"}; $unfavor = 3 if $unfavor{"/$host$part"}; if ($oldNFSopt{"/$host$spart"}) { $o = $oldNFSopt{"/$host$spart"}; print FSTAB "$host:$part\t/$host$spart\tnfs\t$o\t0\t0\n"; } else { print FSTAB "$host:$part\t/$host$spart\tnfs\t$nfsopts\t0\t0\n"; } $keep_mounted{"/$host$spart"} = $host; $mklink{"/net/$host"} = "/$host"; $mounted = 1; if ($favor > $unfavor) { $host{$part} = "/$host"; $parts{$part} += 1; } next; } if ($ignore{"/net/$host$spart"}) { print "ignoring /net/$host$spart..."; next; } $favor = 3 if $favor{"/net/$host$part"}; $unfavor = 3 if $unfavor{"/net/$host$part"}; if ($part eq "//") { # apollo print "It't an (ugh!) apollo..."; print SOFT "\n\n/net/$host $host://\n"; die "ugh" if $apollo; die "bla" if $started; push(@apollo,$host); $apollo = "/$host"; next; } die "futz" if $apollo; if ($favor > $unfavor) { $parts{$part} += 1; $host{$part} = "/net/$host"; } unless ($started) { print HARD "\n/net/$host"; $started = 1; } print HARD "\t\\\n $part $host:$part"; } } $parts{$host} = 100; print HARD "\n" if $started; print SOFT "\n" if $apollo; if (! $started && ! $apollo && ! $mounted) { print "Could not find any partitions..."; if ($comment{$host} =~ /apollo/) { push(@dumb_apollos,$host); print "Assuming its an apollo..."; } } print "\n"; if ($started || $apollo) { $mklink{"/$host"} = "/net/$host$apollo"; } } for $part (sort keys(%parts)) { next if $parts{$part} > 1; next if $part =~ m!/.*/!; die "nuuu" if $parts{$part} != 1; print "$part is uniq... making a link for it...\n"; $mklink{"/$part"} = "$host{$part}$part"; } die "cannot find any working apollos" if (@dumb_apollo && !@apollo); @apollo{@apollo} = @apollo; for $dumb (@dumb_apollos) { $apollo = $apollo[rand($#apollo)]; unless (-l "/$dumb" && readlink("/$dumb") =~ m,/net/(\S+)/$dumb$, && defined($apollo{$1}) && $apollo{$1}) { $mklink{"/$dumb"} = "/net/$apollo/$dumb"; } } for $from (sort keys (%mklink)) { $to = $mklink{$from}; if (-l $from) { if (readlink($from) ne $to) { if (readlink($from) =~ m,^/net/, || $from =~ m,^/net/,) { $install .= "/bin/rm $from\n"; $install .= "ln -s $to /\n"; $update .= "/bin/rm $from\n"; $update .= "ln -s $to /\n"; } else { $install .= "/bin/rm -i $from\n"; $install .= "ln -s $to /\n"; $update .= "# /bin/rm -i $from\n"; $update .= "# ln -s $to /\n"; } } } elsif (-d $from) { print "Warning: will remove $from\n"; $install .= "/bin/rm -ri $from\n"; $install .= "ln -s $to /\n"; $update .= "# /bin/rm -ri $from\n"; $update .= "# ln -s $to /\n"; } else { $install .= "ln -s $to /\n"; $update .= "ln -s $to /\n"; } } # doesn't get used. for $rm (sort keys (%empty)) { if (-l $rm) { if ($rm =~ m,^/net/,) { $install .= "/bin/rm $rm\n"; $update .= "/bin/rm $rm\n"; } else { $install .= "/bin/rm -i $rm\n"; $update .= "# /bin/rm -i $rm\n"; } } elsif (-e $rm) { $install .= "/bin/rm -ri $rm\n"; $update .= "# /bin/rm -ri $rm\n"; } } open(RC,"/etc/rc.local") || die "could not open /etc/rc.local"; if (!grep(m!automount -v -f /etc/auto.master -M /auto!,)) { $install .= <<'END'; echo 'if [ -f /etc/auto.master ]; then' >>/etc/rc.local echo " automount -v -f /etc/auto.master -M /auto & (echo -n ' automount') >/dev/console" >>/etc/rc.local echo 'fi' >>/etc/rc.local END $update .= "# add automounter startup code to /etc/rc.local...\n"; $update .= "# automount -v -f /etc/auto.master -M $autodir & (echo -n ' automount')\n"; } close(RC); print SOFT "\n"; print HARD "\n"; sub bylength_space { index($a,' ') <=> index($b,' '); } sub by_length { length($b) <=> length($a); } $header .= "/bin/rm -f /tmp/um$$\n"; $header .= "mount -p | awk -f auto.awkml >/tmp/um$$\n"; print AWKML "\$3 != \"nfs\" {next}\n"; print AWKML "\$2 ~ /^\\/auto\\// {next}\n"; for $lp (sort by_length keys(%unmount)) { if ($keep_mounted{$lp} eq $unmount{$lp}) { print AWKML "\$2 == \"$lp\" {next}\n"; } else { $header .= "umount $lp\n"; print AWKML "\$2 == \"$lp\" {print \$2}\n"; } } $header .= <<; @ x = `cat /tmp/um$$ | wc -l`; if (\$x != 0) then echo "Could not unmount `cat /tmp/um$$`" /bin/rm -f /tmp/um$$ mount -a exit 1; endif /bin/rm -f /tmp/um$$ $post = "sh -c 'mount -a'\n"; open(PS,"ps cx|") || warn "popen ps cs|: $!"; $found = 0; while() { if (/^\s*(\d+)\s+.*\sautomount$/) { $post .= "kill -1 $1\n"; $found = 1; } } close(PS); print INSTALL $header; print INSTALL $postheader; print INSTALL $install; print INSTALL $post; print INSTALL "automount -v -f /etc/auto.master -M $autodir &\n" unless $found; print INSTALL "exit 0\n"; print UPDATE $header; print UPDATE $postheader; print UPDATE $update; print UPDATE $post; print UPDATE "exit 0\n"; close(HARD); close(SOFT); close(INSTALL); close(UPDATE); close(MASTER); close(FSTAB); close(AWKML); print <<; To install the automounter, bring the system to single user mode and run $cwd/auto.install. To update the automounter configuration files, run $cwd/auto.update. system("chmod +x auto.update"); exit(0); ' ############# BEGIN NROFF/PERL TRANSITION ########### .00; .\"'; 'di .nr nl 0-1 .nr % 0 '; __END__ .\" ########### BEGIN MANUAL PAGE ################# .TH AUTOAUTOMOUNT 8 "January 29, 1992" .AT 3 .SH NAME autoautomount \- automatically configures the automounter .SH SYNOPSIS .B autoautomount [ .I -autoupdate ] [ .I -silent ] [ .I -flush [ .IR hostname ...\ ]\ ] [ .I -favor ] [ .I -unfavor ] .SH DESCRIPTION .B autoautomount will generate and maintain .BR automount (8) configuration files. It will also maintain the fstab. .B autoautomount assumes that you want all of the exported filesystems of computer .I x mounted at .IR /x . This is fundemental to .B autoautomount so if it does not fit your requirements, do not use .BR autoautomount ! .B autoautomount is designed to be used in a network that includes both Sun and Apollo workstations. .LP There are two primary ways to use .BR autoautomount : the first is to use it to install .BR automount ; the second is to maintain your .B automount configuration. Whenever .B autoautomount is run, it generates shell scripts for both installing and maintaining your .B automount configuration files. These scripts are named .IR auto.install , and .I auto.update respectively. .LP Although it is not always required, it is usually a good idea to run .I auto.install in single-user mode because it has to be able unmount filesystems with impunity. To make sure that .I auto.install is examined before it is run, .B autoautomount does not turn on execute permission for .IR auto.install . .LP Invoked without any options, .B autoautomount will just create a few files for you to look at. There is no risk in running .B autoautomount in an empty directory. .LP The basic activity of .B autoautomount is to run a .B showmount\ -e on each host listed in the .B /etc/hosts file and build an .B automount mount map using the information returned. .LP Because apollo computers do not work very well, .B autoautomount treats them specially. It soft-mounts them instead of hard mounting them. It also will make links so that you can access ones that are not NFS servers through ones that are. .SH OPTIONS In its normal mode of operation, .B autoautomount is somewhat verbose; it reports each host as it processes it. This verbosity can be supressed with the .B -silent option. .LP One common way to use .B autoautomount is to run it from .BR cron (8) once a week. The .B -autoupdate option will cause the .B auto.update script to be run automatically. If combined with the .B -silent option, there will not be any output if everything works. .LP Because an important system might not be up during a particular run of .BR autoautomount , the output from .BR showmount (8) is cached in .BR /etc/auto.master . If you wish to flush the cached output, you can invoke .B autoautomount with the .B -flush option. If you also specify some hosts, it will only flush the information on the hosts specified. .LP Normally, .B autoautomount makes links in the root level for each host and unique filesystem. Links are only make for hosts and filesystems that receive consideration. By default, everything receives consideration. The .B -unfavor option reverses the default. The .B -favor option restores it. .SH FSTAB DIRECTIVES Directives can be placed as comments in your .BR fstab (5) file to control the action of the .BR autoautomount . Each directive must begin at the start of a line with the following magic cookie: .br .TP .B # auto .I DIRECTIVE host/filesystem ... .br .PP The following directives are recognized: .br .TP 10 .B ignore specifices that a host or filesystem should be ignored by the .BR autoautomount er. It will not be removed from the fstab (if present), and it will not be put into the .B automout configuration files. .TP .B remount specifies that a host should have its fstab entries rewritten so that it mounts everything. .B autoautomout always mounts other hosts at the root level. .TP .B unfavor specifies that a host or filesystem should not be considered when making top level links. .TP .B favor specifies that a host or filesystem should be considered when making top level links. By default, all hosts and filesystems are considered for links, but if the favor option is used, and neither the .B -favor or .B -unfavor command line arguments are used, then only those hosts and filesystems that are explicitly favored get consideration. .TP .B include specifies another file with directives for .BR autoautomount . Unlink .BR /etc/fstab , the magic cookie is not required in additional files. .SH HOSTS DIRECTIVES As .B autoautomount processes the .B /etc/hosts file, it looks for a couple of magic cookies in the comments. If it finds the comment, .BR no\ nfs , on the same line as a system, then it will skip that system (very similar to the .B ignore directive in .BR /etc/hosts ). .LP If it finds the string, .BR apollo , in the comment field, then if it cannot get a .B showmount\ -e to report anything, it will make the assumption that the corresponding system is running Domain OS, and add in a link to it through another apollo system. .SH ENVIRONMENT No enviroment variables are used. .SH FILES .PD 0 .TP 20 .B /etc/fstab .TP .B /etc/hosts .TP .B /etc/rc.local .TP .B /etc/auto.master .B automount master map. .TP .B /etc/auto.hard indirect map of hard mounts. .TP .B /etc/auto.soft indirect map of soft mounts (apollo). .TP .B auto.install generated installation script. .TP .B auto.update generated update script. .TP .B auto.fstab new .B /etc/fstab file. .TP .B auto.master new .B /etc/auto.master file. .TP .B auto.hard new .B /etc/auto.hard file. .TP .B auto.soft new .B /etc/auto.soft file. .PD .br .SH SEE ALSO .BR automount (8), .BR mount (8), .BR showmount (8), .BR fstab (5), .BR rc (8) .BR .LP .SH BUGS .B autoautomount is not very flexible. It was built to support a particular environment and its usefulness to anyone else depends on how closely their environment matches ours. .LP A host and a filesystem with the same name might confuse .BR autoautomount . Ignoring or unfavoring one or the other should work around this problem. .LP When unmounting filesystems, .B autoautomount does not notice if they have filesystems mounted on top of them. This can cause the process to fail. This will not be a problem if you do the unmounting by hand. .LP It is assumed that .B mount -a is a harmless command. This is usually an acceptable assumption. .SH AUTHOR .I David Muir Sharnoff\ \ \ \ \ \ \ \ Comdisco System