Skip to content
runtests.pl 90.7 KiB
Newer Older
        logmsg "RUN: FTP$id$nameext server is now running PID $ftppid\n";
    return ($pid2, $ftppid);
#######################################################################
# start the ftps server (or rather, tunnel)
#
sub runftpsserver {
    my ($verbose, $ipv6) = @_;
    my $STATUS;
    my $RUNNING;
    my $ip = $HOSTIP;
    # don't retry if the server doesn't work
    if ($doesntrun{$pidfile}) {
        return (0,0);
    }

    if($pid > 0) {
        # kill previous stunnel!
        stopserver($pid);
    }

    my $flag=$debugprotocol?"-v ":"";
    my $cmd="$perl $srcdir/httpsserver.pl $flag -p ftps -s \"$stunnel\" -d $srcdir -r $FTPPORT $FTPSPORT";

    my ($ftpspid, $pid2) = startnew($cmd, $pidfile, 15, 0);
    if($ftpspid <= 0 || !kill(0, $ftpspid)) {
        logmsg "RUN: failed to start the FTPS server\n";
        return(0,0);
    }

    # Server is up. Verify that we can speak to it.
    my $pid3 = verifyserver("ftps", $ip, $FTPSPORT);
    if(!$pid3) {
        logmsg "RUN: FTPS server failed verification\n";
        # failed to talk to it properly. Kill the server and return failure
        stopserver("$ftpspid $pid2");
    # Here pid3 is actually the pid returned by the unsecure-ftp server.

    if($verbose) {
        logmsg "RUN: FTPS server is now running PID $ftpspid\n";
    }

    sleep(1);

    return ($ftpspid, $pid2);
}

#######################################################################
# start the tftp server
#
sub runtftpserver {
    my ($id, $verbose, $ipv6) = @_;
    my $STATUS;
    my $RUNNING;
    my $port = $TFTPPORT;
    # check for pidfile
    my $pidfile = $TFTPPIDFILE;
    my $ip=$HOSTIP;
    my $nameext;
    my $cmd;

    if($ipv6) {
        # if IPv6, use a different setup
        $pidfile = $TFTP6PIDFILE;
        $port = $TFTP6PORT;
        $ip = $HOST6IP;
        $nameext="-ipv6";
    }

    # don't retry if the server doesn't work
    if ($doesntrun{$pidfile}) {
        return (0,0);
    }

    my $pid = checkserver($pidfile);
        stopserver($pid);
    }

    # start our server:
    my $flag=$debugprotocol?"-v ":"";
    $flag .= "-s \"$srcdir\" ";
    if($id) {
        $flag .="--id $id ";
    }
    if($ipv6) {
        $flag .="--ipv6 ";
    }
    $cmd="./server/tftpd --pidfile $pidfile $flag $port";
    my ($tftppid, $pid2) = startnew($cmd, $pidfile, 15, 0);
    if($tftppid <= 0 || !kill(0, $tftppid)) {
        # it is NOT alive
        logmsg "RUN: failed to start the TFTP$id$nameext server\n";
    }

    # Server is up. Verify that we can speak to it.
    my $pid3 = verifyserver("tftp", $ip, $port);
    if(!$pid3) {
        logmsg "RUN: TFTP$id$nameext server failed verification\n";
        # failed to talk to it properly. Kill the server and return failure
        stopserver("$tftppid $pid2");
        return (0,0);
        logmsg "RUN: TFTP$id$nameext server is now running PID $tftppid\n";
    return ($pid2, $tftppid);
#######################################################################
# Start the scp/sftp server
#
sub runsshserver {
    my ($id, $verbose, $ipv6) = @_;
    my $ip=$HOSTIP;
    my $port = $SSHPORT;
    # don't retry if the server doesn't work
    if ($doesntrun{$pidfile}) {
        return (0,0);
    }

    my $pid = checkserver($pidfile);
    if($pid > 0) {
        stopserver($pid);
    }
    my $flag=$verbose?'-v ':'';
    $flag .= '-d ' if($debugprotocol);

    my $cmd="$perl $srcdir/sshserver.pl ${flag}-u $USER -l $ip -p $port -s $socksport";
    my ($sshpid, $pid2) = startnew($cmd, $pidfile, 60, 0);
    # on loaded systems sshserver start up can take longer than the timeout
    # passed to startnew, when this happens startnew completes without being
    # able to read the pidfile and consequently returns a zero pid2 above.

    if($sshpid <= 0 || !kill(0, $sshpid)) {
        logmsg "RUN: failed to start the SSH server\n";
        stopserver("$pid2");
    # ssh server verification allows some extra time for the server to start up
    # and gives us the opportunity of recovering the pid from the pidfile, when
    # this verification succeeds the recovered pid is assigned to pid2.

    my $pid3 = verifyserver("ssh",$ip,$port);
    if(!$pid3) {
        logmsg "RUN: SSH server failed verification\n";
        # failed to fetch server pid. Kill the server and return failure
        stopserver("$sshpid $pid2");
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }
    $pid2 = $pid3;

    # once it is known that the ssh server is alive, sftp server verification
    # is performed actually connecting to it, authenticating and performing a
    # very simple remote command.  This verification is tried only one time.
    if(verifysftp("sftp",$ip,$port) < 1) {
        logmsg "RUN: SFTP server failed verification\n";
        # failed to talk to it properly. Kill the server and return failure
        display_sftplog();
        display_sftpconfig();
        display_sshdlog();
        display_sshdconfig();
        stopserver("$sshpid $pid2");
        logmsg "RUN: SSH server is now running PID $pid2\n";
#######################################################################
# Start the socks server
#
sub runsocksserver {
    my ($id, $verbose, $ipv6) = @_;
    my $ip=$HOSTIP;
    my $port = $SOCKSPORT;
    my $pidfile = $SOCKSPIDFILE;

    # don't retry if the server doesn't work
    if ($doesntrun{$pidfile}) {
        return (0,0);
    }

    my $pid = checkserver($pidfile);
    if($pid > 0) {
        stopserver($pid);
    }
    unlink($pidfile);

    # The ssh server must be already running
    if(!$run{'ssh'}) {
        logmsg "RUN: SOCKS server cannot find running SSH server\n";
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }

    # Find out ssh daemon canonical file name
    my $sshd = find_sshd();
    if(!$sshd) {
        logmsg "RUN: SOCKS server cannot find $sshdexe\n";
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }

    # Find out ssh daemon version info
    ($sshdid, $sshdvernum, $sshdverstr, $sshderror) = sshversioninfo($sshd);
    if(!$sshdid) {
        # Not an OpenSSH or SunSSH ssh daemon
        logmsg "$sshderror\n" if($verbose);
        logmsg "SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later\n";
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }
    logmsg "ssh server found $sshd is $sshdverstr\n" if($verbose);
    # Find out ssh client canonical file name
    my $ssh = find_ssh();
    if(!$ssh) {
        logmsg "RUN: SOCKS server cannot find $sshexe\n";
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }

    # Find out ssh client version info
    my ($sshid, $sshvernum, $sshverstr, $ssherror) = sshversioninfo($ssh);
    if(!$sshid) {
        # Not an OpenSSH or SunSSH ssh client
        logmsg "$ssherror\n" if($verbose);
        logmsg "SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later\n";
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }

    # Verify minimum ssh client version
    if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) ||
       (($sshid =~ /SunSSH/)  && ($sshvernum < 100))) {
        logmsg "ssh client found $ssh is $sshverstr\n";
        logmsg "SCP, SFTP and SOCKS tests require OpenSSH 2.9.9 or later\n";
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }
    logmsg "ssh client found $ssh is $sshverstr\n" if($verbose);

    # Verify if ssh client and ssh daemon versions match
    if(($sshdid ne $sshid) || ($sshdvernum != $sshvernum)) {
        # Our test harness might work with slightly mismatched versions
        logmsg "Warning: version mismatch: sshd $sshdverstr - ssh $sshverstr\n"
    # Config file options for ssh client are previously set from sshserver.pl
    if(! -e $sshconfig) {
        logmsg "RUN: SOCKS server cannot find $sshconfig\n";
        $doesntrun{$pidfile} = 1;
        return (0,0);
    }

    # start our socks server
    my $cmd="$ssh -N -F $sshconfig $ip > $sshlog 2>&1";
    my ($sshpid, $pid2) = startnew($cmd, $pidfile, 30, 1);
    if($sshpid <= 0 || !kill(0, $sshpid)) {
        # it is NOT alive
        logmsg "RUN: failed to start the SOCKS server\n";
        display_sshdlog();
        display_sshdconfig();
        stopserver("$pid2");
        return (0,0);
    }

    # Ugly hack but ssh doesn't support pid files
    my $pid3 = verifyserver("socks",$ip,$port);
    if(!$pid3) {
        logmsg "RUN: SOCKS server failed verification\n";
        # failed to talk to it properly. Kill the server and return failure
        stopserver("$sshpid $pid2");
        logmsg "RUN: SOCKS server is now running PID $pid2\n";
#######################################################################
# Remove all files in the specified directory
#
sub cleardir {
    my $dir = $_[0];
    my $count;
Daniel Stenberg's avatar
Daniel Stenberg committed
    my $file;

    # Get all files
    opendir(DIR, $dir) ||
        return 0; # can't open dir
    while($file = readdir(DIR)) {
        if($file !~ /^\./) {
            unlink("$dir/$file");
            $count++;
        }
    }
    closedir DIR;
    return $count;
}

#######################################################################
# filter out the specified pattern from the given input file and store the
# results in the given output file
#
sub filteroff {
    my $infile=$_[0];
    my $filter=$_[1];
    my $ofile=$_[2];

    # logmsg "FILTER: off $filter from $infile to $ofile\n";
        $_ =~ s/$filter//;

#######################################################################
# compare test results with the expected output, we might filter off
# some pattern that is allowed to differ, output test results
#

sub compare {
    # filter off patterns _before_ this comparison!
    my ($subject, $firstref, $secondref)=@_;
    my $result = compareparts($firstref, $secondref);
            logmsg "\n $subject FAILED:\n";
            logmsg showdiff($LOGDIR, $firstref, $secondref);
    return $result;
#######################################################################
# display information about curl and the host the test suite runs on
#

    unlink($memdump); # remove this if there was one left

    my $versretval;
    my $versnoexec;
    my @version=();

    my $curlverout="$LOGDIR/curlverout.log";
    my $curlvererr="$LOGDIR/curlvererr.log";
    my $versioncmd="$CURL --version 1>$curlverout 2>$curlvererr";

    unlink($curlverout);
    unlink($curlvererr);

    $versretval = runclient($versioncmd);
    open(VERSOUT, "<$curlverout");
    @version = <VERSOUT>;
    close(VERSOUT);
        if($_ =~ /^curl/) {
            $curl = $_;
            $curl =~ s/^(.*)(libcurl.*)/$1/g;
            if($curl =~ /mingw32/) {
                # This is a windows minw32 build, we need to translate the
                # given path to the "actual" windows path.

                my @m = `mount`;
                my $matchlen;
                my $bestmatch;
                my $mount;

# example mount output:
# C:\DOCUME~1\Temp on /tmp type user (binmode,noumount)
# c:\ActiveState\perl on /perl type user (binmode)
# C:\msys\1.0\bin on /usr/bin type user (binmode,cygexec,noumount)
# C:\msys\1.0\bin on /bin type user (binmode,cygexec,noumount)

                foreach $mount (@m) {
                    if( $mount =~ /(.*) on ([^ ]*) type /) {
                        my ($mingw, $real)=($2, $1);
                        if($pwd =~ /^$mingw/) {
                            # the path we got from pwd starts with the path
                            # we found on this line in the mount output

                            my $len = length($real);
                            if($len > $matchlen) {
                                # we remember the match that is the longest
                                $matchlen = $len;
                                $bestmatch = $real;
                            }
                        }
                    }
                }
                if(!$matchlen) {
                    logmsg "Serious error, can't find our \"real\" path\n";
                }
                else {
                    # now prepend the prefix from the mount command to build
                    # our "actual path"
                    $pwd = "$bestmatch$pwd";
                }
                $pwd =~ s#\\#/#g;
            }
            elsif ($curl =~ /win32/) {
               # Native Windows builds don't understand the
               # output of cygwin's pwd.  It will be
               # something like /cygdrive/c/<some path>.
               #
               # Use the cygpath utility to convert the
               # working directory to a Windows friendly
               # path.  The -m option converts to use drive
               # letter:, but it uses / instead \.  Forward
               # slashes (/) are easier for us.  We don't
               # have to escape them to get them to curl
               # through a shell.
               chomp($pwd = `cygpath -m $pwd`);
           }
           elsif ($libcurl =~ /openssl/i) {
           elsif ($libcurl =~ /gnutls/i) {
               $ssllib="NSS";
           }
           elsif ($libcurl =~ /yassl/i) {
               $has_yassl=1;
               $has_openssl=1;
               $ssllib="yassl";
            # these are the protocols compiled in to this libcurl
            @protocols = split(' ', $1);

            # Generate a "proto-ipv6" version of each protocol to match the
            # IPv6 <server> name. This works even if IPv6 support isn't
            # compiled in because the <features> test will fail.
            push @protocols, map($_ . "-ipv6", @protocols);

            # 'none' is used in test cases to mean no server
            push @protocols, ('none');
            if($feat =~ /debug/i) {
                # debug is a listed "feature", use that knowledge
                $curl_debug = 1;
                # set the NETRC debug env
                $ENV{'CURL_DEBUG_NETRC'} = "$LOGDIR/netrc";
            if($feat =~ /Largefile/i) {
                # large file support
                $large_file=1;
            }
Daniel Stenberg's avatar
Daniel Stenberg committed
            if($feat =~ /IPv6/i) {
                $has_ipv6 = 1;
            }
        logmsg "unable to get curl's version, further details are:\n";
        logmsg "issued command: \n";
        if ($versretval == -1) {
            logmsg "command failed with: \n";
            logmsg "$versnoexec \n";
        }
        elsif ($versretval & 127) {
            logmsg sprintf("command died with signal %d, and %s coredump.\n",
                           ($versretval & 127), ($versretval & 128)?"a":"no");
        }
        else {
            logmsg sprintf("command exited with value %d \n", $versretval >> 8);
        logmsg "contents of $curlverout: \n";
        displaylogcontent("$curlverout");
        logmsg "contents of $curlvererr: \n";
        displaylogcontent("$curlvererr");
        die "couldn't get curl's version";
        open(CONF, "<../lib/config.h");
            if($_ =~ /^\#define HAVE_GETRLIMIT/) {
                $has_getrlimit = 1;
            }
        }
        # client has ipv6 support

        # check if the HTTP server has it!
        my @sws = `server/sws --version`;
        if($sws[0] =~ /IPv6/) {
            # HTTP server has ipv6 support!
            $http_ipv6 = 1;
        }
        @sws = `server/sockfilt --version`;
        if($sws[0] =~ /IPv6/) {
            # FTP server has ipv6 support!
            $ftp_ipv6 = 1;
        }
    if(!$curl_debug && $torture) {
        die "can't run torture tests since curl was not build with debug";
    }

    # curl doesn't list cryptographic support separately, so assume it's
    # always available
    $has_crypto=1;

    my $hostname=join(' ', runclientoutput("hostname"));
    my $hosttype=join(' ', runclientoutput("uname -a"));
    logmsg ("********* System characteristics ******** \n",
    "* Features: $feat\n",
Daniel Stenberg's avatar
Daniel Stenberg committed
    "* Host: $hostname",
    "* System: $hosttype");

    logmsg sprintf("* Server SSL:     %s\n", $stunnel?"ON":"OFF");
    logmsg sprintf("* libcurl SSL:    %s\n", $ssl_version?"ON":"OFF");
    logmsg sprintf("* libcurl debug:  %s\n", $curl_debug?"ON":"OFF");
    logmsg sprintf("* valgrind:       %s\n", $valgrind?"ON":"OFF");
    logmsg sprintf("* HTTP IPv6       %s\n", $http_ipv6?"ON":"OFF");
    logmsg sprintf("* FTP IPv6        %s\n", $ftp_ipv6?"ON":"OFF");

    logmsg sprintf("* HTTP port:      %d\n", $HTTPPORT);
    logmsg sprintf("* FTP port:       %d\n", $FTPPORT);
    logmsg sprintf("* FTP port 2:     %d\n", $FTP2PORT);
        logmsg sprintf("* FTPS port:      %d\n", $FTPSPORT);
        logmsg sprintf("* HTTPS port:     %d\n", $HTTPSPORT);
        logmsg sprintf("* HTTP IPv6 port: %d\n", $HTTP6PORT);
        logmsg sprintf("* FTP IPv6 port:  %d\n", $FTP6PORT);
    logmsg sprintf("* TFTP port:      %d\n", $TFTPPORT);
    if($tftp_ipv6) {
        logmsg sprintf("* TFTP IPv6 port: %d\n", $TFTP6PORT);
    }
    logmsg sprintf("* SCP/SFTP port:  %d\n", $SSHPORT);
    logmsg sprintf("* SOCKS port:     %d\n", $SOCKSPORT);
        logmsg sprintf("* SSL library:    %s\n", $ssllib);
    $has_textaware = ($^O eq 'MSWin32') || ($^O eq 'msys');

    logmsg sprintf("* Libtool lib:    %s\n", $libtool?"ON":"OFF");
    logmsg "***************************************** \n";
#######################################################################
# substitute the variable stuff into either a joined up file or
# a command, in either case passed by reference
#
sub subVariables {
  my ($thing) = @_;
  $$thing =~ s/%HOSTIP/$HOSTIP/g;
  $$thing =~ s/%HOST6IP/$HOST6IP/g;
  $$thing =~ s/%HTTP6PORT/$HTTP6PORT/g;
  $$thing =~ s/%HTTPSPORT/$HTTPSPORT/g;
  $$thing =~ s/%FTPPORT/$FTPPORT/g;
  $$thing =~ s/%FTPSPORT/$FTPSPORT/g;
  $$thing =~ s/%SRCDIR/$srcdir/g;
  $$thing =~ s/%PWD/$pwd/g;
  $$thing =~ s/%TFTPPORT/$TFTPPORT/g;
  $$thing =~ s/%TFTP6PORT/$TFTP6PORT/g;
  $$thing =~ s/%SSHPORT/$SSHPORT/g;
  $$thing =~ s/%SOCKSPORT/$SOCKSPORT/g;
  $$thing =~ s/%CLIENTIP/$CLIENTIP/g;
  $$thing =~ s/%CLIENT6IP/$CLIENT6IP/g;

  # The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be
  # used for time-out tests and that whould work on most hosts as these
  # adjust for the startup/check time for this particular host. We needed
  # to do this to make the test suite run better on very slow hosts.

  my $ftp2 = $ftpchecktime * 2;
  my $ftp3 = $ftpchecktime * 3;

  $$thing =~ s/%FTPTIME2/$ftp2/g;
  $$thing =~ s/%FTPTIME3/$ftp3/g;
#######################################################################
# Run a single specified test case
#

sub singletest {
    # load the test case file definition
    if(loadtest("${TESTDIR}/test${testnum}")) {
        if($verbose) {
            # this is not a test
            logmsg "RUN: $testnum doesn't look like a test case\n";
    }
    else {
        @what = getpart("client", "features");
        elsif($f eq "OpenSSL") {
            if($has_openssl) {
                next;
            }
        }
        elsif($f eq "GnuTLS") {
            if($has_gnutls) {
                next;
            }
        }
Daniel Stenberg's avatar
Daniel Stenberg committed
        elsif($f eq "ipv6") {
            if($has_ipv6) {
                next;
            }
        }
        elsif($f eq "getrlimit") {
            if($has_getrlimit) {
                next;
        # See if this "feature" is in the list of supported protocols
        elsif (grep /^$f$/, @protocols) {
            next;
        }
    my $dbghosttype=join(' ', runclientoutput("uname -a"));
    if(($dbghosttype =~ /SMP PREEMPT/) && ($dbghosttype =~ /i686 GNU/)) {
Yang Tse's avatar
Yang Tse committed
        if(!$curl_debug) {
            if(($testnum != 1)   && ($testnum != 100) &&
               ($testnum != 500) && ($testnum != 507) &&
               ($testnum != 517) && ($testnum != 534) &&
               ($testnum != 557) && ($testnum != 1013)) {
                $why = "debugging icc build";
            }
        }
    if(!$why) {
        my @keywords = getpart("info", "keywords");
        my $k;
        for $k (@keywords) {
            chomp $k;
            if ($disabled_keywords{$k}) {
            	$why = "disabled by keyword";
            } elsif ($enabled_keywords{$k}) {
            	$match = 1;

	if(!$why && !$match && %enabled_keywords) {
	  $why = "disabled by missing keyword";
	}
    if(!$why) {
        $why = serverfortest($testnum);
    }

        my @precheck = getpart("client", "precheck");
            } elsif($?) {
                $why = "precheck command error";
            logmsg "prechecked $cmd\n" if($verbose);
    if($why && !$listonly) {
        # there's a problem, count it as "skipped"
        $skipped++;
        $skipped{$why}++;
        $teststat[$testnum]=$why; # store reason for this test case
            printf "test %03d SKIPPED: $why\n", $testnum;
    logmsg sprintf("test %03d...", $testnum);
    # extract the reply data
    my @reply = getpart("reply", "data");
    my @replycheck = getpart("reply", "datacheck");

    if (@replycheck) {
        # we use this file instead to check the final output against
Daniel Stenberg's avatar
Daniel Stenberg committed

        my %hash = getpartattr("reply", "datacheck");
        if($hash{'nonewline'}) {
            # Yes, we must cut off the final newline from the final line
            # of the datacheck
            chomp($replycheck[$#replycheck]);
        }
        @reply=@replycheck;
    }

    # curl command to run
    my @curlcmd= fixarray ( getpart("client", "command") );
    # this is the valid protocol blurb curl should generate
    my @protocol= fixarray ( getpart("verify", "protocol") );
    # redirected stdout/stderr to these files
    $STDOUT="$LOGDIR/stdout$testnum";
    $STDERR="$LOGDIR/stderr$testnum";
    # if this section exists, we verify that the stdout contained this:
    my @validstdout = fixarray ( getpart("verify", "stdout") );
    # if this section exists, we verify upload
    my @upload = getpart("verify", "upload");
    # if this section exists, it might be FTP server instructions:
    my @ftpservercmd = getpart("reply", "servercmd");
    my $CURLOUT="$LOGDIR/curl$testnum.out"; # curl output if not stdout
    # name of the test
    my @testname= getpart("client", "name");
        my $name = $testname[0];
        $name =~ s/\n//g;
Daniel Stenberg's avatar
Daniel Stenberg committed
    if($listonly) {
        return 0; # look successful
    }

    my @codepieces = getpart("client", "tool");

    my $tool="";
    if(@codepieces) {
        $tool = $codepieces[0];
        chomp $tool;
    }

Daniel Stenberg's avatar
Daniel Stenberg committed
    unlink($SERVERIN);
Daniel Stenberg's avatar
Daniel Stenberg committed

    if(@ftpservercmd) {
        # write the instructions to file
        writearray($FTPDCMD, \@ftpservercmd);
    }

    my (@setenv)= getpart("client", "setenv");
    my @envs;

    my $s;
    for $s (@setenv) {
        chomp $s; # cut off the newline

        subVariables \$s;

        if($s =~ /([^=]*)=(.*)/) {
            my ($var, $content)=($1, $2);
            $ENV{$var}=$content;
            # remember which, so that we can clear them afterwards!
            push @envs, $var;
        }
    }

    # get the command line options to use
    my @blaha;
    ($cmd, @blaha)= getpart("client", "command");

    # make some nice replace operations
    $cmd =~ s/\n//g; # no newlines please
Daniel Stenberg's avatar
Daniel Stenberg committed
    # substitute variables in the command line
    # create a (possibly-empty) file before starting the test
    my @inputfile=getpart("client", "file");
    my %fileattr = getpartattr("client", "file");
    my $filename=$fileattr{'name'};
    if(@inputfile || $filename) {
            logmsg "ERROR: section client=>file has no name attribute\n";
        my $fileContent = join('', @inputfile);
        subVariables \$fileContent;
#        logmsg "DEBUG: writing file " . $filename . "\n";
        open(OUTFILE, ">$filename");