1: #!/usr/bin/perl -w
2:
3: require 5;
4: use strict;
5: use Getopt::Std;
6: use File::Find;
7: use vars qw(%opts @mailboxen $file $access $mod $user $unread $i $j @passwd $name @oldusers $mailbytes $mailsize $homebytes $homesize @sorted @units @multipliers $limit $outputstring $length);
8:
9: getopts('ho:al:', \%opts);
10:
11: sub usage(){
12: print <<EOF;
13: Usage: $0 [options]
14: Example: $0 -om -l m=10m
15: Synopsis: Checks the age and size of all mailboxen on the system, to help you isolate dead accounts, or disk hogs.
16:
17: -h : Displays this help screen.
18: -o : Order of results[1].
19: -a : List all users, not just those with unread mail.
20: -l : Limit. Format is 'F=LLU', comma seperated, where 'F' is the field[2], 'L' the limit, and 'U' the unit[3].
21: Example: $0 -l u=1w,m=5m
22: (This lists all users with unread mail who haven't checked there mailbox in over a week, and which is over 5 megabytes in size)
23:
24: [1]: Can be ordered by 'a' (alphabetic), 'u' (time mailbox unread), 'm' (mailbox size), 'h' (home dir size) or 't' (total disk usage).
25: [2]: Field can be any listed above, except 'a'.
26: [3]: Unit is the first letter of whichever unit you wish to use.
27: i.e. for times: 's' (second), 'm' (minute), 'h' (hour), 'd' (day), 'w' (week) or 'y' (year).
28: or for memory: 'b' (bytes), 'k' (Kb), 'm' (Mb) or 'g' (Gb).
29:
30: EOF
31: exit;
32: }
33:
34: if ($opts{'h'}){
35: usage();
36: }
37:
38: sub subdivide ($$\@\@$) {
39:
40: my ($ordinal, $unit, $result);
41: my $time = shift;
42: my $depth = shift;
43: my $mult_ref = shift;
44: my @multipliers = @$mult_ref;
45: my $unit_ref = shift;
46: my @Units = @$unit_ref;
47: my $pluralise = shift;
48:
49: my $k;
50: my $l = 1;
51: for ($k=0; $k<@units; $k++) {
52:
53: if ($k == @multipliers || $time < $l * $multipliers[$k]) {
54: $ordinal = int ( $time / $l );
55: $unit = $units[$k];
56: $time -= $ordinal * $l;
57: last;
58: }
59:
60: $l *= $multipliers[$k];
61: }
62:
63: if ($pluralise && ($ordinal > 1)) {
64: $unit .= 's';
65: }
66:
67: $result = "$ordinal $unit";
68:
69: if ($depth && $time) {
70: $result .= ", " . subdivide($time, --$depth, \@multipliers, \@units, $pluralise);
71: }
72:
73: return $result;
74: }
75:
76: sub multiplyup ($\@\@) {
77:
78: my $time = shift;
79: my $result = substr ($time, 0, -1);
80: my $unit = substr ($time, -1, 1);
81: my $mult_ref = shift;
82: my @multipliers = @$mult_ref;
83: my $unit_ref = shift;
84: my @Units = @$unit_ref;
85:
86: my $k;
87: for ($k=0; $k<@units; $k++) {
88:
89: if ($unit eq $units[$k]) {
90: last;
91: }
92:
93: $result *= $multipliers[$k];
94: }
95:
96: return $result;
97: }
98:
99: open PASSWD, "/etc/passwd" or die "Could now open /etc/passwd, wtf?";
100: @passwd = <PASSWD>;
101:
102: opendir MAIL, "/var/spool/mail" or die "Could not open /var/spool/mail, wtf?";
103: @mailboxen = grep { ! /^\..*$/ } readdir MAIL;
104: closedir MAIL;
105:
106: my $longestname = 0;
107:
108: for ($i=0; $i<@mailboxen; $i++) {
109:
110: $user = $mailboxen[$i];
111: $file = "/var/spool/mail/$user";
112:
113: $access = (-A $file);
114: $mod = (-M $file);
115:
116: if ($access > $mod || $opts{'a'}) {
117:
118: @multipliers = (60, 60, 24, 7, 365/7);
119: @units = ('second', 'minute', 'hour', 'day', 'week', 'year');
120: $unread = $access > $mod ? subdivide(int($access * 86400), 1, @multipliers, @units, 1) : "no time";
121:
122: for ($j=0; $j<@passwd; $j++) {
123: if ($passwd[$j] =~ /^$user:[^:]+:[^:]+:[^:]+:([^,:]+).+$/) {
124: $name = $1;
125: $name =~ s/\\//;
126: $name =~ s/(\b)(\w+)/$1\u\L$2/g;
127: last;
128: }
129: }
130:
131: if (length($name) > $longestname) { $longestname = length($name) }
132:
133: @multipliers = (1024, 1024, 1024);
134: @units = ('bytes', 'Kb', 'Mb', 'Gb');
135: $mailbytes = -s $file;
136: $mailsize = subdivide($mailbytes, 0, @multipliers, @units, 0);
137:
138: $homebytes = 0;
139: find sub { $homebytes += -s }, "/home/$user";
140: $homesize = subdivide($homebytes, 0, @multipliers, @units, 0);
141:
142: push @oldusers, { user => "$user",
143: unread => "$unread",
144: name => "$name",
145: access => $access > $mod ? "$access" : 0,
146: mailbytes => "$mailbytes",
147: mailsize => "$mailsize",
148: homebytes => "$homebytes",
149: homesize => "$homesize" };
150:
151: }
152: }
153:
154: if ( $opts{'l'} ) {
155: my %limits = split /[,=]/, $opts{'l'};
156:
157: if ( $limits{'u'} ) {
158: @multipliers = (60, 60, 24, 7, 365/7);
159: @units = ('s', 'm', 'h', 'd', 'w', 'y');
160: $limit = multiplyup($limits{'u'}, @multipliers, @units) / 86400;
161: @oldusers = grep { $_->{access} > $limit } @oldusers;
162: }
163:
164: if ( $limits{'m'} ) {
165: @multipliers = (1024, 1024, 1024);
166: @units = ('b', 'k', 'm', 'g');
167: $limit = multiplyup($limits{'m'}, @multipliers, @units);
168: @oldusers = grep { $_->{mailbytes} > $limit } @oldusers;
169: }
170:
171: if ( $limits{'h'} ) {
172: @multipliers = (1024, 1024, 1024);
173: @units = ('b', 'k', 'm', 'g');
174: $limit = multiplyup($limits{'h'}, @multipliers, @units);
175: @oldusers = grep { $_->{homebytes} > $limit } @oldusers;
176: }
177:
178: if ( $limits{'t'} ) {
179: @multipliers = (1024, 1024, 1024);
180: @units = ('b', 'k', 'm', 'g');
181: $limit = multiplyup($limits{'t'}, @multipliers, @units);
182: @oldusers = grep { $_->{mailbytes} + $_->{homebytes} > $limit } @oldusers;
183: }
184:
185: }
186:
187:
188: if ( !defined( $opts{'o'} ) || $opts{'o'} eq 'u') {
189: @sorted = sort { $b->{access} <=> $a->{access} } @oldusers;
190: }
191: elsif ($opts{'o'} eq 'm') {
192: @sorted = sort { $b->{mailbytes} <=> $a->{mailbytes} } @oldusers;
193: }
194: elsif ($opts{'o'} eq 'h') {
195: @sorted = sort { $b->{homebytes} <=> $a->{homebytes} } @oldusers;
196: }
197: elsif ($opts{'o'} eq 't') {
198: @sorted = sort { $b->{mailbytes} + $b->{homebytes} <=> $a->{mailbytes} + $a->{homebytes} } @oldusers;
199: }
200: elsif ($opts{'o'} eq 'a') {
201: @sorted = sort { $a->{name} cmp $b->{name} } @oldusers;
202: }
203: else {
204: warn "Bad ordering option, returning results unordered.";
205: }
206:
207: print "Name" . ' ' x ($longestname+1) ."Unread For Mailbox Size Home Dir Size\n";
208:
209: for ($i=0; $i<@sorted; $i++) {
210: $outputstring = "$sorted[$i]{name} " . '-' x $longestname;
211: $outputstring = substr($outputstring, 0, $longestname + 4);
212:
213: $outputstring .= " $sorted[$i]{unread} ----------------------";
214: $outputstring = substr($outputstring, 0, $longestname + 40 - length($sorted[$i]{mailsize}));
215:
216: $outputstring .= " $sorted[$i]{mailsize} ------------";
217: $outputstring = substr($outputstring, 0, $longestname + 56 - length($sorted[$i]{homesize}));
218:
219: $outputstring .= " $sorted[$i]{homesize}\n";
220:
221: print $outputstring;
222: }
223:
224: exit;