#!/bin/sh  
# \
exec oagwish "$0" "$@"
wm withdraw .

#
# applicationPatch copies scripts, executables, and tcl library files
#   given on the command line to the appropriate lib and bin patch 
#   directories. Permissions are tested, and in the case of tcl
#   library files, the tclIndex file is regenerated after the copy.
#

#
# $Log: not supported by cvs2svn $
# Revision 1.17  2003/01/23 19:47:07  soliday
# The accelerator subnet changed to accel.ntw0rk
#
# Revision 1.16  1997/03/06 22:48:37  saunders
# *** empty log message ***
#
# Revision 1.15  1997/01/16 22:43:11  saunders
# In process of being revised.
#
# Revision 1.14  1996/11/07 21:26:06  saunders
# Removed redundant puts.
#
# Revision 1.13  1996/11/07 21:18:53  saunders
# Removed logging for /net/phoebus .
#
# Revision 1.12  1996/11/07 20:58:04  saunders
# Fixed bug with logging.
#
# Revision 1.11  1996/11/07 17:02:58  saunders
# Now virtually identical to cppatch, except activity is logged.
#
# Revision 1.10  1996/06/10 19:11:22  saunders
# Changed logMessage cmds to use default logDaemon.
#
# Revision 1.9  1996/06/04 19:29:48  saunders
# Changed serviceId and location of log files.
#
# Revision 1.8  1996/05/16 15:48:34  saunders
# Changed sourceId string.
#
# Revision 1.7  1996/05/14 18:52:20  saunders
# *** empty log message ***
#
# Revision 1.6  1996/05/14 18:50:54  saunders
# *** empty log message ***
#
# Revision 1.5  1996/05/14 18:41:17  saunders
# *** empty log message ***
#
# Revision 1.4  1996/05/10 13:51:37  saunders
# Reinstalling.
#
# 

set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]

APSDebugPath

APSStandardSetup

set CVSRevisionAuthor "\$Revision: 1.18 $ \$Author: soliday $"

set testMode 1
if {$testMode} {
    set libPatchDir /home/phebos/SAUNDERS/lib
    set binPatchDir /home/phebos/SAUNDERS/bin
} else {
    set libPatchDir /usr/local/oag/apps/lib
    set binPatchDir /usr/local/oag/apps/bin
}

set sourceId appVersionAudit
set archList {sun4 solaris}

#
# Procedure definitions
#
proc printUsage {} {
    global argv0
    puts stderr "usage: $argv0 <file> <file> ..."
    puts stderr "applicationPatch copies scripts, executables, and tcl library files"
    puts stderr "  given on the command line to the appropriate lib and bin patch"
    puts stderr "  directories. Permissions are tested, and in the case of tcl"
    puts stderr "  library files, the tclIndex file is regenerated after the copy."
}

proc APSFileLockExit {directory lockFd} {
    global apsFileLockInit

    if {[info exists apsFileLockInit($directory)]} {
	catch {os lockf $lockFd F_ULOCK 0}
	catch {close $lockFd}
	unset apsFileLockInit($directory)
    }
}

proc APSFileLock {args} {
    global apsFileLockInit
    set lockFile ./installLock
    set action lock
    set timeout 10
    APSParseArguments {action lockFile timeout}

    # Lock directory
    if {![string compare $action lock]} {
	if {![info exists apsFileLockInit($lockFile)]} {
	    if [catch {open $lockFile w+} res] {
		return -code error "Unable to open lock file: $res"
	    } else {
		set lockFd $res
	    }
	    set apsFileLockInit($lockFile) $lockFd
	    global atExitList
	    dp_atexit set atExitList
	    dp_atexit append "APSFileLockExit $lockFile $lockFd"
	} else {
	    set lockFd $apsFileLockInit($lockFile)
	}
	if {$timeout == 0} {
	    if [catch {os lockf $lockFd F_LOCK 0} res ] {
		return -code error "unable to acquire lock"
	    } else {
		return -code ok 0
	    }
	} else {
	    set tryAgain $timeout
	    while {$tryAgain} {
		if [catch {os lockf $lockFd F_TLOCK 0} res] {
		    if {![string compare $res EAGAIN]} {
			# file is locked already
			incr tryAgain -1
			if {!$tryAgain} {
			    return -code error "timeout on acquiring lock"
			}
			after 1000
		    } else {
			return -code error "failed to acquire lock"
		    }
		} else {
		    return -code ok 0
		}
	    }
	}
    } else {
	# Unlock directory
	if {[info exists apsFileLockInit($lockFile)]} {
	    set lockFd $apsFileLockInit($lockFile)
	    catch {os lockf $lockFd F_ULOCK 0}
	    catch {close $lockFd}
	    unset apsFileLockInit($lockFile)	    
	}

    }
}

#
# Given full path to a file, search for the highest serial numbered
# version of that file. Return the serial numbered file name if
# found, or -1 if it doesn't exist.
#
proc highestVersion {path} {
    set dir [file dirname $path]
    set file [file tail $path]
    set fileList [glob -nocomplain ${path}.0*]

    set maxSerial 0
    foreach f $fileList {
	set serialNo -1
	regexp {[.]([0-9]+)} $f match serialNo
	scan $serialNo "%d" serialNo
	if {$serialNo > $maxSerial} {
	    set maxSerial $serialNo
	}
    }
    if {$maxSerial == 0} {
	return -1
    } else {
	return ${dir}/${file}.[format "%05d" $maxSerial]
    }
}

#
# Determine if given path is a symbolic link. If so, return file
#  tail of link destination. Otherwise just return file name.
#
proc getSymbolicLinkDestination {path} {
    if {[catch "file readlink $path" res]} {
	return [file tail $path]
    } else {
	return [file tail $res]
    }
}


#
# Copy given <file> to the appropriate destination based on 
#  given <type> and <arch>.
#
proc copyArch {type file arch} {
    global libPatchDir binPatchDir testMode

    switch -exact $type {
	lib {
	    safeCopy $arch $file $libPatchDir/$arch
	    if {!$testMode} {
		safeCopy $arch $file /net/phoebus${libPatchDir}/$arch
	    }
	}
	executable {
	    safeCopy $arch $file $binPatchDir/$arch
	    if {!$testMode} {
		safeCopy $arch $file /net/phoebus${binPatchDir}/$arch
	    }
	}
    }
}

# 
# Copy file <from> to <to>. Assumes that all permissions and existence
#   checks have been performed on directories.
#
proc safeCopy {arch from toDir} {
    global argv0
  
    set fileTail [file tail $from]
    set highestVersion [highestVersion $toDir/$fileTail]
    if {[file exists $from]} {
	set mtimefrom [file mtime $from]
    } else {
	puts stderr "$argv0: $from does not exist"
	return
    }
    if {$highestVersion != -1 && [file exists $highestVersion]} {
	set mtimeto [file mtime $highestVersion]
    } else {
	set mtimeto -1
    }

    if {$mtimeto < $mtimefrom} {
	if [catch {exec OAGInstall -noLock 1 -group oagmgr $from $toDir >&@ stdout <@ stdin} res] {
	    puts "  Unable to exec OAGInstall: $res"
	} 
    } elseif {$mtimeto == $mtimefrom} {
	puts "  Same file date: $highestVersion"
	puts "  No Copy Performed!!"
    } else {
	puts "  File: $highestVersion is newer than: $from"
	puts "  File information:" 
	puts "  [eval exec ls -la $from]"
	puts "  [eval exec ls -la $highestVersion]"
	puts -nonewline "  Copy anyway \[y/N\]? "
	gets stdin response
	if {![string compare $response "y"] || \
	      ![string compare $response "Y"]} {
	    if [catch {exec OAGInstall -noLock 1 -group oagmgr $from $toDir >&@ stdout <@ stdin} res] {
		puts "  Unable to exec OAGInstall: $res"
		return -1
	    } else {
		return 0
	    }
	}
    }
}

#
# Main Program
#

# Verify that this is being run on helios subnet

if {!$testMode} {
    if {([string compare $apsNetworkDomain "accel.ntw0rk"]) && ([string compare $apsNetworkDomain "aps4.anl.gov"])} {
	puts stderr "You are only allowed to run $argv0 from the helios subnet. Please log onto a machine there and try again."
	exit
    }
}

# Print usage message if no arguments given.

if {$argc == 0} {
    printUsage
    exit
}

# Verify that we have permission to copy into patch directories

foreach arch $archList {
    set mkIndex($arch) 0
    set pathOk [expr [file exists $libPatchDir/$arch] && \
		  [file exists $binPatchDir/$arch]]
    set writable [expr [file writable $libPatchDir/$arch] && \
		    [file writable $binPatchDir/$arch]]
    if {!$pathOk || !$writable} {
	puts stderr "$argv0: You don't have permissions to copy into patch directories:"
	puts stderr "        $binPatchDir and $libPatchDir"
	puts stderr "        You must be member of oagmgr group."
	exit
    }
}

#
# Get comments from user regarding reason for performing this patch.
#
if [catch {exec OAGInstallComments -installDirectory all <@ stdin >&@ stdout} res] {
    puts stderr "$argv0: unable to log comments: $res"
}

#
# Place a lock on one of the destination dirs. 
#
if [catch {APSFileLock -lockFile $binPatchDir/solaris/installLock -action lock} res] {
    puts stderr "$argv0: $res"
    exit 1
}

#
# Loop over files and architectures
#
foreach file "$argv" {
    puts "Processing: $file"
    if {[file exists $file]} {
	set tclLibFile [expr ![string compare [file extension $file] ".tcl"]]
	foreach arch $archList {
	    if {$tclLibFile} {
		# Tcl library file
		set mkIndex($arch) 1
		copyArch lib $file $arch
	    } else {
		# Assumed to be a script
		copyArch executable $file $arch
	    }
	}
    } else {
	# Doesn't exist in directory, look in architecture object directories
	foreach arch $archList {
	    set subfile O.$arch/$file
	    if {[file exists $subfile]} {
		copyArch executable $subfile $arch
	    } else {
		puts stderr "  cannot find $file or $subfile"
	    }
	}
    }
}

foreach arch $archList {
    if {$mkIndex($arch)} {
	puts "Updating tclIndex:"
	foreach library "$libPatchDir/$arch /net/phoebus$libPatchDir/$arch" {
	    # Delete tclIndex
	    if [catch {exec rm -f $library/tclIndex} err] {
		puts " *** Error ($library): $err"
	    }
	    # Re-create tclIndex
	    if [catch {auto_mkindex $library *.tcl} err] {
		puts " *** Error ($library): $err"
	    } else {
		puts "  Auto path updated for $library"
	    }
	    # Change permissions and primary group membership
	    catch {exec chmod g+w $library/tclIndex} 
	    catch {exec chgrp oagmgr $library/tclIndex}
	}
    }
}

exit 0

