#!/usr/bin/perl -w # # dirmon.pl # An NT "service" script to help with process management on development servers. # NOT RECOMMENDED FOR INSTALLATION ON A PRODUCTION SERVER # # This script and it counterpart, mngsvr.pl, should not be used on an open server. # The server should be secured by at least IP and User restrictions. Possibilities for # user restrictions: For IIS, use NT username integration, for Netscape, use LDAP. # # amonotod June 2000 # amonotod@netscape.net # Originally by Dave Roth, modified by amonotod # Thank you, Dave; Daemon.pm rocks! # Daemon.pm available at http://www.roth.net/ # # This script is distributed "as is". No warranty of any kind is # expressed or implied. You use at your own risk. The author # will not be liable for data loss, damages, loss of profits or # any other kind of loss while using or misusing this software. use vars qw( $VERSION ); use Win32; use Win32::Daemon; use Win32::ChangeNotify; $VERSION = 20000213; my %Config = ( monitor_sub_dirs => 0, timeout_value => 2, monitor_dir => "d:/web/jobs", log_file => "c:/joblogs/monlog.txt", ); my @snd2s = ("AdminSta1"); #Computer names to send message to my $FileList = {}; my $WatchDir; while( my $Arg = shift @ARGV ) { if( $Arg =~ s#^[-/]## ) { if( $Arg =~ /^install$/i ) { # Installation Install(); exit; } elsif( $Arg =~ /^remove$/i ) { # Removal Remove(); exit; } } } if( open( LOG, ">$Config{log_file}" ) ) { my $TempSelect = select( LOG ); $| = 1; select( $TempSelect ); print LOG "# Software: $0\n"; print LOG "# Date: " . localtime() . "\n"; print LOG "# MonitorDir: $Config{monitor_dir}\n"; } foreach (@snd2s) { system "net send $_ " .'"The server has completed boot-up."'. "\n"; } GetList( $Config{monitor_dir}, $FileList ); $WatchDir = new Win32::ChangeNotify( $Config{monitor_dir}, $Config{monitor_sub_dirs}, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE ); if( ! $WatchDir ) { if( fileno( LOG ) ) { print LOG "Failed to monitor watch directory '$Config{monitor_dir}'\n"; print LOG "Error: " . GetError() . "\n"; close( LOG ); } exit(); } # Start the service... if( ! Win32::Daemon::StartService() ) { if( fileno( LOG ) ) { print LOG "Failed to start this script as a Win32 service.\n"; print LOG "Error: " . GetError() . "\n"; close( LOG ); } exit(); } while( SERVICE_STOPPED != ( $State = Win32::Daemon::State() ) ){ if( SERVICE_START_PENDING == $State ) { # Initialization code Win32::Daemon::State( SERVICE_RUNNING ); } elsif( SERVICE_PAUSE_PENDING == $State ) { # "Pausing..."; Win32::Daemon::State( SERVICE_PAUSED ); next; } elsif( SERVICE_CONTINUE_PENDING == $State ) { # "Resuming..."; Win32::Daemon::State( SERVICE_RUNNING ); next; } elsif( SERVICE_STOP_PENDING == $State ) { # "Stopping..."; Win32::Daemon::State( SERVICE_STOPPED ); next; } elsif( SERVICE_RUNNING == $State ) { # The service is running as normal... my $Result = $WatchDir->wait( $Config{timeout_value} * 1000 ); if( $Result ) { $FileList = ProcessDir( $FileList ); $WatchDir->reset(); } } else { sleep( $Config{timeout_value} ); } } $WatchDir->close(); Win32::Daemon::StopService(); if( fileno( LOG ) ) { close( LOG ); } # "Finished.\n"; sub ProcessDir { my( $OrigList ) = @_; my $NewList = {}; my $Time = scalar localtime(); GetList( $Config{monitor_dir}, $NewList ); # First check for additions... foreach my $File ( ReportNewFiles( $OrigList, $NewList ) ) { print LOG "$Time: File '$File->{name}' added \n"; if ($File->{name} eq 'webcmd.txt') { if ( open (JOBLOG, ">> c:/joblogs/joblog.txt") ) { my $filename = $Config{monitor_dir} .'/'. $File->{name}; #print LOG "$filename is a text file\n"; if (open COMMAND, "$filename") { my @cmds = (); foreach (@cmds) { chomp $_; print JOBLOG "$_ " . localtime() . "\n"; } my @sttval = split / /, $cmds[0]; my $cmdparam = $sttval[0]; my $cmdtorun = "d:/perl/bin/perl.exe d:/web/cgi-bin/mngsvr.pl svcs $cmdparam"; #print JOBLOG "$cmdtorun \n"; my @cmdresult = `$cmdtorun`; #foreach (@cmdresult) { print JOBLOG "$_"; } close (COMMAND); if ( unlink $filename) { #print LOG "Deleted $filename\n"; } } else { print LOG "Cannot open $File->{name}...\n"; } close JOBLOG; } else { print LOG "Cannot open the JOBLOG...\n"; } } else { print LOG "File is a". substr $File->{name}, -3, 3 ." file\n"; } } # Now check for file size changes foreach my $File ( ReportRemovedFiles( $OrigList, $NewList ) ) { print LOG "$Time: File '$File->{name}' removed.\n"; } # Now check for file size changes foreach my $File ( ReportChangedFiles( $OrigList, $NewList ) ) { print LOG "$Time: File '$File->{name}' size changed by '$File->{owner}'.\n"; } return( $NewList ); } sub GetList { my( $Dir, $List ) = @_; if( opendir( DIR, $Dir ) ) { my @Files; my @Dirs; while( my $File = readdir( DIR ) ) { next if( ( "." eq $File ) || ( ".." eq $File ) ); push( @Files, $File ) if( -f "$Dir/$File" ); push( @Dirs, $File ) if( -d "$Dir/$File" ); } closedir( DIR ); foreach my $File ( @Files ) { my %Entry; my $Perm; my @Stats; $Entry{name} = $File; @Stats = stat( "$Dir/$File" ); $Entry{size} = $Stats[7]; $Entry{date} = $Stats[10]; $List->{lc $File} = \%Entry; } if( $Config{monitor_sub_dirs} ) { foreach my $SubDir ( @Dirs ) { GetList( "$Dir/$SubDir", $List ); } } } } sub ReportNewFiles { my( $Old, $New ) = @_; my $TotalOld = scalar ( keys( %$Old ) ); my @NewFiles; foreach my $NewName ( sort( keys( %$New ) ) ) { my $iCount = $TotalOld; foreach my $OldName ( keys( %$Old ) ) { last if( lc $NewName eq lc $OldName ); $iCount--; } push( @NewFiles, $New->{$NewName} ) if( 0 == $iCount ); } return( @NewFiles ); } sub ReportRemovedFiles { my( $Old, $New ) = @_; my $TotalNew = scalar ( keys( %$New ) ); my @RemovedFiles; foreach my $OldName ( sort( keys( %$Old ) ) ) { my $iCount = $TotalNew; foreach my $NewName ( keys( %$New ) ) { last if( lc $NewName eq lc $OldName ); $iCount--; } push( @RemovedFiles, $Old->{$OldName} ) if( 0 == $iCount ); } return( @RemovedFiles ); } sub ReportChangedFiles { my( $Old, $New ) = @_; my @Files; foreach my $Name ( sort( keys( %$Old ) ) ) { my $LCName = lc $Name; next unless( defined $New->{$LCName} ); push( @Files, $New->{$Name} ) if( $Old->{$LCName}->{size} != $New->{$LCName}->{size} ); } return( @Files ); } sub GetServiceConfig { my $ScriptPath = join( "", Win32::GetFullPathName( $0 ) ); my %Hash = ( name => 'DirMon', display => 'Dir Mon Service', path => $^X, user => $Config{account_id}, pwd => $Config{account_password}, parameters => "$ScriptPath -d \"$Config{monitor_dir}\" -l \"$Config{log_file}\" -t $Config{timeout_value}", ); return( \%Hash ); } sub Install { my $ServiceConfig = GetServiceConfig(); if( Win32::Daemon::CreateService( $ServiceConfig ) ) { print "The $ServiceConfig->{display} was successfully installed.\n"; } else { print "Failed to add the $ServiceConfig->{display} service.\nError: " . GetError() . "\n"; } } sub Remove { my $ServiceConfig = GetServiceConfig(); if( Win32::Daemon::DeleteService( $ServiceConfig->{name} ) ) { print "The $ServiceConfig->{display} was successfully removed.\n"; } else { print "Failed to remove the $ServiceConfig->{display} service.\nError: " . GetError() . "\n"; } } sub DumpError { print GetError(), "\n"; } sub GetError { return( Win32::FormatMessage( Win32::Daemon::GetLastError() ) ); } sub Syntax { my( $Script ) = ( $0 =~ m#([^\\/]+)$# ); my $Line = "-" x length( $Script ); print << "EOT"; $Script $Line A Win32 service that monitors activity on a specified directory. Version: $VERSION Syntax: $0 [-d ] [-s][-t