I’ve had a few issues with disk quotas recently on my OS X Server file servers, and I needed to come up with a way for my student assistants to be able to view disk quota values for my staff so that they could easily tell who was over or approaching their quota.
Read on for a way to monitor disk quotas in a web browser…I really don’t want to give them any shell or Server Admin access for this server, so I decided to whip something up in PHP to do this. Be warned that I don’t consider myself the best PHP programmer on the face of the planet, so it is likely there are more efficient ways to do this, and I know there are definitely more elegant solutions….
Efficiency suggestions would be appreciated, I promise not to get all macho-geek and deride them. 🙂
To get started, issue the following command at the terminal:
<code> /bin/date > /tmp/quotas && /usr/sbin/repquota -au >> /tmp/quotas </code>
What this does is execute the command “date”, which will give you output something like:
<code> Mon Dec 6 08:57:25 EST 2004 </code>
The ‘>’ redirects the output to replace the file “/tmp/quotas”.
The ‘&&’ means execute another command afterwards, in this case “repquota -au”, which reports all user quotas for all local filesystems.
The ‘>>’ redirects the output to append to the file “/tmp/quotas”.
If you have a look at this file, you’ll see something like:
<code> me@server: ~ $ head /tmp/quotas Mon Dec 6 09:00:00 EST 2004 1K Block limits File limits User used soft hard grace used soft hard grace cherylstaff-- 2755724 0 0 15678 0 0 brucestaff -- 5738512 0 0 7830 0 0 </code>
The output of this is kind of ugly, so you’ll see there is a fair bit of munging going on in the php code to clean it up.
The output will look something like this example screenshot.
And here is the PHP code I use to display this. By default it will sort in descending order by the percent of quota used, so that the users closest to their quota will appear at the top. You can sort by any column however. The “$warnlimit” variable means that users who are above this value will appear in red and in a larger font.
You can also download the script as a file.
<code> <html> <head><title>File Quota Report</title> <style> body { color: black; background: white; margin-left: 10% } .list0 {font:12px Arial,Helvetica; color:#000000; background-color:#eeeeee} .list1 {font:12px Arial,Helvetica; color:#000000; background-color:#cccccc} .headerrow {font:18px Arial,Helvetica; color:#000000; background-color:#888888} .warn {font:14px Arial, Helvetica, sans-serif; color:#ff0000; } </style> </head> <body> <?php $quotafile = file ("/tmp/quotas"); $colour = 0; $self = $_SERVER['PHP_SELF']; $warnlimit = 70; echo "<b>Report Date:</b><i> $quotafile[0]</i><br /><br />"; $quotas = array(); for ($i=3 ; $i < count($quotafile) ; $i++) { $thisline = $quotafile[$i]; $thisline = preg_replace("/([\s]--)/", "", $thisline); $thisline = preg_split("/(\s)/e", $thisline, -1, PREG_SPLIT_NO_EMPTY); $quotas[$i]['user'] = str_replace("--", "", $thisline[0]); $quotas[$i]['mb_used'] = round (($thisline[1] / 1024), 2); $quotas[$i]['mb_soft'] = round (($thisline[2] / 1024), 2); $quotas[$i]['mb_hard'] = round (($thisline[3] / 1024), 2); if ($thisline[3] != 0) { $quotas[$i]['mb_percent_used'] = round((($quotas[$i]['mb_used'] / $quotas[$i]['mb_hard']) * 100), 1); } else { $quotas[$i]['mb_percent_used'] = 0; } $quotas[$i]['file_used'] = $thisline[4]; $quotas[$i]['file_soft'] = $thisline[5]; $qoutas[$i]['file_hard'] = $thisline[6]; } if (!$_GET['sort']) { $sort = 'mb_percent_used'; } else { $sort = $_GET['sort']; } if (!$_GET['order']) { $order = "desc"; } else { $order = $_GET['order']; } foreach ($quotas as $key => $row) { $user[$key] = $row['user']; $mb_used[$key] = $row['mb_used']; $mb_soft[$key] = $row['mb_soft']; $mb_hard[$key] = $row['mb_hard']; $mb_percent_used[$key] = $row['mb_percent_used']; $file_used[$key] = $row['file_used']; $file_soft[$key] = $row['file_soft']; $file_hard[$key] = $row['file_hard']; } switch ($sort) { case "user": $sortkey =& $user; break; case "mb_used": $sortkey =& $mb_used; break; case "mb_soft": $sortkey =& $mb_soft; break; case "mb_hard": $sortkey =& $mb_hard; break; case "mb_percent_used": $sortkey =& $mb_percent_used; break; case "file_used": $sortkey =& $file_used; break; case "file_soft": $sortkey =& $file_used; break; case "file_hard": $sortkey =& $file_hard; break; } switch ($order) { case "asc": $sortorder = SORT_ASC; $newsort = "desc"; break; case "desc": $sortorder = SORT_DESC;$newsort = "asc"; break; } array_multisort($sortkey, $sortorder, $quotas); echo '<table border="0" cellpadding="3">'; echo '<tr class="headerrow">'; echo '<td>'; echo '<a href="' . $self . '?sort=user&order='; if ($sort == "user") { echo $newsort; } else { echo 'asc'; } echo '">User</a>'; echo '</td>'; echo '<td>'; echo '<a href="' . $self . '?sort=mb_used&order='; if ($sort == "mb_used") { echo $newsort; } else { echo 'asc'; } echo '">Used (Mb)</a>'; echo '</td>'; echo '<td>'; echo '<a href="' . $self . '?sort=mb_soft&order='; if ($sort == "mb_soft") { echo $newsort; } else { echo 'asc'; } echo '">SoftQuota(Mb)</a>'; echo '</td>'; echo '<td>'; echo '<a href="' . $self . '?sort=mb_hard&order='; if ($sort == "mb_hard") { echo $newsort; } else { echo 'asc'; } echo '">HardQuota(Mb)</a>'; echo '</td>'; echo '<td>'; echo '<a href="' . $self . '?sort=mb_percent_used&order='; if ($sort == "mb_percent_used") { echo $newsort; } else { echo 'asc'; } echo '">% Used</a>'; echo '</td>'; echo '<td>'; echo '<a href="' . $self . '?sort=file_used&order='; if ($sort == "file_used") { echo $newsort; } else { echo 'asc'; } echo '">Used(files)</a>'; echo '</td>'; echo '<td>'; echo '<a href="' . $self . '?sort=file_soft&order='; if ($sort == "file_soft") { echo $newsort; } else { echo 'asc'; } echo '">SoftQuota(Files)</a>'; echo '</td>'; echo '</tr>'; foreach ($quotas as $quotareport) { if ($colour == 0) { $colour = 1; } else { $colour = 0; } if ( $quotareport['mb_percent_used'] > $warnlimit) { $warn = 1; } else { $warn = 0; } echo '<tr class="list' . $colour . '">'; foreach ($quotareport as $quotaelement) { if ($warn) { echo '<td class="warn">' . $quotaelement . '</td>'; } else { echo '<td>' . $quotaelement . '</td>'; } } echo '</tr>'; } echo '</table>'; ?> </table> </body> </html> </code>
Securing access to this file is up to you!
I’m not going to cover any Apache realm stuff as there is a wealth of documentation out there about it.
So, to keep this current, I have the following line in /etc/crontab
<code> */5 * * * * root /bin/date > /tmp/quotas && /usr/sbin/repquota -au >> /tmp/quotas </code>
This means that every five minutes, a quota report is dumped to “/tmp/quotas”. People viewing the php page can look at the date at the top of the file to see how current it is.
I’ve done the same thing for Cyrus mail quotas by the way, so if anyone is interested, I could post that code. It is almost exactly the same, but the file munging is slightly different.
Over-quota users tends to be a chronic problem for me too. Here’s a script I
made for checking the quota status for users with networked home folders on
the client side as they login. Call it quotagauge and stick it in /usr/local/
bin/:
Create an AppleScript application to act as a wrapper with the following code:
Put the AppleScript in /Library/Scripts/ and add to to all your users Login
Items.
Letting users know where they stand in terms of remaining quota space at
login has really cut down on the number problems. Hope this helps.
That’s an excellent idea. nice one.
Do you find that the time to execute the ‘du’ command is too long? Perhaps it
would be better to combine it with my method to grab the quota usage from
the server directly, as it is keeping track of it all anyway.
I might take that and modify that way, and change it to be used with LanOSD
so that you get really pretty messages… 🙂
Yeah, du is pretty slow, isn’t it? I’d like to see what you do this.
LanOSD looks really cool; I’ve never seen see it before.
Funny, I was thinking "Hey, this quotagauge script looks <i>familiar</i>" then I look at who posted.
I made similar changes for LDAP and it gets hung up at du as well.
This is really cool, I think I’ll give a shot at integrating the two approaches.
Ha ha, my script-fu is world famous! Or at least CCA famous…
hi
new to scripts, but like the idea of this. would be great if this could be modified
to show a student when they log in how much of thier allocated space they
have used… how have you implemented this?
any help greatly appreciated
many thanks
chris