spewlogfile.in 5.24 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh Stoller's avatar
Leigh Stoller committed
2
#
3
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
Leigh Stoller's avatar
Leigh Stoller committed
23
#
24
use strict;
25 26 27 28
use English;
use Getopt::Std;

#
29 30 31
# Spew the current log file for an experiment or template to stdout.
# This is for use by the web interface, so it can send the logfile to
# the user in a web page.
32 33 34 35 36 37 38
#
# The wrinkle is that the logfile only exists while the experiment is
# in transition, and we have to quit when the experiment is no longer in
# transition so that the web page can finish.
#
sub usage()
{
39 40
    print("Usage: spewlogfile -i logid\n".
	  "Spew a logfile to stdout, as for the web interface\n");
41 42
    exit(-1);
}
43
my $optlist = "wi:an";
44
my $fromweb = 0;
45
my $anon    = 0;
46
my $nowait  = 0;
47 48 49 50 51 52 53
  
#
# Configure variables
#
my $TB		= "@prefix@";
my $TBOPS       = "@TBOPSEMAIL@";
my $TBLOGS      = "@TBLOGSEMAIL@";
54
my $GUNZIP	= "/usr/bin/gunzip";
55 56

my $logname;
57
my $isopen;
58
my $logfile;
59 60 61 62 63

#
# Load the Testbed support stuff. 
#
use lib "@prefix@/lib";
64
use emdb;
65
use libtestbed;
66
use User;
67
use Logfile;
68 69 70 71 72 73 74 75 76 77 78 79

# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

# Turn off line buffering on output
$| = 1; 

#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
80
my %options = ();
81 82 83
if (! getopts($optlist, \%options)) {
    usage();
}
84 85 86
if (defined($options{"w"})) {
    $fromweb = 1;
}
87 88 89
if (defined($options{"a"})) {
    $anon = 1;
}
90 91 92
if (defined($options{"n"})) {
    $nowait = 1;
}
93
if (defined($options{"i"})) {
94 95 96 97 98 99
    $logfile = Logfile->Lookup($options{"i"});
    if (! $logfile) {
	die("*** $0:\n".
	    "    No such logfile in the Emulab Database.\n");
    }
}
100
usage()
101
    if (@ARGV || !$logfile);
102 103 104 105 106 107 108 109 110

#
# This script is setuid, so please do not run it as root. Hard to track
# what has happened.
# 
if ($UID == 0) {
    die("*** $0:\n".
	"    Please do not run this as root! Its already setuid!\n");
}
111

112

113
#
114
# Allow for anonymous users to request a public file.
115
# Verify user and get his DB uid and other info for later.
116
#
117 118 119 120 121 122 123 124 125 126 127 128 129
if (!$anon) {
    my $this_user = User->ThisUser();
    if (! defined($this_user)) {
	die("*** $0:\n".
	    "    You ($UID) do not exist!");
    }
    #
    # Verify that this person is allowed to do this. 
    #
    if (!$logfile->AccessCheck($this_user)) {
	die("*** $0:\n".
	    "    You do not have permission to view logfile!\n");
    }
130
}
131
elsif (!$logfile->public()) {
132 133
    die("*** $0:\n".
	"    You do not have permission to view logfile!\n");
134
}
135 136
$logname = $logfile->filename();
$isopen  = $logfile->isopen();
137 138 139 140 141

use Fcntl;
use IO::Handle;
STDOUT->autoflush(1);

142 143 144 145
#
# if the file is closed do it the quick way. No locking, so this could
# mess up sometimes.
#
146
if (!$isopen || $nowait) {
147
    printf("%-15s %s\n", "Created:", $logfile->date_created());
148 149 150 151 152 153
    if ($logfile->MetadataList()) {
	foreach my $ref (@{ $logfile->MetadataList() }) {
	    my ($key,$val) = @{$ref};
	    printf("%-15s %s\n", "$key:", $val);
	}
    }
154 155
    print "\n";
    print "----------------------------------\n";
156 157 158 159
    if (!defined($logname)) {
	print STDOUT "Log file has no content; this is not an error.\n";
    }
    elsif ($logfile->compressed()) {
160 161 162 163 164 165 166 167
	system("$GUNZIP -c $logname");
    }
    else {
	system("/bin/cat $logname");
    }
    exit(0);
}

168
#
169 170 171
# Open the file up while still root. We verified permission above, and the
# added check using the filesystems permissions if more of a pain then it
# buys us. Well, might revisit this.
172
#
173 174
sysopen(LOG, $logname, O_RDONLY | O_NONBLOCK) or
    die("*** $0:\n".
175 176
	"    Could not open $logname: $!\n");

177 178
# Now flip back to user.
$EUID = $UID;
179

180 181 182 183 184
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
    $atime,$mtime,$ctime,$blksize,$blocks) = stat(LOG);

#
# Icky. If the file is open and less then 1024 bytes, send out some
185
# stuff at the beginning to make the browser do something. This is terrible,
186 187 188
# but not sure what else to do.
#
if ($fromweb && $isopen && $size < 1024) {
189
    for (my $i = $size; $i <= 1024; $i++) {
190 191 192 193 194
	print " ";
    }
    print "\n";
}

195 196 197 198 199 200 201 202 203
if ($logfile->MetadataList()) {
    foreach my $ref (@{ $logfile->MetadataList() }) {
	my ($key,$val) = @{$ref};
	printf("%-15s %s\n", "$key:", $val);
    }
    print "\n";
    print "---------------------\n";
}

204 205
#
# Loop reading the file in nonblocking mode. Sleep between loops, and
206
# check for a change in status.
207 208 209
#
while (1) {
    my $tmp;
210
    my $buf;
211 212 213 214
    
    while (sysread(LOG, $buf, 2048)) {
	print STDOUT "$buf";
    }
215 216 217 218
    # Stop if the logfile object becomes invalid (deleted by someone).
    last
	if ($logfile->Refresh() != 0 || !$logfile->isopen());

219
    sleep(2);
220 221 222 223
}
close(LOG);
exit(0);