184 lines
4.6 KiB
Perl
Executable file
184 lines
4.6 KiB
Perl
Executable file
#!/usr/local/bin/perl
|
||
#
|
||
# DESC:
|
||
# Program is used to sychronize write access to public motd file.
|
||
# Program acquires advisory exclusive lock, then brings up editor
|
||
# to edit file. On return from editor, motd file will be unlocked.
|
||
# If program cannot acquire exclusive lock, it prints out the current
|
||
# user holding exclusive lock.
|
||
#
|
||
# WRITTEN BY:
|
||
# Andrew Choi
|
||
# Fixed by:
|
||
# Ben Scott
|
||
# Arvin Hsu
|
||
|
||
use strict;
|
||
use Fcntl ':flock';
|
||
use Errno;
|
||
use Getopt::Std;
|
||
use File::Copy;
|
||
|
||
my $motd = "/etc/motd.public";
|
||
my $motdbackup = "/tmp/motd.public.b.$>.$$"; # EUID + PID
|
||
my $motdcurrent = "/tmp/motd.public.r.$>.$$"; # EUID + PID
|
||
my $motdtemp = "/tmp/motd.public.t.$>.$$"; # EUID + PID
|
||
my $motdmerged = "/tmp/motd.public.m.$>.$$"; # EUID + PID
|
||
|
||
$motd = "/csua/tmp/motd.kinney" if (getpwuid($<))[0] eq 'kinney';
|
||
my $editor = $ENV{MOTDEDITOR};
|
||
$editor ||= $ENV{VISUAL};
|
||
$editor ||= $ENV{EDITOR};
|
||
$editor ||= "/usr/bin/ed";
|
||
|
||
my %opt;
|
||
|
||
$opt{t} = 600;
|
||
getopts("mnst:h?",\%opt);
|
||
&Usage if $opt{h};
|
||
|
||
## Set environment vars for vi users
|
||
## Thanks, jon.
|
||
|
||
$ENV{NEXINIT} ||= $ENV{EXINIT};
|
||
unless ( $ENV{NEXINIT} ) {
|
||
unless (open (EXRC,"$ENV{HOME}/.nexrc")) {
|
||
unless (open (EXRC,"$ENV{HOME}/.exrc")) {
|
||
$ENV{NEXINIT} = "set nolock";
|
||
}
|
||
}
|
||
unless ($ENV{NEXINIT}) {
|
||
($ENV{NEXINIT} = join ("",<EXRC>)) && close EXRC;
|
||
}
|
||
}
|
||
$ENV{NEXINIT} .= "\nset nolock\n";
|
||
|
||
# Set alarm for being locked too damn long
|
||
$SIG{ALRM} = \&Unlock;
|
||
alarm $opt{t};
|
||
|
||
# Open file as append so that lock can be used on it
|
||
open(M, "$motd") || die "open $motd: $!";
|
||
|
||
# Lock file. If success, execute edit command and exit
|
||
flock(M, LOCK_EX|LOCK_NB);
|
||
if ($!{EWOULDBLOCK}) {
|
||
if ($opt{n}) {
|
||
print "Motd currently locked. Editing anyways.";
|
||
&Edit;
|
||
}
|
||
else {
|
||
flock (M, LOCK_UN);
|
||
print "Motd currently locked\nWait to acquire lock [y/N] ";
|
||
chomp(my $ans = <>);
|
||
if ($ans =~ /^y$/i) {
|
||
flock(M, LOCK_EX);
|
||
&Edit;
|
||
}
|
||
}
|
||
} else {
|
||
&Edit;
|
||
}
|
||
|
||
close M;
|
||
system "/csua/bin/mtd";
|
||
exit 0;
|
||
|
||
sub Unlock {
|
||
flock(M, LOCK_UN);
|
||
print
|
||
"\r*** MOTD GOD PRONOUNCES: *** \r\n*** You have locked the motd for too long, you idle hoser... *** \r\n*** Your lock has been removed. *** \r\n";
|
||
}
|
||
|
||
sub Usage {
|
||
print STDERR
|
||
"$0 Edit /etc/motd.public with locking and merge.
|
||
|
||
Usage: $0 [-m] [-s] [-t n]
|
||
-t n Set timeout for releasing lock to n seconds (default $opt{t})
|
||
-m Turns auto-merging off.
|
||
-s If merge fails, will stomp over other changes.
|
||
-n Does not wait for lock before allowing edit.
|
||
(the other person may overwrite your post)
|
||
";
|
||
exit 2;
|
||
}
|
||
|
||
sub Edit {
|
||
alarm $opt{t};
|
||
print "";
|
||
#check if merge option is desired
|
||
if (!$opt{m}) {
|
||
copy($motd,$motdbackup);
|
||
copy($motd,$motdcurrent);
|
||
my $lastmodtime = (stat($motd))[9];
|
||
system("$editor $motdcurrent");
|
||
my $currmodtime = (stat($motd))[9];
|
||
if ($currmodtime > $lastmodtime) {
|
||
&Merge;
|
||
}
|
||
else {
|
||
copy($motdcurrent,$motd);
|
||
}
|
||
unlink </tmp/motd.public.*>;
|
||
}
|
||
else {
|
||
system("$editor $motd");
|
||
}
|
||
}
|
||
|
||
|
||
# Attempts to auto-merge using "merge, diff -c | patch, diff | patch"
|
||
# If auto-merge fails, allows manual merge
|
||
# Saves final version as $motd
|
||
sub Merge {
|
||
copy($motd,$motdmerged);
|
||
system("merge -p -q -L \"Other Changes Below\" -L \"Original MOTD\" -L \"Your Changes Above\" $motd $motdbackup $motdcurrent > $motdtemp");
|
||
|
||
# Check to see if merge failed. if fail, try diff -c | patch
|
||
if (($? >> 8) > 0) {
|
||
system("diff -c $motdbackup $motdcurrent | patch -s -f $motdmerged 2> /dev/null");
|
||
|
||
# Check to see if diff -c | patch, if fail, try diff | patch
|
||
if (($? >> 8) > 0) {
|
||
system("diff $motdbackup $motdcurrent | patch -s -f $motdmerged 2> /dev/null");
|
||
|
||
# If everything has failed, put the merge notation in, and let the user edit.
|
||
if (($? >> 8) > 0) {
|
||
if ($opt{s}) {
|
||
copy($motdcurrent,$motdmerged);
|
||
}
|
||
else {
|
||
print "CONCURRENT CHANGES\r\nAll merge & patch attempts have failed.\r\nMerge Manually? [y/n]";
|
||
chomp(my $answ = <>);
|
||
if ($answ =~ /^y$/i) {
|
||
copy($motdtemp,$motdcurrent);
|
||
copy($motd,$motdbackup);
|
||
my $lastmodtime = (stat($motd))[9];
|
||
system("$editor $motdcurrent");
|
||
my $currmodtime = (stat($motd))[9];
|
||
if ($currmodtime > $lastmodtime) {
|
||
&Merge;
|
||
}
|
||
else {
|
||
copy($motdcurrent,$motdmerged);
|
||
}
|
||
}
|
||
else {
|
||
print "Stomp on other people's changes? [y/n]";
|
||
chomp(my $answ = <>);
|
||
if ($answ =~ /^y$/i) {
|
||
copy($motdcurrent,$motdmerged);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
# Merge was successful, copy it over.
|
||
copy($motdtemp,$motdmerged);
|
||
}
|
||
copy($motdmerged,$motd);
|
||
}
|
||
|