#! /usr/local/bin/perl
eval 'exec perl -S $0 ${1+"$@"} ;' unless 1;

# This code forces a perl filehandle to be opened with O_APPEND so
# proper atomic appending can be done from perl.  The normal perl open
# just seeks to what the end of the file is when the open happens and
# is not safe for multiple writers of logfiles.
#
# Corey Satten, corey @ cac.washington.edu, 3/21/96
# http://staff.washington.edu/corey

#require("syscall.ph");			# inline for speed, may lose portability
    sub SYS_write {4;}
    sub SYS_open {5;}
    sub SYS_close {6;}
    sub SYS_dup2 {90;}

#require("sys/file.ph");		# inline for speed, may lose portability
    sub O_WRONLY {001;}
    sub O_APPEND {010;}

#===============================================================================
# usage example: open the file, have another process append, then we append.
# if one were to use open(LOGFILE, ">>outfile"), the shell output would be lost.
#===============================================================================

$demonstrate_problem = 0;		# change this to 1 to see the problem
if ($demonstrate_problem) {
    open(LOGFILE, ">>outfile");		# this shows the problem
    }
else {
    &open_append(LOGFILE, "outfile");	# this fixes the problem
    }
system("echo this is from a shell >> outfile");
print LOGFILE "this is from perl\n";
close(LOGFILE);

#args: filehandle to create, filename to open
sub open_append {
    local(*HANDLE, $path) = @_;
    local($fd, $rv);
    open(HANDLE, ">>$path");		# to create a handle
    $fd = syscall(&SYS_open, "$path", &O_WRONLY + &O_APPEND, 0666);
    if ($fd < 0 ) {
	close(HANDLE); warn("couldn't syscall O_APPEND");
	return(0);
	}
    $rv = syscall(&SYS_dup2, $fd, fileno(HANDLE));
    if ($rv < 0 ) {
	close(HANDLE); warn("couldn't dup2 in open_append");
	return(0);
	}
    syscall(&SYS_close, $fd);
    return(1);
    }
