Quota support on Mac OS X

Setup | Recording Usage | Imposing Limits

Various quota systems exist for Unix operating systems. These record disk usage on a per-user (and per-group) basis, and optionally impose disk usage limits. Mac OS X version 10.2 ships with the Berkeley Software Distribution (BSD) quota system. These notes cover manual setup of quota support on a Mac OS X 10.2.6 system, along with uses of disk quotas. Those in a hurry should consider the following article: an easy method of creating disk quotas for users.

Quota setup works under Mac OS X Tiger (10.4.2). Soft limits do not issue any warning, while hard limits should display some sort of error message. To handle soft limit violations, create a script that checks for users above the soft limit and notify them.


The quotacheck(8) command reports estimates of disk usage. This poses a problem, as the man(1) pages on Mac OS X 10.2 incorrectly state the quota file locations. Now, a digression into Unix debugging. To determine what file the quotacheck command needs, use the kernel tracing facility via the ktrace(1) command. The results of ktrace can be read from ktrace.out with the kdump(1) command.

$ sudo ktrace quotacheck -a
$ sudo kdump -f ktrace.out | fgrep .quota
7870 quotacheck NAMI "//.quota.ops.group"
7870 quotacheck NAMI "//.quota.ops.user"
7870 quotacheck NAMI "/Volumes/Spider/.quota.ops.group"
7870 quotacheck NAMI "/Volumes/Spider/.quota.ops.user"

The trace output shows quotacheck looking on the startup disk and an external firewire disk for the user and group quota setting files, .quota.ops.user and .quota.ops.group. These files must be created on each filesystem quota support will be enabled on, which can be done from the ktrace.out file with shell scripting.

$ sudo kdump -f ktrace.out | fgrep quota.ops | \
perl -nle 'print /"([^"]+)"/' | xargs sudo touch

$ sudo rm ktrace.out
$ ls /.quota* /Volumes/Spider/.quota*
/.quota.ops.group /Volumes/Spider/.quota.ops.group
/.quota.ops.user /Volumes/Spider/.quota.ops.user

Now quotacheck provides disk usage on all currently mounted filesystems; the results of the run will be saved to the .quota.{user,group} index files:

$ sudo quotacheck -a
quotacheck: creating quota file //.quota.user
quotacheck: creating quota file //.quota.group
quotacheck: creating quota file /Volumes/Spider/.quota.user
quotacheck: creating quota file /Volumes/Spider/.quota.group

One way to view the resulting disk usage data is via the repquota(8) command.

$ sudo repquota -a -v

With empty .quota.ops.* quota configuration files, there should be no user or group disk space limitations. Current limitations can be viewed with the quota(1) command.

$ sudo quota
Disk quotas for user root (uid 0): none

To enable automatic quota index updates without rebooting the system, use the quotaon(8) command. The quotaon manual indicates quota support will be automatically enabled at filesystem mount time for volumes with the proper .quota.* files.

$ sudo quotaon -a
$ ls -lt /.quota.*
-rw-r----- 1 root operator 131136 Aug 7 14:01 /.quota.group
-rw-r----- 1 root operator 524352 Aug 7 14:01 /.quota.user
-rw-r--r-- 1 root admin 0 Aug 6 19:45 /.quota.ops.group
-rw-r--r-- 1 root admin 0 Aug 6 19:45 /.quota.ops.user

Summary of Setup Tasks

  1. Create .quota.ops.user and .quota.ops.group.
  2. Create these empty files as root at the top level of each filesystem to track disk usage on.

  3. Run quotacheck -a.
  4. The quotacheck command creates (or updates) the .quota.user and .quota.group index files recording current usage.

  5. Run quotaon -a.
  6. This command enables automatic tracking of disk usage for filesystems the above steps have been performed on.

Setup Commands

Quick example of a quota reset and setup from scratch.

$ sudo rm -f /.quota.*
$ sudo ktrace quotacheck -a
$ sudo kdump -f ktrace.out | fgrep quota.ops | \
perl -nle 'print /"([^"]+)"/' | xargs sudo touch

$ sudo rm ktrace.out
$ sudo quotacheck -a
$ sudo quotaon -a
$ sudo edquota www

Recording Usage

To maintain historical logs of disk usage, the typical approach is to run repquota from cron(8), and to parse the resulting output into plaintext files, spreadsheet, or database. One tool of note is RRDTool, which can facilitate the generation of graphs on webpages, among other things.

The pquotarep script may help parsing the output of repquota into a format more suitable for conversion into other utilities.

$ sudo repquota -av | pquotarep | head -1
fs=/ type=group blocks=6264 blocks-hard=0 blocks-soft=0 files=785 files-hard=0 ?
files-soft=0 name=500

Imposing Limits

To impose limits, additional information on the totals for the filesystem in question can be obtained from the df(1) command. Both disk space usage and inode counts will need to be considered. The following commands show how to list that data for physical disk filesystems.

$ df -k | egrep '(^Filesystem|disk)'
Filesystem 1K-blocks Used Avail Capacity Mounted on
/dev/disk0s2 19533300 9578416 9759552 49% /
/dev/disk1s4 39064200 32956248 6107952 84% /Volumes/Spider
$ df -i | egrep '(^Filesystem|disk)'
Filesystem 512-blocks Used Avail Capacity iused ifree ?
%iused Mounted on
/dev/disk0s2 39066600 19156832 19519104 49% 2443435 2439888 ?
50% /
/dev/disk1s4 78128400 65912496 12215904 84% 8239060 1526988 ?
84% /Volumes/Spider

To edit quota limits, use the edquota(8) command. This will launch vi(1) by default to edit the quota data, which will confound those of you not versed in Unix editors. An alternative is to use Webmin to setup and manage quotas.

$ sudo edquota $USER

The best way to test quotas is to create a new user account and subject it to various limits, rather than locking your main user account out or running the risk of preferences files being corrupted if hard limits are exceeded.

I have not been able to change the default grace period times via the -t flag to edquota.

To replace vi(1) with another editor, set the EDITOR environment variable to point at a different text editor, such as pico.

$ which pico
$ sudo env EDITOR=pico edquota www

Example quota limitations for the user www:

Quotas for user www:
/: 1K blocks in use: 14120, limits (soft = 99999, hard = 999999)
inodes in use: 1225, limits (soft = 9999, hard = 99999)