diff options
Diffstat (limited to 'eg')
-rw-r--r-- | eg/ADB | 8 | ||||
-rw-r--r-- | eg/README | 18 | ||||
-rw-r--r-- | eg/changes | 34 | ||||
-rw-r--r-- | eg/dus | 22 | ||||
-rw-r--r-- | eg/findcp | 53 | ||||
-rw-r--r-- | eg/findtar | 17 | ||||
-rw-r--r-- | eg/g/gcp | 114 | ||||
-rw-r--r-- | eg/g/gcp.man | 77 | ||||
-rw-r--r-- | eg/g/ged | 21 | ||||
-rw-r--r-- | eg/g/ghosts | 33 | ||||
-rw-r--r-- | eg/g/gsh | 116 | ||||
-rw-r--r-- | eg/g/gsh.man | 80 | ||||
-rw-r--r-- | eg/myrup | 29 | ||||
-rw-r--r-- | eg/nih | 10 | ||||
-rw-r--r-- | eg/rmfrom | 7 | ||||
-rw-r--r-- | eg/scan/scan_df | 51 | ||||
-rw-r--r-- | eg/scan/scan_last | 57 | ||||
-rw-r--r-- | eg/scan/scan_messages | 222 | ||||
-rw-r--r-- | eg/scan/scan_passwd | 30 | ||||
-rw-r--r-- | eg/scan/scan_ps | 32 | ||||
-rw-r--r-- | eg/scan/scan_sudo | 54 | ||||
-rw-r--r-- | eg/scan/scan_suid | 84 | ||||
-rw-r--r-- | eg/scan/scanner | 87 | ||||
-rw-r--r-- | eg/shmkill | 24 | ||||
-rw-r--r-- | eg/van/empty | 45 | ||||
-rw-r--r-- | eg/van/unvanish | 66 | ||||
-rw-r--r-- | eg/van/vanexp | 21 | ||||
-rw-r--r-- | eg/van/vanish | 65 |
28 files changed, 1477 insertions, 0 deletions
diff --git a/eg/ADB b/eg/ADB new file mode 100644 index 0000000000..1a43b90380 --- /dev/null +++ b/eg/ADB @@ -0,0 +1,8 @@ +#!/usr/bin/perl + +# $Header: ADB,v 2.0 88/06/05 00:16:39 root Exp $ + +# This script is only useful when used in your crash directory. + +$num = shift; +exec 'adb', '-k', "vmunix.$num", "vmcore.$num"; diff --git a/eg/README b/eg/README new file mode 100644 index 0000000000..bec7538f83 --- /dev/null +++ b/eg/README @@ -0,0 +1,18 @@ +This stuff is supplied on an as-is basis--little attempt has been made to make +any of it portable. It's mostly here to give you an idea of what perl code +looks like, and what tricks and idioms are used. + +System administrators responsible for many computers will enjoy the items +down in the g directory very much. The scan directory contains the beginnings +of a system to check on and report various kinds of anomalies. + +If you machine doesn't support #!, the first thing you'll want to do is +replace the #! with a couple of lines that look like this: + + eval "exec /usr/bin/perl -S $0 $*" + if $running_under_some_shell; + +being sure to include any flags that were on the #! line. A supplied script +called "nih" will translate perl scripts in place for you: + + nih g/g?? diff --git a/eg/changes b/eg/changes new file mode 100644 index 0000000000..db9b7b1d53 --- /dev/null +++ b/eg/changes @@ -0,0 +1,34 @@ +#!/usr/bin/perl -P + +# $Header: changes,v 2.0 88/06/05 00:16:41 root Exp $ + +($dir, $days) = @ARGV; +$dir = '/' if $dir eq ''; +$days = '14' if $days eq ''; + +# Masscomps do things differently from Suns + +#if defined(mc300) || defined(mc500) || defined(mc700) +open(Find, "find $dir -mtime -$days -print |") || + die "changes: can't run find"; +#else +open(Find, "find $dir \\( -fstype nfs -prune \\) -o -mtime -$days -ls |") || + die "changes: can't run find"; +#endif + +while (<Find>) { + +#if defined(mc300) || defined(mc500) || defined(mc700) + $x = `/bin/ls -ild $_`; + $_ = $x; + ($inode,$perm,$links,$owner,$group,$size,$month,$day,$time,$name) + = split(' '); +#else + ($inode,$blocks,$perm,$links,$owner,$group,$size,$month,$day,$time,$name) + = split(' '); +#endif + + printf("%10s%3s %-8s %-8s%9s %3s %2s %s\n", + $perm,$links,$owner,$group,$size,$month,$day,$name); +} + diff --git a/eg/dus b/eg/dus new file mode 100644 index 0000000000..8c7ff94340 --- /dev/null +++ b/eg/dus @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +# $Header: dus,v 2.0 88/06/05 00:16:44 root Exp $ + +# This script does a du -s on any directories in the current directory that +# are not mount points for another filesystem. + +($mydev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat('.'); + +open(ls,'ls -F1|'); + +while (<ls>) { + chop; + next unless s|/$||; + ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat($_); + next unless $dev == $mydev; + push(@ary,$_); +} + +exec 'du', '-s', @ary; diff --git a/eg/findcp b/eg/findcp new file mode 100644 index 0000000000..57cac2e367 --- /dev/null +++ b/eg/findcp @@ -0,0 +1,53 @@ +#!/usr/bin/perl + +# $Header: findcp,v 2.0 88/06/05 00:16:47 root Exp $ + +# This is a wrapper around the find command that pretends find has a switch +# of the form -cp host:destination. It presumes your find implements -ls. +# It uses tar to do the actual copy. If your tar knows about the I switch +# you may prefer to use findtar, since this one has to do the tar in batches. + +sub copy { + `tar cf - $list | rsh $desthost cd $destdir '&&' tar xBpf -`; +} + +$sourcedir = $ARGV[0]; +if ($sourcedir =~ /^\//) { + $ARGV[0] = '.'; + unless (chdir($sourcedir)) { die "Can't find directory: $sourcedir"; } +} + +$args = join(' ',@ARGV); +if ($args =~ s/-cp *([^ ]+)/-ls/) { + $dest = $1; + if ($dest =~ /(.*):(.*)/) { + $desthost = $1; + $destdir = $2; + } + else { + die "Malformed destination--should be host:directory"; + } +} +else { + die("No destination specified"); +} + +open(find,"find $args |") || die "Can't run find for you."; + +while (<find>) { + @x = split(' '); + if ($x[2] =~ /^d/) { next;} + chop($filename = $x[10]); + if (length($list) > 5000) { + do copy(); + $list = ''; + } + else { + $list .= ' '; + } + $list .= $filename; +} + +if ($list) { + do copy(); +} diff --git a/eg/findtar b/eg/findtar new file mode 100644 index 0000000000..8b604b396f --- /dev/null +++ b/eg/findtar @@ -0,0 +1,17 @@ +#!/usr/bin/perl + +# $Header: findtar,v 2.0 88/06/05 00:16:49 root Exp $ + +# findtar takes find-style arguments and spits out a tarfile on stdout. +# It won't work unless your find supports -ls and your tar the I flag. + +$args = join(' ',@ARGV); +open(find,"/usr/bin/find $args -ls |") || die "Can't run find for you."; + +open(tar,"| /bin/tar cIf - -") || die "Can't run tar for you."; + +while (<find>) { + @x = split(' '); + if ($x[2] =~ /^d/) { print tar '-d ';} + print tar $x[10],"\n"; +} diff --git a/eg/g/gcp b/eg/g/gcp new file mode 100644 index 0000000000..6b4a9a79f7 --- /dev/null +++ b/eg/g/gcp @@ -0,0 +1,114 @@ +#!/usr/bin/perl + +# $Header: gcp,v 2.0 88/06/05 00:17:02 root Exp $ + +# Here is a script to do global rcps. See man page. + +$#ARGV >= 1 || die "Not enough arguments.\n"; + +if ($ARGV[0] eq '-r') { + $rcp = 'rcp -r'; + shift; +} else { + $rcp = 'rcp'; +} +$args = $rcp; +$dest = $ARGV[$#ARGV]; + +$SIG{'QUIT'} = 'CLEANUP'; +$SIG{'INT'} = 'CONT'; + +while ($arg = shift) { + if ($arg =~ /^([-a-zA-Z0-9_+]+):/) { + if ($systype && $systype ne $1) { + die "Can't mix system type specifers ($systype vs $1).\n"; + } + $#ARGV < 0 || $arg !~ /:$/ || die "No source file specified.\n"; + $systype = $1; + $args .= " $arg"; + } else { + if ($#ARGV >= 0) { + if ($arg =~ /^[\/~]/) { + $arg =~ /^(.*)\// && ($dir = $1); + } else { + if (!$pwd) { + chop($pwd = `pwd`); + } + $dir = $pwd; + } + } + if ($olddir && $dir ne $olddir && $dest =~ /:$/) { + $args .= " $dest$olddir; $rcp"; + } + $olddir = $dir; + $args .= " $arg"; + } +} + +die "No system type specified.\n" unless $systype; + +$args =~ s/:$/:$olddir/; + +chop($thishost = `hostname`); + +$one_of_these = ":$systype:"; +if ($systype =~ s/\+/[+]/g) { + $one_of_these =~ s/\+/:/g; +} +$one_of_these =~ s/-/:-/g; + +@ARGV = (); +push(@ARGV,'.grem') if -f '.grem'; +push(@ARGV,'.ghosts') if -f '.ghosts'; +push(@ARGV,'/etc/ghosts'); + +$remainder = ''; + +line: while (<>) { + s/[ \t]*\n//; + if (!$_ || /^#/) { + next line; + } + if (/^([a-zA-Z_0-9]+)=(.+)/) { + $name = $1; $repl = $2; + $repl =~ s/\+/:/g; + $repl =~ s/-/:-/g; + $one_of_these =~ s/:$name:/:$repl:/; + $repl =~ s/:/:-/g; + $one_of_these =~ s/:-$name:/:-$repl:/g; + next line; + } + @gh = split(' '); + $host = $gh[0]; + next line if $host eq $thishost; # should handle aliases too + $wanted = 0; + foreach $class (@gh) { + $wanted++ if index($one_of_these,":$class:") >= 0; + $wanted = -9999 if index($one_of_these,":-$class:") >= 0; + } + if ($wanted > 0) { + ($cmd = $args) =~ s/[ \t]$systype:/ $host:/g; + print "$cmd\n"; + $result = `$cmd 2>&1`; + $remainder .= "$host+" if + $result =~ /Connection timed out|Permission denied/; + print $result; + } +} + +if ($remainder) { + chop($remainder); + open(grem,">.grem") || (printf stderr "Can't create .grem\n"); + print grem 'rem=', $remainder, "\n"; + close(grem); + print 'rem=', $remainder, "\n"; +} + +sub CLEANUP { + exit; +} + +sub CONT { + print "Continuing...\n"; # Just ignore the signal that kills rcp + $remainder .= "$host+"; +} diff --git a/eg/g/gcp.man b/eg/g/gcp.man new file mode 100644 index 0000000000..83c5d85ca4 --- /dev/null +++ b/eg/g/gcp.man @@ -0,0 +1,77 @@ +.\" $Header: gcp.man,v 2.0 88/06/05 00:17:05 root Exp $ +.TH GCP 1C "13 May 1988" +.SH NAME +gcp \- global file copy +.SH SYNOPSIS +.B gcp +file1 file2 +.br +.B gcp +[ +.B \-r +] file ... directory +.SH DESCRIPTION +.I gcp +works just like rcp(1C) except that you may specify a set of hosts to copy files +from or to. +The host sets are defined in the file /etc/ghosts. +(An individual host name can be used as a set containing one member.) +You can give a command like + + gcp /etc/motd sun: + +to copy your /etc/motd file to /etc/motd on all the Suns. +If, on the other hand, you say + + gcp /a/foo /b/bar sun:/tmp + +then your files will be copied to /tmp on all the Suns. +The general rule is that if you don't specify the destination directory, +files go to the same directory they are in currently. +.P +You may specify the union of two or more sets by using + as follows: + + gcp /a/foo /b/bar 750+mc: + +which will copy /a/foo to /a/foo on all 750's and Masscomps, and then copy +/b/bar to /b/bar on all 750's and Masscomps. +.P +Commonly used sets should be defined in /etc/ghosts. +For example, you could add a line that says + + pep=manny+moe+jack + +Another way to do that would be to add the word "pep" after each of the host +entries: + + manny sun3 pep +.br + moe sun3 pep +.br + jack sun3 pep + +Hosts and sets of host can also be excluded: + + foo=sun-sun2 + +Any host so excluded will never be included, even if a subsequent set on the +line includes it: + + foo=abc+def +.br + bar=xyz-abc+foo + +comes out to xyz+def. + +You can define private host sets by creating .ghosts in your current directory +with entries just like /etc/ghosts. +Also, if there is a file .grem, it defines "rem" to be the remaining hosts +from the last gsh or gcp that didn't succeed everywhere. +.PP +Interrupting with a SIGINT will cause the rcp to the current host to be skipped +and execution resumed with the next host. +To stop completely, send a SIGQUIT. +.SH SEE ALSO +rcp(1C) +.SH BUGS +All the bugs of rcp, since it calls rcp. diff --git a/eg/g/ged b/eg/g/ged new file mode 100644 index 0000000000..bb7c222b3a --- /dev/null +++ b/eg/g/ged @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +# $Header: ged,v 2.0 88/06/05 00:17:08 root Exp $ + +# Does inplace edits on a set of files on a set of machines. +# +# Typical invokation: +# +# ged vax+sun /etc/passwd +# s/Freddy/Freddie/; +# ^D +# + +$class = shift; +$files = join(' ',@ARGV); + +die "Usage: ged class files <perlcmds\n" unless $files; + +exec "gsh", $class, "-d", "perl -pi.bak - $files"; + +die "Couldn't execute gsh for some reason, stopped"; diff --git a/eg/g/ghosts b/eg/g/ghosts new file mode 100644 index 0000000000..96ec771c4a --- /dev/null +++ b/eg/g/ghosts @@ -0,0 +1,33 @@ +# This first section gives alternate sets defined in terms of the sets given +# by the second section. The order is important--all references must be +# forward references. + +Nnd=sun-nd +all=sun+mc+vax +baseline=sun+mc +sun=sun2+sun3 +vax=750+8600 +pep=manny+moe+jack + +# This second section defines the basic sets. Each host should have a line +# that specifies which sets it is a member of. Extra sets should be separated +# by white space. (The first section isn't strictly necessary, since all sets +# could be defined in the second section, but then it wouldn't be so readable.) + +basvax 8600 src +cdb0 sun3 sys +cdb1 sun3 sys +cdb2 sun3 sys +chief sun3 src +tis0 sun3 +manny sun3 sys +moe sun3 sys +jack sun3 sys +disney sun3 sys +huey sun3 nd +dewey sun3 nd +louie sun3 nd +bizet sun2 src sys +gif0 mc src +mc0 mc +dtv0 mc diff --git a/eg/g/gsh b/eg/g/gsh new file mode 100644 index 0000000000..50ce1f7b00 --- /dev/null +++ b/eg/g/gsh @@ -0,0 +1,116 @@ +#!/bin/perl + +# $Header: gsh,v 2.0 88/06/05 00:17:20 root Exp $ + +# Do rsh globally--see man page + +$SIG{'QUIT'} = 'quit'; # install signal handler for SIGQUIT + +sub getswitches { + while ($ARGV[0] =~ /^-/) { # parse switches + $ARGV[0] =~ /^-h/ && ($showhost++,$silent++,shift,next); + $ARGV[0] =~ /^-s/ && ($silent++,shift,next); + $ARGV[0] =~ /^-d/ && ($dodist++,shift,next); + $ARGV[0] =~ /^-n/ && ($n=' -n',shift,next); + $ARGV[0] =~ /^-l/ && ($l=' -l ' . $ARGV[1],shift,shift,next); + last; + } +} + +do getswitches(); # get any switches before class +$systype = shift; # get name representing set of hosts +do getswitches(); # same switches allowed after class + +if ($dodist) { # distribute input over all rshes? + `cat >/tmp/gsh$$`; # get input into a handy place + $dist = " </tmp/gsh$$"; # each rsh takes input from there +} + +$cmd = join(' ',@ARGV); # remaining args constitute the command +$cmd =~ s/'/'"'"'/g; # quote any embedded single quotes + +$one_of_these = ":$systype:"; # prepare to expand "macros" +$one_of_these =~ s/\+/:/g; # we hope to end up with list of +$one_of_these =~ s/-/:-/g; # colon separated attributes + +@ARGV = (); +push(@ARGV,'.grem') if -f '.grem'; +push(@ARGV,'.ghosts') if -f '.ghosts'; +push(@ARGV,'/etc/ghosts'); + +$remainder = ''; + +line: while (<>) { # for each line of ghosts + + s/[ \t]*\n//; # trim trailing whitespace + if (!$_ || /^#/) { # skip blank line or comment + next line; + } + + if (/^(\w+)=(.+)/) { # a macro line? + $name = $1; $repl = $2; + $repl =~ s/\+/:/g; + $repl =~ s/-/:-/g; + $one_of_these =~ s/:$name:/:$repl:/; # do expansion in "wanted" list + $repl =~ s/:/:-/g; + $one_of_these =~ s/:-$name:/:-$repl:/; + next line; + } + + # we have a normal line + + @attr = split(' '); # a list of attributes to match against + # which we put into an array + $host = $attr[0]; # the first attribute is the host name + if ($showhost) { + $showhost = "$host:\t"; + } + + $wanted = 0; + foreach $attr (@attr) { # iterate over attribute array + $wanted++ if index($one_of_these,":$attr:") >= 0; + $wanted = -9999 if index($one_of_these,":-$attr:") >= 0; + } + if ($wanted > 0) { + print "rsh $host$l$n '$cmd'\n" unless $silent; + $SIG{'INT'} = 'DEFAULT'; + if (open(pipe,"rsh $host$l$n '$cmd'$dist 2>&1|")) { # start an rsh + $SIG{'INT'} = 'cont'; + for ($iter=0; <pipe>; $iter++) { + unless ($iter) { + $remainder .= "$host+" + if /Connection timed out|Permission denied/; + } + print $showhost,$_; + } + close(pipe); + } else { + $SIG{'INT'} = 'cont'; + print "(Can't execute rsh.)\n"; + } + } +} + +unlink "/tmp/gsh$$" if $dodist; + +if ($remainder) { + chop($remainder); + open(grem,">.grem") || (printf stderr "Can't make a .grem file\n"); + print grem 'rem=', $remainder, "\n"; + close(grem); + print 'rem=', $remainder, "\n"; +} + +# here are a couple of subroutines that serve as signal handlers + +sub cont { + print "\rContinuing...\n"; + $remainder .= "$host+"; +} + +sub quit { + $| = 1; + print "\r"; + $SIG{'INT'} = ''; + kill 2, $$; +} diff --git a/eg/g/gsh.man b/eg/g/gsh.man new file mode 100644 index 0000000000..4522129df0 --- /dev/null +++ b/eg/g/gsh.man @@ -0,0 +1,80 @@ +.\" $Header: gsh.man,v 2.0 88/06/05 00:17:23 root Exp $ +.TH GSH 8 "13 May 1988" +.SH NAME +gsh \- global shell +.SH SYNOPSIS +.B gsh +[options] +.I host +[options] +.I command +.SH DESCRIPTION +.I gsh +works just like rsh(1C) except that you may specify a set of hosts to execute +the command on. +The host sets are defined in the file /etc/ghosts. +(An individual host name can be used as a set containing one member.) +You can give a command like + + gsh sun /etc/mungmotd + +to run /etc/mungmotd on all your Suns. +.P +You may specify the union of two or more sets by using + as follows: + + gsh 750+mc /etc/mungmotd + +which will run mungmotd on all 750's and Masscomps. +.P +Commonly used sets should be defined in /etc/ghosts. +For example, you could add a line that says + + pep=manny+moe+jack + +Another way to do that would be to add the word "pep" after each of the host +entries: + + manny sun3 pep +.br + moe sun3 pep +.br + jack sun3 pep + +Hosts and sets of host can also be excluded: + + foo=sun-sun2 + +Any host so excluded will never be included, even if a subsequent set on the +line includes it: + + foo=abc+def + bar=xyz-abc+foo + +comes out to xyz+def. + +You can define private host sets by creating .ghosts in your current directory +with entries just like /etc/ghosts. +Also, if there is a file .grem, it defines "rem" to be the remaining hosts +from the last gsh or gcp that didn't succeed everywhere. + +Options include all those defined by rsh, as well as + +.IP "\-d" 8 +Causes gsh to collect input till end of file, and then distribute that input +to each invokation of rsh. +.IP "\-h" 8 +Rather than print out the command followed by the output, merely prepends the +host name to each line of output. +.IP "\-s" 8 +Do work silently. +.PP +Interrupting with a SIGINT will cause the rsh to the current host to be skipped +and execution resumed with the next host. +To stop completely, send a SIGQUIT. +.SH SEE ALSO +rsh(1C) +.SH BUGS +All the bugs of rsh, since it calls rsh. + +Also, will not properly return data from the remote execution that contains +null characters. diff --git a/eg/myrup b/eg/myrup new file mode 100644 index 0000000000..c32c99ccd2 --- /dev/null +++ b/eg/myrup @@ -0,0 +1,29 @@ +#!/usr/bin/perl + +# $Header: myrup,v 2.0 88/06/05 00:16:51 root Exp $ + +# This was a customization of ruptime requested by someone here who wanted +# to be able to find the least loaded machine easily. It uses the +# /etc/ghosts file that's defined for gsh and gcp to prune down the +# number of entries to those hosts we have administrative control over. + +print "node load (u)\n------- --------\n"; + +open(ghosts,'/etc/ghosts') || die "Can't open /etc/ghosts"; +line: while (<ghosts>) { + next line if /^#/; + next line if /^$/; + next line if /=/; + ($host) = split; + $wanted{$host} = 1; +} + +open(ruptime,'ruptime|') || die "Can't run ruptime"; +open(sort,'|sort +1n'); + +while (<ruptime>) { + ($host,$upness,$foo,$users,$foo,$foo,$load) = split(/[\s,]+/); + if ($wanted{$host} && $upness eq 'up') { + printf sort "%s\t%s (%d)\n", $host, $load, $users; + } +} diff --git a/eg/nih b/eg/nih new file mode 100644 index 0000000000..15cb60f496 --- /dev/null +++ b/eg/nih @@ -0,0 +1,10 @@ +eval "exec /usr/bin/perl -Spi.bak $0 $*" + if $running_under_some_shell; + +# $Header: nih,v 2.0 88/06/05 00:16:54 root Exp $ + +# This script makes #! scripts directly executable on machines that don't +# support #!. It edits in place any scripts mentioned on the command line. + +s|^#!(.*)|#!$1\neval "exec $1 -S \$0 \$*"\n\tif \$running_under_some_shell;| + if $. == 1; diff --git a/eg/rmfrom b/eg/rmfrom new file mode 100644 index 0000000000..0fca30413e --- /dev/null +++ b/eg/rmfrom @@ -0,0 +1,7 @@ +#!/usr/bin/perl -n + +# $Header: rmfrom,v 2.0 88/06/05 00:16:57 root Exp $ + +# A handy (but dangerous) script to put after a find ... -print. + +chop; unlink; diff --git a/eg/scan/scan_df b/eg/scan/scan_df new file mode 100644 index 0000000000..ca316425e4 --- /dev/null +++ b/eg/scan/scan_df @@ -0,0 +1,51 @@ +#!/usr/bin/perl -P + +# $Header: scan_df,v 2.0 88/06/05 00:17:56 root Exp $ + +# This report points out filesystems that are in danger of overflowing. + +(chdir '/usr/adm/private/memories') || die "Can't cd."; +`df >newdf`; +open(Df, 'olddf'); + +while (<Df>) { + ($fs,$kbytes,$used,$avail,$capacity,$mounted_on) = split; + next if $fs =~ /:/; + next if $fs eq ''; + $oldused{$fs} = $used; +} + +open(Df, 'newdf') || die "scan_df: can't open newdf"; + +while (<Df>) { + ($fs,$kbytes,$used,$avail,$capacity,$mounted_on) = split; + next if $fs =~ /:/; + next if $fs eq ''; + $oldused = $oldused{$fs}; + next if ($oldused == $used && $capacity < 99); # inactive filesystem + if ($capacity >= 90) { +#if defined(mc300) || defined(mc500) || defined(mc700) + $_ = substr($_,0,13) . ' ' . substr($_,13,1000); + $kbytes /= 2; # translate blocks to K + $used /= 2; + $oldused /= 2; + $avail /= 2; +#endif + $diff = int($used - $oldused); + if ($avail < $diff * 2) { # mark specially if in danger + $mounted_on .= ' *'; + } + next if $diff < 50 && $mounted_on eq '/'; + $fs =~ s|/dev/||; + if ($diff >= 0) { + $diff = '(+' . $diff . ')'; + } + else { + $diff = '(' . $diff . ')'; + } + printf "%-8s%8d%8d %-8s%8d%7s %s\n", + $fs,$kbytes,$used,$diff,$avail,$capacity,$mounted_on; + } +} + +rename('newdf','olddf'); diff --git a/eg/scan/scan_last b/eg/scan/scan_last new file mode 100644 index 0000000000..25d7843e30 --- /dev/null +++ b/eg/scan/scan_last @@ -0,0 +1,57 @@ +#!/usr/bin/perl -P + +# $Header: scan_last,v 2.0 88/06/05 00:17:58 root Exp $ + +# This reports who was logged on at weird hours + +($dy, $mo, $lastdt) = split(/ +/,`date`); + +open(Last, 'exec last 2>&1 |') || die "scan_last: can't run last"; + +while (<Last>) { +#if defined(mc300) || defined(mc500) || defined(mc700) + $_ = substr($_,0,19) . substr($_,23,100); +#endif + next if /^$/; + (print),next if m|^/|; + $login = substr($_,0,8); + $tty = substr($_,10,7); + $from = substr($_,19,15); + $day = substr($_,36,3); + $mo = substr($_,40,3); + $dt = substr($_,44,2); + $hr = substr($_,47,2); + $min = substr($_,50,2); + $dash = substr($_,53,1); + $tohr = substr($_,55,2); + $tomin = substr($_,58,2); + $durhr = substr($_,63,2); + $durmin = substr($_,66,2); + + next unless $hr; + next if $login eq 'reboot '; + next if $login eq 'shutdown'; + + if ($dt != $lastdt) { + if ($lastdt < $dt) { + $seen += $dt - $lastdt; + } + else { + $seen++; + } + $lastdt = $dt; + } + + $inat = $hr + $min / 60; + if ($tohr =~ /^[a-z]/) { + $outat = 12; # something innocuous + } else { + $outat = $tohr + $tomin / 60; + } + + last if $seen + ($inat < 8) > 1; + + if ($inat < 5 || $inat > 21 || $outat < 6 || $outat > 23) { + print; + } +} diff --git a/eg/scan/scan_messages b/eg/scan/scan_messages new file mode 100644 index 0000000000..6f8ab2b58b --- /dev/null +++ b/eg/scan/scan_messages @@ -0,0 +1,222 @@ +#!/usr/bin/perl -P + +# $Header: scan_messages,v 2.0 88/06/05 00:17:46 root Exp $ + +# This prints out extraordinary console messages. You'll need to customize. + +chdir('/usr/adm/private/memories') || die "Can't cd."; + +$maxpos = `cat oldmsgs 2>&1`; + +#if defined(mc300) || defined(mc500) || defined(mc700) +open(Msgs, '/dev/null') || die "scan_messages: can't open messages"; +#else +open(Msgs, '/usr/adm/messages') || die "scan_messages: can't open messages"; +#endif + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat(Msgs); + +if ($size < $maxpos) { # Did somebody truncate messages file? + $maxpos = 0; +} + +seek(Msgs,$maxpos,0); # Start where we left off last time. + +while (<Msgs>) { + s/\[(\d+)\]/#/ && s/$1/#/g; +#ifdef vax + $_ =~ s/[A-Z][a-z][a-z] +\w+ +[0-9:]+ +\w+ +//; + next if /root@.*:/; + next if /^vmunix: 4.3 BSD UNIX/; + next if /^vmunix: Copyright/; + next if /^vmunix: avail mem =/; + next if /^vmunix: SBIA0 at /; + next if /^vmunix: disk ra81 is/; + next if /^vmunix: dmf. at uba/; + next if /^vmunix: dmf.:.*asynch/; + next if /^vmunix: ex. at uba/; + next if /^vmunix: ex.: HW/; + next if /^vmunix: il. at uba/; + next if /^vmunix: il.: hardware/; + next if /^vmunix: ra. at uba/; + next if /^vmunix: ra.: media/; + next if /^vmunix: real mem/; + next if /^vmunix: syncing disks/; + next if /^vmunix: tms/; + next if /^vmunix: tmscp. at uba/; + next if /^vmunix: uba. at /; + next if /^vmunix: uda. at /; + next if /^vmunix: uda.: unit . ONLIN/; + next if /^vmunix: .*buffers containing/; + next if /^syslogd: .*newslog/; +#endif + next if /unknown service/; + next if /^\.\.\.$/; + if (/^[A-Z][a-z][a-z] [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]/) { + $pfx = ''; + next; + } + next if /^[ \t]*$/; + next if /^[ 0-9]*done$/; + if (/^A/) { + next if /^Accounting [sr]/; + } + elsif (/^C/) { + next if /^Called from/; + next if /^Copyright/; + } + elsif (/^E/) { + next if /^End traceback/; + next if /^Ethernet address =/; + } + elsif (/^K/) { + next if /^KERNEL MODE/; + } + elsif (/^R/) { + next if /^Rebooting Unix/; + } + elsif (/^S/) { + next if /^Sun UNIX 4\.2 Release/; + } + elsif (/^W/) { + next if /^WARNING: clock gained/; + } + elsif (/^a/) { + next if /^arg /; + next if /^avail mem =/; + } + elsif (/^b/) { + next if /^bwtwo[0-9] at /; + } + elsif (/^c/) { + next if /^cgone[0-9] at /; + next if /^cdp[0-9] at /; + next if /^csr /; + } + elsif (/^d/) { + next if /^dcpa: init/; + next if /^done$/; + next if /^dts/; + next if /^dump i\/o error/; + next if /^dumping to dev/; + next if /^dump succeeded/; + $pfx = '*' if /^dev = /; + } + elsif (/^e/) { + next if /^end \*\*/; + next if /^error in copy/; + } + elsif (/^f/) { + next if /^found /; + } + elsif (/^i/) { + next if /^ib[0-9] at /; + next if /^ie[0-9] at /; + } + elsif (/^l/) { + next if /^le[0-9] at /; + } + elsif (/^m/) { + next if /^mem = /; + next if /^mt[0-9] at /; + next if /^mti[0-9] at /; + $pfx = '*' if /^mode = /; + } + elsif (/^n/) { + next if /^not found /; + } + elsif (/^p/) { + next if /^page map /; + next if /^pi[0-9] at /; + $pfx = '*' if /^panic/; + } + elsif (/^q/) { + next if /^qqq /; + } + elsif (/^r/) { + next if /^read /; + next if /^revarp: Requesting/; + next if /^root [od]/; + } + elsif (/^s/) { + next if /^sc[0-9] at /; + next if /^sd[0-9] at /; + next if /^sd[0-9]: </; + next if /^si[0-9] at /; + next if /^si_getstatus/; + next if /^sk[0-9] at /; + next if /^skioctl/; + next if /^skopen/; + next if /^skprobe/; + next if /^skread/; + next if /^skwrite/; + next if /^sky[0-9] at /; + next if /^st[0-9] at /; + next if /^st0:.*load/; + next if /^stat1 = /; + next if /^syncing disks/; + next if /^syslogd: going down on signal 15/; + } + elsif (/^t/) { + next if /^timeout [0-9]/; + next if /^tm[0-9] at /; + next if /^tod[0-9] at /; + next if /^tv [0-9]/; + $pfx = '*' if /^trap address/; + } + elsif (/^u/) { + next if /^unit nsk/; + next if /^use one of/; + $pfx = '' if /^using/; + next if /^using [0-9]+ buffers/; + } + elsif (/^x/) { + next if /^xy[0-9] at /; + next if /^write [0-9]/; + next if /^xy[0-9]: </; + next if /^xyc[0-9] at /; + } + elsif (/^y/) { + next if /^yyy [0-9]/; + } + elsif (/^z/) { + next if /^zs[0-9] at /; + } + $pfx = '*' if /^[a-z]+:$/; + s/pid [0-9]+: //; + if (/last message repeated ([0-9]+) time/) { + $seen{$last} += $1; + next; + } + s/^/$pfx/ if $pfx; + unless ($seen{$_}++) { + push(@seen,$_); + } + $last = $_; +} +$max = tell(Msgs); + +open(tmp,'|sort >oldmsgs.tmp') || die "Can't create tmp file."; +while ($_ = pop(@seen)) { + print tmp $_; +} +close(tmp); +open(tmp,'oldmsgs.tmp') || die "Can't reopen tmp file."; +while (<tmp>) { + if (/^nd:/) { + next if $seen{$_} < 20; + } + if (/NFS/) { + next if $seen{$_} < 20; + } + if (/no carrier/) { + next if $seen{$_} < 20; + } + if (/silo overflow/) { + next if $seen{$_} < 20; + } + print $seen{$_},":\t",$_; +} + +print `rm -f oldmsgs.tmp 2>&1; echo $max > oldmsgs 2>&1`; diff --git a/eg/scan/scan_passwd b/eg/scan/scan_passwd new file mode 100644 index 0000000000..62ef1e7794 --- /dev/null +++ b/eg/scan/scan_passwd @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +# $Header: scan_passwd,v 2.0 88/06/05 00:17:49 root Exp $ + +# This scans passwd file for security holes. + +open(Pass,'/etc/passwd') || die "Can't open passwd file"; +# $dotriv = (`date` =~ /^Mon/); +$dotriv = 1; + +while (<Pass>) { + ($login,$pass,$uid,$gid,$gcos,$home,$shell) = split(/:/); + if ($shell eq '') { + print "Short: $_"; + } + next if /^[+]/; + if ($pass eq '') { + if (index(":sync:lpq:+:", ":$login:") < 0) { + print "No pass: $login\t$gcos\n"; + } + } + elsif ($dotriv && crypt($login,substr($pass,0,2)) eq $pass) { + print "Trivial: $login\t$gcos\n"; + } + if ($uid == 0) { + if ($login !~ /^.?root$/ && $pass ne '*') { + print "Extra root: $_"; + } + } +} diff --git a/eg/scan/scan_ps b/eg/scan/scan_ps new file mode 100644 index 0000000000..bb33b87ae8 --- /dev/null +++ b/eg/scan/scan_ps @@ -0,0 +1,32 @@ +#!/usr/bin/perl -P + +# $Header: scan_ps,v 2.0 88/06/05 00:17:51 root Exp $ + +# This looks for looping processes. + +#if defined(mc300) || defined(mc500) || defined(mc700) +open(Ps, '/bin/ps -el|') || die "scan_ps: can't run ps"; + +while (<Ps>) { + next if /rwhod/; + print if index(' T', substr($_,62,1)) < 0; +} +#else +open(Ps, '/bin/ps auxww|') || die "scan_ps: can't run ps"; + +while (<Ps>) { + next if /dataserver/; + next if /nfsd/; + next if /update/; + next if /ypserv/; + next if /rwhod/; + next if /routed/; + next if /pagedaemon/; +#ifdef vax + ($user,$pid,$cpu,$mem,$sz,$rss,$tt,$stat,$start,$time) = split; +#else + ($user,$pid,$cpu,$mem,$sz,$rss,$tt,$stat,$time) = split; +#endif + print if length($time) > 4; +} +#endif diff --git a/eg/scan/scan_sudo b/eg/scan/scan_sudo new file mode 100644 index 0000000000..e0a99ee0c3 --- /dev/null +++ b/eg/scan/scan_sudo @@ -0,0 +1,54 @@ +#!/usr/bin/perl -P + +# $Header: scan_sudo,v 2.0 88/06/05 00:18:01 root Exp $ + +# Analyze the sudo log. + +chdir('/usr/adm/private/memories') || die "Can't cd."; + +if (open(Oldsudo,'oldsudo')) { + $maxpos = <Oldsudo>; + close Oldsudo; +} +else { + $maxpos = 0; + `echo 0 >oldsudo`; +} + +unless (open(Sudo, '/usr/adm/sudo.log')) { + print "Somebody removed sudo.log!!!\n" if $maxpos; + exit 0; +} + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat(Sudo); + +if ($size < $maxpos) { + $maxpos = 0; + print "Somebody reset sudo.log!!!\n"; +} + +seek(Sudo,$maxpos,0); + +while (<Sudo>) { + s/^.* :[ \t]+//; + s/ipcrm.*/ipcrm/; + s/kill.*/kill/; + unless ($seen{$_}++) { + push(@seen,$_); + } + $last = $_; +} +$max = tell(Sudo); + +open(tmp,'|sort >oldsudo.tmp') || die "Can't create tmp file."; +while ($_ = pop(@seen)) { + print tmp $_; +} +close(tmp); +open(tmp,'oldsudo.tmp') || die "Can't reopen tmp file."; +while (<tmp>) { + print $seen{$_},":\t",$_; +} + +print `(rm -f oldsudo.tmp; echo $max > oldsudo) 2>&1`; diff --git a/eg/scan/scan_suid b/eg/scan/scan_suid new file mode 100644 index 0000000000..4f62705504 --- /dev/null +++ b/eg/scan/scan_suid @@ -0,0 +1,84 @@ +#!/usr/bin/perl -P + +# $Header: scan_suid,v 2.0 88/06/05 00:17:54 root Exp $ + +# Look for new setuid root files. + +chdir '/usr/adm/private/memories' || die "Can't cd."; + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat('oldsuid'); +if ($nlink) { + $lasttime = $mtime; + $tmp = $ctime - $atime; + if ($tmp <= 0 || $tmp >= 10) { + print "WARNING: somebody has read oldsuid!\n"; + } + $tmp = $ctime - $mtime; + if ($tmp <= 0 || $tmp >= 10) { + print "WARNING: somebody has modified oldsuid!!!\n"; + } +} else { + $lasttime = time - 60 * 60 * 24; # one day ago +} +$thistime = time; + +#if defined(mc300) || defined(mc500) || defined(mc700) +open(Find, 'find / -perm -04000 -print |') || + die "scan_find: can't run find"; +#else +open(Find, 'find / \( -fstype nfs -prune \) -o -perm -04000 -ls |') || + die "scan_find: can't run find"; +#endif + +open(suid, '>newsuid.tmp'); + +while (<Find>) { + +#if defined(mc300) || defined(mc500) || defined(mc700) + $x = `/bin/ls -il $_`; + $_ = $x; + s/^ *//; + ($inode,$perm,$links,$owner,$group,$size,$month,$day,$time,$name) + = split; +#else + s/^ *//; + ($inode,$blocks,$perm,$links,$owner,$group,$size,$month,$day,$time,$name) + = split; +#endif + + if ($perm =~ /[sS]/ && $owner eq 'root') { + ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat($name); + $foo = sprintf("%10s%3s %-8s %-8s%9s %3s %2s %s %s\n", + $perm,$links,$owner,$group,$size,$month,$day,$name,$inode); + print suid $foo; + if ($ctime > $lasttime) { + if ($ctime > $thistime) { + print "Future file: $foo"; + } + else { + $ct .= $foo; + } + } + } +} +close(suid); + +print `sort +7 -8 newsuid.tmp >newsuid 2>&1`; +$foo = `/bin/diff oldsuid newsuid 2>&1`; +print "Differences in suid info:\n",$foo if $foo; +print `mv oldsuid oldoldsuid 2>&1; mv newsuid oldsuid 2>&1`; +print `touch oldsuid 2>&1;sleep 2 2>&1;chmod o+w oldsuid 2>&1`; +print `rm -f newsuid.tmp 2>&1`; + +@ct = split(/\n/,$ct); +$ct = ''; +$* = 1; +while ($#ct >= 0) { + $tmp = shift(@ct); + unless ($foo =~ "^>.*$tmp\n") { $ct .= "$tmp\n"; } +} + +print "Inode changed since last time:\n",$ct if $ct; + diff --git a/eg/scan/scanner b/eg/scan/scanner new file mode 100644 index 0000000000..25e953d402 --- /dev/null +++ b/eg/scan/scanner @@ -0,0 +1,87 @@ +#!/usr/bin/perl + +# $Header: scanner,v 2.0 88/06/05 00:17:42 root Exp $ + +# This runs all the scan_* routines on all the machines in /etc/ghosts. +# We run this every morning at about 6 am: + +# !/bin/sh +# cd /usr/adm/private +# decrypt scanner | perl >scan.out 2>&1 +# mail admin <scan.out + +# Note that the scan_* files should be encrypted with the key "-inquire", and +# scanner should be encrypted somehow so that people can't find that key. +# I leave it up to you to figure out how to unencrypt it before executing. + +$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/ucb:.'; + +$| = 1; # command buffering on stdout + +print "Subject: bizarre happenings\n\n"; + +(chdir '/usr/adm/private') || die "Can't cd."; + +if ($#ARGV >= 0) { + @scanlist = @ARGV; +} else { + @scanlist = split(/[ \t\n]+/,`echo scan_*`); +} + +scan: while ($scan = shift(@scanlist)) { + print "\n********** $scan **********\n"; + $showhost++; + + $systype = 'all'; + + open(ghosts, '/etc/ghosts') || die 'No /etc/ghosts file'; + + $one_of_these = ":$systype:"; + if ($systype =~ s/\+/[+]/g) { + $one_of_these =~ s/\+/:/g; + } + + line: while (<ghosts>) { + s/[ \t]*\n//; + if (!$_ || /^#/) { + next line; + } + if (/^([a-zA-Z_0-9]+)=(.+)/) { + $name = $1; $repl = $2; + $repl =~ s/\+/:/g; + $one_of_these =~ s/:$name:/:$repl:/; + next line; + } + @gh = split; + $host = $gh[0]; + if ($showhost) { $showhost = "$host:\t"; } + class: while ($class = pop(gh)) { + if (index($one_of_these,":$class:") >=0) { + $iter = 0; + `exec crypt -inquire <$scan >.x 2>/dev/null`; + unless (open(scan,'.x')) { + print "Can't run $scan."; + next scan; + } + $cmd = <scan>; + unless ($cmd =~ s/#!(.*)\n/$1/) { + $cmd = '/usr/bin/perl'; + } + close(scan); + if (open(pipe,"exec rsh $host '$cmd' <.x|")) { + sleep(5); + unlink '.x'; + while (<pipe>) { + last if $iter++ > 1000; # must be looping + next if /^[0-9.]+u [0-9.]+s/; + print $showhost,$_; + } + close(pipe); + } else { + print "(Can't execute rsh.)\n"; + } + last class; + } + } + } +} diff --git a/eg/shmkill b/eg/shmkill new file mode 100644 index 0000000000..ba288d8e0d --- /dev/null +++ b/eg/shmkill @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +# $Header: shmkill,v 2.0 88/06/05 00:16:59 root Exp $ + +# A script to call from crontab periodically when people are leaving shared +# memory sitting around unattached. + +open(ipcs,'ipcs -m -o|') || die "Can't run ipcs"; + +while (<ipcs>) { + $tmp = index($_,'NATTCH'); + $pos = $tmp if $tmp >= 0; + if (/^m/) { + ($m,$id,$key,$mode,$owner,$group,$attach) = split; + if ($attach != substr($_,$pos,6)) { + die "Different ipcs format--can't parse!"; + } + if ($attach == 0) { + push(@goners,'-m',$id); + } + } +} + +exec 'ipcrm', @goners if $#goners >= 0; diff --git a/eg/van/empty b/eg/van/empty new file mode 100644 index 0000000000..11a55583e1 --- /dev/null +++ b/eg/van/empty @@ -0,0 +1,45 @@ +#!/usr/bin/perl + +# $Header: empty,v 2.0 88/06/05 00:17:39 root Exp $ + +# This script empties a trashcan. + +$recursive = shift if $ARGV[0] eq '-r'; + +@ARGV = '.' if $#ARGV < 0; + +chop($pwd = `pwd`); + +dir: foreach $dir (@ARGV) { + unless (chdir $dir) { + print stderr "Can't find directory $dir\n"; + next dir; + } + if ($recursive) { + do cmd('find . -name .deleted -exec /bin/rm -rf {} ;'); + } + else { + if (-d '.deleted') { + do cmd('rm -rf .deleted'); + } + else { + if ($dir eq '.' && $pwd =~ m|/\.deleted$|) { + chdir '..'; + do cmd('rm -rf .deleted'); + } + else { + print stderr "No trashcan found in directory $dir\n"; + } + } + } +} +continue { + chdir $pwd; +} + +# force direct execution with no shell + +sub cmd { + system split(' ',join(' ',@_)); +} + diff --git a/eg/van/unvanish b/eg/van/unvanish new file mode 100644 index 0000000000..4a83c81232 --- /dev/null +++ b/eg/van/unvanish @@ -0,0 +1,66 @@ +#!/usr/bin/perl + +# $Header: unvanish,v 2.0 88/06/05 00:17:30 root Exp $ + +sub it { + if ($olddir ne '.') { + chop($pwd = `pwd`) if $pwd eq ''; + (chdir $olddir) || die "Directory $olddir is not accesible"; + } + unless ($olddir eq '.deleted') { + if (-d '.deleted') { + chdir '.deleted' || die "Directory .deleted is not accesible"; + } + else { + chop($pwd = `pwd`) if $pwd eq ''; + die "Directory .deleted does not exist" unless $pwd =~ /\.deleted$/; + } + } + print `mv $startfiles$filelist..$force`; + if ($olddir ne '.') { + (chdir $pwd) || die "Can't get back to original directory: $pwd"; + } +} + +if ($#ARGV < 0) { + open(lastcmd,'.deleted/.lastcmd') || + open(lastcmd,'.lastcmd') || + die "No previous vanish in this dir"; + $ARGV = <lastcmd>; + close(lastcmd); + @ARGV = split(/[\n ]+/,$ARGV); +} + +while ($ARGV[0] =~ /^-/) { + $_ = shift; + /^-f/ && ($force = ' >/dev/null 2>&1'); + /^-i/ && ($interactive = 1); + if (/^-+$/) { + $startfiles = '- '; + last; + } +} + +while ($file = shift) { + if ($file =~ s|^(.*)/||) { + $dir = $1; + } + else { + $dir = '.'; + } + + if ($dir ne $olddir) { + do it() if $olddir; + $olddir = $dir; + } + + if ($interactive) { + print "unvanish: restore $dir/$file? "; + next unless <stdin> =~ /^y/i; + } + + $filelist .= $file; $filelist .= ' '; + +} + +do it() if $olddir; diff --git a/eg/van/vanexp b/eg/van/vanexp new file mode 100644 index 0000000000..29b42e8edf --- /dev/null +++ b/eg/van/vanexp @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +# $Header: vanexp,v 2.0 88/06/05 00:17:34 root Exp $ + +# This is for running from a find at night to expire old .deleteds + +$can = $ARGV[0]; + +exit 1 unless $can =~ /.deleted$/; + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat($can); + +exit 0 unless $size; + +if (time - $mtime > 2 * 24 * 60 * 60) { + `/bin/rm -rf $can`; +} +else { + `find $can -ctime +2 -exec rm -f {} \;`; +} diff --git a/eg/van/vanish b/eg/van/vanish new file mode 100644 index 0000000000..b665e7c8d9 --- /dev/null +++ b/eg/van/vanish @@ -0,0 +1,65 @@ +#!/usr/bin/perl + +# $Header: vanish,v 2.0 88/06/05 00:17:36 root Exp $ + +sub it { + if ($olddir ne '.') { + chop($pwd = `pwd`) if $pwd eq ''; + (chdir $olddir) || die "Directory $olddir is not accesible"; + } + if (!-d .deleted) { + print `mkdir .deleted; chmod 775 .deleted`; + die "You can't remove files from $olddir" if $?; + } + $filelist =~ s/ $//; + $filelist =~ s/#/\\#/g; + if ($filelist !~ /^[ \t]*$/) { + open(lastcmd,'>.deleted/.lastcmd'); + print lastcmd $filelist,"\n"; + close(lastcmd); + print `/bin/mv $startfiles$filelist .deleted$force`; + } + if ($olddir ne '.') { + (chdir $pwd) || die "Can't get back to original directory: $pwd"; + } +} + +while ($ARGV[0] =~ /^-/) { + $_ = shift; + /^-f/ && ($force = ' >/dev/null 2>&1'); + /^-i/ && ($interactive = 1); + if (/^-+$/) { + $startfiles = '- '; + last; + } +} + +chop($pwd = `pwd`); + +while ($file = shift) { + if ($file =~ s|^(.*)/||) { + $dir = $1; + } + else { + $dir = '.'; + } + + if ($interactive) { + print "vanish: remove $dir/$file? "; + next unless <stdin> =~ /^y/i; + } + + if ($file eq '.deleted') { + print stderr "To delete .deleted (the trashcan) use the 'empty' command.\n"; + next; + } + + if ($dir ne $olddir) { + do it() if $olddir; + $olddir = $dir; + } + + $filelist .= $file; $filelist .= ' '; +} + +do it() if $olddir; |