initial commit of file from CVS for smeserver-durep on Sat Sep 7 20:21:52 AEST 2024

This commit is contained in:
Trevor Batley
2024-09-07 20:21:52 +10:00
parent b7162f2054
commit ce6f5341b1
30 changed files with 1974 additions and 2 deletions

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
enabled

View File

@@ -0,0 +1 @@
service

View File

@@ -0,0 +1,3 @@
#!/bin/bash
echo "Initial run of durep ... please wait."
/usr/sbin/durep.daily >/dev/null

View File

@@ -0,0 +1,4 @@
# Generate DUREP reports
01 0 * * * root /usr/sbin/durep.daily

View File

@@ -0,0 +1,41 @@
#------------------------------------------------------------
# durep for user panel
#------------------------------------------------------------
{
use esmith::db;
my %accounts;
tie %accounts, 'esmith::config', '/home/e-smith/db/accounts';
my $globalpanels = db_get_prop(\%accounts, 'globalUP', 'AdminPanels');
$globalpanels = '' if ( ! defined ($globalpanels) );
my @globalpanels = split (/,/, $globalpanels, -1);
my $key;
my $value;
my $file = "durep";
my $require = "require user ";
while (($key,$value) = each %accounts)
{
my ($type, %properties) = split (/\|/, $value, -1);
if ($type eq 'user')
{
my $adminpanels = db_get_prop(\%accounts, $key, 'AdminPanels');
$adminpanels = "" if (! defined $adminpanels );
my @adminpanels = split (/,/, $adminpanels, -1);
push @adminpanels, @globalpanels ;
if (grep (/^$file$/, @adminpanels))
{
# Build a files require line for each panel
$panelshash{$file} .= " $key"
}
}
}
$OUT .= "\n";
$OUT .= " <Directory \"/etc/e-smith/web/panels/manager/html/durep\"> \n";
$OUT .= " require user admin$panelshash{$file}\n";
$OUT .= " </Directory>\n";
}

View File

@@ -0,0 +1,73 @@
#!/usr/bin/perl -wT
#----------------------------------------------------------------------
# heading : Administration
# description : Disk usage report
# navigation : 4000 4390
#
#----------------------------------------------------------------------
package esmith;
use strict;
use CGI ':all';
use CGI::Carp qw(fatalsToBrowser);
use esmith::cgi;
use esmith::db;
use esmith::util;
sub showInitial ($);
BEGIN
{
# Clear PATH and related environment variables so that calls to
# external programs do not cause results to be tainted. See
# "perlsec" manual page for details.
$ENV {'PATH'} = '/bin:/usr/bin';
$ENV {'SHELL'} = '/bin/bash';
delete $ENV {'ENV'};
}
esmith::util::setRealToEffective ();
$CGI::POST_MAX=1024 * 100; # max 100K posts
$CGI::DISABLE_UPLOADS = 1; # no uploads
my %conf;
tie %conf, 'esmith::config';
#------------------------------------------------------------
# examine state parameter and display the appropriate form
#------------------------------------------------------------
my $q = new CGI;
if (! grep (/^state$/, $q->param))
{
showInitial ($q);
}
else
{
esmith::cgi::genStateError ($q, \%conf);
}
exit (0);
#------------------------------------------------------------
# subroutine to display initial form
#------------------------------------------------------------
sub showInitial ($)
{
my ($q) = @_;
my $url = "/server-manager/durep/durep.cgi";
print $q->redirect(-location => $url);
## these lines aren't that important, they just prevent a
## premature end of script headers error
esmith::cgi::genHeaderNonCacheable ($q, \%conf, 'DUREP reports');
esmith::cgi::genFooter ($q);
}

View File

@@ -0,0 +1 @@
../../../functions/durep

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

View File

@@ -0,0 +1,379 @@
#!/usr/bin/perl -w
#############################################################################
# durep - Disk Usage Report Generator #
# #
# Copyright (C) 2004 Damian Kramer (psiren@hibernaculum.net) #
# #
# You may distribute this program under the terms of the Artistic License. #
# #
# This program 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 #
# Artistic License for more details. #
#############################################################################
use MLDBM qw(DB_File Storable);
use POSIX;
use strict;
## Set these variables as appropriate.
## --------------------------------------------------
our $datadir = "/var/lib/durep"; # Filesystem path to the data files.
our $css_file = "/server-manager/durep/style.css"; # URL to CSS file
our $bar_image = "/server-manager/durep/bar.png"; # URL to image used in bar graph
our $show_mtime = 1; # Show file modifcation time
our $show_opts = 0; # Show options used
## --------------------------------------------------
### NO USER-SERVICEABLE PARTS BEYOND THIS POINT ###
our ($me, $data, @ancestors, @records, %input, $temp, $version, $top_node, $collated);
our ($TYPE_FILE, $TYPE_DIR, $TYPE_EMPTY, $TYPE_COALESCED, $TYPE_COLLAPSED);
$me = $ENV{SCRIPT_NAME};
$TYPE_FILE = 0;
$TYPE_DIR = 1;
$TYPE_EMPTY = 2;
$TYPE_COALESCED = 4;
$TYPE_COLLAPSED = 8;
$version = "0.9";
$ENV{PATH} = "/bin:/usr/bin";
$top_node = {};
$collated = loadCollateFile($datadir);
getInput();
if(%input) {
fetchData();
displayData();
}
else {
displayList();
}
# Return to system
exit 0;
sub getInput {
if($ENV{REQUEST_METHOD} eq 'POST') {
chomp($_ = <STDIN>);
}
elsif($ENV{REQUEST_METHOD} eq 'GET') {
$_ = $ENV{QUERY_STRING};
}
else {
return;
}
for $temp (split("&", $_)) {
my ($var, $val) = split ('=', $temp);
$val =~ s/\+/ /g;
$val =~ s/%(..)/pack("H2", $1)/eg;
if(defined $input{$var}) {
$input{$var} .= "\0$val";
}
else {
$input{$var} = $val;
}
}
}
sub displayInput {
print "Content-type: text/html\n\n";
my ($key, $val);
print "<html><head><title>SMESERVER Disk Usage Report</title></head>";
print "<body bgcolor='#FFFFFF' text='#000000' link='#0000FF' vlink='#0000AA'><br><br>";
print "<table cellpadding=0 cellspacing=0 border=1>";
while(($key, $val) = each %input) {
my $length = length $val;
print "<tr><td><pre>$key</pre></td><td><pre>[$length]</pre></td><td><pre>[$val]</pre></td></tr>\n";
}
print "</table></pre>";
print "</body></html>";
}
sub fetchData {
my $root_node = {};
my $node;
tie %{$root_node}, 'MLDBM', "$datadir/$collated->{$input{fid}}->{FILENAME}", O_RDONLY, 0640 or errorPage();
%{$data} = (%{$root_node->{DATA}});
%{$top_node} = (%{$root_node->{$input{nid}}});
$node = $top_node;
while($node->{PARENT}) {
my $tmp = {};
%{$tmp} = (%{$root_node->{$node->{PARENT}}});
unshift @ancestors, $tmp;
$node = $tmp;
}
foreach $node (@{$top_node->{CHILDREN}}) {
my $tmp = {};
%{$tmp} = (%{$root_node->{$node}});
push @records, $tmp;
}
@records = reverse sort sortBySize @records;
untie %{$root_node};
}
sub displayList {
print "Content-type: text/html\n\n";
my $hash = sortCollateFile($collated);
my ($key, $val);
print qq{
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Disk Usage Report</title>
<link rel="stylesheet" href="$css_file" type="text/css"/>
</head>
<body>
<h1>Disk Usage Report</h1>
<table class='list' cellpadding=0 cellspacing=0 border=0>
<tr><th>&nbsp;</th><th>Path</th><th>Description</th><th>Size</th><th>Dirs</th><th>Files</th><th>Date</th></tr>
};
foreach my $host (keys %{$hash}) {
print "<tr><td colspan=7 class='dark'>$host</td></tr>\n";
my $flip = 0;
foreach my $e (reverse sort sortByDate @{$hash->{$host}}) {
if($flip) { print "<tr class='mid'>"; }
else { print "<tr class='light'>"; }
$flip = !$flip;
print "<td>&nbsp;</td>";
print "<td><a href='$me?fid=$e->{ID}&nid=1'>$e->{PATH}</a></td>";
printf "<td><a href='$me?fid=$e->{ID}&nid=1'>%s</a></td>", $e->{DESC} || "-";
printf "<td>%s</td>", prettyFileSize($e->{SIZE});
printf "<td>%s</td>", prettyNum($e->{DIR_COUNT});
printf "<td>%s</td>", prettyNum($e->{FILE_COUNT});
printf "<td>%s</td>", prettyDate($e->{LAST_UPDATE});
print "</tr>\n";
}
}
# table to show df of all disk on main page
print qq{
</table>
<table class='list' cellpadding=0 cellspacing=0 border=0>
<tr><th>Filesystem</th><th>Sized</th><th>Used</th><th>Available</th><th>Use %</th><th>Mounted on</th></tr>
};
my $dflist = `df -hP|grep -v 'Use%'|sed 's#^#<tr><td>#g'|sed 's#\$#</td></tr>#g'`;
$dflist =~ s/[ ]+/<\/td><td>/g;
print $dflist;
print qq{
</table>
</body>
</html>
};
}
sub displayData {
print "Content-type: text/html\n\n";
my ($key, $val);
print qq{
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Disk Usage Report ($data->{HOSTNAME})</title>
<link rel="stylesheet" href="$css_file" type="text/css"/>
</head>
<body>
<h1>Disk Usage Report ($data->{HOSTNAME})</h1>
<div class='tbar'><table class='location'><tr><td>[<a href='$me'>Home</a>]
};
foreach my $tmp (@ancestors) {
printf "<a href='$me?fid=$input{fid}&nid=%d'>$tmp->{NAME}</a>%s", $tmp->{ID}, (($tmp->{NAME} =~ m|\/$|) ? "" : "/");
}
print "$top_node->{NAME}</td>";
printf "<td class='right'>%s</td>", prettyFileSize($top_node->{SIZE});
print "</tr></table></div>";
print "<table class='report' cellpadding=0 cellspacing=0 border=0>\n";
print "<tr class='dark'><th>Size</th><th colspan=2>Percentage</th>";
print "<th class='right'>Dirs</th><th class='right'>Files</th>";
print "<th>Modified</th>" if $show_mtime;
print "<th>File</th></tr>";
my $flip = 0;
foreach my $node (@records) {
my $percent = $top_node->{SIZE} ? ($node->{SIZE}/$top_node->{SIZE}*100) : 0;
if($flip) { print "<tr class='mid'>"; }
else { print "<tr class='light'>"; }
$flip = !$flip;
print "<td class='right'>";
print prettyFileSize($node->{SIZE});
print "</td><td>";
print barChart($percent);
printf("</td><td class='right'>%4.2f%%</td>", $percent);
if($node->{TYPE} & $TYPE_DIR) {
if($node->{TYPE} & $TYPE_EMPTY) {
print "<td class='right'>0</td><td class='right'>0</td>";
printf("<td>%s</td>", shortDate($node->{MTIME})) if $show_mtime;
print "<td><span class='empty'>$node->{NAME}/</span></td>";
}
else {
printf("<td class='right'>%d</td>", $node->{DCOUNT});
printf("<td class='right'>%d</td>", $node->{FCOUNT});
printf("<td>%s</td>", shortDate($node->{MTIME})) if $show_mtime;
print "<td><span class='dir'><a href='$me?fid=$input{fid}&nid=$node->{ID}'>$node->{NAME}/</a></span></td>";
}
}
elsif($node->{TYPE} & $TYPE_COALESCED) {
printf "<td>&nbsp;</td><td class='right'>%d</td>", $node->{FCOUNT};
printf("<td>%s</td>", shortDate($node->{MTIME})) if $show_mtime;
print "<td><span class='coalesced'>$node->{NAME}</span></td>";
}
else {
print "<td>&nbsp;</td><td>&nbsp;</td>";
printf("<td>%s</td>", shortDate($node->{MTIME})) if $show_mtime;
print "<td>$node->{NAME}</td>";
}
print "</tr>\n";
}
print "</table>\n";
print "<div class='bbar'><table class='location'><tr>";
printf "<td>%s</td>", scalar localtime($data->{LAST_UPDATE});
print "<td class='right'>Generated by <a href='http://www.hibernaculum.net/'>durep</a> v. $version</td>";
print "</tr></table></div>\n";
if($show_opts && $data->{OPTIONS}) {
print "<div class='options'><ul>";
print "<li>Scanning files only.</li>" if $data->{OPTIONS}->{FILES};
print "<li>Restricting to single filesystem.</li>" if $data->{OPTIONS}->{ONEFILESYSTEM};
printf "<li>Collapsing paths matching <b>%s</b>.</li>", $data->{OPTIONS}->{COLLAPSEPATH} if $data->{OPTIONS}->{COLLAPSEPATH};
printf "<li>Excluding paths matching <b>%s</b>.</li>", $data->{OPTIONS}->{EXCLUDEPATH} if $data->{OPTIONS}->{EXCLUDEPATH};
printf "<li>Coalescing files below <b>%s</b>.</li>", prettyFileSize($data->{OPTIONS}->{COALESCEFILES}) if $data->{OPTIONS}->{COALESCEFILES};
print "</ul></div>";
}
print "</body></html>";
}
### All this does is create an HTML table bar graph type thingy.
sub barChart {
my $percent = int($_[0]*2+0.5);
my $rv = "<div class='graph'>";
if($percent) {
$rv .= "<img src='$bar_image' style=\"width:${percent}px; height: 15px;\"/>";
}
else {
$rv .= "&nbsp;";
}
$rv .= "</div>";
return $rv;
}
# Generates a human readable file size string
sub prettyFileSize {
my $val = $_[0];
my $dtype = "b";
if($val >= 1024) {
$val /= 1024;
$dtype = "K";
}
if($val >= 1024) {
$val /= 1024;
$dtype = "M";
}
if($val >= 1024) {
$val /= 1024;
$dtype = "G";
}
if($dtype eq "b") {
return sprintf("%d%s", $val, $dtype);
}
else {
return sprintf("%.1f%s", $val, $dtype);
}
}
sub prettyDate {
return POSIX::strftime("%T %a %b %e %Y", localtime $_[0]);
}
sub shortDate {
if($_[0] < (time - 31536000)) {
return POSIX::strftime("%b %e %Y", localtime $_[0]);
}
return POSIX::strftime("%b %e %H:%M", localtime $_[0]);
}
sub prettyNum {
my $r = reverse shift;
$r =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
return scalar reverse $r;
}
sub sortBySize {
return $a->{SIZE} <=> $b->{SIZE};
}
sub sortByDate {
return $a->{LAST_UPDATE} <=> $b->{LAST_UPDATE};
}
sub sortByPath {
return $a->{PATH} cmp $b->{PATH};
}
sub loadCollateFile {
my $dir = shift;
my %db;
my $r;
tie %db, 'MLDBM', "$dir/durep.cds", O_RDONLY, 0640 or errorPage();
foreach my $key (keys %db) {
$r->{$key} = \%{$db{$key}};
}
untie %db;
return $r;
}
sub sortCollateFile {
my $hash = shift;
my $r;
foreach my $key (keys %{$hash}) {
my $hostname = $hash->{$key}->{HOSTNAME};
push @{$r->{$hostname}}, \%{$hash->{$key}};
}
return $r;
}
sub errorPage {
print "Content-type: text/html\n\n";
print qq{
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Disk Usage Report</title>
<link rel="stylesheet" href="$css_file" type="text/css"/>
</head>
<body>
<h1>Durep encountered an error!</h1>
<p>Please check that you have collated the files and that the permissions on them are correct.</p>
</body>
</html>
};
exit 0;
}

View File

@@ -0,0 +1,125 @@
a:hover {
background-color: #DDDDDD;
}
body {
text-align: center;
background-color: #ffffff;
}
div.tbar {
text-align: left;
width: 100%;
background-color: #EEEEEE;
border-top: solid 1px #DDDDDD;
border-bottom: solid 1px #DDDDDD;
}
div.bbar {
text-align: left;
width: 100%;
background-color: #EEEEEE;
border-top: solid 1px #DDDDDD;
border-bottom: solid 1px #DDDDDD;
}
div.bbar * {
font-size: 90%;
}
div.options {
text-align: left;
margin: 2em;
background-color: #EEEEEE;
border: solid 1px #DDDDDD;
}
.light {
background-color: #ffffff;
}
.mid {
background-color: #f6f6f6;
}
.dark {
background-color: #f0f0f0;
}
.tbar table {
width: 100%;
padding-left: 2pt;
font-weight: bold;
}
.bbar table {
width: 100%;
padding-left: 2pt;
}
table.list {
margin: 2em 0px;
border: solid 1px #CCCCCC;
margin-left: auto;
margin-right: auto;
}
table.list td {
text-align: left;
padding: 2px 5px;
}
table.list th {
text-align: left;
padding: 2px 5px;
text-align: left;
background-color: #DDDDDD;
}
table.report {
margin: 2em 0px;
border: solid 1px #CCCCCC;
text-align: left;
margin-left: auto;
margin-right: auto;
}
table.report td {
padding: 2px 5px;
}
table.report th {
padding: 2px 5px;
text-align: left;
background-color: #DDDDDD;
}
.graph {
padding: 0px;
background-color: #eeeeee;
width: 200px;
height: 15px;
}
th.right {
text-align: right;
}
td.right {
text-align: right;
}
span.dir {
font-weight: bold;
}
span.empty {
color: #006600;
font-weight: bold;
}
span.coalesced {
color: #880000;
font-weight: bold;
}

View File

@@ -0,0 +1 @@
/etc/e-smith/web/panels/manager/html/durep

452
root/usr/local/bin/durep Executable file
View File

@@ -0,0 +1,452 @@
#!/usr/bin/perl -w
#############################################################################
# durep - Disk Usage Report Generator #
# #
# Copyright (C) 2004 Damian Kramer (psiren@hibernaculum.net) #
# #
# You may distribute this program under the terms of the Artistic License. #
# #
# This program 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 #
# Artistic License for more details. #
#############################################################################
use Getopt::Long;
use File::Basename;
use MLDBM qw(DB_File Storable);
use Fcntl;
use Sys::Hostname;
use POSIX;
use Cwd qw(cwd);
use strict;
our ($version, %options);
our ($root_node, $filesystem_id, @stats);
our ($opt_help, $opt_version, $opt_textdepth, $opt_hidesize, $opt_showdate, $opt_nosort, $opt_quiet);
our ($opt_savefile, $opt_loadfile, $opt_desc, $opt_collate);
our ($opt_files, $opt_onefilesystem, $opt_collapsepath, $opt_excludepath, $opt_coalescefiles);
our ($root_dir, $file_count, $dir_count, $next_id);
our ($TYPE_FILE, $TYPE_DIR, $TYPE_EMPTY, $TYPE_COALESCED, $TYPE_COLLAPSED);
$TYPE_FILE = 0;
$TYPE_DIR = 1;
$TYPE_EMPTY = 2;
$TYPE_COALESCED = 4;
$TYPE_COLLAPSED = 8;
$version = "0.9";
$| = 1;
$SIG{INT} = \&catchError;
%options = ("h|help" => \$opt_help,
"v|version" => \$opt_version,
"td|text-depth=i" => \$opt_textdepth,
"hs|hide-size=s" => \$opt_hidesize,
"sd|show-date" => \$opt_showdate,
"ns|nosort" => \$opt_nosort,
"q|quiet" => \$opt_quiet,
"sf|save-file=s" => \$opt_savefile,
"lf|load-file=s" => \$opt_loadfile,
"d|desc=s" => \$opt_desc,
"c|collate=s" => \$opt_collate,
"f|files" => \$opt_files,
"x|one-file-system" => \$opt_onefilesystem,
"cp|collapse-path=s" => \$opt_collapsepath,
"ep|exclude-path=s" => \$opt_excludepath,
"cf|coalesce-files=s" => \$opt_coalescefiles
);
&usage unless (GetOptions(%options));
&usage if(defined $opt_help);
if(defined $opt_version) {
print "durep version $version\n";
exit 0;
}
## Process options
if($opt_collate) {
collate();
exit 0;
}
$opt_hidesize = processSizeOption($opt_hidesize) if(defined $opt_hidesize);
$opt_coalescefiles = processSizeOption($opt_coalescefiles) if(defined $opt_coalescefiles);
doAbort("Depth must be greater than 0.") if(defined $opt_textdepth && $opt_textdepth < 1);
doAbort("You must specify a save file if you use --quiet.") if(defined $opt_quiet && !defined $opt_savefile);
doAbort("You can't use --load-file and --save-file at the same time.") if(defined $opt_loadfile && defined $opt_savefile);
if($opt_savefile) {
$opt_savefile .= ".ds" unless $opt_savefile =~ /\.ds$/;
}
push @ARGV, "." unless @ARGV;
$root_dir = shift;
chop $root_dir if $root_dir =~ m|./$|; # Remove trailing /
doAbort("`$root_dir' not a valid directory.") unless -d $root_dir;
# Get the absolute pathname rather than relative pathname
$_ = cwd();
chdir($root_dir) or doAbort("Unable to chdir to '$root_dir'.");
$root_dir = cwd();
chdir($_);
if($opt_loadfile) {
tie %{$root_node}, 'MLDBM', "$opt_loadfile", O_RDONLY, 0640 or doAbort("Unable to tie file '$opt_loadfile'.");
}
else {
## Perform scan
$file_count = 0;
$dir_count = 0;
$next_id = 1;
$root_node = {};
if($opt_savefile) {
if(-r $opt_savefile) {
print "Removing existing savefile '$opt_savefile'.\n" unless $opt_quiet;
unlink $opt_savefile;
}
tie %{$root_node}, 'MLDBM', "$opt_savefile", O_CREAT|O_RDWR, 0640 or doAbort("Unable to tie file '$opt_savefile'.");
}
($filesystem_id) = stat $root_dir if defined $opt_onefilesystem;
$root_node->{1} = recursiveScan($root_dir, undef, 1);
my $data;
$data->{FILE_COUNT} = $file_count;
$data->{DIR_COUNT} = $dir_count;
$data->{LAST_UPDATE} = time;
$data->{HOSTNAME} = hostname();
$data->{DESC} = $opt_desc if $opt_desc;
$data->{OPTIONS}->{FILES} = 1 if $opt_files;
$data->{OPTIONS}->{ONEFILESYSTEM} = 1 if $opt_onefilesystem;
$data->{OPTIONS}->{COLLAPSEPATH} = $opt_collapsepath if $opt_collapsepath;
$data->{OPTIONS}->{EXCLUDEPATH} = $opt_excludepath if $opt_excludepath;
$data->{OPTIONS}->{COALESCEFILES} = $opt_coalescefiles if $opt_coalescefiles;
$root_node->{DATA} = $data;
}
# use Data::Dumper;
# print Dumper($root_node);
if(!$opt_quiet) {
printf "[ %s %s (%d files, %d dirs) ]\n", $root_node->{1}->{NAME}, prettyFileSize($root_node->{1}->{SIZE}),
$root_node->{1}->{FCOUNT}, $root_node->{1}->{DCOUNT};
printDir($root_node->{1}, 0);
}
if($opt_savefile || $opt_loadfile) {
untie %{$root_node};
}
exit 0;
## End of program.
sub recursiveScan {
my ($dir, $parent, $store) = @_;
my @children;
my $coalesced_count = 0;
my $coalesced_size = 0;
my $node = {};
my $temp;
my $dirhandle;
$node->{ID} = $next_id++;
if(defined $parent) {
$node->{NAME} = basename($dir);
$node->{PARENT} = $parent;
}
else {
$node->{NAME} = $dir;
}
$node->{SIZE} = 0;
$node->{TYPE} = $TYPE_DIR;
$node->{DCOUNT} = 0;
$node->{FCOUNT} = 0;
if($store) {
$store = 0 if($opt_collapsepath && $dir =~ m/$opt_collapsepath/);
}
$node->{TYPE} &= $TYPE_COLLAPSED unless $store;
opendir($dirhandle, $dir) or warn "Unable to open dir '$dir': $!\n" and return $node;
foreach(readdir($dirhandle)) {
@stats = lstat "$dir/$_" or warn "Unable to lstat '$dir/$_': $!\n" and next;
$node->{MTIME} = $stats[9] if($_ eq ".");
# Skip '.' and '..'
next if(/^\.{1,2}$/);
if(-d _ && ! -l _ && !$opt_files) {
if(! -x _) {
warn "Unable to read directory `$dir/$_'. Skipping.\n";
next;
}
next if($opt_excludepath && "$dir/$_" =~ m/$opt_excludepath/);
next if($opt_onefilesystem && ($stats[0] != $filesystem_id));
$temp = recursiveScan("$dir/$_", $node->{ID}, $store);
$node->{SIZE} += $temp->{SIZE};
if($store) {
$root_node->{$temp->{ID}} = $temp;
push @children, $temp->{ID};
$dir_count++;
$node->{DCOUNT}++;
}
next;
}
if($opt_coalescefiles && $stats[7] < $opt_coalescefiles) {
$coalesced_count++;
$coalesced_size += $stats[7];
}
else {
if($store) {
my $file = {};
$file->{ID} = $next_id++;
$file->{NAME} = $_;
$file->{SIZE} = $stats[7];
$file->{PARENT} = $node->{ID};
$file->{TYPE} = $TYPE_FILE;
$file->{MTIME} = $stats[9];
$root_node->{$file->{ID}} = $file;
push @children, $file->{ID};
}
$node->{SIZE} += $stats[7];
}
$file_count++;
$node->{FCOUNT}++;
}
closedir($dirhandle);
if($coalesced_count) {
if($store) {
my $file = {};
$file->{ID} = $next_id++;
$file->{NAME} = "[COALESCED FILES]";
$file->{SIZE} = $coalesced_size;
$file->{PARENT} = $node->{ID};
$file->{TYPE} = $TYPE_FILE|$TYPE_COALESCED;
$file->{MTIME} = 0;
$file->{FCOUNT} = $coalesced_count;
$root_node->{$file->{ID}} = $file;
push @children, $file->{ID};
}
$node->{SIZE} += $coalesced_size;
}
if(@children) {
$node->{CHILDREN} = \@children;
}
else {
$node->{TYPE} = $TYPE_DIR|$TYPE_EMPTY;
}
# $root_node->{$node->{ID}} = $node;
return $node;
}
sub collate {
my %db;
doAbort("'$opt_collate' is not a valid directory.") unless -d $opt_collate;
tie %db, 'MLDBM', "$opt_collate/durep.cds", O_CREAT|O_RDWR, 0640 or doAbort("Unable to tie file '$opt_collate/durep.cds'");
my @files;
my $next_id = 1;
opendir(DIR, $opt_collate) or doAbort("Unable to open dir '$opt_collate': $!");
foreach(readdir(DIR)) {
# Skip unless a .ds file
next unless(/\.ds$/);
push @files, $_;
}
closedir(DIR);
foreach my $file (sort @files) {
my $id = $next_id++;
my %temp;
tie %temp, 'MLDBM', "$opt_collate/$file", O_RDONLY, 0640 or doAbort("Unable to tie file '$opt_collate/$file'");
my %data = (%{$temp{DATA}});
$data{FILENAME} = $file;
$data{SIZE} = $temp{1}->{SIZE};
$data{ID} = $id;
$data{PATH} = $temp{1}->{NAME};
$db{$id} = \%data;
untie %temp;
}
untie %db;
}
sub printDir {
my ($dir, $indent) = @_;
my @entries;
foreach my $entry (@{$dir->{CHILDREN}}) {
$entry = $root_node->{$entry};
next if(defined $opt_hidesize && $entry->{SIZE} < $opt_hidesize);
my $e = {};
$e->{NAME} = $entry->{NAME};
$e->{SIZE} = $entry->{SIZE};
$e->{TYPE} = $entry->{TYPE};
$e->{MTIME} = $entry->{MTIME};
$e->{CHILDREN} = $entry->{CHILDREN} if $entry->{CHILDREN};
push @entries, $e;
}
@entries = reverse sort sortBySize @entries unless $opt_nosort;
foreach my $entry (@entries) {
my $numofchars;
my $percent = $dir->{SIZE} == 0 ? 0 : ($entry->{SIZE}/$dir->{SIZE})*100;
print " " x $indent;
print prettyFileSize($entry->{SIZE});
$numofchars = int ((30 / 100) * $percent);
printf(" [%s%s] ", "#" x $numofchars, " " x (30-$numofchars));
printf("%6.2f%% ", $percent);
printf("%s ", shortDate($entry->{MTIME})) if $opt_showdate;
printf("%s%s\n", $entry->{NAME}, $entry->{TYPE} & $TYPE_DIR ? "/" : "");
if($entry->{TYPE} & $TYPE_DIR) {
printDir($entry, $indent+1) if(!defined $opt_textdepth || ($opt_textdepth > $indent+1));
}
}
}
sub processSizeOption {
my ($size, $temp);
if($_[0] =~ m/[bBkKmMgG]$/) {
($size, $temp) = $_[0] =~ m/^(.+)([bBkKmMgG])$/;
}
else {
$size = $_[0];
}
unless (defined $size && ($size =~ m/^\d+$/ || $size =~ m/^\d+\.\d+$/)) {
doAbort("Malformed argument: $_[0]");
}
if(defined $temp) {
if($temp =~ m/^[kK]/) {
return $size * 1024;
}
elsif ($temp =~ m/^[mM]/) {
return $size * 1048576;
}
elsif ($temp =~ m/^[mM]/) {
return $size * 1048576 * 1024;
}
return $size;
}
}
sub prettyFileSize {
my $val = $_[0];
my $dtype = "b";
if($val >= 1024) {
$val /= 1024;
$dtype = "K";
}
if($val >= 1024) {
$val /= 1024;
$dtype = "M";
}
if($val >= 1024) {
$val /= 1024;
$dtype = "G";
}
if($dtype eq "b") {
return sprintf("%6d%s", $val, $dtype);
}
else {
return sprintf("%6.1f%s", $val, $dtype);
}
}
sub shortDate {
if($_[0] < (time - 31536000)) {
return POSIX::strftime("%b %e %Y", localtime $_[0]);
}
return POSIX::strftime("%b %e %H:%M", localtime $_[0]);
}
sub sortBySize {
return $a->{SIZE} <=> $b->{SIZE};
}
### End program with error message
sub doAbort {
warn "Error: $_[0]\n";
exit 1;
}
sub catchError {
warn "Program interrupted.\n";
if($opt_savefile || $opt_loadfile) {
untie %{$root_node};
}
exit 1;
}
sub usage {
print <<EOF;
Usage: durep [OPTION(S)] [DIRECTORY]
-h, --help this help
-v, --version show version number
Text Ouput Options:
-td, --text-depth=N limit text report on directories to depth N
-hs, --hide-size=N[bkmg] do not display entries using N Bytes/Kb/Mb/Gb
or less (default Bytes)
-sd, --show-date show modification date
-ns, --nosort do not sort results by size
-q, --quiet do not produce text output
File Options:
-sf, --save-file=<file> save the results of the scan into this file
-lf, --load-file=<file> load the results of a scan from this file
-d, --desc=<description> give description of save file
-c, --collate=<dir> collate save files in dir for web report
Inclusion Options:
-f, --files do not descend into subdirs, only report files
-x, --one-file-system do not traverse file systems
-cp, --collapse-path=<regexp> hide entries below paths that match regexp
-ep, --exclude-path=<regexp> ignore paths that match regexp
-cf, --coalesce-files=N[bkmg] coalesce files less than N Bytes/Kb/Mb/Gb
into one entry (default Bytes)
EOF
exit 0;
}

View File

@@ -0,0 +1,290 @@
.\" Automatically generated by Pod::Man version 1.15
.\" Fri Nov 26 12:13:59 2004
.\"
.\" Standard preamble:
.\" ======================================================================
.de Sh \" Subsection heading
.br
.if t .Sp
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Ip \" List item
.br
.ie \\n(.$>=3 .ne \\$3
.el .ne 3
.IP "\\$1" \\$2
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. | will give a
.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used
.\" to do unbreakable dashes and therefore won't be available. \*(C` and
.\" \*(C' expand to `' in nroff, nothing in troff, for use with C<>
.tr \(*W-|\(bv\*(Tr
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
'br\}
.\"
.\" If the F register is turned on, we'll generate index entries on stderr
.\" for titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and
.\" index entries marked with X<> in POD. Of course, you'll have to process
.\" the output yourself in some meaningful fashion.
.if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. nr % 0
. rr F
.\}
.\"
.\" For nroff, turn off justification. Always turn off hyphenation; it
.\" makes way too many mistakes in technical documents.
.hy 0
.if n .na
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
.bd B 3
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ======================================================================
.\"
.IX Title "DUREP 1"
.TH DUREP 1 "durep version " "2004-09-05" "Disk Usage Report Generator"
.UC
.SH "NAME"
durep \- disk usage report generator
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
durep [\s-1OPTIONS\s0]... [\s-1DIRECTORY\s0]
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
\&\fBdurep\fR creates disk usage reports with bar graphs, allowing one to
easily deduce which directories are using the most space. Although
\&\fBdurep\fR can produce text output similar to du, its real power lies in
the ability to store reports in a file, which can then be viewed as a
web page with the supplied cgi script.
.SH "OPTIONS"
.IX Header "OPTIONS"
Options are groubed into three distinct sections.
.Sh "Text Output Options"
.IX Subsection "Text Output Options"
These options are for controlling the text report output.
.Ip "\fB\-td, \-\-text-depth\fR=\fIN\fR" 7
.IX Item "-td, --text-depth=N"
Limit text report on directories to depth \fIN\fR. No directories below
this level will be shown in the report.
.Ip "\fB \-hs, \-\-hide-size\fR=\fIN[bkmg]\fR" 7
.IX Item " -hs, --hide-size=N[bkmg]"
Do not display entries using \fIN\fR Bytes/Kb/Mb/Gb or less (default
Bytes). This is to reduce clutter in the reports. It allows you to
remove small files from the text report.
.Ip "\fB \-sd, \-\-show-date\fR" 7
.IX Item " -sd, --show-date"
Display the modification date of the file or directory in the report.
.Ip "\fB\-ns, \-\-nosort\fR" 7
.IX Item "-ns, --nosort"
Do not sort results by size. Leaves results in the order in which they
were scanned, which is highly dependant on the filesystem.
.Ip "\fB\-q, \-\-quiet\fR" 7
.IX Item "-q, --quiet"
Do not produce text output. This stops the creation of a text report,
and is useful when you are only interested in generating a save-file
for use with the web report.
.Sh "File Options"
.IX Subsection "File Options"
These options control load and save files.
.Ip "\fB\-sf, \-\-save-file\fR=\fI\s-1FILE\s0\fR" 7
.IX Item "-sf, --save-file=FILE"
Save the results of the scan into this file. This can be loaded for a
text report, but is generally used by the cgi script to display web
reports. The filename should end in \fI.ds\fR (it is appended if it does
not).
.Ip "\fB\-lf, \-\-load-file\fR=\fI\s-1FILE\s0\fR" 7
.IX Item "-lf, --load-file=FILE"
Load the results of a scan from this file. This takes the place of
scanning a directory. Inclusion options (described below) will not
take effect if this option is used.
.Ip "\fB\-d, \-\-desc\fR=\fI\s-1DESCRIPTION\s0\fR" 7
.IX Item "-d, --desc=DESCRIPTION"
Give a description to be stored in the save-file. This is displayed on
the web report summary page.
.Ip "\fB\-c, \-\-collate=\fR=\fI\s-1DIR\s0\fR" 7
.IX Item "-c, --collate==DIR"
Collate the save-files in the given directory. This creates a
\&\fIdurep.cds\fR file, which is used by the cgi script to manage and
display save-files. See \fBWeb Reports\fR section below for more detail.
.Sh "Inclusion Options"
.IX Subsection "Inclusion Options"
These options control which directories and files should be included in the report.
.Ip "\fB\-f, \-\-files\fR" 7
.IX Item "-f, --files"
Do not descend into sub-directories, only report files.
.Ip "\fB\-x, \-\-one-file-system\fR" 7
.IX Item "-x, --one-file-system"
Do not traverse file systems. This is similar to the \fB\-x\fR option for
du, allowing easy checking of an entire filesystem such as /.
.Ip "\fB\-cp, \-\-collapse-path=\fR\fI\s-1PATTERN\s0\fR" 7
.IX Item "-cp, --collapse-path=PATTERN"
Hide entries below paths that match \fI\s-1PATTERN\s0\fR. This allows you to
conceal the contents of certain directories in the report. You may
wish perhaps to show home directories in a report but not show their
content in which case you could use the option \f(CW\*(C`\-cp
\&'/home'\*(C'\fR.
.Ip "\fB\-ep, \-\-exclude-path\fR=\fI\s-1PATTERN\s0\fR" 7
.IX Item "-ep, --exclude-path=PATTERN"
Ignore paths that match \fI\s-1PATTERN\s0\fR. This works in a smilar manner to
\&\f(CW\*(C`\-cp\*(C'\fR above, except it excludes the directory from the scan itself.
.Ip "\fB\-cf, \-\-coalesce-files=\fR=\fIN[bkmg]\fR" 7
.IX Item "-cf, --coalesce-files==N[bkmg]"
Coalesces entries for files below the given size into one entry. This
is useful for reducing clutter in reports.
.SH "WEB REPORTS"
.IX Header "WEB REPORTS"
Since version 0.9, durep no longer directly generates html files for
its web reports. It now uses a cgi script that reads data from
save-files. The script will handle multiple save-files, potentially
from multiple hosts, so you can consolidate your reports into one
place. Copying save-files from other hosts is left as an exercise for
the reader.
.PP
It is necessary to collate the save-files before viewing them via the
cgi script. This process creates the file \f(CW\*(C`durep.cds\*(C'\fR which contains
metadata about all of the save-files. From this a summary page is
shown where you can choose which report you wish to view. The
collation must be done any time a save-file is added or overwritten.
.PP
The cgi-script has some configurable variables at the top. These tell
the script where to look for the css file and the graphic used for the
bar graphs. There are also options to set whether the modification
date, and/or the options used to create the save-file should be
shown. These are both set to 1 by default.
.PP
As always, you should take care when installing the cgi script. I've
done my best, but I make no guarantees about its security. It would
probably be unwise to allow this script to be accessed from the
internet at large.
.SH "EXAMPLES"
.IX Header "EXAMPLES"
.Ip "1." 3
\&\fBdurep \-td 2\fR
.Sp
This would print the directory tree starting from the current
directory to depth 2.
.Ip "2." 3
\&\fBdurep \-f /var/spool/mail\fR
.Sp
This might be useful for keeping a check on the mail directory. The
\&\f(CW\*(C`\-f\*(C'\fR switch tells durep to just scan files and not descend into
directories.
.Ip "3." 3
\&\fBdurep \-x \-cp \*(L"/(etc|usr/share)\*(R" \-ep \*(L"/var\*(R" \-sf /var/lib/durep/root.ds /\fR
.Sp
This more complicated version does the following. It scans the root
filesystem only, collapses the contents of any paths begining \fI/etc\fR
or \fI/usr/share\fR and skips the contents of the \fI/var\fR directory. It
saves the output of this report into the file
\&\fI/var/lib/durep/root.ds\fR. No text report is produced.
.Ip "4." 3
\&\fBdurep \-lf /var/lib/durep/root.ds \-hs 1m\fR
.Sp
This reads the save-file \fI/var/lib/durep/root.ds\fR and produces a text
report from it, hiding any files below 1 megabyte.
.Ip "5." 3
\&\fBdurep \-c /var/lib/durep\fR
.Sp
This collates any save-files in \fI/var/lib/durep\fR.
.SH "SEE ALSO"
.IX Header "SEE ALSO"
\&\fIdu\fR\|(1), \fIperl\fR\|(1)
.SH "AUTHOR"
.IX Header "AUTHOR"
Damian Kramer <psiren@hibernaculum.net>

41
root/usr/sbin/durep.daily Normal file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
# shall we run ?
status=$(/sbin/e-smith/db configuration getprop durep status || echo 'enabled')
if [[ "$status" == "disabled" ]]; then
exit
fi
# original folders to be accounted
/usr/local/bin/durep -q -x -sf /var/lib/durep/user.ds /home/e-smith/files/users
/usr/local/bin/durep -q -x -sf /var/lib/durep/ibays.ds /home/e-smith/files/ibays
# known folder from contribs and from base
folders=( "/home/e-smith/files/ezmlm" "/home/e-smith/files/shares" "/home/e-smith/db" "/opt/webshare")
# user added folder to stat
userfolders=$(/sbin/e-smith/db configuration getprop durep folders || echo '')
ufolders=(${userfolders//,/ })
folders=("${folders[@]}" "${ufolders[@]}")
for folder in "${folders[@]}"
do
name=` echo ${folder//\//_}`
#name=`basename $folder`
if [ -d "$folder" ]; then
/usr/local/bin/durep -q -x -sf /var/lib/durep/$name.ds $folder
else
if [ -f "/var/lib/durep/$name.ds" ];then
rm /var/lib/durep/$name.ds -f
fi
fi
done
# make the stats viewable
/usr/local/bin/durep -c /var/lib/durep/
chmod 644 /var/lib/durep/*
chown root:admin /etc/e-smith/web/panels/manager/html/durep/*.cgi
chmod 750 /etc/e-smith/web/panels/manager/html/durep/*.cgi
# remove ds file not renewd for more than 24 hours
find /var/lib/durep/ -type f -iname *.ds -mtime +"1" |xargs rm -f

View File

@@ -0,0 +1,67 @@
package SrvMngr::Controller::Durep;
#----------------------------------------------------------------------
# heading : System
# description : Disk usage report
# navigation : 4000 390
# menu : A
#
# name : durep, method : get, url : /durep, ctlact : durep#main
#
# routes : end
#----------------------------------------------------------------------
use strict;
use warnings;
use Mojo::Base 'Mojolicious::Controller';
use Locale::gettext;
use SrvMngr::I18N;
use SrvMngr qw(theme_list init_session);
sub main {
my $c = shift;
$c->app->log->info($c->log_req);
my $modul = get_du( $c );
$c->stash( modul => $modul );
$c->render(template => 'durep');
}
sub get_du {
my ($c) = @_;
my $tx = $c->tx;
my $req = $tx->req;
# 3 env variables for durep.cgi
$ENV{'SCRIPT_NAME'} = 'durep';
$ENV{'REQUEST_METHOD'} = $req->method;
$ENV{'QUERY_STRING'} = $req->url->query->to_string;
my $res = `/etc/e-smith/web/panels/manager/html/durep/durep.cgi`;
$res =~ s|server-manager/durep|smanager/images|g;
my $step = 0; my $out;
my @lines = split /\n/, $res;
# remove except 'body'
foreach my $line (@lines) {
if ( $line =~ m|<body>| ) {
$step = 1;
} elsif ( $line =~ m|</body>| ) {
$step = 2;
} elsif ( $step == 1 ) {
$out .= $line;
}
}
return $out;
}
1;

View File

@@ -0,0 +1 @@
'dur_FORM_TITLE' => 'Disk usage report',

View File

@@ -0,0 +1,127 @@
/*
a:hover {
background-color: #DDDDDD;
}
body {
text-align: center;
background-color: #ffffff;
}
*/
div.tbar {
text-align: left;
width: 100%;
background-color: #EEEEEE;
border-top: solid 1px #DDDDDD;
border-bottom: solid 1px #DDDDDD;
}
div.bbar {
text-align: left;
width: 100%;
background-color: #EEEEEE;
border-top: solid 1px #DDDDDD;
border-bottom: solid 1px #DDDDDD;
}
div.bbar * {
font-size: 90%;
}
div.options {
text-align: left;
margin: 2em;
background-color: #EEEEEE;
border: solid 1px #DDDDDD;
}
.light {
background-color: #ffffff;
}
.mid {
background-color: #f6f6f6;
}
.dark {
background-color: #f0f0f0;
}
.tbar table {
width: 100%;
padding-left: 2pt;
font-weight: bold;
}
.bbar table {
width: 100%;
padding-left: 2pt;
}
table.list {
margin: 2em 0px;
border: solid 1px #CCCCCC;
margin-left: auto;
margin-right: auto;
}
table.list td {
text-align: left;
padding: 2px 5px;
}
table.list th {
text-align: left;
padding: 2px 5px;
text-align: left;
background-color: #DDDDDD;
}
table.report {
margin: 2em 0px;
border: solid 1px #CCCCCC;
text-align: left;
margin-left: auto;
margin-right: auto;
}
table.report td {
padding: 2px 5px;
}
table.report th {
padding: 2px 5px;
text-align: left;
background-color: #DDDDDD;
}
.graph {
padding: 0px;
background-color: #eeeeee;
width: 200px;
height: 15px;
}
th.right {
text-align: right;
}
td.right {
text-align: right;
}
span.dir {
font-weight: bold;
}
span.empty {
color: #006600;
font-weight: bold;
}
span.coalesced {
color: #880000;
font-weight: bold;
}

View File

@@ -0,0 +1,24 @@
% layout 'default', title => 'Sme server 2 - Durep';
% content_for 'head_contrib' => begin
%= stylesheet '/css/durep.css'
%end
% content_for 'module' => begin
% if ($config->{debug} == 1) {
<p>
%= dumper $c->current_route
</p>
% }
<div id="central" class="module durep-panel">
% if ( stash 'error' ) {
<br><div class=sme-error>
%= $c->render_to_string(inline => stash 'error')
</div>
%}
%= $c->render_to_string(inline => $modul)
</div>
% end

0
root/var/lib/durep/.gitignore vendored Normal file
View File

0
root/var/www/.gitignore vendored Normal file
View File