diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbb3a13 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.rpm +*.log +*spec-20* +*.tar.gz diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2c0d480 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +# Makefile for source rpm: smeserver-durep +# $Id: Makefile,v 1.1 2020/10/23 10:38:14 brianr Exp $ +NAME := smeserver-durep +SPECFILE = $(firstword $(wildcard *.spec)) + +define find-makefile-common +for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done +endef + +MAKEFILE_COMMON := $(shell $(find-makefile-common)) + +ifeq ($(MAKEFILE_COMMON),) +# attept a checkout +define checkout-makefile-common +test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2 +endef + +MAKEFILE_COMMON := $(shell $(checkout-makefile-common)) +endif + +include $(MAKEFILE_COMMON) diff --git a/README.md b/README.md index 3d2d25a..c3256f8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,15 @@ -# smeserver-durep +# smeserver-durep -SMEServer Koozali developed git repo for smeserver-durep smecontribs \ No newline at end of file +SMEServer Koozali developed git repo for smeserver-durep smecontribs + +## Wiki +
https://wiki.koozali.org/Durep + +## Bugzilla +Show list of outstanding bugs: [here](https://bugs.koozali.org/buglist.cgi?component=smeserver-durep&product=SME%20Contribs&query_format=advanced&limit=0&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=CONFIRMED) + +## Description + +
*This description has been generated by an LLM AI system and cannot be relied on to be fully correct.* +*Once it has been checked, then this comment will be deleted* +
diff --git a/additional/CHANGELOG.git b/additional/CHANGELOG.git new file mode 100644 index 0000000..6293558 --- /dev/null +++ b/additional/CHANGELOG.git @@ -0,0 +1,18 @@ +commit b29b1c88044b93702cf926739a05792467cc2ab8 +Author: Stephane de Labrusse +Date: Sat Jun 21 12:27:27 2014 +0200 + + modification find in thread https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=482061 of closedir() attempted on invalid dirhandle DIR + +commit 519860b663752fd066111497d32ab24411c31ec9 +Author: Stephane de Labrusse +Date: Sat Jun 21 11:57:46 2014 +0200 + + * Sat Jun 21 2014 stephane de Labrusse 1.5.0-1.sme + - Initial release to sme9 + +commit e81c813da1cb02ddd21c31241ccac8b6cdbd9e1d +Author: Stephane de Labrusse +Date: Sat Jun 21 11:55:52 2014 +0200 + + first commit to SME Server 9 diff --git a/additional/README.md b/additional/README.md new file mode 100644 index 0000000..d40bf3b --- /dev/null +++ b/additional/README.md @@ -0,0 +1 @@ +smeserver-durep is a contrib for SME Server, a Linux distro oriented server. see http://wiki.contribs.org diff --git a/additional/smeserver-durep.spec b/additional/smeserver-durep.spec new file mode 100644 index 0000000..515f684 --- /dev/null +++ b/additional/smeserver-durep.spec @@ -0,0 +1,99 @@ +# $Id: smeserver-durep.spec,v 1.3 2012/08/15 22:15:30 unnilennium Exp $ +# Authority: unnilennnium +# Name: JP Pialasse + +%define name smeserver-durep +Name: %{name} +%define version 1.5.0 +Version: %{version} +%define release 1 +Release: %{release}%{?dist} +License: GPL +Source: %{name}-%{version}.tar.gz +BuildRoot: /var/tmp/%{name}-%{version}-buildroot +BuildRequires: e-smith-devtools +BuildArch: noarch +Group: Networking/Daemons +Summary: DUREP - Graphic Report for Disk Usage +Requires: perl(Data::Dumper) +Requires: perl(MLDBM) >= 1.21-4 +Obsoletes: smeserver-durep-saco +Obsoletes: e-smith-durep + + +%changelog +* Sat Jun 21 2014 stephane de Labrusse 1.5.0-1.sme +- Initial release to sme9 + +* Thu Sep 13 2012 JP Pialasse 1.3.0-6.sme +- add Obsoletes smeserver-durep-saco e-smith-durep [SME 7108] +- TODO cleaning spec file post and filelist chmod + +* Mon Sep 10 2012 JP Pialasse 1.3.0-5.sme +- fix do not copy files and filelist [SME 7098] +- patch df of plugged disk + +* Sun Sep 09 2012 JP Pialasse 1.3.0-4.sme +- dependencies resolution + +* Fri Aug 31 2012 JP Pialasse 1.3.0-3.sme +- build error fix : prep setup + +* Wed Aug 15 2012 JP Pialasse 1.3.0-1.sme +- update from 1.03-02sn to comply with SME8 and SME7 +- moved archives to /var/lib/durep +- moved web files to manager/html +- cleaned spec + +%description +DUREP is a Report Generator that creates graphical Output for the "du" command + +%prep +%setup + +%install +/bin/rm -rf $RPM_BUILD_ROOT +(cd root; /usr/bin/find . -depth -print | /bin/cpio -dump $RPM_BUILD_ROOT) +/bin/rm -f %{name}-%{version}-filelist +/sbin/e-smith/genfilelist $RPM_BUILD_ROOT > %{name}-%{version}-filelist + + +%clean +/bin/rm -rf $RPM_BUILD_ROOT + +%files -f %{name}-%{version}-filelist +%defattr(-,root,root) + +#%attr(0644 root root) "/etc/e-smith/templates/etc/crontab/durep" +#%attr(4750 root admin) "/etc/e-smith/web/functions/durep" +#%attr(0777 root root) "/etc/e-smith/web/panels/manager/cgi-bin/durep" +#%attr(0644 root root) "/usr/local/bin/durep" +#%dir %attr(0755 root root) "/usr/local/man" +#%dir %attr(0755 root root) "/usr/local/man/man1" +#%attr(0644 root root) "/usr/local/man/man1/durep.1" +#%dir %attr(0755 root root) "/usr/sbin" +#%attr(0644 root root) "/usr/sbin/durep.daily" +#%dir %attr(0755 root root) "/var/lib/durep" +#%dir %attr(0755 root root) "/etc/e-smith/web/panels/manager/html/durep" +#%attr(0644 root root) "/etc/e-smith/web/panels/manager/html/durep/bar.png" +#%attr(0644 root root) "/etc/e-smith/web/panels/manager/html/durep/durep.cgi" +#%attr(0644 root root) "/etc/e-smith/web/panels/manager/html/durep/style.css" + +%pre -p /bin/sh + +%post -p /bin/sh +chmod 755 /usr/local/bin/durep +chmod 755 /usr/sbin/durep.daily +/sbin/e-smith/expand-template /etc/crontab +echo "Initial run of durep ... please wait." +/usr/sbin/durep.daily >/dev/null +/etc/e-smith/events/actions/navigation-conf >/dev/null 2>&1 + +%preun -p /bin/sh + +%postun -p /bin/sh +if [ "$1" = 0 ]; then + /sbin/e-smith/expand-template /etc/crontab + /etc/e-smith/events/actions/navigation-conf 2>/dev/null +fi + diff --git a/contriborbase b/contriborbase new file mode 100644 index 0000000..9b7fd51 --- /dev/null +++ b/contriborbase @@ -0,0 +1 @@ +contribs10 diff --git a/createlinks b/createlinks new file mode 100644 index 0000000..d435bf2 --- /dev/null +++ b/createlinks @@ -0,0 +1,33 @@ +#!/usr/bin/perl -w +# This script creates the symlinks needed by this RPM +# Specific support exists to create symlinks within e-smith web "panels" +# and for links from named "events" directories into the "actions" directory +use esmith::Build::CreateLinks qw(:all); + +safe_symlink("/etc/e-smith/web/functions/wrapper","root/etc/e-smith/web/panels/manager/cgi-bin/durep"); + +#-------------------------------------------------- +# actions for post-upgrade: +#-------------------------------------------------- +$event = "post-upgrade"; +event_link("durep-init", $event, "90"); + +#-------------------------------------------------- +# actions for smeserver-durep-update event: +#-------------------------------------------------- +$event = "smeserver-durep-update"; + +event_link("navigation-conf", $event, "50"); +event_link("durep-init", $event, "90"); +templates2events("/etc/crontab", $event ); + +safe_symlink('restart', "root/etc/e-smith/events/$event/services2adjust/smanager"); +event_link('navigation2-conf', "$event", '80'); +event_link('routes2-conf', "$event", '80'); +event_link('locales2-conf', "$event", '80'); +safe_symlink('/etc/e-smith/web/panels/manager/html/durep/bar.png', 'root/usr/share/smanager/themes/default/public/images/bar.png'); + +use esmith::Build::Backup qw(:all); +backup_includes("smeserver-durep", qw( +/var/lib/durep +)); diff --git a/root/etc/e-smith/db/configuration/defaults/durep/folders b/root/etc/e-smith/db/configuration/defaults/durep/folders new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/root/etc/e-smith/db/configuration/defaults/durep/folders @@ -0,0 +1 @@ + diff --git a/root/etc/e-smith/db/configuration/defaults/durep/status b/root/etc/e-smith/db/configuration/defaults/durep/status new file mode 100644 index 0000000..86981e6 --- /dev/null +++ b/root/etc/e-smith/db/configuration/defaults/durep/status @@ -0,0 +1 @@ +enabled diff --git a/root/etc/e-smith/db/configuration/defaults/durep/type b/root/etc/e-smith/db/configuration/defaults/durep/type new file mode 100644 index 0000000..24e1098 --- /dev/null +++ b/root/etc/e-smith/db/configuration/defaults/durep/type @@ -0,0 +1 @@ +service diff --git a/root/etc/e-smith/events/actions/durep-init b/root/etc/e-smith/events/actions/durep-init new file mode 100644 index 0000000..533f177 --- /dev/null +++ b/root/etc/e-smith/events/actions/durep-init @@ -0,0 +1,3 @@ +#!/bin/bash +echo "Initial run of durep ... please wait." +/usr/sbin/durep.daily >/dev/null diff --git a/root/etc/e-smith/templates/etc/crontab/durep b/root/etc/e-smith/templates/etc/crontab/durep new file mode 100644 index 0000000..6b8efdc --- /dev/null +++ b/root/etc/e-smith/templates/etc/crontab/durep @@ -0,0 +1,4 @@ + +# Generate DUREP reports + +01 0 * * * root /usr/sbin/durep.daily diff --git a/root/etc/e-smith/templates/etc/httpd/admin-conf/httpd.conf/90e-smithAccess40durep b/root/etc/e-smith/templates/etc/httpd/admin-conf/httpd.conf/90e-smithAccess40durep new file mode 100644 index 0000000..5c4521a --- /dev/null +++ b/root/etc/e-smith/templates/etc/httpd/admin-conf/httpd.conf/90e-smithAccess40durep @@ -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 .= " \n"; + $OUT .= " require user admin$panelshash{$file}\n"; + $OUT .= " \n"; + +} + diff --git a/root/etc/e-smith/web/functions/durep b/root/etc/e-smith/web/functions/durep new file mode 100755 index 0000000..09a85fd --- /dev/null +++ b/root/etc/e-smith/web/functions/durep @@ -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); +} diff --git a/root/etc/e-smith/web/panels/manager/cgi-bin/durep b/root/etc/e-smith/web/panels/manager/cgi-bin/durep new file mode 120000 index 0000000..567930b --- /dev/null +++ b/root/etc/e-smith/web/panels/manager/cgi-bin/durep @@ -0,0 +1 @@ +../../../functions/durep \ No newline at end of file diff --git a/root/etc/e-smith/web/panels/manager/html/durep/bar.png b/root/etc/e-smith/web/panels/manager/html/durep/bar.png new file mode 100644 index 0000000..ea64e90 Binary files /dev/null and b/root/etc/e-smith/web/panels/manager/html/durep/bar.png differ diff --git a/root/etc/e-smith/web/panels/manager/html/durep/durep.cgi b/root/etc/e-smith/web/panels/manager/html/durep/durep.cgi new file mode 100755 index 0000000..b191a45 --- /dev/null +++ b/root/etc/e-smith/web/panels/manager/html/durep/durep.cgi @@ -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($_ = ); + } + 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 "SMESERVER Disk Usage Report"; + print "

"; + + print ""; + while(($key, $val) = each %input) { + my $length = length $val; + print "\n"; + } + print "
$key
[$length]
[$val]
"; + print ""; +} + +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{ + + + +Disk Usage Report + + + +

Disk Usage Report

+ + +}; + foreach my $host (keys %{$hash}) { + print "\n"; + my $flip = 0; + foreach my $e (reverse sort sortByDate @{$hash->{$host}}) { + if($flip) { print ""; } + else { print ""; } + $flip = !$flip; + print ""; + print ""; + printf "", $e->{DESC} || "-"; + printf "", prettyFileSize($e->{SIZE}); + printf "", prettyNum($e->{DIR_COUNT}); + printf "", prettyNum($e->{FILE_COUNT}); + printf "", prettyDate($e->{LAST_UPDATE}); + print "\n"; + } + } +# table to show df of all disk on main page + print qq{ +
 PathDescriptionSizeDirsFilesDate
$host
 $e->{PATH}%s%s%s%s%s
+ + +}; +my $dflist = `df -hP|grep -v 'Use%'|sed 's#^##g'`; +$dflist =~ s/[ ]+/<\/td>
FilesystemSizedUsedAvailableUse %Mounted on
#g'|sed 's#\$#
/g; +print $dflist; + + + print qq{ +
+ + +}; +} + +sub displayData { + print "Content-type: text/html\n\n"; + + my ($key, $val); +print qq{ + + + +Disk Usage Report ($data->{HOSTNAME}) + + + +

Disk Usage Report ($data->{HOSTNAME})

+
"; + printf "", prettyFileSize($top_node->{SIZE}); + print "
[Home] +}; + foreach my $tmp (@ancestors) { + printf "$tmp->{NAME}%s", $tmp->{ID}, (($tmp->{NAME} =~ m|\/$|) ? "" : "/"); + } + print "$top_node->{NAME}%s
"; + + print "\n"; + print ""; + print ""; + print "" if $show_mtime; + print ""; + + my $flip = 0; + foreach my $node (@records) { + my $percent = $top_node->{SIZE} ? ($node->{SIZE}/$top_node->{SIZE}*100) : 0; + if($flip) { print ""; } + else { print ""; } + $flip = !$flip; + print "", $percent); + + if($node->{TYPE} & $TYPE_DIR) { + if($node->{TYPE} & $TYPE_EMPTY) { + print ""; + printf("", shortDate($node->{MTIME})) if $show_mtime; + print ""; + } + else { + printf("", $node->{DCOUNT}); + printf("", $node->{FCOUNT}); + printf("", shortDate($node->{MTIME})) if $show_mtime; + print ""; + } + } + elsif($node->{TYPE} & $TYPE_COALESCED) { + printf "", $node->{FCOUNT}; + printf("", shortDate($node->{MTIME})) if $show_mtime; + print ""; + } + else { + print ""; + printf("", shortDate($node->{MTIME})) if $show_mtime; + print ""; + } + print "\n"; + } + print "
SizePercentageDirsFilesModifiedFile
"; + print prettyFileSize($node->{SIZE}); + print ""; + print barChart($percent); + printf("%4.2f%%00%s$node->{NAME}/%d%d%s$node->{NAME}/ %d%s$node->{NAME}  %s$node->{NAME}
\n"; + + print "
"; + printf "", scalar localtime($data->{LAST_UPDATE}); + print ""; + print "
%sGenerated by durep v. $version
\n"; + + if($show_opts && $data->{OPTIONS}) { + print "
    "; + print "
  • Scanning files only.
  • " if $data->{OPTIONS}->{FILES}; + print "
  • Restricting to single filesystem.
  • " if $data->{OPTIONS}->{ONEFILESYSTEM}; + printf "
  • Collapsing paths matching %s.
  • ", $data->{OPTIONS}->{COLLAPSEPATH} if $data->{OPTIONS}->{COLLAPSEPATH}; + printf "
  • Excluding paths matching %s.
  • ", $data->{OPTIONS}->{EXCLUDEPATH} if $data->{OPTIONS}->{EXCLUDEPATH}; + printf "
  • Coalescing files below %s.
  • ", prettyFileSize($data->{OPTIONS}->{COALESCEFILES}) if $data->{OPTIONS}->{COALESCEFILES}; + print "
"; + } + print ""; +} + +### All this does is create an HTML table bar graph type thingy. +sub barChart { + my $percent = int($_[0]*2+0.5); + my $rv = "
"; + if($percent) { + $rv .= ""; + } + else { + $rv .= " "; + } + $rv .= "
"; + 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{ + + + +Disk Usage Report + + + +

Durep encountered an error!

+

Please check that you have collated the files and that the permissions on them are correct.

+ + +}; +exit 0; +} diff --git a/root/etc/e-smith/web/panels/manager/html/durep/style.css b/root/etc/e-smith/web/panels/manager/html/durep/style.css new file mode 100644 index 0000000..46b03d4 --- /dev/null +++ b/root/etc/e-smith/web/panels/manager/html/durep/style.css @@ -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; +} + diff --git a/root/etc/e-smith/web/panels/user/html/durep b/root/etc/e-smith/web/panels/user/html/durep new file mode 120000 index 0000000..ce314cb --- /dev/null +++ b/root/etc/e-smith/web/panels/user/html/durep @@ -0,0 +1 @@ +/etc/e-smith/web/panels/manager/html/durep \ No newline at end of file diff --git a/root/usr/local/bin/durep b/root/usr/local/bin/durep new file mode 100755 index 0000000..95210c2 --- /dev/null +++ b/root/usr/local/bin/durep @@ -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 < save the results of the scan into this file + -lf, --load-file= load the results of a scan from this file + -d, --desc= give description of save file + -c, --collate= 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= hide entries below paths that match regexp + -ep, --exclude-path= 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; +} + diff --git a/root/usr/local/man/man1/durep.1 b/root/usr/local/man/man1/durep.1 new file mode 100644 index 0000000..520fa85 --- /dev/null +++ b/root/usr/local/man/man1/durep.1 @@ -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 diff --git a/root/usr/sbin/durep.daily b/root/usr/sbin/durep.daily new file mode 100644 index 0000000..0fe8444 --- /dev/null +++ b/root/usr/sbin/durep.daily @@ -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 + diff --git a/root/usr/share/smanager/lib/SrvMngr/Controller/Durep.pm b/root/usr/share/smanager/lib/SrvMngr/Controller/Durep.pm new file mode 100644 index 0000000..6226961 --- /dev/null +++ b/root/usr/share/smanager/lib/SrvMngr/Controller/Durep.pm @@ -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|| ) { + $step = 1; + } elsif ( $line =~ m|| ) { + $step = 2; + } elsif ( $step == 1 ) { + $out .= $line; + } + } + return $out; +} + + +1; diff --git a/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Durep/durep_en.lex b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Durep/durep_en.lex new file mode 100644 index 0000000..1819b7f --- /dev/null +++ b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Durep/durep_en.lex @@ -0,0 +1 @@ +'dur_FORM_TITLE' => 'Disk usage report', diff --git a/root/usr/share/smanager/themes/default/public/css/durep.css b/root/usr/share/smanager/themes/default/public/css/durep.css new file mode 100644 index 0000000..a788457 --- /dev/null +++ b/root/usr/share/smanager/themes/default/public/css/durep.css @@ -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; +} + diff --git a/root/usr/share/smanager/themes/default/templates/durep.html.ep b/root/usr/share/smanager/themes/default/templates/durep.html.ep new file mode 100644 index 0000000..c5820de --- /dev/null +++ b/root/usr/share/smanager/themes/default/templates/durep.html.ep @@ -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) { +

+ %= dumper $c->current_route +

+ % } + +
+ % if ( stash 'error' ) { +
+ %= $c->render_to_string(inline => stash 'error') +
+ %} + + %= $c->render_to_string(inline => $modul) + +
+% end diff --git a/root/var/lib/durep/.gitignore b/root/var/lib/durep/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/root/var/www/.gitignore b/root/var/www/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/smeserver-durep.spec b/smeserver-durep.spec new file mode 100644 index 0000000..fd0faef --- /dev/null +++ b/smeserver-durep.spec @@ -0,0 +1,151 @@ +# $Id: smeserver-durep.spec,v 1.15 2024/03/01 15:05:04 brianr Exp $ +# Authority: unnilennnium +# Name: JP Pialasse + +%define name smeserver-durep +Name: %{name} +%define version 1.5.0 +Version: %{version} +%define release 18 +Release: %{release}%{?dist} +License: GPL +Source: %{name}-%{version}.tar.xz + + +BuildRoot: /var/tmp/%{name}-%{version}-buildroot +BuildRequires: e-smith-devtools +BuildArch: noarch +Group: Networking/Daemons +Summary: DUREP - Graphic Report for Disk Usage +Requires: perl(Data::Dumper) +Requires: perl(MLDBM) >= 1.21-4 +Obsoletes: smeserver-durep-saco +Obsoletes: e-smith-durep + +AutoReqProv: no + +%changelog +* Sat Sep 07 2024 cvs2git.sh aka Brian Read 1.5.0-18.sme +- Roll up patches and move to git repo [SME: 12338] + +* Sat Sep 07 2024 BogusDateBot +- Eliminated rpmbuild "bogus date" warnings due to inconsistent weekday, + by assuming the date is correct and changing the weekday. + +* Fri Mar 01 2024 Brian Read 1.5.0-17.sme +- Edit SM2 Menu entry to conform to new arrangements [SME: 12493] + +* Thu Mar 23 2023 Michel Begue 1.5.0-16.sme +- fix typo in previous release [SME: 12342] + +* Wed Mar 22 2023 Michel Begue 1.5.0-15.sme +- allow access to bar.png image in SM2 [SME: 12342] + +* Sat Jul 30 2022 Brian Read 1.5.0-14.sme +- Re-build and link to latest devtools [SME: 11997] + +* Fri Jul 22 2022 Jean-Philippe Pialasse 1.5.0-13.sme +- add to core backup [SME: 12007] + +* Wed May 18 2022 Jean-Philippe Pialasse 1.5.0-12.sme +- allow access to user with userpanel [SME: 11975] + +* Sat Jan 08 2022 Michel Begue 1.5.0-11.sme +- Re-build and link to latest devtools wrong localisation directory [SME: 11841] + +* Fri Jan 07 2022 Brian Read 1.5.0-10.sme +- Add-class-to-div-for-AdminLTE [SME: 11835] + +* Thu Jun 03 2021 Michel Begue 1.5.0-9.sme +- first use with smeserver-manager [SME: 11618] + +* Thu Mar 04 2021 Jean-Philipe Pialasse 1.5.0-8.sme +- Re-build and link to latest devtools permissions of cgi inside spec file too + +* Thu Mar 04 2021 Michel Begue 1.5.0-7.sme +- Re-build and link to latest devtools permissions of cgi and data files + +* Mon Feb 22 2021 Jean-Philipe Pialasse 1.5.0-6.sme +- add smeserver-durep-update event [SME: 10893] + make up spec file + +* Fri Oct 23 2020 Brian Read 1.5.0-5.sme +- Initial import to SME10 tree [SME: 10893] +- Add in link to wrapper in createlinks + +* Sat Dec 28 2019 Jean-Philipe Pialasse 1.5.0-4.sme +- output all mounted points with df on one line using Posix + +* Sat Feb 10 2018 Jean-Philipe Pialasse 1.5.0-3.sme +- add hability to stat more directories [SME: 10118] +- add status enabled or disabled + +* Sat Aug 22 2015 stephane de Labrusse 1.5.0-2.sme +- Initial release to contribs9 + +* Sat Jun 21 2014 stephane de Labrusse 1.5.0-1.sme +- Initial release to sme9 + +* Thu Sep 13 2012 JP Pialasse 1.3.0-6.sme +- add Obsoletes smeserver-durep-saco e-smith-durep [SME 7108] +- TODO cleaning spec file post and filelist chmod + +* Mon Sep 10 2012 JP Pialasse 1.3.0-5.sme +- Re-build and link to latest devtools do not copy files and filelist [SME 7098] +- patch df of plugged disk + +* Sun Sep 09 2012 JP Pialasse 1.3.0-4.sme +- dependencies resolution + +* Fri Aug 31 2012 JP Pialasse 1.3.0-3.sme +- build error fix : prep setup + +* Wed Aug 15 2012 JP Pialasse 1.3.0-1.sme +- update from 1.03-02sn to comply with SME8 and SME7 +- moved archives to /var/lib/durep +- moved web files to manager/html +- cleaned spec + +%description +DUREP is a Report Generator that creates graphical Output for the "du" command + +%prep +%setup + +%build +perl createlinks + +%install +/bin/rm -rf $RPM_BUILD_ROOT +(cd root; /usr/bin/find . -depth -print | /bin/cpio -dump $RPM_BUILD_ROOT) +/bin/rm -f %{name}-%{version}-filelist +/sbin/e-smith/genfilelist $RPM_BUILD_ROOT \ + --file "/usr/local/bin/durep" 'attr(0755,root,root)' \ + --file "/usr/sbin/durep.daily" 'attr(0755,root,root)' \ + --file '/etc/e-smith/web/panels/manager/html/durep/durep.cgi' 'attr(0750,root,admin)' \ +> %{name}-%{version}-filelist + + +%clean +/bin/rm -rf $RPM_BUILD_ROOT + +%files -f %{name}-%{version}-filelist +%defattr(-,root,root) + +%pre -p /bin/sh + +%post -p /bin/sh + +if (systemctl list-unit-files |grep smanager) then + echo "Smanager restart in spec file" + /sbin/e-smith/signal-event smanager-refresh; +fi + + +%preun -p /bin/sh + +%postun -p /bin/sh +if [ $1 = 0 ] ; then + /bin/rm -f /usr/share/smanager/themes/default/images/bar.png +fi +true