diff options
author | jkar8572 <jkar8572> | 2001-03-23 12:03:26 +0000 |
---|---|---|
committer | jkar8572 <jkar8572> | 2001-03-23 12:03:26 +0000 |
commit | 869fe242340fefe0540fdcf51698ba4c3c8c07bb (patch) | |
tree | 950fa3f5997c1e8ee68c0f17d4eaf17abef64f34 | |
download | linuxquota-869fe242340fefe0540fdcf51698ba4c3c8c07bb.tar.gz |
Initial revision
-rw-r--r-- | Changelog | 497 | ||||
-rw-r--r-- | Makefile.in | 140 | ||||
-rw-r--r-- | README.gettext | 21 | ||||
-rw-r--r-- | bylabel.c | 256 | ||||
-rw-r--r-- | bylabel.h | 4 | ||||
-rw-r--r-- | common.c | 74 | ||||
-rw-r--r-- | common.h | 30 | ||||
-rwxr-xr-x | configure | 1721 | ||||
-rw-r--r-- | configure.in | 73 | ||||
-rw-r--r-- | convertquota.8 | 51 | ||||
-rw-r--r-- | convertquota.c | 136 | ||||
-rw-r--r-- | doc/edquota(8).html | 96 | ||||
-rw-r--r-- | doc/fstab(5).html | 127 | ||||
-rw-r--r-- | doc/quota(1).html | 92 | ||||
-rw-r--r-- | doc/quota.html | 288 | ||||
-rw-r--r-- | doc/quota4th.fig | 62 | ||||
-rw-r--r-- | doc/quotacheck(8).html | 94 | ||||
-rw-r--r-- | doc/quotactl(2).html | 197 | ||||
-rw-r--r-- | doc/quotaon(8).html | 80 | ||||
-rw-r--r-- | doc/quotas-1.eps | 3716 | ||||
-rw-r--r-- | doc/quotas.ms | 318 | ||||
-rw-r--r-- | doc/quotas.preformated | 330 | ||||
-rw-r--r-- | doc/repquota(8).html | 68 | ||||
-rw-r--r-- | doc/rquotad(8).html | 38 | ||||
-rw-r--r-- | dqblk_rpc.h | 20 | ||||
-rw-r--r-- | dqblk_v1.h | 18 | ||||
-rw-r--r-- | dqblk_v2.h | 36 | ||||
-rw-r--r-- | dqblk_xfs.h | 25 | ||||
-rw-r--r-- | edquota.8 | 95 | ||||
-rw-r--r-- | edquota.c | 200 | ||||
-rwxr-xr-x | install-sh | 251 | ||||
-rw-r--r-- | mntopt.h | 22 | ||||
-rw-r--r-- | po/pl.po | 857 | ||||
-rw-r--r-- | pot.c | 15 | ||||
-rw-r--r-- | pot.h | 24 | ||||
-rw-r--r-- | quot.8 | 45 | ||||
-rw-r--r-- | quot.c | 352 | ||||
-rw-r--r-- | quot.h | 113 | ||||
-rw-r--r-- | quota.1 | 100 | ||||
-rw-r--r-- | quota.c | 226 | ||||
-rw-r--r-- | quota.h | 83 | ||||
-rw-r--r-- | quotacheck.8 | 94 | ||||
-rw-r--r-- | quotacheck.c | 849 | ||||
-rw-r--r-- | quotacheck.h | 44 | ||||
-rw-r--r-- | quotacheck_v1.c | 83 | ||||
-rw-r--r-- | quotacheck_v2.c | 344 | ||||
-rw-r--r-- | quotactl.2 | 231 | ||||
-rw-r--r-- | quotaio.c | 238 | ||||
-rw-r--r-- | quotaio.h | 141 | ||||
-rw-r--r-- | quotaio_rpc.c | 55 | ||||
-rw-r--r-- | quotaio_v1.c | 302 | ||||
-rw-r--r-- | quotaio_v1.h | 39 | ||||
-rw-r--r-- | quotaio_v2.c | 734 | ||||
-rw-r--r-- | quotaio_v2.h | 88 | ||||
-rw-r--r-- | quotaio_xfs.c | 277 | ||||
-rw-r--r-- | quotaio_xfs.h | 159 | ||||
-rw-r--r-- | quotaon.8 | 168 | ||||
-rw-r--r-- | quotaon.c | 277 | ||||
-rw-r--r-- | quotaon.h | 22 | ||||
-rw-r--r-- | quotaon_xfs.c | 206 | ||||
-rw-r--r-- | quotaops.c | 476 | ||||
-rw-r--r-- | quotaops.h | 16 | ||||
-rw-r--r-- | quotastats.c | 59 | ||||
-rw-r--r-- | quotasys.c | 442 | ||||
-rw-r--r-- | quotasys.h | 75 | ||||
-rw-r--r-- | repquota.8 | 71 | ||||
-rw-r--r-- | repquota.c | 160 | ||||
-rw-r--r-- | rquota.3 | 34 | ||||
-rw-r--r-- | rquota.x | 139 | ||||
-rw-r--r-- | rquota_client.c | 309 | ||||
-rw-r--r-- | rquota_client.h | 18 | ||||
-rw-r--r-- | rquota_server.c | 342 | ||||
-rw-r--r-- | rquota_svc.c | 233 | ||||
-rw-r--r-- | rquotad.8 | 45 | ||||
-rw-r--r-- | set_limits_example.c | 60 | ||||
-rw-r--r-- | setquota.8 | 88 | ||||
-rw-r--r-- | setquota.c | 232 | ||||
-rwxr-xr-x | setup_quota_group | 12 | ||||
-rw-r--r-- | warnquota.8 | 37 | ||||
-rw-r--r-- | warnquota.c | 374 | ||||
-rw-r--r-- | warnquota.conf | 16 | ||||
-rw-r--r-- | xqmstats.c | 53 |
82 files changed, 18633 insertions, 0 deletions
diff --git a/Changelog b/Changelog new file mode 100644 index 0000000..2f009ca --- /dev/null +++ b/Changelog @@ -0,0 +1,497 @@ +Changes in quota-package from 2.00 to 3.01 + +* This is a complete rewrite of the quota package, most importantly adding + support for the new Linux quota format and also support for XFS quota. + +* The internal data structures and algorithms were redesigned and rewritten by + Jan Kara (jack@ucw.cz) so that different versions and different types of + quota can be used with these tools. + +* Support for XFS quota has been added by Nathan Scott (nathans@sgi.com). + +* Add options like RPC, ALT_FORMAT, RPC_SETQUOTA, EXT2_DIRECT to configure. + (Jan Kara) + +* Fix atoi() -> strtol() and detect mistakes in numeric input. (Jan Kara) + +* Add '-V' option to all tools to display the version. (Jan Kara) + +* Reworked time conversion routines. (Jan Kara) + +* setquota - added -t parameter and allow variable number of filesystems to + be specified. (Jan Kara) + +* Fixed endian bug in the ext2 mount by LABEL or by UUID handling code, and + added XFS support to this code also. (Nathan Scott) + +* Fix bug in handling of multiple mount points sharing the same device. + (Jan Kara) + +* Fix warnquota output for devices with long names. (Jan Kara) + +* Updated man pages. (Jan Kara, Nathan Scott) + +* Added a port of the BSD quot(8) utility, with XFS support. (Nathan Scott) + +* Added xqmstats(8) utility for reporting activity statistics for the XFS + Quota Manager - XQM. (Nathan Scott) + +* Fix up numerous compiler warnings and all the minor problems that revealed - + package now compiled with -Wall by default. (Jan Kara, Nathan Scott) + +Changes in quota-package from 1.70 to 2.00 + +* Added patches from Steven Walker <smw8923@cmsu2.cmsu.edu> for supporting + rpc_setquota call and tcp-wrappers check in rquotad. + +* Splited quota manipulation from setquota, edquota, quota etc. to quotaops.c + so things are coded only once. Also added support for remote quota editing + and setting using rquota extensions. + +* Fixed problems with parsing of /etc/fstab in hasquota.c (incorrectly + assumed that it was the only option followed by an '='). Patch by + Simon Huggins <huggie@earth.li>. + +* Extracted quota-io into quotaio.c so we only need to update repquota.c and + quotaio.c when we change the way quotas are stored in the quotafile for bigger + uids and gids. + +* Added prototype user copying to setquota ala edquota -p only this + time only for a specific filesystem. + +* Fixed quota tools for quotas bigger then 4 Gb. + Patch by Stephen C. Tweedie <sct@redhat.com> + +* Changed rpc.rquotad to scan all device entries in /dev to support also devfs + systems and systems with special hardware RAID controllers. + +* Added autoconf support to the quota-utils. + Patches by Andreas Gruenbacher <a.gruenbacher@bestbits.at> + +* Added extra filesystem types to mntent to reflect the current linux filesystems + +* Rewrote hasquota.c to check for the MNTOPT_QUOTA option. + (Request from Phil Stracchino <alaric@babcom.com>) + +* Removed searching of /dev dir from rquota_server. Only lookup mounted filesystems. + (Patch by Roman Kagan <Roman.Kagan@itep.ru>) + +* Added gettext NLS support all credits go to the guys named in the + README.gettext. + +* Added the redhat patches to the standard tree. + * blocksize patch + * fhs patch + * hjl patch + * label patch + * SPARC patch + +* Changed Q_SETQUOTA to Q_SETQLIM in quotaops.c for the putprivs function. This fixed + a problem where we restore bogos usage info by edquota etc. when a user resets its + quota usage while running for example edquota. We should only change the limits + because thats the only things we can change using these kind of tools. + (Bug report by Dr. Michael Meskes <michael@fam-meskes.de> from the Debian bug-archive) + +* Added numeric option to quota and setquota to allow to set quota for users/groups not + in the localy known through name-services. + (Modified the patches send by Oscar Martín <oscar@cdrtcampos.es>) + +Changes in quota-package from 1.65 to 1.70 + +* Fixed problems when turning off one type of quota taking offline the + other type too. + +* Fixed bugs as reported on bugtraq for negative ids and problems + with usernames with only digits. + +* Added setquota (to se quotas from the commandline) as send to me by + Martin Bene <mb@sime.com> + +Changes in quota-package from 1.60 to 1.65 + +* Created new diffs again for the newer kernel (2.1.[78]x). + +* Added sample program that copies quota-settings from one user + to an other. + +* Added /etc/quotatab support as developed by Jon Lewis + <jlewis@inorganic5.fdt.net> + +* Added some changes to /usr/src/linux/fs/nfsd/vfs.c to support quotas + for the kernel-nfsd too. (Most other filesystems are gone and the ones + remaining either don't need quotas or are not used by big groups of users.) + +Changes in quota-package from 1.55 to 1.60 + +* Added new option to kernel root_squash which means when that option is + set the kernel system threats root as any normal user and he cannot + write to any file anymore without obeing the quota limits. + +* Added support for root_squash to quotaon and quotaoff using the new + rsquash option in mntent. In the run also rewrote the hasquota function. + +* Added patches to Makefile.std which should make it more FSSTND compliant. + +* Added extra check to rpc.rquotad to check the special device type when + scanning the /dev dir for the right device. + +Changes in quota-package from 1.52 to 1.55 + +* Added all patches and enhancements I collected the last few months. + (As always some have undergone some rewriting and are only a special + option. But they are in) + +* Changed check on ruid in edquota to an access-check on the quota-files. + If you have write permissions on the quota-files as a group its probably + ok to allow you to change the quotas. If not the system operator should + take apropriate actions. Install edquota SUID-root if you want people + who are able to write to your quotafiles to change quotas. If you don't + install it SUID root it will only update the files which can give strange + problems with the kernel overwriting your updates. + +* Added the EPS-file of the sheets from Remy Card which he used at the + Berlin Linux seminar. And because they describe everything in detail + its a nice enhancement to the current HTML docs. + +Changes in quota-package from 1.50 to 1.52 + +* Hopefully fixed some problems with makefiles and the like. + +* Did some rewrite on the mountlist handling, removed limit on number of + superblocks by allocating them within the mountlist. + (This code is not available within the standard kernel. Until I find the + time and feel like it I will put all my new enhancements in my very own + (just a bit different) kernel sourcetree back into the mainstream kernels.) + +Changes in quota-package from 1.34 to 1.50 + +* Wrote some new docs, right into html use Mosaic, Netscape or lynx or + whatever HTML-browser to see whats in. Also did the manual-pages, + its just a quick hack hope this helps people using quota. + +* Added DIRECT EXT2 access to quotacheck which should make scanning ext2 + disks quite some faster. On the other hand you now need the ext2fs + libs to compile the quotacheck program. (Enhancement by Edvard Tuinder) + +* Added dquot_operations to include/linux/fs.h + +* Changed include/linux/quota.h according to new standard. + +* Changed fs/dquot.c according to new standard. + +* Added support to quotaon-systemcall for initializing the superblock + with a pointer to the dquot operations. + +* Remove fs/fileio.c and include/linux/fileio.h including all references to it. + +* Added support to the different filesystems to call the new dquot_alloc and + dquot_free functions on block/inode allocation or freeing. (currently ext2) + +* People can add support to any filesystem if they want, for now I have been + lazy and only implemented it for ext2-fs. Which by the way is probably + the most difficult of all the filesystems. If one feels up to it you can + try adding it to your favorit filesystem. I will accept patches, and + include them with or without changes. + +* Added some patches for dynamic allocation of quotafilenames in hasquota. + (patches by Remy Card) + +* Rewrote quota_transfer again, as a never ending story... + +* A new run off cleanups have been taking place, removed the QF_OPENING and + QF_CLOSING flags because we don't need them anymore. The new code uses dquot + pointers. If we initialize the dquot pointer after we have setup everything + we don't have do be afraid that we get dqget calls while we don't want them. + +* Fixed some bugs with not dropping dquot pointers which lead to memory leaks + in the long run because dquots kept being hold because the kernel thought + it was still being used. + +* Added some stats to the code which can be viewed with quotastats. Not real + interesting at the user level but quite handy debugging the quota system. + +Changes in quota-package from 1.33 to 1.34 + +* Changed hasquota.c to not insert a slash when the mnt->mnt_dir already ends + with a slash. So something like //quota.user shouldn't happen anymore. + +* Cleaned up fs/fileio.c, removed some unneeded dummy_inodes in unlink and + rmdir vfs functions. Now rely on incrementing i_count when deleting a + dir or file and release it when I iput the inode. Should work because when + a executable is running when it gets deleted this also happens. Also + renamed and cleanup the rest of the funtions. vfs_rename function should + now also work for a hardlinked file. + +* Changed vfs_chown functions to reset SUID and SGID on a chown because the + new kernel wants that. + +* Changed locking on I/O to use semaphores instead off the mnt_flags + used before. The old stuff could lock quota easily probably because + the operation wasn't atomic. This should now be fixed. + +* Fixed check_bdq to only give back a available blocks when the current + number of blocks are below the hardlimit. There was a bugfix for this + one so I applied that. + +* Changed has_quota funtion to use a static buffer instead of mallocing + one everytime it needs one. Hope this helps with the reported memory + leak on the rquotad. + +* Fixed some little bugs in dquot.c with the setting of the QF_OPENING + flag and not resseting it on failure of opening the quotafile. + +* Added changes needed because the VFS-layer changed to use iattr structs + for the notify_change function. + +* Fixed quota_transfer to work again with the new iattr structs, hopefully + it works ok now. It was brought to my attension that it wasn't working + the way it should in the old version. So I first checked out the fix that + I received, but that didn't solve the problem either so I fixed it myself. + +* Combined the new writeaccess stuff with the stuff I already had. Also + cleaned up vfs layer some more because of the use of the new + vfs_getwriteaccess and vfs_putwriteaccess functions. This also involved + the quotaon function that should now return a propper errno on failure and + not the standard EIO that it was in earlier versions. + +Changes in quota-package from 1.32 to 1.33 + +* Ported the stuff back to the normal kernel to make a diff-file quite easy. + +* Fixed some typos that could trigger a kernel panic because the locking gets + killed when a quota is exeeded. + +* Fixed the stuff to work with the the new-tty-drivers. + +* This patches aren't that well tested on the machines I use because I use a + complete different kernel over here. But thats why this is called BETA + software. The bigfiles in this package are copies of the files used in my + kernel so some thing are tested more then others. + +* Fixed quotacheck not to memset the whole quota when there are no blocks + allocated by this user. + +Changes in quota-package from 1.31 to 1.32 + +* Fixed diff-files, the are now made as unified diffs. + +* Checked the specifications for the rquota service, I was correct we only need + to respond to udp connections. + +Changes in quota-package from 1.3 to 1.31 + +* Changed quotacheck program to stuff directories it encounters on a + directory stack and check them later on. This way there is at any + time one directory opened for reading. In the old situation it could + happen that more then one directory were open at the same time and + with nasty directory structures this could give to much open directories + at ones, leading to an error by the O.S. + +* Added some hooks for debugging the memory usage by the program, and make + the stdout used for the -v flag non-buffered for more speed. + +* Added variabele to mountstruct for flags, now we can mask when we are + opening or closeing a quotafile, when we are we may not give out + pointers with the dq_get function, otherwise we run into problems + later on. + +* Ok updated fs/*.c missed patch to fs/inode.c that solves a race condition. + +* Added vfs_rename function that takes care of renaming files on top of already + existing files. We were missing those ones, thanks to David Black for + reporting this. If there are still problems I will hear so and try to fix them + as soon as I can. + +Changes in quota-package from 1.2 to 1.3 + +* We only reply to rpc_quota_request made to the udp port of the + rquotad, I just removed support for the TCP service, I don't + think it's needed to have the TCP service for just exchanging + about 40 bytes of data. Too much overhead setting up a TCP connection. + +* Changed vfs_write function within fileio.h to be a bit smarter. If + the fileposition + number of bytes to be written is less then the + current size of the file we should even bother checking it. And if + the number of wanted_blocks equals to 0 why even bother checking + the quota no changes are made anyway. + +* Rewrote the quota stuff to be much more flexible, we now use pointers + that are located within the inode for fast lookup. This is a bit more + to setup but is much faster when used over and over again. Its based + on the setup used for inode caching and is mostly rewritten code with + some extensions that were needed for the dquot structs. And of course + a lot extra because dquot aren't exactly inodes. + +* Ok file is called dquot.c again because it specific to diskquotas. If + we ever get process quota, we have to move the system-call interface to + the kernel dir. + +* splitted fileio header into fileio.c and fileio.h. Fileio.c contains + the code for all the functions, fileio.h contains the prototypes for + the functions when quota is enabled and defines to the the default + inode operations if it is disabled. + +* Moved device management code to the file fs/super.c and made it a + bit more general. The stuff now can also be used for other purposes. + For now it contains the devicename, the directory the filesystem is + mounted on, a pointer to the superblock and the quota expire times + and filepointers, this can be extended in the future and this can be + used for other purposes then only quota. Its in super.c because it + is related to mounting a filesystem. The rootfilesystem is a special + case for which I don't have a nice solution right now. + +* Cleaned up the file file_table.c and renamed it to file.c, otherwise + we should call inode.c inode_table.c etc. More is static now, the + file_table isn't accesable anymore from everywhere, and the functions + that need the info within file.c should be located within that file. + A good example is the function used by the vhangup code, it now calls + a routine within file.c and so we don't have export any data anymore. + +* changed decrement quota to reset the DQ_INODES and DQ_BLKS flag on + a decrement of a quota. It seems that we should bark again when one + goes over his quota after he removed something, ok should work this + way. + +* changed set_dqblk to set the grace period when a new usage is set + and one exceeds his softlimit by that operation. Better then just + setting the graceperiod when he allocates any more inodes or blocks. + Only can give surprises when logging in but who cares they can ask + the sysadmin to give them a hand with cleaning there dirs. + +* quotaoff is very simple now just reset all the pointers that point + to a dquot and trash the cache for all dquots that are related to + the device being turned of. This way the next time you put it on the + stuff get read again from disk and not from the cache. + +* changed most of the file structs to be a filepointer and request it + with get_empty_filp. This way we allocate it from the file_table which + is more the way it should be, Ok I know the dummy_inodes isn't that + nice either, but for that we don't have an other choice. Also it makes + live much easier this way. See the core dump stuff. + +* used some more constants for setting up the file pointers, this should + make it easier to read. So ok Edvard ? + +* rewrote most functions such as quota_alloc, quota_remove and quota_transfer + to use a for loop which counts from 0 to the number of quotas -1. This way + it should be easy to extend the quota stuff to maintain even more types of + quota. (At the moment I can think of one more, what about quotas for a + processgroups) :-) + +* rewrote quota_transfer, its still the most complicated function of the + three manipulate functions, but it looks much cleaner then the one we + had. + +* changed the system-call interface again this should be the last time, + hope to have it made more intelligent now, most of the calls are quite + the same, so just set flags and call one functions. Saves some functions. + +* And more cleanups to the vfs-layer. Did a kind of indent on all the sources + in the fs-dir by hand. All references to file pointers are now done by a + variable that is called filp. This is done to be a bit more consistent all + through the code. Before is was called file, filp, f etc. + +* As of the indent I changed all tabs to be 3 spaces this makes it a bit + larger but much better to read. + +* Someone reported that there are problems with fstab when you use something + like usrquota=/usr/adm/quota.user,grpquota=/usr/adm/quota.grp. I don't know + if the problems is also in the new libs, if so I have a replacement here for + the entire mntent stuff. I wrote this way back and it work ok so if you + have problems mail me and I will send you the sources. For now I didn't + include it yet in the standard mainline distribution. + +* Ok added hooks to the fork code forgot that, ok this has cost me some + searching. We must doe an vfs_open_filp when a process forks and the + filepointers are copied or incremented. + +Changes in quota-package from 1.1 to 1.2 + +* Changed repquota.c to display at max 8 chars of username. + +* Changed rquota_svc.c and rquota_server.c to handle both version 1 + and 2 requests. Now we should be able to communicate with sun systems. + SUN systems send out version 1 request which we can handle now. + +* Changed quota.c to first send out a version 2 rquota request and if + that fails to try it with a version 1 request. Now we should be able to + query a rquotad on a sun-server exporting a NFS disk. + +* Changed kernel diffs, now use a header file fileio.h with vfs functions + for writing, truncating, creating files/nodes. This cleaned up the + kernel diffs quite a bit. (Should have done this way back, but it is + done now) + +* Fixed some small bugs with handling graceperiods again. Changed the code + in the systemcall interface all bugs should be gone now there. + +* Wrote a new program warnquota. No manpage yet but it has no flags so + that's simple. You can run this from your crontab just like you run + quotacheck every night from cron. This program mails a message to all + users that violated the quota system. + +* Changed fileio.h with unlinking and rmdir to make a copy of the inode. + Hope this fixes some problems we have seen with xiafs. It isn't to bad + either should have been this way from the beginning. A pointer to a + inode that is removed is a bit to tricky a copy in local memory is much + saver. + +* Changed fs/quota.c to not check if the quotafile is on the same device + as the device for which it contains info. Found that in a document but + it's silly and so it's removed now. Who cares where you put it as long + the kernel can find it and it is the right format. + (Now something like usrquota="/var/adm/quota_src.user" should work :-)) + +* Changed edquota behaviour with -p flag. It now copies the current + usage to the new situation. + +Changes in quota-package from 1.0 to 1.1 + +* Moved check to test on quota on a certain filesystem to seperate file + hasquota.c + +* Changed hasquota.c to use quotafile given in fstab file instead + of the default name of a quotafile. We now can define ourself where + to put our quotafile. Something like "usrquota=/usr/adm/quotasrc.user" + +* Changed graceperiod counting was doing it the wrong way around. Now we + add the expiretime to the current time and that is the grace-period a user + has before we see a softlimit as a hardlimit. + +* Changed allocation when not enough blocks can be allocated from ones quota. + Now you get as many blocks as you can affort yourself and not as in the + earlier version, nothing. This was a bit of a bitch to tackle but it seems + to work ok now for regular files and core-files. + +* Changed the quota.h file to include a prototype for a new function + blocks_to_isize that calculates the maximum isize for a file when allocating + less blocks than requested. Also included macro's for min() and max(). + +* Added rquotad program for own convinience, this was build from scratch with + only the rquota.x file. It seems to work quite nice between LINUX machines + don't have the resources to test it with other then LINUX machines. + We probably need a new version number for this type of rquota. + Something like rquota version 2 or something like that. + +* Changed quota program to use a rpc-call to the rquotad on one of you + disk server machines. See #ifdef RPC in quota.c. Use small timeout because + I don't wanna wait to long when a machine is down. Increase it when you have + problems with slow hosts. + +* Rewrite of quotacheck program. This one is much faster, about 60%. Thanks + to Edvard for this big improvement. + +* Changed namei.c to iput the inode of a dir when doing a remove of a dir. + I never had problems with it but it seems that ext2 doesn't care to much when + you unlink a dir while you have the inode still open. Fixed it and it works + now ok also on xiafs which had problems with it, and of course the fragment + should have give this error because you have to iput the dir before you remove + it. + +* Changed source of quotacheck to create new quotafile with at least the + gracetimes. Now there should never be a problem when turning on quota with + the quotactl systemcall after one has run quotacheck to create the correct + quotafiles. + +* Changed code of quota.c to read MOUNTED(mtab) instead of FSTAB(fstab) when + showing quotainfo. diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..7033965 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,140 @@ +PROGS = quotacheck quotaon quota quot repquota warnquota quotastats xqmstats edquota setquota convertquota rpc.rquotad +CFLAGS = @CFLAGS@ @EXT2_DIRECT@ -D_GNU_SOURCE -Wall +EXT2LIBS = @EXT2LIBS@ +RPCSRC = rquota.h rquota_xdr.c rquota_clnt.c +VERSIONDEF = -DQUOTA_VERSION=\"3.01\" +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ + +# +# Uncomment the two lines below to add tcp_wrapper support for rpc.rquotad +# Then add lines to /etc/hosts.allow and /etc/hosts.deny +# like: "rquotad: ALL@ALL except my.host.i.want.com" in hosts.deny means +# only the host designated can get info from rquotad +# NOTE: I used gethostbyaddr(), so you may need FQDN or merely host name +# depending on how your resolver returns first. IP Addresses will work as well. +# +CFLAGS += @HOSTS_ACCESS@ +CFLAGS += $(VERSIONDEF) + +INSTALL = @INSTALL@ +LN = ln -sf +ROOTDIR = +SUPER_OWNER = root +BIN_OWNER = bin +BIN_GROUP = bin +DEF_SUID_MODE = 4511 +DEF_BIN_MODE = 555 +DEF_SBIN_MODE = 555 +DEF_MAN_MODE = 444 +RPCGEN = rpcgen + +prefix = @prefix@ +bindir = $(prefix)/bin +sbindir = $(prefix)/sbin +mandir = @mandir@ +includedir = $(prefix)/include +root_sbindir = /sbin +locale_dir = $(prefix)/share/locale + +RPCCLNTOBJS = rquota_xdr.o rquota_client.o rquota_clnt.o +IOOBJS = quotaio.o quotaio_v1.o quotaio_v2.o quotaio_rpc.o quotaio_xfs.o +IOOBJS += $(RPCCLNTOBJS) +LIBOBJS = bylabel.o common.o quotasys.o pot.o $(IOOBJS) +LIBOBJS += @LIBMALLOC@ +INCLUDE = common.h quotasys.h bylabel.h + +all: $(PROGS) + +clean: + -rm -f core *.o + +clobber: clean + -rm -f $(PROGS) Makefile config.{status,cache,log} + +realclean: clobber + -rm -f $(RPCSRC) po/*.mo + +pot: + xgettext -k_ -d pot *.c + +mo: po + for n in $(shell ls po/*.po); do \ + msgfmt -o po/`basename $$n .po`.mo $$n; \ + done + +inst_mo: mo + mkdir -p $(locale_dir) + for n in $(shell ls po/*.po | sed 's/\.po/\.mo/'); do \ + l=`basename $$n .mo`; \ + $(INSTALL) -m 755 -d $(ROOTDIR)$(locale_dir)/$$l; \ + $(INSTALL) -m 755 -d $(ROOTDIR)$(locale_dir)/$$l/LC_MESSAGES; \ + $(INSTALL) -m 644 $$n $(ROOTDIR)$(locale_dir)/$$l/LC_MESSAGES/quota.mo; \ + done + +install: all inst_mo + -$(INSTALL) -m $(DEF_SBIN_MODE) \ + quotacheck quotaon $(ROOTDIR)$(root_sbindir) + $(LN) quotaon $(ROOTDIR)$(root_sbindir)/quotaoff + chown -h $(BIN_OWNER):$(BIN_GROUP) $(ROOTDIR)$(root_sbindir)/quotaoff + -$(INSTALL) -m $(DEF_SBIN_MODE) \ + edquota repquota warnquota quotastats setquota quot $(ROOTDIR)$(sbindir) + -$(INSTALL) -m 755 -d $(ROOTDIR)$(includedir)/rpcsvc + -$(INSTALL) -m 644 rquota.h rquota.x $(ROOTDIR)$(includedir)/rpcsvc + -$(INSTALL) -s -m $(DEF_SBIN_MODE) quota $(ROOTDIR)$(bindir) + -$(INSTALL) -s -m $(DEF_SBIN_MODE) rpc.rquotad $(ROOTDIR)$(sbindir) + -$(INSTALL) -m $(DEF_MAN_MODE) *.1 $(ROOTDIR)$(mandir)/man1 + -$(INSTALL) -m $(DEF_MAN_MODE) *.2 $(ROOTDIR)$(mandir)/man2 + -$(INSTALL) -m $(DEF_MAN_MODE) *.3 $(ROOTDIR)$(mandir)/man3 + -$(INSTALL) -m $(DEF_MAN_MODE) *.8 $(ROOTDIR)$(mandir)/man8 + +quotaon: $(INCLUDE) quotaon.o quotaon_xfs.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ quotaon.o quotaon_xfs.o $(LIBOBJS) + +quotacheck: $(INCLUDE) quotacheck.o quotacheck_v1.o quotacheck_v2.o quotacheck.h $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ quotacheck.o quotacheck_v1.o quotacheck_v2.o $(EXT2LIBS) $(LIBOBJS) + +quota: $(INCLUDE) rquota.h quota.o quotaops.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ quota.o quotaops.o $(LIBOBJS) + +quot: $(INCLUDE) quot.h quot.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ quot.o $(LIBOBJS) + +repquota: $(INCLUDE) repquota.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ repquota.o $(LIBOBJS) + +warnquota: $(INCLUDE) common.h warnquota.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ warnquota.o $(LIBOBJS) + +quotastats: quotastats.o pot.o + $(CC) $(LDFLAGS) -o $@ quotastats.o pot.o + +xqmstats: xqmstats.o pot.o + $(CC) $(LDFLAGS) -o $@ xqmstats.o pot.o + +edquota: $(INCLUDE) quotaops.h quotaio.h edquota.o quotaops.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ edquota.o quotaops.o $(LIBOBJS) + +setquota: $(INCLUDE) setquota.o quotaops.o rquota.h $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ setquota.o quotaops.o $(LIBOBJS) + +convertquota: $(INCLUDE) convertquota.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ convertquota.o $(LIBOBJS) + +rpc.rquotad: $(INCLUDE) rquota.h rquota_server.o rquota_svc.o $(LIBOBJS) + $(CC) $(LDFLAGS) -o $@ rquota_server.o rquota_svc.o $(LIBOBJS) $(LIBS) + +pot.o: pot.c pot.h + $(CC) $(CFLAGS) -c $< + +rquota.h: rquota.x + $(RPCGEN) -h -o $@ $< + +rquota_xdr.c: rquota.x + $(RPCGEN) -c -o $@ $< + +rquota_xdr.o: rquota_xdr.c rquota.h + $(CC) $(CFLAGS) -Wno-unused -c $< + +rquota_clnt.c: rquota.x + $(RPCGEN) -l -o $@ $< diff --git a/README.gettext b/README.gettext new file mode 100644 index 0000000..6bcb14f --- /dev/null +++ b/README.gettext @@ -0,0 +1,21 @@ +If you want to generate new po file: "make pot" and look for a file named +pot.po. To generate mo files from po files: "make mo", it's also done when +you "make install", if you want to install only mo files ( no programs ) +"make inst_mo", mo files will be copied to: +/usr/share/locale/'languages names'/LC_MESSAGES/quota.mo. + +warnquota +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +this program was modifiated to be more configurable - you can now specify +new warning message ( also sender, cc, etc. ) without recompiling the +program. all you need is to edit pot.po ( make pot ), you will find +in it mail message, and etc. - create new strings, make mo with msgfmt, and copy +mo file to /usr/share/locale/'lang'/LC_MESSAGES/quota.mo. now you have new +warning mail message. + +gettext support was added by Paul Niewiadomski <lilo@free.poltronic.net>, any +questions, suggestions are welcome. + +thanks to +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Roman_Kaminski@saba.com.pl
\ No newline at end of file diff --git a/bylabel.c b/bylabel.c new file mode 100644 index 0000000..3ce77b2 --- /dev/null +++ b/bylabel.c @@ -0,0 +1,256 @@ +/* + * Derived from the util-linux/mount/mount_by_label.c source, + * currently maintained by Andries Brouwer <aeb@cwi.nl>. + * + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> + * - added Native Language Support + * 2000-01-20 James Antill <james@and.org> + * - Added error message if /proc/partitions cannot be opened + * 2000-05-09 Erik Troan <ewt@redhat.com> + * - Added cache for UUID and disk labels + * 2000-11-07 Nathan Scott <nathans@sgi.com> + * - Added XFS support + */ + +#include <stdio.h> +#include <sys/param.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <unistd.h> + +#include "bylabel.h" +#include "common.h" +#include "pot.h" + +#define PROC_PARTITIONS "/proc/partitions" +#define DEVLABELDIR "/dev" + +static struct uuidCache_s { + struct uuidCache_s *next; + char uuid[16]; + char *label; + char *device; +} *uuidCache = NULL; + +#define EXT2_SUPER_MAGIC 0xEF53 +struct ext2_super_block { + u_char s_dummy1[56]; + u_char s_magic[2]; + u_char s_dummy2[46]; + u_char s_uuid[16]; + u_char s_volume_name[16]; +}; + +#define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define XFS_SUPER_MAGIC "XFSB" +#define XFS_SUPER_MAGIC2 "BSFX" +struct xfs_super_block { + u_char s_magic[4]; + u_char s_dummy[28]; + u_char s_uuid[16]; + u_char s_dummy2[60]; + u_char s_fsname[12]; +}; + +static inline unsigned short swapped(unsigned short a) +{ + return (a >> 8) | (a << 8); +} + +/* for now, only ext2 and xfs are supported */ +static int get_label_uuid(const char *device, char **label, char *uuid) +{ + + /* start with ext2 and xfs tests, taken from mount_guess_fstype */ + /* should merge these later */ + int fd; + int rv = 1; + size_t namesize; + struct ext2_super_block e2sb; + struct xfs_super_block xfsb; + + fd = open(device, O_RDONLY); + if (fd < 0) + return rv; + + if (lseek(fd, 1024, SEEK_SET) == 1024 + && read(fd, (char *)&e2sb, sizeof(e2sb)) == sizeof(e2sb) + && ext2magic(e2sb) == EXT2_SUPER_MAGIC) { + memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid)); + namesize = sizeof(e2sb.s_volume_name); + *label = smalloc(namesize + 1); + sstrncpy(*label, e2sb.s_volume_name, namesize); + rv = 0; + } + else if (lseek(fd, 0, SEEK_SET) == 0 + && read(fd, (char *)&xfsb, sizeof(xfsb)) == sizeof(xfsb) + && (strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0 || + strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC2, 4) == 0)) { + memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid)); + namesize = sizeof(xfsb.s_fsname); + *label = smalloc(namesize + 1); + sstrncpy(*label, xfsb.s_fsname, namesize); + rv = 0; + } + + close(fd); + return rv; +} + +static void uuidcache_addentry(char *device, char *label, char *uuid) +{ + struct uuidCache_s *last; + + if (!uuidCache) { + last = uuidCache = smalloc(sizeof(*uuidCache)); + } + else { + for (last = uuidCache; last->next; last = last->next); + last->next = smalloc(sizeof(*uuidCache)); + last = last->next; + } + last->next = NULL; + last->device = device; + last->label = label; + memcpy(last->uuid, uuid, sizeof(last->uuid)); +} + +static void uuidcache_init(void) +{ + char line[100]; + char *s; + int ma, mi, sz; + static char ptname[100]; + FILE *procpt; + char uuid[16], *label; + char device[110]; + int firstPass; + int handleOnFirst; + + if (uuidCache) + return; + + procpt = fopen(PROC_PARTITIONS, "r"); + if (!procpt) + return; + + for (firstPass = 1; firstPass >= 0; firstPass--) { + fseek(procpt, 0, SEEK_SET); + + while (fgets(line, sizeof(line), procpt)) { + if (sscanf(line, " %d %d %d %[^\n ]", &ma, &mi, &sz, ptname) != 4) + continue; + + /* skip extended partitions (heuristic: size 1) */ + if (sz == 1) + continue; + + /* look only at md devices on first pass */ + handleOnFirst = !strncmp(ptname, "md", 2); + if (firstPass != handleOnFirst) + continue; + + /* skip entire disk (minor 0, 64, ... on ide; + 0, 16, ... on sd) */ + /* heuristic: partition name ends in a digit */ + + for (s = ptname; *s; s++); + if (isdigit(s[-1])) { + /* + * Note: this is a heuristic only - there is no reason + * why these devices should live in /dev. + * Perhaps this directory should be specifiable by option. + * One might for example have /devlabel with links to /dev + * for the devices that may be accessed in this way. + * (This is useful, if the cdrom on /dev/hdc must not + * be accessed.) + */ + sprintf(device, "%s/%s", DEVLABELDIR, ptname); + if (!get_label_uuid(device, &label, uuid)) + uuidcache_addentry(sstrdup(device), label, uuid); + } + } + } + + fclose(procpt); +} + +#define UUID 1 +#define VOL 2 + +static char *get_spec_by_x(int n, const char *t) +{ + struct uuidCache_s *uc; + + uuidcache_init(); + uc = uuidCache; + + while (uc) { + switch (n) { + case UUID: + if (!memcmp(t, uc->uuid, sizeof(uc->uuid))) + return sstrdup(uc->device); + break; + case VOL: + if (!strcmp(t, uc->label)) + return sstrdup(uc->device); + break; + } + uc = uc->next; + } + return NULL; +} + +static u_char fromhex(char c) +{ + if (isdigit(c)) + return (c - '0'); + else if (islower(c)) + return (c - 'a' + 10); + else + return (c - 'A' + 10); +} + +static char *get_spec_by_uuid(const char *s) +{ + u_char uuid[16]; + int i; + + if (strlen(s) != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') + goto bad_uuid; + for (i = 0; i < 16; i++) { + if (*s == '-') + s++; + if (!isxdigit(s[0]) || !isxdigit(s[1])) + goto bad_uuid; + uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1])); + s += 2; + } + return get_spec_by_x(UUID, uuid); + + bad_uuid: + fprintf(stderr, _("Found an invalid UUID: %s\n"), s); + return NULL; +} + +static char *get_spec_by_volume_label(const char *s) +{ + return get_spec_by_x(VOL, s); +} + +const char *get_device_name(const char *item) +{ + const char *rc; + + if (!strncmp(item, "UUID=", 5)) + rc = get_spec_by_uuid(item + 5); + else if (!strncmp(item, "LABEL=", 6)) + rc = get_spec_by_volume_label(item + 6); + else + rc = sstrdup(item); + if (!rc) + fprintf(stderr, _("Error checking device name: %s\n"), item); + return rc; +} diff --git a/bylabel.h b/bylabel.h new file mode 100644 index 0000000..271c5cb --- /dev/null +++ b/bylabel.h @@ -0,0 +1,4 @@ +#ifndef _BYLABEL_H_ +#define _BYLABEL_H_ +const char *get_device_name(const char *item); +#endif /* _BYLABEL_H_ */ diff --git a/common.c b/common.c new file mode 100644 index 0000000..f77f2e5 --- /dev/null +++ b/common.c @@ -0,0 +1,74 @@ +/* + * + * Common things for all utilities + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include <sys/types.h> + +#include "pot.h" +#include "common.h" + +void die(int ret, char *fmtstr, ...) +{ + va_list args; + + va_start(args, fmtstr); + vfprintf(stderr, fmtstr, args); + va_end(args); + exit(ret); +} + +void *smalloc(size_t size) +{ + void *ret = malloc(size); + + if (!ret) { + puts("Not enough memory.\n"); + exit(3); + } + return ret; +} + +void sstrncpy(char *d, const char *s, int len) +{ + strncpy(d, s, len); + d[len - 1] = 0; +} + +void sstrncat(char *d, const char *s, int len) +{ + strncat(d, s, len); + d[len - 1] = 0; +} + +char *sstrdup(const char *s) +{ + char *r = strdup(s); + + if (!r) { + puts("Not enough memory."); + exit(3); + } + return r; +} + +void version(void) +{ + printf(_("Quota utilities version %s.\n"), QUOTA_VERSION); +#if defined(RPC) || defined(EXT2_DIRECT) + printf(_("Compiled with ")); +#if defined(RPC) && defined(EXT2_DIRECT) + puts(_("RPC and EXT2_DIRECT")); +#elif defined(RPC) + puts(_("RPC")); +#else + puts(_("EXT2_DIRECT")); +#endif /* defined RPC && EXT2_DIRECT */ +#endif /* defined RPC || EXT2_DIRECT */ +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..8da6df9 --- /dev/null +++ b/common.h @@ -0,0 +1,30 @@ +/* + * + * Various things common for all utilities + * + */ + +#ifndef _COMMON_H +#define _COMMON_H + +#define MY_EMAIL "mvw@planets.elm.net, jack@atrey.karlin.mff.cuni.cz" + +/* Finish programs being */ +void die(int, char *, ...); + +/* malloc() with error check */ +void *smalloc(size_t); + +/* Safe strncpy - always finishes string */ +void sstrncpy(char *, const char *, int); + +/* Safe strncat - always finishes string */ +void sstrncat(char *, const char *, int); + +/* Safe version of strdup() */ +char *sstrdup(const char *s); + +/* Print version string */ +void version(void); + +#endif /* _COMMON_H */ diff --git a/configure b/configure new file mode 100755 index 0000000..e329c8f --- /dev/null +++ b/configure @@ -0,0 +1,1721 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-altformat=[yes/no] Enable alternative format used by edquota [default=yes]." +ac_help="$ac_help + --enable-rpc=[yes/no] Enable RPC support [default=yes]." +ac_help="$ac_help + --enable-rpcsetquota=[yes/no] Use RPC for setting quotas [default=yes]." +ac_help="$ac_help + --enable-libefence=[yes/no] Use Electric Fence memory checks [default=no]." + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=quota.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:537: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:567: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:618: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:650: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 661 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:666: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:692: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:697: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:706: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:725: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:757: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 772 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:778: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 789 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:795: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 806 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:812: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:837: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 842 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:850: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 867 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 885 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 906 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:917: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:971: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +echo $ac_n "checking for com_err in -lcom_err""... $ac_c" 1>&6 +echo "configure:1025: checking for com_err in -lcom_err" >&5 +ac_lib_var=`echo com_err'_'com_err | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcom_err $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1033 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char com_err(); + +int main() { +com_err() +; return 0; } +EOF +if { (eval echo configure:1044: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo com_err | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lcom_err $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for ext2fs_initialize in -lext2fs""... $ac_c" 1>&6 +echo "configure:1072: checking for ext2fs_initialize in -lext2fs" >&5 +ac_lib_var=`echo ext2fs'_'ext2fs_initialize | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lext2fs $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1080 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ext2fs_initialize(); + +int main() { +ext2fs_initialize() +; return 0; } +EOF +if { (eval echo configure:1091: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo ext2fs | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lext2fs $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +EXT2LIBS=${LIBS} + +LIBS="" + +echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6 +echo "configure:1123: checking for main in -lnsl" >&5 +ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1131 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:1138: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lnsl $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for main in -lwrap""... $ac_c" 1>&6 +echo "configure:1166: checking for main in -lwrap" >&5 +ac_lib_var=`echo wrap'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lwrap $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1174 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:1181: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo wrap | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lwrap $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + +if test ${ac_cv_lib_com_err_com_err} = yes && + test ${ac_cv_lib_ext2fs_ext2fs_initialize} = yes; then + ac_safe=`echo "ext2fs/ext2fs.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for ext2fs/ext2fs.h""... $ac_c" 1>&6 +echo "configure:1213: checking for ext2fs/ext2fs.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1218 "configure" +#include "confdefs.h" +#include <ext2fs/ext2fs.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1223: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 + + echo 'ERROR: could not find ext2fs/ext2fs.h - missing ext2 package' + exit 1 + +fi + + EXT2_DIRECT="-DEXT2_DIRECT" + +fi + +if test ${ac_cv_lib_wrap_main} = yes; then + ac_safe=`echo "tcpd.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for tcpd.h""... $ac_c" 1>&6 +echo "configure:1255: checking for tcpd.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1260 "configure" +#include "confdefs.h" +#include <tcpd.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1265: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 + + echo 'ERROR: could not find tcpd.h - missing TCP wrappers package' + exit 1 + +fi + + HOSTS_ACCESS="-DHOSTS_ACCESS" + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:1295: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1300 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:1349: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:1370: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <<EOF +#line 1377 "configure" +#include "confdefs.h" + +int main() { +} $ac_kw foo() { +; return 0; } +EOF +if { (eval echo configure:1384: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <<EOF +#define inline $ac_cv_c_inline +EOF + ;; +esac + + +# Check whether --enable-altformat or --disable-altformat was given. +if test "${enable_altformat+set}" = set; then + enableval="$enable_altformat" + : +else + enable_altformat="yes" +fi + +# Check whether --enable-rpc or --disable-rpc was given. +if test "${enable_rpc+set}" = set; then + enableval="$enable_rpc" + : +else + enable_rpc="yes" +fi + +# Check whether --enable-rpcsetquota or --disable-rpcsetquota was given. +if test "${enable_rpcsetquota+set}" = set; then + enableval="$enable_rpcsetquota" + : +else + enable_rpcsetquota="yes" +fi + +# Check whether --enable-libefence or --disable-libefence was given. +if test "${enable_libefence+set}" = set; then + enableval="$enable_libefence" + : +else + enable_libefence="no" +fi + + +if test "$enable_altformat" = "yes" ; then + CFLAGS="-DALT_FORMAT $CFLAGS"; +fi +if test "$enable_rpc" = "yes" ; then + CFLAGS="-DRPC $CFLAGS"; +fi +if test "$enable_rpcsetquota" = "yes" ; then + CFLAGS="-DRPC_SETQUOTA $CFLAGS" +fi +if test "$enable_libefence" = "yes" ; then + LIBMALLOC="/usr/lib/libefence.a" +fi + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@EXT2LIBS@%$EXT2LIBS%g +s%@EXT2_DIRECT@%$EXT2_DIRECT%g +s%@HOSTS_ACCESS@%$HOSTS_ACCESS%g +s%@LIBMALLOC@%$LIBMALLOC%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..bcabb3a --- /dev/null +++ b/configure.in @@ -0,0 +1,73 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(quota.c) + +dnl Checks for programs. +AC_PROG_CC +AC_HEADER_STDC +AC_PROG_INSTALL + +dnl Checks for libraries. +AC_CHECK_LIB(com_err, com_err) +AC_CHECK_LIB(ext2fs, ext2fs_initialize) +EXT2LIBS=${LIBS} +AC_SUBST(EXT2LIBS) +LIBS="" + +AC_CHECK_LIB(nsl, main) +AC_CHECK_LIB(wrap, main) + +if test ${ac_cv_lib_com_err_com_err} = yes && + test ${ac_cv_lib_ext2fs_ext2fs_initialize} = yes; then + AC_CHECK_HEADER(ext2fs/ext2fs.h,, [ + echo 'ERROR: could not find ext2fs/ext2fs.h - missing ext2 package' + exit 1 + ]) + EXT2_DIRECT="-DEXT2_DIRECT" + AC_SUBST(EXT2_DIRECT) +fi + +if test ${ac_cv_lib_wrap_main} = yes; then + AC_CHECK_HEADER(tcpd.h,, [ + echo 'ERROR: could not find tcpd.h - missing TCP wrappers package' + exit 1 + ]) + HOSTS_ACCESS="-DHOSTS_ACCESS" + AC_SUBST(HOSTS_ACCESS) +fi + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE + +AC_ARG_ENABLE(altformat, + [ --enable-altformat=[yes/no] Enable alternative format used by edquota [default=yes].], + , + enable_altformat="yes") +AC_ARG_ENABLE(rpc, + [ --enable-rpc=[yes/no] Enable RPC support [default=yes].], + , + enable_rpc="yes") +AC_ARG_ENABLE(rpcsetquota, + [ --enable-rpcsetquota=[yes/no] Use RPC for setting quotas [default=yes].], + , + enable_rpcsetquota="yes") +AC_ARG_ENABLE(libefence, + [ --enable-libefence=[yes/no] Use Electric Fence memory checks [default=no].], + , + enable_libefence="no") + +if test "$enable_altformat" = "yes" ; then + CFLAGS="-DALT_FORMAT $CFLAGS"; +fi +if test "$enable_rpc" = "yes" ; then + CFLAGS="-DRPC $CFLAGS"; +fi +if test "$enable_rpcsetquota" = "yes" ; then + CFLAGS="-DRPC_SETQUOTA $CFLAGS" +fi +if test "$enable_libefence" = "yes" ; then + LIBMALLOC="/usr/lib/libefence.a" +fi +AC_SUBST(LIBMALLOC) + +AC_OUTPUT(Makefile) diff --git a/convertquota.8 b/convertquota.8 new file mode 100644 index 0000000..de0d76e --- /dev/null +++ b/convertquota.8 @@ -0,0 +1,51 @@ +.TH CONVERTQUOTA 8 "Fri Aug 20 1999" +.UC 4 +.SH NAME +convertquota \- convert quota from old file format to new one +.SH SYNOPSIS +.B convertquota +[ +.B -ug +] +.I filesystem +.SH DESCRIPTION +.B convertquota +converts old quota files +.BR quota.user +and +.BR quota.group +to files +.BR aquota.user +and +.BR aquota.group +in new format currently used by kernels 2.4.0-ac? and newer on +.IR filesystem . +.PP +New file format allows using quotas for 32-bit uids / gids, setting quotas for root, +accounting used space in bytes (and so allowing use of quotas in ReiserFS) and it +is also architecture independent. This format introduces radix trie (a simple form of tree +structure) to quota file. +.SH OPTIONS +.TP +.B -u +convert user quota file. This is default. +.TP +.B -g +convert group quota file. +.SH FILES +.TP 20 +.B aquota.user +user quota file +.TP +.B aquota.group +group quota file +.SH "SEE ALSO" +.BR quota (1), +.BR setquota (8), +.BR edquota (8), +.BR quotacheck (8), +.BR quotaon (8), +.BR repquota (8) +.SH AUTHOR +Jan Kara \<jack@atrey.karlin.mff.cuni.cz\> + diff --git a/convertquota.c b/convertquota.c new file mode 100644 index 0000000..26f34e9 --- /dev/null +++ b/convertquota.c @@ -0,0 +1,136 @@ +/* + * + * Utility for converting quota file from old to new format + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <asm/byteorder.h> + +#include "pot.h" +#include "common.h" +#include "quotaio.h" +#include "quotasys.h" +#include "quota.h" +#include "bylabel.h" + +char *mntpoint; +int ucv, gcv; +struct quota_handle *qn; /* Handle of new file */ + +void parse_options(int argcnt, char **argstr) +{ + int ret; + char *slash = strrchr(argstr[0], '/'), cmdname[PATH_MAX]; + + if (!slash) + slash = argstr[0]; + else + slash++; + sstrncpy(cmdname, slash, sizeof(cmdname)); + while ((ret = getopt(argcnt, argstr, "Vugh:")) != EOF) { + switch (ret) { + case '?': + case 'h': +usage: + printf(_("Utility for converting quota files.\nUsage:\n%s [-u] [-g] mountpoint\n"), cmdname); + printf(_("Bugs to %s\n"), MY_EMAIL); + exit(1); + case 'V': + version(); + exit(0); + case 'u': + ucv = 1; + break; + case 'g': + gcv = 1; + break; + } + } + if (optind + 1 != argcnt) { + puts(_("Bad number of arguments.")); + goto usage; + } + if (!(ucv | gcv)) + ucv = 1; + mntpoint = argstr[optind]; +} + +int convert_dquot(struct dquot *dquot) +{ + struct dquot newdquot; + + memset(&newdquot, 0, sizeof(newdquot)); + newdquot.dq_id = dquot->dq_id; + newdquot.dq_h = qn; + newdquot.dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; + newdquot.dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; + newdquot.dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; + newdquot.dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; + newdquot.dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; + newdquot.dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; + newdquot.dq_dqb.dqb_btime = dquot->dq_dqb.dqb_btime; + newdquot.dq_dqb.dqb_itime = dquot->dq_dqb.dqb_itime; + if (qn->qh_ops->commit_dquot(&newdquot) < 0) { + fprintf(stderr, _("Can't commit dquot for id %u: %s\n"), (uint)dquot->dq_id, strerror(errno)); + return -1; + } + return 0; +} + +void convert_file(int type) +{ + struct quota_handle *qo; + char *qfname, namebuf[PATH_MAX]; + FILE *mntf; + struct mntent *mnt; + const char *dev; + + if (!(mntf = setmntent(MOUNTED, "r"))) + die(2, _("Can't open %s: %s\n"), MOUNTED, strerror(errno)); + while ((mnt = getmntent(mntf))) { + if (!(dev = get_device_name(mnt->mnt_fsname))) + continue; + if (!strcmp(dev, mntpoint) || !strcmp(mnt->mnt_dir, mntpoint)) + break; + } + if (!mnt) + die(1, _("Can't find given mountpoint %s\n"), mntpoint); + if (!(qo = init_io(mnt, type, QF_VFSOLD))) { + fprintf(stderr, _("Can't open old format file for %ss on %s\n"), type2name(type), mntpoint); + return; + } + if (!(qn = new_io(mnt, type, QF_VFSV0))) { + fprintf(stderr, _("Can't create file for %ss for new format on %s: %s\n"), type2name(type), mntpoint, strerror(errno)); + end_io(qo); + return; + } + if (qo->qh_ops->scan_dquots(qo, convert_dquot) >= 0) { /* Conversion succeeded? */ + qfname = get_qf_name(mnt, type, QF_VFSV0); + strcpy(namebuf, qfname); + sstrncat(namebuf, ".new", sizeof(namebuf)); + if (rename(namebuf, qfname) < 0) + fprintf(stderr, _("Can't rename new quotafile %s to name %s: %s\n"), namebuf, qfname, strerror(errno)); + free(qfname); + } + endmntent(mntf); + end_io(qo); + end_io(qn); +} + +int main(int argcnt, char **argstr) +{ + parse_options(argcnt, argstr); + if (ucv) + convert_file(USRQUOTA); + if (ucv) + convert_file(GRPQUOTA); + return 0; +} + diff --git a/doc/edquota(8).html b/doc/edquota(8).html new file mode 100644 index 0000000..201f443 --- /dev/null +++ b/doc/edquota(8).html @@ -0,0 +1,96 @@ +<HTML> +<HEAD> +<TITLE>edquota(8) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +edquota - edit user quotas +<H1>SYNOPSIS</H1> +<B>edquota</B> +[ +<B>-p</B> +<B>proto-user</B> +] [ +<B>-ug</B> +] +<B>name</B> +<BR> +<B>edquota</B> +[ +<B>-ug</B> +] +<B>-t</B> +<H1>DESCRIPTION</H1> +<B>edquota</B> +is a quota editor. One or more users or groups may be specified on the command +line. For each user or group a temporary file is created with an +<B>ASCII</B> +representation of the current disk quotas for that user or group and an editor +is then invoked on the file. The quotas may then be modified, new +quotas added, etc. Upon leaving the editor, +<B>edquota</B> +reads the temporary file and modifies the binary quota files to reflect +the changes made. +<P> +The editor invoked is +<B>vi (1)</B> +unless the +<B>EDITOR</B> +environment variable specifies otherwise. +<P> +Only the super-user may edit quotas. (In order for quotas to be +established on a file system, the root directory of the file system must +contain a file, owned by root, called +<B>quota.user</B> +or +<B>quota.group</B> +. See +<A HREF="quotaon(8).html">quotaon (8)</A> +for details.) +<H1>OPTIONS</H1> +<UL> +<LI> +<B>-u</B> +<BR> +Edit the userquota. This is the default. +<LI> +<B>-g</B> +<BR> +Edit the groupquota. +<LI> +<B>-p</B> +<BR> +Duplicate the quotas of the prototypical user specified for each user specified. +This is the normal mechanism used to initialize quotas for groups of users. +<LI> +<B>-t</B> +<BR> +Edit the soft time limits for each file system. If the time limits are zero, +the default time limits in <linux/quota.h> are used. Time units of sec(onds), +min(utes), hour(s), day(s), week(s), and month(s) are understood. Time limits +are printed in the greatest possible time unit such that the value is greater +than or equal to one. +</UL> +<H1>FILES</H1> +<B>quota.user</B> + : located at the filesystem root with user quotas +<BR> +<B>quota.group</B> + : located at the filesystem root with group quotas +<BR> +<B>/etc/fstab</B> + : to find filesystem names and locations +<H1>SEE ALSO</H1> +<A HREF="quota(1).html">quota (1)</A>, +<A HREF="quotactl(2).html">quotactl (2)</A>, +<A HREF="fstab(5).html">fstab (5)</A>, +<A HREF="quotacheck(8).html">quotacheck (8)</A>, +<A HREF="quotaon(8).html">quotaon (8)</A>, +<A HREF="repquota(8).html">repquota (8)</A> +<H1>BUGS</H1> +The format of the temporary file is inscrutable. +</BODY> +</HTML> diff --git a/doc/fstab(5).html b/doc/fstab(5).html new file mode 100644 index 0000000..e627015 --- /dev/null +++ b/doc/fstab(5).html @@ -0,0 +1,127 @@ +<HTML> +<HEAD> +<TITLE>fstab(5) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +fstab - static information about the filesystems +<H1>SYNOPSIS</H1> +#include <fstab.h> +<H1>DESCRIPTION</H1> +The file +<B>fstab</B> +contains descriptive information about the various file systems. +<B>fstab</B> +is only read by programs, and not written; it is the duty of the system +administrator to properly create and maintain this file. Each filesystem +is described on a separate line; fields on each line are separated by tabs +or spaces. The order of records in +<B>fstab</B> +is important because fsck (8), mount (8), and umount (8) sequentially iterate through +<B>fstab</B> +doing their thing. +<P> +The first field, +<B>fs_spec</B> +describes the block special device or remote filesystem to be mounted. +<P> +The second field, +<B>fs_file</B> +describes the mount point for the filesystem. For swap partitions, this +field should be specified as ``none''. +<P> +The third field, +<B>fs_vfstype</B> +describes the type of the filesystem. The system currently supports three +types of filesystems: +<UL> +<LI> +<B>minix</B> +<BR> +a local filesystem, supporting filenames of length 14 or 30 characters. +<LI> +<B>ext</B> +<BR> +a local filesystem with longer filenames and larger inodes. This +filesystem has been replaced by the +<B>ext2</B> +file system, and should no longer be used. +<LI> +<B>ext2</B> +<BR> +a local filesystem with longer filenames, larger inodes, and lots of other +features. +<LI> +<B>xiafs</B> +<BR> +a local filesystem with longer filenames, larger inodes, and lots of other +features. +<LI> +<B>msdos</B> +<BR> +a local filesystem for MS-DOS partitions. +<LI> +<B>hpfs</B> +<BR> +a local filesystem for HPFS partitions. +<LI> +<B>iso9660</B> +<BR> +a local filesystem used for CD-ROM drives. +<LI> +<B>nfs</B> +<BR> +a filesystem for mounting partitions from remote systems. +<LI> +<B>swap</B> +<BR> +a disk partition to be used for swapping. +</UL> +<P> +If +<B>vfs_fstype</B> +is specified as ``ignore'' the entry is ignored. This is useful to show +disk partitions which are currently unused. +<P> +The fourth field, +<B>fs_mntops</B> +describes the mount options associated with the filesystem. +It is formatted as a comma separated list of options. It contains at least +the type of mount plus any additional options appropriate to the filesystem +type. For documentation on all of the available options, see mount (8). +<P> +The fifth field, +<B>fs_freq</B> +is used for these filesystems by the dump (8) command to determine which +filesystems need to be dumped. If the fifth field is not present, a value +of zero is returned and dump will assume that the filesystem does not need +to be dumped. +<P> +The sixth field, +<B>fs_passno</B> +is used by the fsck (8) program to determine the order in which filesystem +checks are done at reboot time. The root filesystem should be specified +with a +<B>fs_passno</B> +of 1, and other filesystems should have a +<B>fs_passno</B> +of 2. Filesystems within a drive will be checked sequentially, but +filesystems on different drives will be checked at the same time to utilize +parallelism available in the hardware. If the sixth field is not present +or zero, a value of zero is returned and fsck will assume that the filesystem +does not need to be checked. +<P> +The proper way to read records from +<B>fstab</B> +is to use the routines getmntent (3). +<H1>FILES</H1> +<B>/etc/fstab</B> +resides in +<B>/etc</B> +<H1>SEE ALSO</H1> +getmntent (3), mount (8), swapon (8) +</BODY> +</HTML> diff --git a/doc/quota(1).html b/doc/quota(1).html new file mode 100644 index 0000000..77f8242 --- /dev/null +++ b/doc/quota(1).html @@ -0,0 +1,92 @@ +<HTML> +<HEAD> +<TITLE>quota(1) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +quota - display disk usage and limits +<H1>SYNOPSIS</H1> +quota [ +<B>-guv | q</B> +] +<BR> +quota [ +<B>-uv | q</B> +] user +<BR> +quota [ +<B>-gv | q</B> +] group +<H1>DESCRIPTION</H1> +<B>Quota</B> +displays users' disk usage and limits. +By default only the user quotas are printed. +<UL> +<LI> +<B>-g</B> +<BR> +Print group quotas for the group of which the user is a member. The optional +<LI> +<B>-u</B> +<BR> +flag is equivalent to the default. +<LI> +<B>-v</B> +<BR> +will display quotas on filesystems where no storage is allocated. +<LI> +<B>-q</B> +<BR> +Print a more terse message, containing only information +on filesystems where usage is over quota. +</UL> +Specifying both +<B>-g</B> +and +<B>-u</B> +displays both the user quotas and the group quotas (for the user). +<P> +Only the super-user may use the +<B>-u</B> +flag and the optional +<B>user</B> +argument to view the limits of other users. Non-super-users can use the the +<B>-g</B> +flag and optional +<B>group</B> +argument to view only the limits of groups of which they are members. +<P> +The +<B>-q</B> +flag takes precedence over the +<B>-v</B> +flag. +<P> +<B>Quota</B> +reports the quotas of all the filesystems listed in +<B>/etc/fstab.</B> +For filesystems that are NFS-mounted a call to the rpc.rquotad on +the server machine is performed to get the information. If +<B>quota</B> +exits with a non-zero status, one or more filesystems are over quota. +<H1>FILES</H1> +<B>quota.user</B> + : located at the filesystem root with user quotas +<BR> +<B>quota.group</B> + : located at the filesystem root with group quotas +<BR> +<B>/etc/fstab</B> + : to find filesystem names and locations +<H1>SEE ALSO</H1> +<A HREF="quotactl(2).html">quotactl (2)</A>, +<A HREF="fstab(5).html">fstab (5)</A>, +<A HREF="edquota(8).html">edquota (8)</A>, +<A HREF="quotacheck(8).html">quotacheck (8)</A>, +<A HREF="quotaon(8).html">quotaon (8)</A>, +<A HREF="repquota(8).html">repquota (8)</A> +</BODY> +</HTML> diff --git a/doc/quota.html b/doc/quota.html new file mode 100644 index 0000000..2e86b5c --- /dev/null +++ b/doc/quota.html @@ -0,0 +1,288 @@ +<HTML> +<HEAD> +<TITLE>Linux DiskQuota system</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>General</H1> +<P> +In most computing environments, disc space is not infinite. The +diskquota system provides a mechanism to control usage of disc space, +on an individual basis. Quotas may be set for each individual user, on +any, or all filesystems. The quota system will warn users when they +exceed their allotted limit, but allow some extra space for current work. +Repeatedly remaining over quota at logout, will cause a fatal over quota +condition eventually. The quota system is an optional part of LINUX that +may be included when the system is configured. This document will describe +from what view the +<A HREF="#USERVIEW">Users</A> +will see the quota-system and the way the quota-system can be configured +by the +<A HREF="#ADMINISTERING">System Administator</A> +. +<P> +<A NAME="USERVIEW"><H1>Users' view of diskquotas</H1></A> +<H2>General</H2> +To most users, diskquotas will either be of no concern, or a fact of life +that cannot be avoided. The +<A HREF="quota(1).html">quota(1)</A> +command will provide information on +any disc quotas that may have been imposed upon a user. +<P> +There are two individual possible quotas that may be imposed, usually if +one is, both will be. A limit can be set on the amount of space a user can +occupy, and there may be a limit on the number of files (inodes) he can own. +Quota provides information on the quotas that have been set by the system +administrators, in each of these areas, and current usage. The inode limit and +block limit are impossed both on uid and on gid. So if there are group quotas +you can be limited because the group can't allocate any more space even if you +as user still can allocate the space. +<P> +There are four numbers for each limit, the current usage, soft limit (quota), +hard limit, and time remaining bfore the softlimit is intepretted as a hard +limit. The soft limit is the number of 1K blocks (or files) that the user is +expected to remain below. Each time the user's usage goes past this limit, he +will be warned. The hard limit cannot be exceeded. If a user's usage reaches +this number, further requests for space (or attempts to create a file) will +fail with an EDQUOT error, and the first time this occurs, a message will +be written to the user's terminal. Only one message will be output, until space +occupied is reduced below the limit, and reaches it again, in order to avoid +continual noise from those programs that ignore write errors. +<P> +When a use exeeds his softlimit a timer is set that normaly expires wuthin +7 days (1 week). The user can remove files in this period to make sure he is +under the softlimit again before the timer expires. When the timer expires the +particular limit that has been exceeded will be treated as if the hard limit +has been reached, and no more resources will be allocated to the user. The only +way to reset this condition is to reduce usage below the softlimit. +<P> +<H2>Surviving when quota limit is reached</H2> +In most cases, the only way to recover from over quota conditions, is to abort +whatever activity was in progress on the filesystem that has reached its limit, +remove sufficient files to bring the limit back below quota, and retry the +failed program. +<P> +However, if you are in the editor and a write fails because of an over quota +situation, that is not a suitable course of action, as it is most likely that +initially attempting to write the file will have truncated its previous +contents, so should the editor be aborted without correctly writing the file +not only will the recent changes be lost, but possibly much, or even all, of +the data that previously existed. +<P> +There are several possible safe exits for a user caught in this situation. +He may use the editor ! shell escape command to examine his file space, and +remove surplus files. Alternatively, using csh, he may suspend the editor, +remove some files, then resume it. A third possibility, is to write the file +to some other filesystem (perhaps to a file on /tmp) where the user's quota +has not been exceeded. Then after rectifying the quota situation, the file +can be moved back to the filesystem it belongs on. +<A NAME="ADMINISTERING"><H1>Administering the quota system</H1></A> +To set up and establish the diskquota system, there are several steps necessary +to be performed by the system administrator. The following steps must be taken: +<UL> +<LI> +<A HREF="#KERNEL">Kernel configuration</A> +<LI> +<A HREF="#ELECTING">Electing filesystems</A> +<LI> +<A HREF="#ENABLING">Enabling quotas</A> +<LI> +<A HREF="#CHECKING">Checking a filesystem for quotas</A> +<LI> +<A HREF="#SPECIFYING">Specifing a quota for a user or group</A> +<LI> +<A HREF="#CHECKING">Checking quotas for a user or group</A> +<LI> +<A HREF="#DISABLING">Disabling quota for a user or group</A> +<LI> +<A HREF="#NFS">Quotas on NFS-mounted disks</A> +</UL> +<A NAME="KERNEL"><H2>Kernel configuration</H2></A> +Before you can use the quota-system you must compile a kernel +with the quota-system enabled. This is done by answering yes +to the Disk QUOTA support question when running <make config>. Then +run <make> and install the new kernel images as the one that is booted +at boottime. +<A NAME="ELECTING"><H2>Electing filesystems</H2></A> +When you have a kernel that supports quota you need to make a decision as to what +filesystems need to have quotas applied. Usually, only filesystems that house +users' home directories, or other user files, will need to be subjected to the +quota system, though it may also prove useful to also include /usr if its writable +by normal users. +<P> +To enable quotas on a certain filesystem one should edit the /etc/fstab +file and add entries for usrquota and grpquota. Mine looks like : +<PRE> +# device directory type options +/dev/hda1 / ext2 defaults +/dev/hda2 none swap sw +/dev/hda3 /usr ext2 defaults +/dev/hdb1 /usr/users ext2 defaults,usrquota,grpquota +/dev/hdb2 /usr/src ext2 defaults,usrquota +none /proc proc defaults +</PRE> +The keyword "usrquota" in the options field of each fstab-entry turns on +userquota for this device. The keyword "grpquota" in the options field turns +on groupquota for the device. When you use the usrquota and grpquota options +without the "=" option you quotafiles are located in the rootdir of each +filesystem. A file called "quota.user" is used for userquota and a file called +"quota.group" is used for groupquota. +<P> +You can also define your quotafile yourself. Something like +"usrquota=/usr/adm/quotasrc.user" puts the quotafile in /usr/adm with the +name quotasrc.user. Please be aware of the maximum lenght a line can have +in your fstab, see +<B>mntent.h</B> +for a definition. +<P> +<A NAME="ENABLING"><H2>Enabling quotas</H2></A> +Periodically (certainly after each unclean reboot, and when quotas are first +enabled for a filesystem), the records retained in the quota file should be +checked for consistency with the actual number of blocks and files allocated +to the user. The +<A HREF="quotacheck(8).html">quotacheck(8)</A> +command can be used to accomplish this. It is +not necessary to dismount the filesystem, or disable the quota system to run +this command, though on active filesystems inaccurate results may occur. This +does no real harm in most cases, another run of quotacheck when the +filesystem is idle will certainly correct any inaccuracy. +<P> +To check the filesystem for the actual number of blocks used by a user run +<KBD>quotacheck -avug</KBD> +to install or update all the quotafiles. +<P> +The quotacheck program takes some time on large filesystems, but whith the +new version it is quite acceptable on my machine. But when you are hacking +the kernel, I recommend not to use it because it takes some time every time +you have to reboot your machine. You also can also put it in you rc script +and run it like you run fsck on your filesystems only when the fastreboot +flag is not set. There is no support for parallel checking of filesystems. +<P> +Ok now one should have all the quotafiles one needs. +Now you can add a line like: +<KBD>/usr/etc/quotaon -avug</KBD> +<P> +to your /etc/rc. This is to turn the quotas on when you boot your machine. +This is they way to go and not turn it on yourself any time when you boot +your machine. +<A NAME="CHECKING"><H2>Checking a filesystem for quotas</H2></A> +The super-user may use the +<A HREF="quota(1).html">quota (1)</A> +command to examine the usage and quotas +of any user, and the +<A HREF="repquota(8).html">repquota (8)</A> +command may be used to check the usages and +limits for all users on a filesystem. Just run +<KBD>quotacheck -avug</KBD> +and the quotafiles are updated automagicaly and also the tables that are +currently used by the kernel. Watch for the "updating in core quotas" message +of the +<A HREF="quotacheck(8).html">quotacheck (8)</A> +program this says if it updates the in core quotas in the kernel. +<P> +I cannot state this enough the quotafile is build as (uid || gid * +sizeof(struct dquot)) so when you have nobody as uid 65535 and nobody owns a +file you get big quota files, lets say of about 2 Mb all filed with zero's +for users that don't have quota. So please be aware of that and don't mail +me about that. It isn't much of a problem because the file isn't that big +really all 0 blocks are not allocated on the disk. +<A NAME="SPECIFYING"><H2>Specifing a quota for a user or group</H2></A> +To edit the quotas for various users we use the +<A HREF="edquota(8).html">edquota (8)</A> program. Now use +<KBD>edquota -u <username | uid></KBD> +to edit user quotas and +<KBD>edquota -g <groupname | gid></KBD> +to edit group quotas. +<P> +Edit only the numbers behind the soft and hard keywords. There are two lines +for each filesystem that has quota turned on. Soft means the softlimit, if +people or groups go over there softlimit they have some grace period to make +sure they go under there softlimit. +<P> +The graceperiod can be changed with +<KBD>edquota -t</KBD> +and enter the number of days there. If they don't remove it within there graceperiod +it is counted as a hardlimit. The hardlimit is the absolute maximum they can allocate, +if they want more the files are truncated. +<P> +The one line that says blocks is the number of blocks one can allocate, +the line that says inodes is the number of inodes +(files/named pipes/devices/etc.) one can allocate. +<P> +Most of the time you have groups of users with the same quota. A quick way of editing +the quota for all those users is change to the dir where there homedirs reside. Do a +edquota for one of the users and change the quotas to the approriate values. This user +becomes the so called prototype user or group for all the others. Then execute +<KBD>edquota -p prototypeusername *</KBD> +this should do the trick, all users now have the quota they need, now +you could edit the ones that still need other values. +<A NAME="CHECKING"><H2>Checking quotas for a user or group</H2></A> +Run the quota program. The syntax for this program is : +<PRE> +quota [-guqv] +quota [-qv] -u username ... +quota [-qv] -g groupname ... +</PRE> +Use -v to see the quotas on +<UL> +<LI> +filesystems you don't have quotas on +<LI> +filesystems on which you do have quota but haven't allocated any blocks yet +</UL> +Use -q to only see filesystems on which you are over your softlimit or +have reached your hardlimit. +<P> +The -g flags give you all quotas for the groups you are in (also +additional groups). +<A NAME="DISABLING"><H2>Disabling quota for a user or group</H2></A> +When you want to disable quotas for a certain user use the quota editor +edquota. Type +<KBD>edquota username | uid</KBD> +or +<KBD>edquota -g groupname | gid</KBD> +and set block softlimit and hardlimit, and the inode soft- and hardlimit to 0. +This should disable the quota for that user an the user can allocate as many +blocks and inodes as he/she wants. +<A NAME="NFS"><H2>Quotas on NFS-mounted disks</H2></A> +To have quotas on NFS filesystems, you need to install quotas on the +fileserver and not on the client. Clients can obtain quota information +with the quota command which does a query to the +<A HREF="rquotad(8).html">rquotad (8)</A> +running on the fileserver from which you mount your NFS disks. So don't put any +usrquota or grpquota flags in the flags for mounting NFS disks. Instead install +quotas on your fileserver. And start the rpc.rquotad from your network rc-file. +<H1>Some implementation details</H2> +Diskquota usage and information is stored in a file on the filesystem that the +quotas are to be applied to. Conventionally, this file is quota.user or quota.group +in the root of the filesystem. +<P> +The data in the file comprises an array of structures, indexed by uid or gid, one +structure for each user or group on the system (whether the user or group has a +quota on this filesystem or not). If the uid or gid space is sparse, then the +file may have holes in it, which would be lost by copying, so it is best to avoid +this. +<P> +The system is informed of the existence of the quota file by the +<A HREF="quotactl(2).html">quotactl (2)</A> +system call. It then reads the quota entries for each user or group currently +active, then for any files open owned by users who are not currently active. +Each subsequent open of a file on the filesystem, will be accompanied by a +pairing with its quota information. In most cases this information will be +retained in core, either because the user who owns the file is running some +process, because other files are open owned by the same user, or because +some file (perhaps this one) was recently accessed. In memory, the quota +information is kept hashed by uid or group and filesystem, and retained in +an LRU chain so recently released data can be easily reclaimed. Information +about those users whose last process has recently terminated is also retained +in this way. +<P> +Each time a block is accessed or released, and each time an inode is allocated +or freed, the quota system gets told about it, and in the case of allocations, +gets the opportunity to object. Measurements have shown that the quota code +uses a very small percentage of the system cpu time consumed in writing a new +block to disk. +</BODY> +</HTML> diff --git a/doc/quota4th.fig b/doc/quota4th.fig new file mode 100644 index 0000000..cd4fc9b --- /dev/null +++ b/doc/quota4th.fig @@ -0,0 +1,62 @@ +#FIG 2.1 +80 2 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 199 119 199 79 79 79 79 119 199 119 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 759 119 759 79 639 79 639 119 759 119 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 759 199 759 159 639 159 639 199 759 199 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 199 199 199 159 79 159 79 199 199 199 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 139 159 139 119 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 699 159 699 119 9999 9999 +2 1 0 4 -1 0 0 0 0.000 -1 0 0 + 39 259 854 259 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 379 119 379 79 259 79 259 119 379 119 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 379 199 379 159 259 159 259 199 379 199 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 579 199 579 159 459 159 459 199 579 199 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 579 119 579 79 459 79 459 119 579 119 9999 9999 +2 2 0 1 -1 0 0 0 0.000 0 0 0 + 519 359 359 359 359 319 519 319 519 359 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 359 339 139 339 139 199 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 519 339 699 339 699 199 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 379 319 379 299 219 299 219 99 259 99 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 419 319 419 279 239 279 239 179 259 179 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 499 319 499 299 619 299 619 99 579 99 9999 9999 +2 1 0 1 -1 0 0 0 0.000 -1 1 0 + 0 0 1.000 4.000 8.000 + 459 319 459 279 599 279 599 179 579 179 9999 9999 +4 0 2 14 0 -1 0 0.00000 4 18 115 259 99 DQUOT_ALLOC_ +4 0 2 14 0 -1 0 0.00000 4 18 48 259 114 INODE +4 0 2 14 0 -1 0 0.00000 4 18 115 259 179 DQUOT_ALLOC_ +4 0 2 14 0 -1 0 0.00000 4 18 51 259 194 BLOCK +4 0 2 14 0 -1 0 0.00000 4 18 107 464 99 DQUOT_FREE_ +4 0 2 14 0 -1 0 0.00000 4 18 48 464 114 INODE +4 0 2 14 0 -1 0 0.00000 4 18 111 459 174 DQUOT_FREE_ +4 0 2 14 0 -1 0 0.00000 4 18 51 459 196 BLOCK +4 0 2 14 0 -1 0 0.00000 4 18 88 19 59 VFS-LAYER +4 0 2 14 0 -1 0 0.00000 4 18 96 19 299 FILESYSTEM +4 0 2 14 0 -1 0 0.00000 4 18 141 374 339 FILESYSTEM OPER +4 0 2 14 0 -1 0 0.00000 4 18 52 104 99 DQGET +4 0 2 14 0 -1 0 0.00000 4 18 36 99 179 IGET +4 0 2 14 0 -1 0 0.00000 4 18 34 659 179 IPUT +4 0 2 14 0 -1 0 0.00000 4 18 50 659 99 DQPUT +4 0 2 14 0 -1 0 0.00000 4 18 317 319 39 DISKQUOTAS FOR LINUX (4th GENERATION) diff --git a/doc/quotacheck(8).html b/doc/quotacheck(8).html new file mode 100644 index 0000000..2a3cf66 --- /dev/null +++ b/doc/quotacheck(8).html @@ -0,0 +1,94 @@ +<HTML> +<HEAD> +<TITLE>quotacheck(8) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +quotacheck - scan a file system for disk usages +<H1>SYNOPSIS</H1> +<B>quotacheck</B> +[-g] [-u] [-v] -a +<BR> +<B>quotacheck</B> +[-g] [-u] [-v] filesys ... +<H1>DESCRIPTION</H1> +<B>Quotacheck</B> +performs a filesystems scan for usage of files and directories, used +by either user or group. The output is the quota file for the +corresponding filesystem. By default the names for these files are: +<UL> +<LI> +A user scan: +<B>quota.user</B> +<LI> +A group scan: +<B>quota.group</B> +</UL> +<P> +The resulting file consist of a +<B>struct dqblk</B> +for each possible id up to the highest existing uid or gid and contains the +values for the disk file and block usage and possibly excess time for these +values. ( for definitions of +<B>struct dqblk</B> +see +<B><linux/quota.h></B> +) +<P> +<B>Quotacheck</B> +should be run each time the system boots and mounts non-valid file systems. +This is most likely to happen after a system crash. +<P> +The speed of the scan decrease with the amount of directories increasing. +The time needed doubles when disk usage is doubled as well. A 100 MB partition +used for 94% is scanned in 1 minute, the same partition used for 50% is +done in 25 seconds. +<H1>OPTIONS</H1> +<UL> +<LI> +<B>-v</B> +<BR> +This way the program will give some usefull information about what it is +doing, plus some fancy stuff. +<LI> +<B>-d</B> +<BR> +This means debug. It will result in a lot of information which can be used +in debugging the program. The output is very verbose and the scan +will not be fast. +<LI> +<B>-u</B> +<BR> +This flag tells the program to scan the disk and to count the files and +directories used by a certain uid. This is the default action. +<LI> +<B>-g</B> +<BR> +This flag forces the program to count the the files and directories +used by a certain gid. +</UL> +<H1>NOTE</H1> +<B>Quotacheck</B> +should only be run as Super User. Non-privilidged users are presumably not allowed +to read all the directories on the given file system. +<H1>FILES</H1> +<B>quota.user</B> +located at the filesystem root with user quotas +<BR> +<B>quota.group</B> +located at the filesystem root with group quotas +<BR> +<B>/etc/fstab</B> +to find filesystem names and locations +<H1>SEE ALSO</H1> +<A HREF="quota(1).html">quota (1)</A>, +<A HREF="quotactl(2).html">quotactl (2)</A>, +<A HREF="fstab(5).html">fstab (5)</A>, +<A HREF="edquota(8).html">edquota (8)</A>, +<A HREF="quotaon(8).html">quotaon (8)</A>, +<A HREF="repquota(8).html">repquota (8)</A> +</BODY> +</HTML> diff --git a/doc/quotactl(2).html b/doc/quotactl(2).html new file mode 100644 index 0000000..63dc934 --- /dev/null +++ b/doc/quotactl(2).html @@ -0,0 +1,197 @@ +<HTML> +<HEAD> +<TITLE>quotactl(2) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +quotactl - manipulate disk quotas +<H1>SYNOPSIS</H1> +<B>#include <linux/quota.h></B> +<P> +<B>int quotactl(cmd, special, uid, addr) +<BR> +int cmd; +<BR> +char **special; +<BR> +int id; +<BR> +caddr_t addr;</B> +<H1>DESCRIPTION</H1> +The +<B>quotactl</B> +call manipulates disk quotas. +<B>cmd</B> +indicates a command to be applied to +<B>UID id</B> +or +<B>GID id</B> +. To set the type of quota use the +<B>QCMD(cmd, type)</B> +macro. +<P> +<B>Special</B> +is a pointer to a null-terminated string containing the path +name of the block special device for the file system being manipulated. +<P> +<B>Addr</B> +is the address of an optional, command specific, data structure +which is copied in or out of the system. The interpretation of +<B>addr</B> +is given with each command below. +<UL> +<LI> +<B>Q_QUOTAON</B> +<BR> +Turn on quotas for a file system. +<B>addr</B> +points to the path name of file containing the quotas for the file system. +The quota file must exist; it is normally created with the +<A HREF="quotacheck(8).html">quotacheck (8)</A> +program. This call is restricted to the super-user. +<LI> +<B>Q_QUOTAOFF</B> +<BR> +Turn off quotas for a file system. +<B>addr</B> +and +<B>id</B> +are ignored. +This call is restricted to the super-user. +<LI> +<B>Q_GETQUOTA</B> +<BR> +Get disk quota limits and current usage for user or group +<B>id</B> +. +<B>Addr</B> +is a pointer to a +<B>dqblk</B> +structure (defined in +<B><linux/quota.h></B> +). +Only the super-user may get the quotas of a user other than himself. +<LI> +<B>Q_SETQUOTA</B> +<BR> +Set disk quota limits and current usage for user or group +<B>id</B> +. +<B>Addr</B> +is a pointer to a +<B>dqblk</B> +structure (defined in +<B><linux/quota.h></B> +). +This call is restricted to the super-user. +<LI> +<B>Q_SETQLIM</B> +<BR> +Set disk quota limits for user or group +<B>id</B> +. +<B>Addr</B> +is a pointer to a +<B>dqblk</B> +structure (defined in +<B><linux/quota.h></B> +). +This call is restricted to the super-user. +<LI> +<B>Q_SYNC</B> +<BR> +Update the on-disk copy of quota usages for a file system. +If +<B>special</B> +is null then all file systems with active quotas are sync'ed. +<B>Addr</B> +and +<B>id</B> +are ignored. +</UL> +<H1>RETURN VALUES</H1> +<B>quotactl</B> +returns: +<UL> +<LI> +0 on success. +<LI> +-1 on failure and sets +<B>errno</B> +to indicate the error. +</UL> +<H1>ERRORS</H1> +<UL> +<LI> +<B>EFAULT</B> +<BR> +<B>addr</B> +or +<B>special</B> +are invalid. +<LI> +<B>EINVAL</B> +<BR> +The kernel has not been compiled with the +<B>QUOTA</B> +option or +<B>cmd</B> +is invalid. +<LI> +<B>ENOENT</B> +<BR> +The file specified by +<B>special</B> +or +<B>addr</B> +does not exist. +<LI> +<B>ENOTBLK</B> +<BR> +<B>special</B> +is not a block device. +<LI> +<B>EPERM</B> +<BR> +The call is privileged and the caller was not the super-user. +<LI> +<B>ESRCH</B> +<BR> +No disc quota is found for the indicated user. +<BR> +Quotas have not been turned on for this file system. +<LI> +<B>EUSERS</B> +<BR> +The quota table is full. +</UL> +<P> +If +<B>cmd</B> +is +<B>Q_QUOTAON quotactl</B> +may set errno to: +<UL> +<LI> +<B>EACCES</B> +<BR> +The quota file pointed to by +<B>addr</B> +exists but is not a regular file. +<LI> +<B>EBUSY</B> +<BR> +<B>Q_QUOTAON</B> +attempted while another +<B>Q_QUOTAON</B> +has already taken place. +</UL> +<H1>SEE ALSO</H1> +<A HREF="quota(1).html">quota (1)</A>, +<A HREF="quotacheck(8).html">quotacheck (8)</A>, +<A HREF="quotaon(8).html">quotaon (8)</A>, +</BODY> +</HTML> diff --git a/doc/quotaon(8).html b/doc/quotaon(8).html new file mode 100644 index 0000000..f384c24 --- /dev/null +++ b/doc/quotaon(8).html @@ -0,0 +1,80 @@ +<HTML> +<HEAD> +<TITLE>quotaon(8) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +quotaon, quotaoff - turn file system quotas on and off +<H1>SYNOPSIS</H1> +<B>quotaon</B> +[ +<B>-vug</B> +] +<B>filesystem</B> +<BR> +<B>quotaon</B> +[ +<B>-avug</B> +] +<P> +<B>quotaoff</B> +[ +<B>-vug</B> +] +<B>filesystem</B> +<BR> +<B>quotaoff</B> +[ +<B>-avug</B> +] +<H1>DESCRIPTION</H1> +<B>quotaon</B> +announces to the system that disk quotas should be enabled on one or +more file systems. The file system quota files must be present in the root +directory of the specified file system and be named +<B>quota.user</B> +for userquota or +<B>quota.group</B> +for groupquota. +<P> +<B>quotaoff</B> +announces to the system that file systems specified should have any disk quotas turned off. +<H1>OPTIONS</H1> +<UL> +<LI> +<B>-a</B> +<BR> +All file systems in +<B>/etc/fstab</B> +marked read-write with quotas will have their quotas turned on. This is normally used at +boot time to enable quotas. +<LI> +<B>-v</B> +<BR> +Display a message for each file system where quotas are turned on. +<LI> +<B>-u</B> +<BR> +Manupulate user quotas. This is the default. +<LI> +<B>-g</B> +<BR> +Manupulate group quotas. +</UL> +<H1>FILES</H1> +<B>quota.user</B> + : located at the filesystem root with user quotas +<BR> +<B>quota.group</B> + : located at the filesystem root with group quotas +<BR> +<B>/etc/fstab</B> + : to find filesystem names and locations +<H1>SEE ALSO</H1> +<A HREF="quotactl(2).html">quotactl (2)</A>, +<A HREF="fstab(5).html">fstab (5)</A> +</BODY> +</HTML> diff --git a/doc/quotas-1.eps b/doc/quotas-1.eps new file mode 100644 index 0000000..84a858d --- /dev/null +++ b/doc/quotas-1.eps @@ -0,0 +1,3716 @@ +%!PS-Adobe-3.0 EPSF-2.0 +%%Creator: Windows PSCRIPT +%%Title: PowerPoint - QUOTAS.PPT +%%DocumentNeededResources: (atend) +%%DocumentSuppliedResources: (atend) +%%Pages: 0 +%%BeginResource: procset Win35Dict 3 1 +%%BoundingBox: 10 13 832 577 +%%EndComments +%%BeginProcSet: epsffit 1 0 +gsave +842.000 0.000 translate +90 rotate +1.000 1.000 scale +%%EndProcSet +/Win35Dict 290 dict def Win35Dict begin/bd{bind def}bind def/in{72 +mul}bd/ed{exch def}bd/ld{load def}bd/tr/translate ld/gs/gsave ld/gr +/grestore ld/M/moveto ld/L/lineto ld/rmt/rmoveto ld/rlt/rlineto ld +/rct/rcurveto ld/st/stroke ld/n/newpath ld/sm/setmatrix ld/cm/currentmatrix +ld/cp/closepath ld/ARC/arcn ld/TR{65536 div}bd/lj/setlinejoin ld/lc +/setlinecap ld/ml/setmiterlimit ld/sl/setlinewidth ld/scignore false +def/sc{scignore{pop pop pop}{0 index 2 index eq 2 index 4 index eq +and{pop pop 255 div setgray}{3{255 div 3 1 roll}repeat setrgbcolor}ifelse}ifelse}bd +/FC{bR bG bB sc}bd/fC{/bB ed/bG ed/bR ed}bd/HC{hR hG hB sc}bd/hC{ +/hB ed/hG ed/hR ed}bd/PC{pR pG pB sc}bd/pC{/pB ed/pG ed/pR ed}bd/sM +matrix def/PenW 1 def/iPen 5 def/mxF matrix def/mxE matrix def/mxUE +matrix def/mxUF matrix def/fBE false def/iDevRes 72 0 matrix defaultmatrix +dtransform dup mul exch dup mul add sqrt def/fPP false def/SS{fPP{ +/SV save def}{gs}ifelse}bd/RS{fPP{SV restore}{gr}ifelse}bd/EJ{gsave +showpage grestore}bd/#C{userdict begin/#copies ed end}bd/FEbuf 2 string +def/FEglyph(G )def/FE{1 exch{dup 16 FEbuf cvrs FEglyph exch 1 exch +putinterval 1 index exch FEglyph cvn put}for}bd/SM{/iRes ed/cyP ed +/cxPg ed/cyM ed/cxM ed 72 100 div dup scale dup 0 ne{90 eq{cyM exch +0 eq{cxM exch tr -90 rotate -1 1 scale}{cxM cxPg add exch tr +90 rotate}ifelse}{cyP +cyM sub exch 0 ne{cxM exch tr -90 rotate}{cxM cxPg add exch tr -90 +rotate 1 -1 scale}ifelse}ifelse}{pop cyP cyM sub exch 0 ne{cxM cxPg +add exch tr 180 rotate}{cxM exch tr 1 -1 scale}ifelse}ifelse 100 iRes +div dup scale 0 0 transform .25 add round .25 sub exch .25 add round +.25 sub exch itransform translate}bd/SJ{1 index 0 eq{pop pop/fBE false +def}{1 index/Break ed div/dxBreak ed/fBE true def}ifelse}bd/ANSIVec[ +16#0/grave 16#1/acute 16#2/circumflex 16#3/tilde 16#4/macron 16#5/breve +16#6/dotaccent 16#7/dieresis 16#8/ring 16#9/cedilla 16#A/hungarumlaut +16#B/ogonek 16#C/caron 16#D/dotlessi 16#27/quotesingle 16#60/grave +16#7C/bar 16#82/quotesinglbase 16#83/florin 16#84/quotedblbase 16#85 +/ellipsis 16#86/dagger 16#87/daggerdbl 16#88/circumflex 16#89/perthousand +16#8A/Scaron 16#8B/guilsinglleft 16#8C/OE 16#91/quoteleft 16#92/quoteright +16#93/quotedblleft 16#94/quotedblright 16#95/bullet 16#96/endash 16#97 +/emdash 16#98/tilde 16#99/trademark 16#9A/scaron 16#9B/guilsinglright +16#9C/oe 16#9F/Ydieresis 16#A0/space 16#A1/exclamdown 16#A4/currency +16#A5/yen 16#A6/brokenbar 16#A7/section 16#A8/dieresis 16#A9/copyright +16#AA/ordfeminine 16#AB/guillemotleft 16#AC/logicalnot 16#AD/hyphen +16#AE/registered 16#AF/macron 16#B0/degree 16#B1/plusminus 16#B2/twosuperior +16#B3/threesuperior 16#B4/acute 16#B5/mu 16#B6/paragraph 16#B7/periodcentered +16#B8/cedilla 16#B9/onesuperior 16#BA/ordmasculine 16#BB/guillemotright +16#BC/onequarter 16#BD/onehalf 16#BE/threequarters 16#BF/questiondown +16#C0/Agrave 16#C1/Aacute 16#C2/Acircumflex 16#C3/Atilde 16#C4/Adieresis +16#C5/Aring 16#C6/AE 16#C7/Ccedilla 16#C8/Egrave 16#C9/Eacute 16#CA +/Ecircumflex 16#CB/Edieresis 16#CC/Igrave 16#CD/Iacute 16#CE/Icircumflex +16#CF/Idieresis 16#D0/Eth 16#D1/Ntilde 16#D2/Ograve 16#D3/Oacute 16#D4 +/Ocircumflex 16#D5/Otilde 16#D6/Odieresis 16#D7/multiply 16#D8/Oslash +16#D9/Ugrave 16#DA/Uacute 16#DB/Ucircumflex 16#DC/Udieresis 16#DD/Yacute +16#DE/Thorn 16#DF/germandbls 16#E0/agrave 16#E1/aacute 16#E2/acircumflex +16#E3/atilde 16#E4/adieresis 16#E5/aring 16#E6/ae 16#E7/ccedilla 16#E8 +/egrave 16#E9/eacute 16#EA/ecircumflex 16#EB/edieresis 16#EC/igrave +16#ED/iacute 16#EE/icircumflex 16#EF/idieresis 16#F0/eth 16#F1/ntilde +16#F2/ograve 16#F3/oacute 16#F4/ocircumflex 16#F5/otilde 16#F6/odieresis +16#F7/divide 16#F8/oslash 16#F9/ugrave 16#FA/uacute 16#FB/ucircumflex +16#FC/udieresis 16#FD/yacute 16#FE/thorn 16#FF/ydieresis ] def/reencdict +12 dict def/IsChar{basefontdict/CharStrings get exch known}bd/MapCh{dup +IsChar not{pop/bullet}if newfont/Encoding get 3 1 roll put}bd/MapDegree{16#b0 +/degree IsChar{/degree}{/ring}ifelse MapCh}bd/MapBB{16#a6/brokenbar +IsChar{/brokenbar}{/bar}ifelse MapCh}bd/ANSIFont{reencdict begin/newfontname +ed/basefontname ed FontDirectory newfontname known not{/basefontdict +basefontname findfont def/newfont basefontdict maxlength dict def basefontdict{exch +dup/FID ne{dup/Encoding eq{exch dup length array copy newfont 3 1 roll +put}{exch newfont 3 1 roll put}ifelse}{pop pop}ifelse}forall newfont +/FontName newfontname put 127 1 159{newfont/Encoding get exch/bullet +put}for ANSIVec aload pop ANSIVec length 2 idiv{MapCh}repeat MapDegree +MapBB newfontname newfont definefont pop}if newfontname end}bd/SB{FC +/ULlen ed/str ed str length fBE not{dup 1 gt{1 sub}if}if/cbStr ed +/dxGdi ed/y0 ed/x0 ed str stringwidth dup 0 ne{/y1 ed/x1 ed y1 y1 +mul x1 x1 mul add sqrt dxGdi exch div 1 sub dup x1 mul cbStr div exch +y1 mul cbStr div}{exch abs neg dxGdi add cbStr div exch}ifelse/dyExtra +ed/dxExtra ed x0 y0 M fBE{dxBreak 0 BCh dxExtra dyExtra str awidthshow}{dxExtra +dyExtra str ashow}ifelse fUL{x0 y0 M dxUL dyUL rmt ULlen fBE{Break +add}if 0 mxUE transform gs rlt cyUL sl [] 0 setdash st gr}if fSO{x0 +y0 M dxSO dySO rmt ULlen fBE{Break add}if 0 mxUE transform gs rlt cyUL +sl [] 0 setdash st gr}if n/fBE false def}bd/font{/name ed/Ascent ed +0 ne/fT3 ed 0 ne/fSO ed 0 ne/fUL ed/Sy ed/Sx ed 10.0 div/ori ed -10.0 +div/esc ed/BCh ed name findfont/xAscent 0 def/yAscent Ascent def/ULesc +esc def ULesc mxUE rotate pop fT3{/esc 0 def xAscent yAscent mxUE transform +/yAscent ed/xAscent ed}if [Sx 0 0 Sy neg xAscent yAscent] esc mxE +rotate mxF concatmatrix makefont setfont [Sx 0 0 Sy neg 0 Ascent] mxUE +mxUF concatmatrix pop fUL{currentfont dup/FontInfo get/UnderlinePosition +known not{pop/Courier findfont}if/FontInfo get/UnderlinePosition get +1000 div 0 exch mxUF transform/dyUL ed/dxUL ed}if fSO{0 .3 mxUF transform +/dySO ed/dxSO ed}if fUL fSO or{currentfont dup/FontInfo get/UnderlineThickness +known not{pop/Courier findfont}if/FontInfo get/UnderlineThickness get +1000 div Sy mul/cyUL ed}if}bd/min{2 copy gt{exch}if pop}bd/max{2 copy +lt{exch}if pop}bd/CP{/ft ed{{ft 0 eq{clip}{eoclip}ifelse}stopped{currentflat +1 add setflat}{exit}ifelse}loop}bd/patfont 10 dict def patfont begin +/FontType 3 def/FontMatrix [1 0 0 -1 0 0] def/FontBBox [0 0 16 16] +def/Encoding StandardEncoding def/BuildChar{pop pop 16 0 0 0 16 16 +setcachedevice 16 16 false [1 0 0 1 .25 .25]{pat}imagemask}bd end/p{ +/pat 32 string def{}forall 0 1 7{dup 2 mul pat exch 3 index put dup +2 mul 1 add pat exch 3 index put dup 2 mul 16 add pat exch 3 index +put 2 mul 17 add pat exch 2 index put pop}for}bd/pfill{/PatFont patfont +definefont setfont/ch(AAAA)def X0 64 X1{Y1 -16 Y0{1 index exch M ch +show}for pop}for}bd/vert{X0 w X1{dup Y0 M Y1 L st}for}bd/horz{Y0 w +Y1{dup X0 exch M X1 exch L st}for}bd/fdiag{X0 w X1{Y0 M X1 X0 sub dup +rlt st}for Y0 w Y1{X0 exch M Y1 Y0 sub dup rlt st}for}bd/bdiag{X0 w +X1{Y1 M X1 X0 sub dup neg rlt st}for Y0 w Y1{X0 exch M Y1 Y0 sub dup +neg rlt st}for}bd/AU{1 add cvi 15 or}bd/AD{1 sub cvi -16 and}bd/SHR{pathbbox +AU/Y1 ed AU/X1 ed AD/Y0 ed AD/X0 ed}bd/hfill{/w iRes 37.5 div round +def 0.1 sl [] 0 setdash n dup 0 eq{horz}if dup 1 eq{vert}if dup 2 eq{fdiag}if +dup 3 eq{bdiag}if dup 4 eq{horz vert}if 5 eq{fdiag bdiag}if}bd/F{/ft +ed fm 256 and 0 ne{gs FC ft 0 eq{fill}{eofill}ifelse gr}if fm 1536 +and 0 ne{SHR gs HC ft CP fm 1024 and 0 ne{/Tmp save def pfill Tmp restore}{fm +15 and hfill}ifelse gr}if}bd/S{PenW sl PC st}bd/m matrix def/GW{iRes +12 div PenW add cvi}bd/DoW{iRes 50 div PenW add cvi}bd/DW{iRes 8 div +PenW add cvi}bd/SP{/PenW ed/iPen ed iPen 0 eq iPen 6 eq or{[] 0 setdash}if +iPen 1 eq{[DW GW] 0 setdash}if iPen 2 eq{[DoW GW] 0 setdash}if iPen +3 eq{[DW GW DoW GW] 0 setdash}if iPen 4 eq{[DW GW DoW GW DoW GW] 0 +setdash}if}bd/E{m cm pop tr scale 1 0 moveto 0 0 1 0 360 arc cp m sm}bd +/AG{/sy ed/sx ed sx div 4 1 roll sy div 4 1 roll sx div 4 1 roll sy +div 4 1 roll atan/a2 ed atan/a1 ed sx sy scale a1 a2 ARC}def/A{m cm +pop tr AG m sm}def/P{m cm pop tr 0 0 M AG cp m sm}def/RRect{n 4 copy +M 3 1 roll exch L 4 2 roll L L cp}bd/RRCC{/r ed/y1 ed/x1 ed/y0 ed/x0 +ed x0 x1 add 2 div y0 M x1 y0 x1 y1 r arcto 4{pop}repeat x1 y1 x0 y1 +r arcto 4{pop}repeat x0 y1 x0 y0 r arcto 4{pop}repeat x0 y0 x1 y0 r +arcto 4{pop}repeat cp}bd/RR{2 copy 0 eq exch 0 eq or{pop pop RRect}{2 +copy eq{pop RRCC}{m cm pop/y2 ed/x2 ed/ys y2 x2 div 1 max def/xs x2 +y2 div 1 max def/y1 exch ys div def/x1 exch xs div def/y0 exch ys div +def/x0 exch xs div def/r2 x2 y2 min def xs ys scale x0 x1 add 2 div +y0 M x1 y0 x1 y1 r2 arcto 4{pop}repeat x1 y1 x0 y1 r2 arcto 4{pop}repeat +x0 y1 x0 y0 r2 arcto 4{pop}repeat x0 y0 x1 y0 r2 arcto 4{pop}repeat +m sm cp}ifelse}ifelse}bd/PP{{rlt}repeat}bd/OB{gs 0 ne{7 3 roll/y ed +/x ed x y translate ULesc rotate x neg y neg translate x y 7 -3 roll}if +sc B fill gr}bd/B{M/dy ed/dx ed dx 0 rlt 0 dy rlt dx neg 0 rlt cp}bd +/CB{B clip n}bd/ErrHandler{errordict dup maxlength exch length gt +dup{errordict begin}if/errhelpdict 12 dict def errhelpdict begin/stackunderflow(operand stack underflow)def +/undefined(this name is not defined in a dictionary)def/VMerror(you have used up all the printer's memory)def +/typecheck(operator was expecting a different type of operand)def +/ioerror(input/output error occured)def end{end}if errordict begin +/handleerror{$error begin newerror{/newerror false def showpage 72 +72 scale/x .25 def/y 9.6 def/Helvetica findfont .2 scalefont setfont +x y moveto(Offending Command = )show/command load{dup type/stringtype +ne{(max err string)cvs}if show}exec/y y .2 sub def x y moveto(Error = )show +errorname{dup type dup( max err string )cvs show( : )show/stringtype +ne{( max err string )cvs}if show}exec errordict begin errhelpdict errorname +known{x 1 add y .2 sub moveto errhelpdict errorname get show}if end +/y y .4 sub def x y moveto(Stack =)show ostack{/y y .2 sub def x 1 +add y moveto dup type/stringtype ne{( max err string )cvs}if show}forall +showpage}if end}def end}bd end +%%EndResource +/SVDoc save def +%%EndProlog +%%BeginSetup +Win35Dict begin +ErrHandler +%%EndSetup +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr + +%%BeginResource: font MSTT31c1bc +/GreNewFont{10 dict dup 3 1 roll def dup begin 6 1 roll/FontType 3 +def/FontMatrix exch def/FontBBox exch def/FontInfo 2 dict def FontInfo +/UnderlinePosition 3 -1 roll put FontInfo/UnderlineThickness 3 -1 +roll put/Encoding 256 array def 0 1 255{Encoding exch/.notdef put}for +/CharProcs 256 dict def CharProcs/.notdef{}put/Metrics 256 dict def +Metrics/.notdef 3 -1 roll put/BuildChar{/char exch def/fontdict exch +def/charname fontdict/Encoding get char get def fontdict/Metrics get +charname get aload pop setcachedevice fontdict begin Encoding char +get CharProcs exch get end exec}def end definefont pop}def/AddChar{begin +Encoding 3 1 roll put CharProcs 3 1 roll put Metrics 3 1 roll put end}def +/MSTT31c1bc [58.0 0 0 0 0 0] 51 -102 [-58.0 -58.0 58.0 58.0] [1 58 div 0 0 1 58 div 0 0] /MSTT31c1bc GreNewFont +%%EndResource + +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font + +%%BeginResource: font MSTT31c1bc +/G54 [35.0 0.0 2.0 0.0 33.0 39.0] +/G54 { + 31 39 true [1 0 0 -1 -2.0 39.0] {<fffffffefffffffef807c03ee007c00ec007c006c007c0068007c0028007c0028007c0020007c000 +0007c0000007c0000007c0000007c0000007c0000007c0000007c0000007c0000007c0000007c000 +0007c0000007c0000007c0000007c0000007c0000007c0000007c0000007c0000007c0000007c000 +0007c0000007c0000007c0000007c0000007c0000007c000000fe000001ff00001ffff00>} imagemask + } + 84 /G54 MSTT31c1bc AddChar +/G68 [28.0 0.0 0.0 0.0 28.0 41.0] +/G68 { + 28 41 true [1 0 0 -1 0.0 41.0] {<038000000f8000007f800000ff8000000f8000000f8000000f8000000f8000000f8000000f800000 +0f8000000f8000000f8000000f8000000f81f0000f87f8000f8ffc000f987e000fa03e000fc03f00 +0f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f00 +0f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f001fc03f80 +fff9fff0>} imagemask + } + 104 /G68 MSTT31c1bc AddChar +/G69 [15.0 0.0 1.0 0.0 14.0 41.0] +/G69 { + 13 41 true [1 0 0 -1 -1.0 41.0] {<038007c007c007c0038000000000000000000000000000000000000003800f807f80ff800f800f80 +0f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f801fc0 +fff8>} imagemask + } + 105 /G69 MSTT31c1bc AddChar +/G72 [19.0 0.0 0.0 0.0 19.0 27.0] +/G72 { + 19 27 true [1 0 0 -1 0.0 27.0] {<0187c00f8fe07f9fe0ffb3e00fe1c00fc0000fc0000f80000f80000f80000f80000f80000f80000f +80000f80000f80000f80000f80000f80000f80000f80000f80000f80000f80000fc0001fe000fff8 +00>} imagemask + } + 114 /G72 MSTT31c1bc AddChar +/G64 [29.0 0.0 2.0 -1.0 29.0 41.0] +/G64 { + 27 42 true [1 0 0 -1 -2.0 41.0] {<00000e0000003e000001fe000003fe0000003e0000003e0000003e0000003e0000003e0000003e00 +00003e0000003e0000003e0000003e00007e3e0001ffbe0003c3fe000f00fe000e007e001e007e00 +3c007e003c003e007c003e0078003e0078003e00f8003e00f8003e00f8003e00f8003e00f8003e00 +f8003e00f8003e00fc003e007c003e007e003e007e003e003f007e003f80fe001fe1bfe00fffbfc0 +03fe3e0000f83800>} imagemask + } + 100 /G64 MSTT31c1bc AddChar +/G20 [15.0 0.0 0.0 0.0 0.0 0.0] +/G20 { +} + 32 /G20 MSTT31c1bc AddChar +/G49 [19.0 0.0 1.0 0.0 18.0 39.0] +/G49 { + 17 39 true [1 0 0 -1 -1.0 39.0] {<ffff800ff80007f00003e00003e00003e00003e00003e00003e00003e00003e00003e00003e00003 +e00003e00003e00003e00003e00003e00003e00003e00003e00003e00003e00003e00003e00003e0 +0003e00003e00003e00003e00003e00003e00003e00003e00003e00007f0000ff800ffff80>} imagemask + } + 73 /G49 MSTT31c1bc AddChar +/G6e [28.0 0.0 0.0 0.0 28.0 27.0] +/G6e { + 28 27 true [1 0 0 -1 0.0 27.0] {<0381f0000f87fc007f8ffc00ff987e000fa03e000fc03f000f801f000f801f000f801f000f801f00 +0f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f00 +0f801f000f801f000f801f000f801f000f801f001fc03f80fff9fff0>} imagemask + } + 110 /G6e MSTT31c1bc AddChar +/G74 [16.0 0.0 0.0 -1.0 16.0 35.0] +/G74 { + 16 36 true [1 0 0 -1 0.0 35.0] {<0080018001800380038007800f801f803f807ffefffe0f800f800f800f800f800f800f800f800f80 +0f800f800f800f800f800f800f800f800f800f800f800f810fc207fc03f801f0>} imagemask + } + 116 /G74 MSTT31c1bc AddChar +/G65 [26.0 0.0 2.0 -1.0 24.0 27.0] +/G65 { + 22 28 true [1 0 0 -1 -2.0 27.0] {<00fe0003ff80070fe00e03f01c01f03801f83800f87000fc7000fc7ffffcfffffcf00000f00000f0 +0000f00000f80000f80000f80004fc000c7e000c7f00187f80383fe0f01ffff00fffe007ffc003ff +8000fc00>} imagemask + } + 101 /G65 MSTT31c1bc AddChar +/G61 [26.0 0.0 2.0 -1.0 26.0 27.0] +/G61 { + 24 28 true [1 0 0 -1 -2.0 27.0] {<01fe000fff801f0fc03c03e07c03f07c01f07c01f07c01f03801f00001f00003f0001ff0007df003 +e1f00781f01f01f03e01f07c01f07801f0f801f0f801f0f801f0fc03f0fc07f17e1df37ff9fe3fe1 +fc0f80f0>} imagemask + } + 97 /G61 MSTT31c1bc AddChar +/G6f [29.0 0.0 2.0 -1.0 27.0 27.0] +/G6f { + 25 28 true [1 0 0 -1 -2.0 27.0] {<007f000001ffc0000783f0000f00f8001e007c001c007e003c003e003c003f0078001f0078001f00 +f8001f80f8000f80f8000f80f8000f80f8000f80f8000f80f8000f80fc000f007c000f007c000f00 +7e000e003e001e003f001c001f003c000f80780007e0f00003ffc000007f0000>} imagemask + } + 111 /G6f MSTT31c1bc AddChar +/G6c [15.0 0.0 1.0 0.0 14.0 41.0] +/G6c { + 13 41 true [1 0 0 -1 -1.0 41.0] {<03800f807f80ff800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f80 +0f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f801fc0 +fff8>} imagemask + } + 108 /G6c MSTT31c1bc AddChar +/G4c [34.0 0.0 0.0 0.0 33.0 39.0] +/G4c { + 33 39 true [1 0 0 -1 0.0 39.0] {<ffff8000000ff800000007f000000003e000000003e000000003e000000003e000000003e0000000 +03e000000003e000000003e000000003e000000003e000000003e000000003e000000003e0000000 +03e000000003e000000003e000000003e000000003e000000003e000000003e000000003e0000000 +03e000000003e000000003e000000003e000000003e000008003e000018003e000010003e0000300 +03e000030003e000070003e0000e0003e0001e0007f0007e000ffffffc00fffffffc00>} imagemask + } + 76 /G4c MSTT31c1bc AddChar +/G75 [28.0 0.0 0.0 -1.0 28.0 26.0] +/G75 { + 28 27 true [1 0 0 -1 0.0 26.0] {<ff81ff001f803f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f00 +0f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f000f801f00 +0f801f000f803f0007c05f0007e19ff003ff1fe001fe1f0000f81c00>} imagemask + } + 117 /G75 MSTT31c1bc AddChar +/G78 [28.0 0.0 0.0 0.0 28.0 26.0] +/G78 { + 28 26 true [1 0 0 -1 0.0 26.0] {<fff07fc03fc01f000fc01e000fc01c0007e0380003f0300001f8600001f8c00000fd8000007f8000 +007f0000003f0000001f8000001f8000001fc0000037e0000063f00000c3f0000181f8000300fc00 +0300fc0006007e000c003f001c003f803e007fc07f81fff0>} imagemask + } + 120 /G78 MSTT31c1bc AddChar +/G43 [39.0 0.0 2.0 -1.0 37.0 40.0] +/G43 { + 35 41 true [1 0 0 -1 -2.0 40.0] {<0001ff0080000ffff180003f00ff80007c003f8001f0000f8003e000078007c00003c00f800001c0 +0f800001c01f000000c01f000000c03e000000c03e000000407e000000007e000000007c00000000 +fc00000000fc00000000fc00000000fc00000000fc00000000fc00000000fc00000000fc00000000 +fc00000000fc000000007e000000007e000000007e000000003f000000003f000000201f80000040 +1f800000c00fc000018007e000030007f000060003fc001c0000ff807800007ffff000001fffc000 +0003fe0000>} imagemask + } + 67 /G43 MSTT31c1bc AddChar +/G66 [18.0 0.0 1.0 0.0 24.0 41.0] +/G66 { + 23 41 true [1 0 0 -1 -1.0 41.0] {<0007e0003ff80070fc00e07e01e03e01c03e03c01c03c00003c00007c00007c00007c00007c00007 +c00007c000ffff80ffff8007c00007c00007c00007c00007c00007c00007c00007c00007c00007c0 +0007c00007c00007c00007c00007c00007c00007c00007c00007c00007c00007c0000fe0001ff000 +ffff00>} imagemask + } + 102 /G66 MSTT31c1bc AddChar +/G63 [26.0 0.0 2.0 -1.0 24.0 27.0] +/G63 { + 22 28 true [1 0 0 -1 -2.0 27.0] {<007f0001ffc00783e00f01f01e01f03c01f83c00f87c00f8780070780000f80000f80000f80000f8 +0000f80000fc0000fc0004fc000cfe000c7e00087f00183f80383fe0f01fffe00fffe007ffc003ff +0000fc00>} imagemask + } + 99 /G63 MSTT31c1bc AddChar +/G2d [19.0 0.0 2.0 11.0 17.0 16.0] +/G2d { + 15 5 true [1 0 0 -1 -2.0 16.0] {<fffefffefffefffefffe>} imagemask + } + 45 /G2d MSTT31c1bc AddChar +/G42 [38.0 0.0 0.0 0.0 35.0 39.0] +/G42 { + 35 39 true [1 0 0 -1 0.0 39.0] {<fffffe00000fffffe00007f00ff80003e001fc0003e000fe0003e0007f0003e0003f0003e0003f80 +03e0001f8003e0001f8003e0001f8003e0001f8003e0001f8003e0003f0003e0003f0003e0007e00 +03e000fe0003e003f80003fffff00003ffffe00003e007fc0003e000ff0003e0007f8003e0001fc0 +03e0001fc003e0000fe003e00007e003e00007e003e00007e003e00007e003e00007e003e0000fc0 +03e0000fc003e0001f8003e0003f8003e0007f0007f803fe000ffffff800ffffff8000>} imagemask + } + 66 /G42 MSTT31c1bc AddChar +/G4d [52.0 0.0 0.0 0.0 52.0 39.0] +/G4d { + 52 39 true [1 0 0 -1 0.0 39.0] {<fff00000007ff00ff0000000ff0007f8000000fe0003f8000001fc0003fc000001fc0003fc000003 +fc0003fe000003fc0003be0000077c0003bf0000077c00039f00000e7c00039f80000e7c00038f80 +000e7c00038fc0001c7c000387c0001c7c000387e000387c000383e000387c000383e000707c0003 +81f000707c000381f000e07c000381f800e07c000380f801c07c000380fc01c07c0003807c01c07c +0003807e03807c0003803e03807c0003803f07007c0003801f07007c0003801f8e007c0003800f8e +007c0003800fdc007c00038007dc007c00038007f8007c00038003f8007c00038003f8007c000380 +01f0007c00038001f0007c0007c000e000fe000fe000e001ff00fffe00401ffff0>} imagemask + } + 77 /G4d MSTT31c1bc AddChar +/G79 [28.0 0.0 0.0 -12.0 28.0 26.0] +/G79 { + 28 38 true [1 0 0 -1 0.0 26.0] {<fff00ff07fc003c03f8003801f8003800f8003000fc0030007c0060007e0060003e0060003f00c00 +01f00c0001f8180000f8180000fc1800007c3000007c3000003e6000003e6000003f6000001fc000 +001fc000000f8000000f8000000780000007000000030000000600000006000000060000000c0000 +000c000000180000001800003c3000007ff000007fe000007f8000001e000000>} imagemask + } + 121 /G79 MSTT31c1bc AddChar +/G39 [29.0 0.0 2.0 0.0 26.0 40.0] +/G39 { + 24 40 true [1 0 0 -1 -2.0 40.0] {<007e0003ff800783c00f01f01e00f03c00783c007c78003c78003e78003ef8001ef8001ff8001ff8 +001ff8001ff8001ffc001f7c001f7c001f7e003f3e003f1f007e0fc3fe07ff7e01f87c00007c0000 +fc0000f80001f00001f00003e00007c00007c0000f80001f00003c0000780001e00007c0007e0000 +>} imagemask + } + 57 /G39 MSTT31c1bc AddChar +/G36 [29.0 0.0 2.0 0.0 26.0 40.0] +/G36 { + 24 40 true [1 0 0 -1 -2.0 40.0] {<00003e0003f0000f80001e00003c0000f80001f00001e00003c00007c0000f80000f80001f00003f +00003e00003e1f807effe07f83f07e00f8fc00fcfc007efc003ef8003ef8003ff8001ff8001ff800 +1ff8001ff8001f78001f7c001e7c001e3c001e3e003c1e003c0f00780f80f007c1e001ffc0007e00 +>} imagemask + } + 54 /G36 MSTT31c1bc AddChar +%%EndResource + +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G31 [29.0 0.0 6.0 0.0 22.0 40.0] +/G31 { + 16 40 true [1 0 0 -1 -6.0 40.0] {<006003e00fe07fe0c7e003e003e003e003e003e003e003e003e003e003e003e003e003e003e003e0 +03e003e003e003e003e003e003e003e003e003e003e003e003e003e003e003e003e003e007f07fff +>} imagemask + } + 49 /G31 MSTT31c1bc AddChar +%%EndResource + +2919 2191 29 (1) 29 SB + +%%BeginResource: font MSTT31c1c9 +11 dict begin +/FontInfo 8 dict dup begin +/FullName (MSTT31c1c9) def +/FamilyName (MSTT31c1c9) def +/Weight (Normal) def +/ItalicAngle 0 def +/isFixedPitch false def +/UnderlinePosition -109 def +/UnderlineThickness 49 def +end def +/FontName /MSTT31c1c9 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [1 2048 div 0 0 1 2048 div 0 0] def +/Encoding 256 array +0 1 255 { 1 index exch /.notdef put } for +30 255 FE +def +/FontBBox { 0 0 0 0 } def +currentdict end +currentfile eexec +9e67edc6f3ddb54d987dfb0ad4392351758038a4ddcd7496126caebf3c4b776a9348fe88419c70c199dfed3be58c5559d44f85ed1b3b2d48c178aedfd3de0022 +1e04c6d4d0f48db1093382653d5c4a389b722bcd118482d76f60847858ee2b7fec8602e8fe84654d4a23e6e5b0a6a07705c6bdece2812668fa8d0c1c49883c1f +ed5ef1fdceb49b11bd5c332ead97409150c8af0e5e03714ae6a229de223eb4d5df5f7ab0118978c08a67ebecb1283fb8e39fb2db8e5600d202b2909bfbdaa269 +abe5b36800302965c990a082835f3ac6efc9d64fe188cac4bb439c5f84ad8b5731ddb08c0b1aace01863a3d07f18d467b74f78e9d59d6f8dbb3c02ff1f33e752 +fcafa6b90648c821a1c6a6996ce5ab2f5507fbd175bf3a4b32a289ea31054444a2d44fcbaf008e1127661229de7dc37108848f4e9d4faf147cc1e00ac8048f85 +d0c3563f9385d8e93c91dc7fc9631ce01da924ff3d51539c2e089feace7a3708e9d2522cd0c4d5cdce2bbeccd30fdee2b9e98a6f99b1f22257b7 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource + +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d07d79b775d66db7f06b827e8ff4a2eb8a86a8433f9bba3a08ac51527ba66676ba5e87a8c35863c1d300d30244be0d12343c25ffa +9f4d05d39ff23460fb3d423dc49c437f6bb9da6732dfcaf8d49f73ecfd0a2cea4b81f4830b5a5141dba90708e5b839ec4995bd45e8afeb94764a0f8aa57ef193 +428bbd3ae615cf958f6d9d734c885a4f29abf4504548ac5a355cb17006a16fdb9408bc90b2dfd2fc1387d824f1debaaa3987bd287feff105b69d7fe93ef6883b +e0af2d2940ca07eb27030f4c14a8450cb52a98ce2500efd110cd8b3ea886053ead9bd5cacec38b807b3fbc94030f664f10b682be9a44509ba251515def870572 +1d26ca3aad2c32bebc5ccee3d18d95267bb565a655cd5ed0ab3a9e405c3eea95f233c357933db74f3a38eee1d08bf0b21ffe1aeacb490e977f4f7584539a1e19 +4c07b8d2e7dbfda90a5904ba54699c108acf1ba19892f8355e4d24639459b4518615fbee2122d9da66f42615386f5ee7925da010effed50b528057fd8f814b55 +b0de7c96c8b2ba89688fc49900ed140cf762bcaab025e4c5238166ea7ee7dac63774dcd1273a5519476b9de552f327588cbd15028562b1f2865acfa2f4ebe964 +15a7797feebc4a244649f27c987a80aac7dfdcb83ded53f98f579846d252ed9ca464e3e02d4d2ca61e0d7ac74b4d21c7b8e8dea84c3190c121b9120a9db2c539 +870be51291b34f801213611c24aa6f704d5c7aa827802af2fede4901f3a5e40c50ee8995745bd2a1fab16b1c3968bfa2454a9f8990036151d9464cddcefe41a1 +9b8bff464e2cf751d3968de0bba7336103fa2be945c74230c360d195a77173fe9e8c90e89ff0908f11381f5ccc9913be734b95d922dfd7a24cce2c2dfee3c400 +eefe54dfe3c5262449debb38fe06d6356cbdc79a707677a9ee854c5fa7a372def6fe9a1fd6fce94f3c73bff36a3e9886953c29dad84b51a55fb29e4aee39bb61 +aa4ee7727b9be20c1dd95828f1e7beb4c63ce43c5c4b5857c8abe1ed4cea10208d1a8bc832e19d32f8ebf5717ac9ba4c99d4607754d5d16229304ba1efa37632 +e6733c0bb38d5b9bac4cda3d111425156fb5da060eef679fd02e5db0aa3ebd42e68485b3835fb33095460cb3d7d33379c65fff26a3972f4eada94b1ccb8b0c53 +9b1a1ed9af028bb2e4aa9a9bbf4eac5ef0ef30c99a07766731df7a7d2cbc2aeba8e813d13f1806b733882dde18d76be093cc4127073081b7f3df1a8b6e40ec83 +506bb12716c247508084301940a874e192125fae70e15e423796cb9e35d45660ddc4e87a78ca22970105b6bb49ccb7e0f25ebd728af622d7298a0816dc6b6767 +3bd4c6c11960cc1a258149bc8bf078c023a283f1479157b66365c4adc8cf9521e696a13ae71466faa926191c6005bcd33075dd7c6cb07c0b822b1262c5cf767e +1b296056976de0d0b744b6f540de9901670a590010ab28d5b2ee9f3c667bb1b76e4ba590daf4029f6829e146ac4293464b19833a2cf1a7c794c73e64f7c82ad1 +a5c1a0fb6f29d70df2201744772878fede649d7a444d479c786009b0b3221fe4c62665daf8ad8b7a160ecd05eeaed8bf1532c13a01467fcd2d95a05e681e1e52 +469bab6485b3d5b2d069d189f051c76a04b3ceed83b0a0f37ffdd8e92698e24ddd12a5b2dd3c9a6fd8db0d5a47629dbb5279a611383b087c971638aec6aa56e0 +84a83ef5589a664941c82ccafaa198c874e85892e67fc685e2a939485e57df8473b7e53cf97f03f2b666dac319895f02b1f167b74f12fcb7104eae01b10c1320 +de826cd4dc760ee59113ec742a7d74ce5c4f9741d3cb13fedadcb71067ad820f92e2b4aa5539707fe3cd6060993ab0d9c95ea8d8349e2fbfde8a05ac7e6fe34c +1dadb4a14df7166de443467a39c7741ae9e1a59cbdf8733cfd5b64bfbf12d37ef50f4a9a765c7bf87079b046828793a5792193fd8985393a9db373c0650306e8 +4ef33c82937580b036eee02ebeea82c84c58552f7c52cf0ef43814cc1b1e9e8908d1150e5d7bbf2ce0e8ac497b04bd310ffdeb76b2d94e3c0a797cab4a992de6 +5858c95ceee596507da6b0896517a13778d028831e02b3059ae80a479f8e0d6a3763b402ed8286329f95ab006611b5fc7502f32e093751cd6bfe3e564078ca23 +504db2e91efa9dee56ac9c1a17a682e99ee9e36221d506fb0a1fc3fb5fb0521cc99b2d4c2d22f284d9cc0aea65a937b7424cc62e4e3815722400a3b8cb0058e6 +695fe0bca7b6d947c89570772e9367bbed7bd86c1c819cfc45d76fe8a6d39edc9d70dd1ffe266ac48c1ea72be9d36850b07cd1ddbedac72d40440cd40808ef58 +cf76954afc94cb71c25297234464c94eed023e49e3f6613f506fab97213a3281cb6a0b58157c6077edf84624eb9c79526ace10116d095e349a71f249d2559c8b +a3b9377d49adc86e27abc0b12c70b8c962ae344c791241359e09504dbe3948b70f5a3e4874b9f0c7824d7fa22db2b93877b31cb9f71df8472fcd23ac7dc46e21 +4aafcfd8d41b80a9d027553a457199ff15ac580547d4db485c7750bddffad0d26fe90668afc59c612d9f4e388c676628118a1d2f977c70a6cb046c710437ce20 +b06af40524ad07e6b40d324e8d6964ab15ea9d6e745f1db5b7b194bfe0f08bc7310a9c41d79e8a34279f5c84988ccd53ad2aa17d82b8c1162e250ec3dadd48b4 +cabb848b84a64d587304eccc885e417a751a3bacdecd49e24163025611497d8734737194a45846f47fbaefe6be519819ba35a562d99808821ced8fc5f8870a03 +22d2015aafcb05ef5c0218cc61802c75cffef07165b98f9c72c0b8c2c09e6302f20465501c66cec8588351b7ebda0309015ef4bcbb1ec92ff2e76cb4a7615ab1 +6495f73631dbfb0c2c4bcd7a0d391cadb9d395e5b9d05a60f16b13317778c03dbd5e9549351f9544ce546f4fe065fe1293fbda5107f133552c0deba970cd47da +9add288cdc884129e8c2f41c96b86955072370a13739df1d8571fde3d2841319c711ad53724cd1f8c5fb5f310d03ac8d8d68e98069a6792f9abf33c32a45dc0f +83c4e02542af6b57ac09d4af238e63458802a95a462241c14139a475335bbe2bde73af860d7dbcf475ff6f35a3e1899a4a4d5085c590c05c84dcf4f35df534a0 +8d1736481a0d22a4408c3ca996e127547352788a7a8b4059fb4f22c8c215c64ac947d46fcc1ab3f87fd3f77040e93630a48ff52ea5c4687d7ab4afb6974a4b3e +d53004e6584a3c3d0a5521180ecebd0f3eceabd76cc46136e7ced8aef737a883422e8e2557c67d46acb63ca2dfc0a9772cbc9f5a6472d2a1395b587b8859ee4e +a41566f7709a78c314e257cf06b1f0d8dffa2116727132af174ea3cbfe255f0ccae43b587f9d9274b4e62d060253327df4ca4f12acaf7e5c7ad603aa44563b1c +2d1073112be1696a9e3bc20d1b06a80dec85b944dc2992cc1e069ee2488f720fa1eaca5e5be9b13870b5a139fdfe917672c78c320594d9a38ef66f00458d5b70 +fad00e5cd296b83df525bc52c14ae625c68cdf9e446ff9ec912b3861d0e6ad408342785b3990afa28877887739420cc3414b0ffbf53e444add20541b0e6e1e86 +32e8cf6ebf640ff1152d1d1bc42df59e4deeee02be60841901a9ca18e811e29c0105034aa87d9359342d6cd08240fbca3ff1ba7e79a70d64c8af8fbb29346a62 +15fa6beab840a28b746462a12e2ea63683079e1ae67db3dd20f55543706eb784875a308ab44ad82eb34dda904501ba6e6798030941545b7515a9457ee6bf926f +247d11735f995c242801c480afd57d7b79ae00c159613807e6280f7f370b3929de9d +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-3 1 SJ +851 796 1387 (Quotas Management) 1387 SB + +%%BeginResource: font MSTT31c1d6 +11 dict begin +/FontInfo 8 dict dup begin +/FullName (MSTT31c1d6) def +/FamilyName (MSTT31c1d6) def +/Weight (Normal) def +/ItalicAngle 0 def +/isFixedPitch false def +/UnderlinePosition -109 def +/UnderlineThickness 49 def +end def +/FontName /MSTT31c1d6 def +/PaintType 0 def +/FontType 1 def +/FontMatrix [1 2048 div 0 0 1 2048 div 0 0] def +/Encoding 256 array +0 1 255 { 1 index exch /.notdef put } for +30 255 FE +def +/FontBBox { 0 0 0 0 } def +currentdict end +currentfile eexec +9e67edc6f3ddb54d987dfb0ad4392351758038a4ddcd7496126caebf3c4b776a9348fe88419c70c199dfed3be58c5559d44f85ed1b3b2d48c178aedfd3de0022 +1e04c6d4d0f48db1093382653d5c4a389b722bcd118482d76f60847858ee2b7fec8602e8fe84654d4a23e6e5b0a6a07705c6bdece2812668fa8d0c1c49883c1f +ed5ef1fdceb49b11bd5c332ead97409150c8af0e5e03714ae6a229de223eb4d5df5f7ab0118978c08a67ebecb1283fb8e39fb2db8e5600d202b2909bfbdaa269 +abe5b36800302965c990a082835f3ac6efc9d64fe188cac4bb439c5f84ad8b5731ddb08c0b1aace01863a3d07f18d467b74f78e9d59d6f8dbb3c02ff1f33e752 +fcafa6b90648c821a1c6a6996ce5ab2f5507fbd175bf3a4b32a289ea31054444a2d44fcbaf008e1127661229de7dc37108848f4e9d4faf147cc1e00ac8048f85 +d0c3563f9385d8e93c91dc7fc9631ce01da924ff3d51539c2e089feace7a3708e9d2522cd0c4d5cdce2bbeccd30fdee2b9e98a6f99b1f22257b7 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource + +32 0 0 150 150 0 0 0 134 /MSTT31c1d6 font +%%BeginResource: font MSTT31c1d6 +currentfile eexec +9e67edc6b858a3e762244b628fb01cf58f07fd3c01ea854585188a66a8f12aa17a95328b3ac7a563452355cdf678c51a4bd3287a046903abe9db4db7daee86d4 +aee44d97fdc85665066b373c0792e435f219551d1b381c469ea92e4ab34b9cf795f06a025e57d038642fbb46bf3d97ce665b4953318c1a4d0b1e84550ff76556 +5e97303458a9a8c72b9c1c85a1f761b3fafb37f172c6d3e4df174826bc2941e412e5cb3ed4d0ac348381fe6d1c11d07f669981e211812e3ebeffb1906914748d +fbeae9ad08622df9c8908991684159d0842814d75741ba962c8dad83e6181fd23644266c2302745f433b949d1695beda980a6c47e997fcf53026e9b40af29b0d +3ea5f5d4a6e9f971d4418b4055584386c498cafe2148f3ac9ae0c79b7fba7e0959e48e2c6a8383995003ec2b90f602f46626f3374925d020c0405bf51ce9eec5 +ce9343477b8c2736bd6894ce1bbbbe9beb6101d80b1f4f63d63334c4045c2426596e994ffe3c36fa7f3adaa39b3ef93106dd774c7f270779a898aa66754f5c52 +690bdae6a204aa4f61efef8f2bb9a72584fc8fc81ee62e3e42378e83753bea564c275fb3662ad1e72ca1623d304c711c7aacc6cea03d6cc24827b0f37dcf82e9 +67362aa9fdd3c5cde7b4ab202acf0a05decf30ab4a5fa2edee73e0e2848351e6e06eeb9bba82744b1a47738896af84b6bf490c479c601f2e6d3abf792667ec4d +17218121218e67ce24323878a663fba773d8460438b0331f727aed6fb7582efafaabebb282ea590ea3af5e1ad02738272586c5de9f881a56b61942fee714f11e +bae04cb115f5f2f69c0ab4ff07faae9d4e7b4ddc6c97cbe0a93c1650f2bd05b6f7363fc395fa7dce160c201534acb0b0c3a5a144d3971aea6a854aba5a70086d +30f20e07a2b7e06e26183c04d88a5de3bca7b245dc79481e693fe24a0d2fc1b5157d9be970905cac9b3cb683f12795e54110b3f8af334b3e2d43689e87a43879 +a0ec0140016e5bf0b954f785adf177e1ddaee7154bd37c9c7814c5d75fde747357e83de8384d06323a2d39654585e6e914bc35b5ecb1fd8c7ab08174de73c86c +5f809a35103df8eddee503cd9d93729ce4cde2e7f70da6bf42f74762ac997262e15bcc4de700145c8950ee8b6a191a6f11b58431edbbe9e6a553ae4c18151cc7 +3137547830daa00df1c47932e85eb2f047e0d26494711f2b3c2069038ce66c1b83fe2e78dacc09599e1d2e6a403b3638a44661461595f7d39486a0c580781dbd +edca70b836e6c4a8003ca70bf2e0528bfa27930c6e54aa458f670ee710ac0e6e06e66dd45c2e6de096ab627509091c5366773a42041bebdeac5fc8e187097288 +1fd06cbb241c402036a5b1604286ba94e61194312ce573b2f97e7ec8e869839bece474f34f158336df468f557cd7b6826f9cc1b05425228a8ca35b7c2075a463 +ef3fde8f1b210a0068a23de1531043ee3ad3916dcc2809ed2c2792bf7b7b28a9a9eb4373f313239573ebb81bcf59ce04525a437f04bacb25d11b10da0d8b2792 +3caffa9f1ed84c3747cf515a8dcd1389a2b01675fe31e21ec54cb395a29b532ca8c51d8002ed87d8b3386de94c7006b6eab7d7093106047ec358e45914918e53 +7786252cd87ce758393ab6101b6da3baaad98db8ea61db22c6d0083646bc00e55b481f91391ef371d6f56fee94350a9d77f45ca5c3315120ceb0873529e463fe +c9236c31fe3fb5866b79d4cd79a52eb6fa9a52cd609e5ca13b1486fd0f05c34cc7cbd139653324ab3eb05081e5abb5b3e1813374a97e8f0a73c0168a2635d5e5 +14de857d3bb39fb208389cffd99ceb7318fd110e543fb58595825c87f0234d97b649f568cdfd32cce2e8f3c6436edd8366193c0a6046b5b19ea6e703fc681fe0 +c1a1edc98389f8f56bf31a0a70149bc5c0618576798edea239fd9baeacb4973a0edfa947ed3934876fd8663deb6164a180b0a19ad1bc268f0084648c4ca2a1e9 +848cb645ab16be2cacc42ae81b22aade1267f4b46a5fef5839a4419457256730d8ab39acc12540d748a49a823731632d452b8ffc10e7c0ce9ca6687cdb5d399d +60fa214693f775f82c7901172520e8bce058193b4e60ac7d656cd7a46973732f329bd6bc2ab5e84a57957eb1aa661c4cafc8566b84b20b988999f664b4a27327 +80f33e0d7c4d418ebe9c9cf09e8c6bf517cbb6bf0b2f70f7efbb81108e59fd17aa1d0428c65988928c03c1ecfb42fb3d02b450651bdc0711e530ee2db6557918 +07fbbd7229ec3b54a0f994f88a410e0fc15544832e7b2324e89e7583069d405eac6dde1898789fd56871bdb8ef6af1103c94a6f9dad0274486a0b4fef6544a9c +8a5a5a8efcdb26569518af945c2819559ae3a1d3e9f0a551e8ea33f3596ebcc11841a811e89034d7ce5621b360f37144e8324d195f3d831b143a28642485ca31 +50e75a876356fec8fb67759efae1bc320162ef7c0431a331a2604a841539010380f7d1a0119a5ac540bbbe04191e7d2097120e124f92916a90d097e325760bc1 +bbdd3978d40787dea9fb014ac2f38a4f85ceff87ff1742908f68633b66b8238bc957c9260d60d8797ba59e4ceaa35417d0cae12261929adcf93cdccbee80f3d7 +b41e2dd5cae13a7a23dcf7e078d19d201f935c64f4309a6d93780da46677fc138a5c1d0ec924cc7cca1efe8c0febbaea1dcd75881f5ad600bc8e3bbcf8362596 +97bad5ae3b15df0ef9e526541f5cae399f26fcc51898fe034a23cb377e7182ed68780450ca3dd264b308e8414be3c306ad83370182e900d46f9acf5ff8339c43 +37d49d9249ccefeafe185fcfeabfbe6bc37bfd717fd5c9cec5d27852a45ce7835ca0691887935114be9cbfa2bfe4058cb06c0bf01810c1fae466284233438a2e +85ef0b276e04bb2c014c51b7e41e07490cf1bde5aade06c2ec1724db884b4a1bcc16b9356872c11fd1d68d0ce070a44ac4769afb6addfb03c2fb1bdbffa86e14 +7f66f7303715b68460bc6f16346543a64fd502ba34eb6849e32bd4466a3e72792d6b7fdffd08ebc11c291286196e49112c05904894aabf9f4e65241605d96d68 +36f3f88cea29b18c07dfe391a17c7d9846eb3d56bb79d08788f4ba52f110058ae2e8ca05a36a5fbdebc60f8372dec37f4fa69ebea445db249511e890b924189d +64f63e0a4ef68acab678ac1dd02499458a63ac9cd933301ac4021cbbfb561da87239312a0f0e54581d952f5e13d2ddb1b5129198eb0e5b180ac5ec495e4dd937 +299002257bb65fc6beac7c58cda87d285e1ad077d2f4ac5de141448d876a97e745fb30fb30a1739e447640962d7586e5fca87e326758fc08cca0e33fe35fc28f +4b1fc6743df8410c4f56d5a621678f5d1aaea549142c900a5bc16000b9409a3100b88a6a2dda20de4d3748433a0bedebff9a457811fe10b47aa459e165c94dfd +9aef1a03128fe57c534119a318251bf8dbdfe096129a81a817f2da16be22fd08e20deae0ca528ce847a0654a40d662572f75650c441527ec864e74e386cef6a4 +572e4678e7a27fc6012d7998d242242e9c5025c5ccd236f5ee9c26682dd476b3f4cdd67e1029f66f100a9c453cee95882a787000ad50313cbeffb728821a8803 +77c5ef67bbd05cf84b5d0a174c321fe523f2838959f21b9b887eaed8194a13df6ed58925d3644787355009950b3cc923c4005588eb72b1948c95634dae8cada2 +a1546a85e4f9ba9e23a85d3448ca1d44f4a960ba33e70c7e5ff991118af2ab4867e86ccbc2c1d377cdc447e4eba65c7e3b353b0f1976a1f45dbe366d9db79c0d +3c77d2f9dad803d120cadd32a5693bee656f5103df4a1b7d9acf67a025603211238d594f5002a1c3f77b12a23dc88d9e6188e2b080d9be48c59eb2d84ed45c51 +cdb0e7041e0221625332d32004df7218d16b1ac59ce8a3d67a6142be7a4d6ac36354b83327b2d0b13c692fda4a440e6d25d78a7787336f64a69b697a4ff4eb56 +d117a877ca60403b49141fd8804e71a8cc050e111ebb03adac4a9232f61ce5e8b6c3ef6acdbb4b85a2023b914c6cd9874531c0633b7fce488a2c54dff63e32b5 +00fa11accac7ef454f4c37b802f315f356fef1f9e81236b70a838e3f737e98c9105ece262566ff77ba49d385d7502c493c0df5af28590fc31f89e4b13456187d +6c1b13bdad9808ca54425b3ca7b909dcfd2efd8f85eae95da7aafb51b2c9a7873665ff14a3c435e1a0d5760b4572ec7a4b7fb1d657cfeb0206e2d9dd84e0a918 +9f40b8510afe50e376b6e19f9ab26e8cc3d078e448ed2d9b7577d9385012a623c687c2d3fd4ccb61ccccda1bd706b7d1ab69790ee7c62010633890ddb8c51ce5 +9997acf6c27052fe3ff554293279290194ae4dec105ed66f0cc8a28409b6f031579ee147574967e7839bbec5a1d5cecdb7152d672a85c85923042d4e6453b0b0 +2b528e31a7820996715aada0af88a73382525d11e3bbcd30a90bb91de040042f694b83ec58b625ede1d1cd7d5d3f34ab287155cc9ed25fbe4597ebb3fba7e1c6 +311d4a51603880fb0700f7f7d7af34776d11b0509fb392d47062b97a20f4a2d0a7882783eb1b1b474f0b5b5c38bbe0ab2a6273326c5b7a434042a2e9cf757067 +ae4a7ab78d9452f8d1695c2beaad2ede70eb76deefb0b4e06dda99d787dc62fb6f6b4e216d5594a8886cdf010b6b9ef4399ddab645a423ce8522ca392983dbcd +e9cf950838daa0fc96301eb7fd82f000c614ab8d977b5569582f4a07432ff9ed0afe2d02b1d4aa400dfa20f552e3f2e56e4ebb4762841a8d5fa13b5218e4b702 +6b07df026de2bf55a00052445468924dd022f9154820a9b8f025f3b7447f6705ccf4b8f70e6a35209bf7d3bb325409154508ae26a51b460ce53fa16b7e0a3a7d +818f8aa445abf2f117cfc0c77c12aafdcd7f3bd30342fea51d4708c0dfec89af089ca8ee924b4669c870562e76c61ccc75de41038bfb27fcde0d1f2d5fc3e0a7 +5516941e7dfd5c48b4fde5b9fe1306714a78a42efde303ed37f55e60a8f40eb43a85655c8da893d267d4808ed8b68c615b3399fcd41e20aaf2eabdec02f400ed +a615940ebf0a01c196b06ed1afb8f18b016362cf4ceeac6a4aaa69824a93577a73c51cdcc74593aaeab758efaedd7d1b68fe185c2ab45fdedf2e1bd7d6335a18 +ff074a447ea06d098c17fd14e03f9cc2d2303c3d57c389880529b0d0177de9871ef27564d1dea98b2369f827f1e810677303c5a7d88a73edcf5ab4834f18d23e +b55e8dd5d6899e7309cb8c425caee5843894f691a80cfb0f2ffa3675f17fcb3dbdde0c44c5a15282a5069471f9658c816258dfcd5a77fc68170d51bdf2bc2225 +f3e012d1a5a70b3d3bc79998656a81a262809bafc4037a3d07a78773d8b0f01266d8438ba0325ccdd02ba692282ec66a4ce4f4773abb43b00566351cd50623d5 +76876a3978017d40e5e5ef536974d6c8dbd7cf9e9d7e00bc8b89179d0cd9948f8b02c9e4eab5d8be491ebb66dce1b8a9fb4fba6a11c1c0dd211428d7db28239a +eb31796198e525ae3bb1cbe28d0d3ee9680610c0e97569207ae5d03042494a83cd4fe924dad70b3e85eb24f02ff529968f7735fef9a9f8c2ae3e3bcdcbf14fa9 +de29d6807d6f5937534c93744863e38b59e4f122abe50700148187b8211576097195d82bedddfa5bc61bc9bcca3fa498fe8a9f6966ce63c044f5c9e2c1ff4fd9 +5ad124ef9fbd324ec5f11eb1f3c882c25487a95f8e84d9b8fc579837136f7ea5400d9c900f77bdffe4ab148d20a8ae6d6668c9021495a800c4e53ecbf8e3fc5b +7f2f57daec9304fb648ab8e05ba9e6566f9dcf552092a73e06d644ac32a445a46ad67d250a2b05e28c6d9395701b563edf11d205c62bdda805e8b7521ff39f7f +515235c13f28f92df2cc2715bfbc3e749baa6bebe253a6d591fcfa35a81ef542b8a662a3130611f331826b1960c1376f716ac214dc9d093399189f8801b4e3d8 +a54c4b38b96a6b681316709ecb90c2187b021323978d1fe6e2cdd99d0cbc2709ea767d26bdb7ede04add2b158fc881ee2900575cf2e1c1519c67fd3174c01474 +977f55e41272a1fa952f96bae267d1fffeecd3083027f6c9df0fdcbaed5b58a2f33f9de42d995b54429e396cdb5950fafb3ff988526ae6dba5985085e868302c +eb553c63daeeef9a08d58f724f51fbad4b1bf53c6b17d59afb92a869b705538590f4b9ca0c1392146122a7c53f76f06d8a7c4b6d55761ee0de89afa6848da5a0 +600a083b2155ff6e2f340dee71e3e9e996db0805075a311d0a7f19c8c7dc24245ad9561c6329aa6315ef611f78c7958d18775e110bf8fd0710a935 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +610 998 1870 (\(Big Brother finally hits Linux\)) 1870 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d07d46fc97f64034f7316f286161df977422c4d4c0134696d3bc14d42a5196465b793903cbaef39f544b1ad2677617c3d7e7c7411 +44760ec4c558100f8d5150125bff221a8d8da1c78d036ae5d0ae1e5b46f2648b1738778da432f2e0a79098c0ab9bc73558835ae1fef4f1844107ef1919c93b0c +b64aae6608a9fc951cd895a6b3f3e90b8e89304f12a55c7de79fe0bc6eceb3abda8db51431b753678b3817f478d9f366b7750a607d8c079f73d8c5e56e068fba +5c63518263c5958057e03a4ba68be49c1abbbc6adc111544551d33c27152a5671bd06bd87987c94f41546459ad4f67e540d8cec6c2662fa09a888fcadff5763a +ddc06e460f56a44cf58f036f265c29ff21007faeb386dc99302fb0c75ec3af2d623b6a9ee8fdc0930d2900a8a0b9485c95943acc8b7144032f285865e89eaf54 +f9489a0aec81c7baff9c82a84b4d36f53c63e16a1b0ba314c92122139d3f1a30663a99febda776f3a5b09f58f3d737c4f97231796513983e74b04468f5e52254 +f96a494e30e009344faadbf40da0a3df5894c843e2c62eb2ed15ba09c643f590ea45c08441ad235a12bc9c8396b5c431b942a496a1135d09cd0f97df836419fd +3262b756126f193819ea64caf51a91c848562fde8e35f695218a75506a7bad9918eec09b13c0b5b50403eec5da0b3e58feed5202207d7224d199f5e6a4ed96b5 +e7f1b4fd4e7346d8d51d4ad11f6001b58242aed085deca4241fad480c8575b56fdef53291f0d4452328374c7a58e5b6caafbc80ec9623be7c85438cea66dda08 +fd1aa589af6b29384796377df9a3bbfbe204f740c572bb1074305a774dd30656a2aa2e1d9b1c0ba7454e81fc0d8a76f20dcfd29525365d5ce4165a7738a4cd6c +0075f2074f3d69ffa948d84e7707e13055c4b9a98a131e7fc595008a6d27350694b44ff7638da1adf4af8a800034b6a67227eba2bfd5365057eb8bba15dc362a +38b23966b57fd5a0d9b85b17910d13f78b357b14380ab23f50e621689bd4fa7c22956258469740feb8b58ffefebc8ace84fd883c822292033f12a2d16aabb3ae +f236023254fefdf6cdf01fcbc61dafd6a55ae23ca0b4ff4cce608f3081b122c411afa788634f11968afaaa7a773d7175da7907d308714ce8e3c39a17920b52e1 +e27fcbba78e824072b162bd0ab6d0826cb0e5d51f2d7437535726aa2b48c6658b4ae98d35e45c285f60cfe4885e5f54b36b4a9f9a740d2203b44cfabebfdbd24 +76fe5d6ed793306e4a9afbda3812514148b680a5c8b96a0499082f5edb83c3a44be7a8c2343f9abeab596d6d07fb252a9d5c1fbce4a9b9404e64ebeb153f89b7 +cdbded7e60aaf93a93bdb0fd19b7f97a4bcf8fdc10be826f733efd9b54af79ed02588e5922c92b79db886d5f68ebaf69e3ec25a0ee3e463ad2d68d3906831ccd +fea8ccc36fdd81934ff30689dc4dc2ceba3566a902aa9b6b2c841ee21c4026fb6cb91abe9d7c17c004ab60eedf8ceba17fb1e7b6df34261f180c1b7be2e6615f +91eb33d8516566c788082983b544b47f94395145b17fc7ce6027029e9111c577c52be631dcef1f6539d76acb3887c258eb017070133424e2ff9433d1738b2d0e +5a98d4eaa9d2f59f5bff8dc52be413ee31f2d9d5f2b8dbcb948b8483eb5b2310b4ddb742920d7466a6c76ad24ffea84db6a7c23de1f5db442e64f715de5d0f34 +2215a008e93426cf76a68e891a542178a9ae7a56bd5e268306a3f96fb2b2a4998c69edb1636255affffe4c65e47626a004a355ad5c1e42cc0dbdac265b27922c +492efb97a21591b0ed96c00148b52390da02edbfe77d173aa2499b4b2a58c7898aaf75ed363330456ae71fe8204c445bd0d12406410ef1c9a935dfbb68 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-1 1 SJ +1351 1340 535 (R\351my Card) 535 SB +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d0448bcdaf2881ea6472bde411d75ff8378c7389b65a1c39cec9312676c8e2b3872d24b1120f81ccbcfaa1a021ebd657347ad9b3a +25a5feba0fed91bf6050489e080e699eac3ff41fd0001afe42e9ff70df6702e91b80c1177cd67f0a885c54b0c6b4eb135acfcd7d8692bafe81b24b78debbb0ce +f5abdb21d9f47ba04d95f4fc9d6d2b0954c04a3fefb6c62aa930b483a5c25c7f0dd61a16733c26008660fec0e413fd51a21264ffd0d6937b113fd314ee1017fc +5dbb10aa8ae6c448992468de3166ddf2ddebe662beed4ccf3c4b905db473fae6e98e56570a34e453ae7e96551b5ce6fecc9892c8f6ab0f30ac94b3f9ac13572e +643c39532c61e72c55fc424a0eaefbcc008eacb07e46f31eada1364a19b316a613c3b59e43c75416d474a8fe4a2355e91a3c9d138c49b3c648aa29d1de834b36 +05f9b104ee2d15a150bed4e0692b562bf866d4a92f3e29ee75608fa3708c799d664220409ee157de6f9830cedaa4ff9a53a0681e55a1b5243b14362ba104143c +d8013ca0ccbb8dc6b3eeecf6bd5d46c3b570ad8fa27a5d0955419b7712941e8677e54fec3580e56d24501b7994395fe19d09230d576918b3ba1763710d0b5e79 +a22a5e73385df5d0a49bdd5537c66520da770173078f784181e3d5d78d5a96f3669cebe588fd60d47bbbf49b30883362e10c4cfd18f30c1283741776f510a394 +89db102e681f8922908cce16341b00c6f7ff3cc48b721f329c2fc45485b235c3c3f97ab6521682eaff9d41fb397c028408615a36ad0f4ea2a638b75a7aacdb5f +7e4fab5e62934289a76dcd109b2bc76fa249996d8cd664e1ece142e04a4b30799e6eb469328dfff6f2e5d73f24e3f8748b3b5370e060bb45ab41c0ae1058c4aa +2cc86efc1bc74d8bdad4e963814ee168ac31af24d74fbb319ad078e08c1cb6b8b4a20c34b3db418f4854bd8a9975dc252a718890ecd206b81c11068887994f8c +fcc12cab7d1d6e7f2ac0b5eb22d5bf57dc4a95877baa293f59815372747501b696f789c1b9a73b30a0a6c0a9406587d35ff5ba009e88a6474acbe8f8fae479fa +9818551348de2f0ac7fe08adbdb5b7fb93e1e101f0ce440b93c035287ff328580520407d2d69a613fc29386a5a3acf42d0ce61315b7caacbce1502158c738641 +a99cf38a32ec1b7daeb408044b3f96c4c9819bc2ea25885b6384bf3420c93d26b31a713a7aa5e5ae66651e96675818982849892b4b2e36b3225e95832285e45e +64474235c0f8f22952804c33581f456c8c75c6f4b3cde3bc7124fbd6f8e0d5afd0afdf95c7a30acdc3f418d9b8ee456ecdcf732fd17c4e7b51720342ac6115d2 +7ec7ef7a1b289f7455d28c1b67ffb8c4e0098ba829bc9b98f6fa4d4f4e1f422d2c2695b2a0583a4d73cd7b9195d284336e275aeecfd0b946f12832341c270ebc +82dcf74e3bb39f384db6563524a0673dd89bd980087543228309d43570e573ef4517496a8f55a1551df3c274fb8ed76e4d7f7e60ab84a7be265f1a72ea11adb3 +183c94f15c27da85467ab0a82e6853116cfb513cef1d4ff13c69b2bca8c14dacd849457d5c477599e297aa882141aa5810366aaf21df11a2da129bfc9012b86b +b04970b544660af9f14d58469aaa4e9dafd128903407546d326095dffaf59898f42c6149ff89f3ba7f51b0783324efef4cee3bfadc43261b7ebac69841c203b5 +98ca01488501df66639fad874d4a65497f77855f36d801e6a04eebd15da373bb79d1c3f94e9b5ea0436db50dd9f7d2c0ccba41aa97ef92c1ec3d4ddc67569197 +050e70236832839b79eab2e9dbfa1e14f46d86d88cccc549070b6a49e429837bb9716f91b09149b52132752507e4f3730c42faa725574b54b0322252729280f7 +76eb7cc1338d6b783249b2b0fc16aff94c6ee02835ad14897576c4d550e5cd871d805d9a86451270ce1cd07b86e5c49f9857af5623260d99860130762948e357 +d8c12871c526705394732e0f497a01c2bb8d12e10620741653a5a3a2c45c847ec86befc0c20ec653fb0b052e85a7c119a8fdc64b21070738c445b4934ef838af +b3fb7e772fb842ef97f1f58d21c226cd31bfe040f39053f1883f9918242e4ea610349ccbd940ab10c957c56ea5b139e22c69864e7cd0e58c6f48d9c6ce56ed52 +519f32cde31069201b2aaf86a7b1e2dd9b7f1484e18989cdaf60b39df3d56058218177229d749332108017ed803b0e0ea1a442f8f858a8c4fad02e8d9f2f0aad +d881e0fde6b0667c277b6d08fd2e9f19decd3359956d5a2177b3d1b49eb5a89a0cecc34bb3d927e988b4f851f92135ccbbaf1c1cef76799e051d745eee9ae5d0 +10599510376287bcbb255661713ed444199b5551b95596c307b8da70cc304fec8f6668e3c8ddf212ecfe12d0e0f6a625ec3301a90c78992cca3937538327d7e5 +6427bbe4704706763c563ba520a468bf6b18533f68ee5593f52d602e216412cab9b3e91a1d6bf2b4d6a39fe07d7df3b75d1cd58ec23d90e88b36539cd199116a +adb476387999b1014549b62fe175a349dcef6a6f105f7fd8fb70923f2d77de2427f3eb4db383f35bc8aec742fb5732e7879dc7ae90e53c0d21b1ba7fd0d04a72 +05e8834226d06a386bbddc257a6f576b94ac7fba2eb353d71041944503aebed5b43c1d1bd1d481009bbb903bf114a6e93ee6d65f974d2146ce3d305d2043aea4 +42b6dbdf556a5c62c6e2912969dd46efd9db94acd1b39d0d000db989d4d4ace46072b658c1a1c1eb0a0c14693616f3d0560c8dfe861da170d4c935b182b47d37 +7f8e693e87ab147a1ee48edbe91c7917d84aa2fecd97ed787174286d9647d8624955683f1d2f9fda1e92c2ff0996ea4cf3d16b +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +1104 1509 143 (car) 142 SB +1246 1509 167 (d@) 166 SB +1412 1509 111 (ex) 110 SB +1522 1509 137 (cal) 136 SB +1658 1509 33 (i) 32 SB +1690 1509 118 (bu) 117 SB +1807 1509 160 (r.ib) 159 SB +1966 1509 59 (p) 58 SB +2024 1509 68 (.f) 69 SB +2093 1509 39 (r) 38 SB +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d062efa8542d7e1727190148f267200f4b0f0b312c62fcf16c9bb3a1ed1ca5003235e108bace76f8cd465fb73141b6671457bfe24 +d3087a80e96a143127f065efd5a70426d02c648a5b6713f0ef8b187b09d22d417b6ec735e018df5521efb68bb7945d3b436b5504e18950cdc524c91cdfbaa538 +ff53cd9c5b23847e32038edcbbcfe0020d30c34229eacea8dceedcdb57e1bd2059b524307421fd01f6e08138e547f0f548bb5753c08a4ce11186ab148affe57d +f211a4012da0db12a069f6d3965954caace909c813406571df2dbee0d1a866fb218c8f0ad696e67512cf4ac2fa5bd89767b80b9c03b44be00729814896ee417a +79b0fd3cdb52a01cde8f32c4270ccb5fd17d506867be5d8851fd986beea38a00770f89ae5f25f4e05a074afc5861e07d3e15c7d8aea289157f8052a04aa74ee8 +3db9f8fa655ca2485e12dc74b08c4b67b131babf237a5b7606839c2dc79b5e57f5bc0fa459a94fca2bb520c6e0906f98f047d163787827c957ad081d640f998e +6ee4374d20b63638a61791971bc7678c8aaeb7fcfdf3b39743047a113562ec98cc58bfd3438b8ab84bdb5d15bd0752135bae7d3baf2837b986bb0d86357e262b +1fb3ccebf477f1b9c92b09a4aa8da142c4cb98800ba8fb79bd201fd60e169056c5e4970ef0d0de7e89456ff11ce40bd20e7075a6786465e0d11327d736480c67 +128c4b87c9fa3fd047d7a4941889822bf4400fe4f65f8ccdc71bff70e6b882ddcbc34c36c06340f9ed5f977141ba4471747fac0d0ab4ea50def3e9561d933230 +36dc2ca89bdbe6cd831bcf9f9376f10210d80be8d0728ab562fb79f92d20774cfc020a8b1c58b8aefbebae453224ce042076267c159a0321913c7432001ae486 +895a6127b493200e04ede57a8d700f22567eac +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-8 2 SJ +1128 1677 987 (Institut Blaise Pascal) 987 SB +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d07d3a1806c63b82e1b0b6863860613ea7c0c2019c973386b8303b2b57a3f751027c7e560901b4a11ecebb6fe5e635fc9cd65b36a +4824b23b464204a5a4e29f389c8782be9a0cc48546e8ff276eb1572e8040eebc12bec610990c830312fc89edd1773d6d686d3f1bc4d6425e4aae6a205c14e756 +ea8ed91a68fafeaa1789dfd79db78443d34fe0725a574387554d4b289736e90d30096822f8efb359ea3b7fed82e0f52581b661100703d0df3898fdf4a901c1c1 +c4607acf54796e8c1e1ef17999d7e6711cac0e56f68eb1d7440d4dea08a4890db7bc1a2becd33a6a398c390129a6a7c36a1e80f10929a8348d9c8c1c88ec2711 +8582773e34254a453ba45989289e36f29d62a9c6dff3b47589a15f9f0d2a761b214e710ca70c124c45b1b84d3c14bec2d979a7ff3fda0dac0cad0de30ed6d15b +0e6f30ed55c4bd7dd45ba7eb7cc447d23c380473efaf740f3290e20609e88fb8f7d237e49ac14a03c9c459683c8acf3bbde20bdd1982eada1b226115528b995b +f886f2f612fa9e7f97a06ae9dbc6beb350f8801f33bba0024c4bf80b11d8fd3e1433157c962b85cab7bd26d3d16c88076246a5e4bc8dbc147282c9a57bc60c1a +9ffe52d1ce9ecde0d29bc4e87aceeb157e452421c33e35fd06e5d752fbb1be789515c546f58f949b9df8b5e49e2dab0710c06a5278e9f5f9b08c19d934c0f50b +a36cda7d90da9c09c983bf49906c97f0cb5c7c499393ba1b0e582fee7093bee4e5013dc3ab78554c1a4af4a0b80237ae22117f28cc652d21191681db064d2c40 +5cc5fed5a1e6fe7bd2cd3abd612c08501d4528cd59769cebb478fc107360517360e288958c74da5cb92a0d922f2e3b70f6bbbf4817c0390b7dcd4f22aebe8259 +8a9d20aaf21d0027b6549d854a4464d4839b0103cc49294e1bd647c7176ee6236908a4011c12dfc3a76121bf1f35e4a3bbebf94fb8be94d8b2c82fcea2dee861 +d01ffe47264ba069a35f17a67ad5aaf697f1962189f8f3522c22918259e3b179e20f6546b183611bae6a3a74cdc9ff0b104275dc74950d6450bcc94e968bf7b8 +cdf0614ed7dc490a1d6c79e9e55adbf20e55ddc515f9af27e448a89577081e7f73fc88316a8dc7bdc93482da7e0c0035d4312467579bc3f4e833b1d39fcfb422 +73df4a6aafafc00f19352cf0ff6cfa34addfbac1d9ceaf9942 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-6 6 SJ +620 1845 2006 (Universit\351 Pierre et Marie Curie \(Paris VI\)) 2006 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G32 [29.0 0.0 1.0 0.0 26.0 40.0] +/G32 { + 25 40 true [1 0 0 -1 -1.0 40.0] {<007e000003ffc00007ffe0000ffff0001e07f8003801fc003000fc002000fc0060007e0040007e00 +00003e0000003e0000003e0000003e0000003c0000003c0000003c00000078000000780000007000 +0000e0000000e0000001c000000380000003800000070000000e0000001c00000038000000300000 +0060000000c000000180000003000080060001000c0007001fffff003ffffe007ffffe00fffffe00 +>} imagemask + } + 50 /G32 MSTT31c1bc AddChar +%%EndResource + +2919 2191 29 (2) 29 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d065133686e273aea657ad4eeb667942355bbf44e5b3127dd61797055dbc6ed38d13c364ca31df6a437b2bf27d1c5ce57b92472fd +0567e62f9d7879b144ad348a752c6f7184215c65c061058bd12a587f902784eb4707535b56e1e47bd57dca41ec9fc95977b30f7236b89bcec1494ae659e38595 +c723fd50fafd771309d4a66d686ddb4ff76f707d181c2ac6702ce5f87481cf81d8bc400f3ab2da3db762d0e5be70030f6d87b568891a899af8427f17634ed0d3 +98a8df688b1d9b939e9e2e34819b1802edc1c2a594a13ab439c605efe344e7186cff66259b040b6e47bb55554272bc496f41bde84e +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +256 284 121 (O) 120 SB +376 284 222 (utli) 223 SB +599 284 84 (n) 83 SB +682 284 74 (e) 74 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 648 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d0578cb0186d4620ef95432fd6faeca0fca7737f96247536631e5e6575a357bcc6c8b4d0c3576fcdf4cf885af2848d87a8abae2eb +7f3f61e803ddbf80caa5712c69691e95d423c96c736ba2cf6a4c589d8afbc9b67365a82aa1e7bd7932238a52abd053e77ca9f2bb3e3af59955ec981c48f64f6b +ef6b6bad5cb0045916060c29795a6a926a9c36958eed0f5e8447dad65a8b2ccbc3a3331eb99c2b4583fbbca75e26226faec4986c28b27517922f6938c3213d95 +4aba452879ee9dafb095476c97deeecfa06d2267046077586fdbcdeabf034fab3472ab8e3d18461c4dffafb40e1f7cfb2334599ec32505654c69dc5d25a82323 +eb5cef1487d3946135a2ac75c70f4c758679017c8a8ec2 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-8 2 SJ +586 615 935 (Principles of quotas) 935 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 817 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d0443b441567658a6856e7adbc62baedf12261c9875c4762d5f6b143a52c4aa4ce21dbb4ff936839757b4a3c065a07fe502a0354a +8ce25f6c10920e15983484eb48cfc7a939fda22bc4a6ec91fbb4b0916edba2f6a514b086eb443fb3eb38b361d95d5feaa9e01aaa83e5d9b36d92e37e0aa4672a +89deaae53dcf2e752fa2ebdbc2e862110838defe717b3c44128d33f2928ece139ecc87804fb5ff9fe84675bea7d752a54cfa1400fd4977c2964b88944a337035 +5e729793e549c5d06a7bfc35000ef31d552db250a6ebc2350ea3429c390fa173091de36f683677c2966043917abad1efb0d0647a850d23f51849151115030860 +e072a1c992b8665630f1bc48dd3f1d2c61d3586e21db6c44ad5816dc55ba1e1b11a17ab27cc66220f2899c6c4a7df9656ec21641de780ffdd7137b6db97e666e +25cd3864ff63039b0f60df920af85299b29c +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-15 3 SJ +586 784 1645 (Configuration of the quota-support) 1645 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 985 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d062647bb1263d8c25299774bfe585fa96223d906032043f9df53b5ea93f1d9c8fe6050ea78c741e63c84b69a755949e25da8285d +1dbcc8d56b993b784ee792db023d6f938f8c3704820cc30539a588b5c33a9da56c2ee373f843867ab024e73d847b9cfe7c27c0baed1952d3f0c7bccca7c01bab +3fbbf1afe64aaaf40492500433a866ee9c4c101976c667778e555af1ace42c5bcf80221cc89566b89aae50c40422326c935dd6998f7048f941418f6c2a7fd903 +284d3b582fe90315 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-12 4 SJ +586 952 1821 (Administration of the quota subsystem) 1821 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 1153 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +-2 1 SJ +586 1120 504 (Quota API) 504 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 1321 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +-12 4 SJ +586 1288 1717 (Implementation of the quota support) 1717 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 1489 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +586 1456 137 (Co) 136 SB +722 1456 59 (n) 58 SB +780 1456 144 (clu) 143 SB +923 1456 46 (s) 45 SB +968 1456 92 (io) 91 SB +1059 1456 59 (n) 58 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G33 [29.0 0.0 2.0 0.0 24.0 40.0] +/G33 { + 22 40 true [1 0 0 -1 -2.0 40.0] {<00fe0003ff8007ffc00fffe01e0fe03803f03001f06001f00000f00000f00000e00000e00000c000 +01c0000180000300000600001f80007fc003ffe0003ff00007f80001f80000fc0000fc00007c0000 +7c00003c00003c00003c0000380000380000380000700000607000e0fc01c0ff07007ffc003fe000 +>} imagemask + } + 51 /G33 MSTT31c1bc AddChar +%%EndResource + +2919 2191 29 (3) 29 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +256 284 140 (In) 139 SB +395 284 186 (tro) 185 SB +580 284 84 (d) 83 SB +663 284 418 (uction) 417 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB + +%%BeginResource: font MSTT31c1f0 +/MSTT31c1f0 [100.0 0 0 0 0 0] 50 -110 [-100.0 -100.0 100.0 100.0] [1 100 div 0 0 1 100 div 0 0] /MSTT31c1f0 GreNewFont +%%EndResource + +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G44 [72.0 0.0 2.0 0.0 68.0 67.0] +/G44 { + 66 67 true [1 0 0 -1 -2.0 67.0] {<fffffffff800000000ffffffffffe000000007fffffffffe00000001fffe003fff80000000ffc000 +07ffe0000000ffc00000fff80000007fc000003ffc0000007fc000001ffe0000007fc0000007ff00 +00007fc0000003ff8000007fc0000001ffc000007fc0000000ffe000007fc00000007ff000007fc0 +0000007ff800007fc00000003ff800007fc00000001ffc00007fc00000001ffc00007fc00000000f +fe00007fc00000000ffe00007fc000000007ff00007fc000000007ff00007fc000000007ff00007f +c000000003ff80007fc000000003ff80007fc000000003ff80007fc000000003ff80007fc0000000 +03ff80007fc000000001ffc0007fc000000001ffc0007fc000000001ffc0007fc000000001ffc000 +7fc000000001ffc0007fc000000001ffc0007fc000000001ffc0007fc000000001ffc0007fc00000 +0001ffc0007fc000000001ffc0007fc000000001ffc0007fc000000001ffc0007fc000000001ffc0 +007fc000000003ff80007fc000000003ff80007fc000000003ff80007fc000000003ff80007fc000 +000003ff00007fc000000007ff00007fc000000007ff00007fc000000007fe00007fc00000000ffe +00007fc00000000ffc00007fc00000001ffc00007fc00000001ff800007fc00000003ff800007fc0 +0000007ff000007fc00000007fe000007fc0000000ffe000007fc0000001ffc000007fc0000003ff +8000007fc0000007ff0000007fc000001ffe0000007fc000003ff8000000ffc00000fff0000000ff +c00007ffc0000001fffe003fff00000007fffffffffc000000ffffffffffc0000000fffffffff800 +000000>} imagemask + } + 68 /G44 MSTT31c1f0 AddChar +/G69 [28.0 0.0 3.0 0.0 25.0 70.0] +/G69 { + 22 70 true [1 0 0 -1 -3.0 70.0] {<00f80001fc0003fe0007ff0007ff0007ff0007ff0007ff0003fe0001fc0000f80000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000e00007e0003fe +000ffe007ffe00fffe00c7fe0003fe0003fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe00 +01fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001 +fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0003ff0003ff +000fffc0fffffcfffffc>} imagemask + } + 105 /G69 MSTT31c1f0 AddChar +/G73 [39.0 0.0 5.0 -1.0 36.0 46.0] +/G73 { + 31 47 true [1 0 0 -1 -5.0 46.0] {<003fc03001fff87007fffff00fc07ff01f800ff03e0007f03e0003f07c0001f07c0001f0fc0000f0 +fc0000f0fc000070fe000070ff000030ff800030ffc000007ff000007ffc00003fff00001fffc000 +0ffff00007fffc0003ffff0000ffff80003fffe0000ffff00003fff80000fff800003ffc00001ffc +000007fe000003fec00001fec00001fee00000fee00000fef00000fef00000fcf80000fcfc0000fc +fe0001f8ff0003f0ffc007e0fff81fc0ffffff80e3fffe00c01ff000>} imagemask + } + 115 /G73 MSTT31c1f0 AddChar +/G6b [50.0 0.0 1.0 0.0 50.0 70.0] +/G6b { + 49 70 true [1 0 0 -1 -1.0 70.0] {<000e0000000000007e000000000003fe00000000000ffe00000000007ffe0000000000fffe000000 +000047fe000000000003fe000000000001fe000000000001fe000000000001fe000000000001fe00 +0000000001fe000000000001fe000000000001fe000000000001fe000000000001fe000000000001 +fe000000000001fe000000000001fe000000000001fe000000000001fe000000000001fe00000000 +0001fe000000000001fe000000000001fe000ffffe0001fe000fffe00001fe0003ff000001fe0001 +fc000001fe0001f8000001fe0001e0000001fe0003c0000001fe000780000001fe000f00000001fe +001e00000001fe003c00000001fe00f800000001fe01e000000001fe03c000000001fe0780000000 +01fe0f0000000001fe1e0000000001fe3e0000000001fe7f0000000001feff8000000001ffff8000 +000001feffc000000001fe7fe000000001fe3ff000000001fe1ff800000001fe1ff800000001fe0f +fc00000001fe07fe00000001fe03ff00000001fe01ff80000001fe01ff80000001fe00ffc0000001 +fe007fe0000001fe003ff0000001fe001ff8000001fe001ff8000001fe000ffc000001fe0007fe00 +0001fe0003ff000001fe0003ff800003ff0001ffc00003ff0001ffe0000fffc003fff800fffffc0f +ffff80fffffc0fffff80>} imagemask + } + 107 /G6b MSTT31c1f0 AddChar +/G20 [25.0 0.0 0.0 0.0 0.0 0.0] +/G20 { +} + 32 /G20 MSTT31c1f0 AddChar +/G70 [50.0 0.0 0.0 -21.0 47.0 46.0] +/G70 { + 47 67 true [1 0 0 -1 0.0 46.0] {<0007001fc000003f00fff80000ff01fffc0007ff07ffff003fff0fffff807fff0fffffc063ff1fff +ffc001ff3f03ffe000ff7800fff000ff70007ff000ffe0003ff800ffc0001ff800ff80000ffc00ff +00000ffc00ff000007fc00ff000007fc00ff000003fe00ff000003fe00ff000003fe00ff000003fe +00ff000001fe00ff000001fe00ff000001fe00ff000001fe00ff000001fe00ff000001fe00ff0000 +01fe00ff000001fe00ff000001fc00ff000001fc00ff000001fc00ff000001fc00ff000003f800ff +000003f800ff000003f000ff000003f000ff000007e000ff800007e000ff80000fc000ffc0001f80 +00ffc0001f8000ffe0003f0000fff800fe0000ff7e03fc0000ff3ffff00000ff1fffc00000ff03fe +000000ff0000000000ff0000000000ff0000000000ff0000000000ff0000000000ff0000000000ff +0000000000ff0000000000ff0000000000ff0000000000ff0000000000ff0000000000ff00000000 +00ff0000000000ff0000000001ff8000000001ff8000000007ffe0000000fffffe000000fffffe00 +0000>} imagemask + } + 112 /G70 MSTT31c1f0 AddChar +/G61 [44.0 0.0 3.0 -1.0 45.0 46.0] +/G61 { + 42 47 true [1 0 0 -1 -3.0 46.0] {<0007ff000000003ffff0000000fffffc000003fc07fe000007f001ff00000fe000ff00000fc0007f +80001fc0007f80001fc0007fc0003fc0003fc0003fc0003fc0003fc0003fc0003fc0003fc0003fc0 +003fc0001f80003fc0000f00003fc0000000007fc000000003ffc00000001fffc00000007fbfc000 +0003fc3fc000000fe03fc000003f803fc00000fe003fc00001f8003fc00007f0003fc0000fe0003f +c0001fc0003fc0003f80003fc0003f80003fc0007f00003fc0007f00003fc000ff00003fc000ff00 +003fc000ff00003fc000ff00003fc000ff80007fc000ff8000ffc000ffc003ffc0407fe007ffe0c0 +7ff83f3fe3c07ffffe3fff803ffffc3fff001ffff01ffe000fffe01ffc0007ff800ff00000fe0007 +c000>} imagemask + } + 97 /G61 MSTT31c1f0 AddChar +/G63 [44.0 0.0 3.0 -1.0 41.0 46.0] +/G63 { + 38 47 true [1 0 0 -1 -3.0 46.0] {<00007fc0000007fff800001ffffc00003f01ff0000fc00ff8001f8007fc003f0003fe007e0003fe0 +07e0003ff00fc0003ff01fc0003ff01f80001ff03f80001ff03f80000fe07f000007c07f00000000 +7f000000007f00000000ff00000000ff00000000ff00000000ff00000000ff00000000ff00000000 +ff80000000ff80000000ff80000000ff80000000ffc00000047fc000000c7fe000000c7fe0000018 +7ff00000183ff00000383ff80000703ffc0000701ffe0001e01fff8003e00fffe01fc007ffffffc0 +03ffffff8001ffffff0000fffffe00007ffffc00003ffff000000fffc0000001fe0000>} imagemask + } + 99 /G63 MSTT31c1f0 AddChar +/G65 [44.0 0.0 3.0 -1.0 41.0 46.0] +/G65 { + 38 47 true [1 0 0 -1 -3.0 46.0] {<0000ff80000007fff000001ffffc00007e07ff0000f801ff8001f000ffc003e0007fe007c0003fe0 +0f80001ff00f00001ff01f00001ff83f00000ff83e00000ff83e00000ffc7e00000ffc7ffffffffc +7ffffffffc7ffffffffcfe00000000fe00000000fe00000000fe00000000fe00000000fe00000000 +ff00000000ff00000000ff00000000ff00000000ff80000000ff800000047fc000000c7fc000000c +7fe00000187ff00000183ff80000383ffc0000701ffe0000f01fff8003e00ffff00fe007ffffffc0 +03ffffff8003ffffff0000fffffe00007ffffc00003ffff800000fffe0000001ff0000>} imagemask + } + 101 /G65 MSTT31c1f0 AddChar +/G6e [50.0 0.0 1.0 0.0 50.0 46.0] +/G6e { + 49 46 true [1 0 0 -1 -1.0 46.0] {<000e001fc00000007e00fff0000003fe01fff800000ffe07fffc00007ffe0ffffe0000fffe1fffff +000047fe3f03ff000003fe7801ff800001fee000ff800001ffc0007f800001ff80007fc00001ff00 +007fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001 +fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc0 +0001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe0000 +3fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe +00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc000 +01fe00003fc00003ff00007fe00003ff00007fe0000fffc001fff800fffffc1fffff80fffffc1fff +ff80>} imagemask + } + 110 /G6e MSTT31c1f0 AddChar +/G6f [50.0 0.0 3.0 -1.0 46.0 46.0] +/G6f { + 43 47 true [1 0 0 -1 -3.0 46.0] {<00007fc000000003fffc0000000fffff0000003f81ff8000007e003fe00000f8001ff00001f8000f +f80003f00007fc0007e00007fc000fe00003fe000fc00001ff001fc00001ff001fc00000ff803f80 +0000ff803f800000ffc07f8000007fc07f8000007fc07f8000007fc07f8000007fe0ff8000003fe0 +ff8000003fe0ff8000003fe0ff8000003fe0ff8000003fe0ff8000003fe0ff8000003fe0ff800000 +3fe0ffc000003fc0ffc000003fc07fc000003fc07fc000003fc07fe000003f807fe000003f803fe0 +00003f803ff000007f001ff000007f001ff800007e000ff80000fe0007fc0000fc0007fe0001f800 +03fe0001f00001ff0003e00000ffc00fc000003ff03f8000001ffffe00000007fff800000000ffc0 +0000>} imagemask + } + 111 /G6f MSTT31c1f0 AddChar +/G74 [28.0 0.0 0.0 -1.0 28.0 60.0] +/G74 { + 28 61 true [1 0 0 -1 0.0 60.0] {<0001000000030000000300000007000000070000000f0000000f0000001f0000001f0000003f0000 +007f000000ff000001ff000003ff00000fff00003fffffc0ffffffc0ffffffc000ff000000ff0000 +00ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000 +00ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000 +00ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000 +00ff000000ff000000ff803000ff8060007fe1e0007fffc0007fff80003fff80001ffe00000ffc00 +0003f000>} imagemask + } + 116 /G74 MSTT31c1f0 AddChar +/G66 [33.0 0.0 3.0 0.0 43.0 70.0] +/G66 { + 40 70 true [1 0 0 -1 -3.0 70.0] {<000000fe0000000fffc000003ffff00000783ff80000f00ffe0001e007fe0003c003ff0007c003ff +000fc001ff000f8000ff001f80007e001f80003c003f800000003f800000003f800000003f800000 +007f800000007f800000007f800000007f800000007f800000007f800000007f800000007f800000 +007f800000fffffff800fffffff800fffffff800007f800000007f800000007f800000007f800000 +007f800000007f800000007f800000007f800000007f800000007f800000007f800000007f800000 +007f800000007f800000007f800000007f800000007f800000007f800000007f800000007f800000 +007f800000007f800000007f800000007f800000007f800000007f800000007f800000007f800000 +007f800000007f800000007f800000007f800000007f800000007f800000007f800000007f800000 +00ffc0000000ffc0000001ffe0000007fff00000ffffffe000ffffffe000>} imagemask + } + 102 /G66 MSTT31c1f0 AddChar +%%EndResource + +586 614 994 (Disk space is not infinite) 994 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 788 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G53 [56.0 0.0 6.0 -1.0 50.0 68.0] +/G53 { + 44 69 true [1 0 0 -1 -6.0 68.0] {<0001ff000300001ffff00300007ffffc070000ff00ff8f0003fc001fff0007f00007ff000fe00003 +ff001fc00001ff001f800000ff003f8000007f003f8000003f007f0000001f007f0000001f00ff00 +00000f00ff0000000f00ff0000000f00ff8000000700ff8000000700ffc000000700ffe000000700 +fff0000003007ff8000003007ffc000003007ffe000000003fff800000003fffe00000001ffff000 +00000ffffc00000007ffff00000007ffffc0000001ffffe0000000fffff80000007ffffe0000001f +ffff8000000fffffc0000003fffff0000000fffff80000003ffffc0000001ffffe00000007ffff00 +000001ffff800000007fff800000001fffc00000000fffc000000003ffe000000001ffe060000000 +fff0600000007ff0600000003ff0700000001ff0700000001ff0700000001ff0700000000ff07800 +00000ff0780000000ff07c0000000fe07c0000000fe07e0000000fe07e0000001fc07f0000001fc0 +7f8000003f807fc000003f007fe000007e007ff80001fc007ffe0003f80070ffc01ff000700fffff +c0006003ffff000060003ff00000>} imagemask + } + 83 /G53 MSTT31c1f0 AddChar +/G6d [78.0 0.0 1.0 0.0 77.0 46.0] +/G6d { + 76 46 true [1 0 0 -1 -1.0 46.0] {<000e001fc00003f80000007e00fff0001ffe000003fe01fffc007fff00000ffe07fffe00ffff8000 +7ffe0fffff01ffffc000fffe1fffff03ffffe00047fe3e07ff87c07fe00003fe7801ff8f003ff000 +03fee000ff9c001ff00001ffc0007ff8000ff00001ff80007ff0000ff80001ff00007fe00007f800 +01fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f800 +01fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f800 +01fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f800 +01fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f800 +01fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f800 +01fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f800 +01fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f80001fe00003fc00007f800 +01fe00003fc00007f80003ff00007fe0000ffc0003ff00007fe0000ffc000fffc001fff8003fff00 +fffffc1fffff83fffff0fffffc1fffff83fffff0>} imagemask + } + 109 /G6d MSTT31c1f0 AddChar +/G6c [28.0 0.0 3.0 0.0 25.0 70.0] +/G6c { + 22 70 true [1 0 0 -1 -3.0 70.0] {<000e00007e0003fe000ffe007ffe00fffe0047fe0003fe0001fe0001fe0001fe0001fe0001fe0001 +fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe +0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe00 +01fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001 +fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0001fe0003ff0003ff +000fffc0fffffcfffffc>} imagemask + } + 108 /G6c MSTT31c1f0 AddChar +/G64 [50.0 0.0 3.0 -1.0 49.0 70.0] +/G64 { + 46 71 true [1 0 0 -1 -3.0 70.0] {<000000000e00000000007e0000000003fe000000000ffe000000007ffe00000000fffe00000000c7 +fe0000000003fe0000000003fe0000000001fe0000000001fe0000000001fe0000000001fe000000 +0001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe00 +00000001fe0000000001fe0000000001fe0000000001fe0000007f81fe000003fff1fe00000ffff9 +fe00003f81fdfe00007e007ffe0000fc001ffe0001f8000ffe0003f00007fe0003e00007fe0007e0 +0003fe000fc00003fe000fc00003fe001f800001fe001f800001fe003f800001fe003f000001fe00 +7f000001fe007f000001fe007f000001fe007f000001fe00ff000001fe00ff000001fe00ff000001 +fe00ff000001fe00ff000001fe00ff000001fe00ff000001fe00ff800001fe00ff800001fe00ff80 +0001fe00ff800001fe007fc00001fe007fc00001fe007fe00001fe003fe00001fe003ff00001fe00 +3ff80001fe001ffc0003fe000ffe0007ff000fff801fff0007ffe07dff8c03fffff9fffc01fffff1 +fff800ffffe1ffc0003fffc1ff00001fff01f8000003fc01c000>} imagemask + } + 100 /G64 MSTT31c1f0 AddChar +/G68 [50.0 0.0 1.0 0.0 50.0 70.0] +/G68 { + 49 70 true [1 0 0 -1 -1.0 70.0] {<000e0000000000007e000000000003fe00000000000ffe00000000007ffe0000000000fffe000000 +0000c7fe000000000003fe000000000001fe000000000001fe000000000001fe000000000001fe00 +0000000001fe000000000001fe000000000001fe000000000001fe000000000001fe000000000001 +fe000000000001fe000000000001fe000000000001fe000000000001fe000000000001fe00000000 +0001fe000000000001fe001fc0000001fe00fff0000001fe03fff8000001fe07fffc000001fe0fff +fe000001fe1fffff000001fe3e07ff000001fe7801ff800001fee000ff800001ffc0007f800001ff +80007f800001ff00007fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc000 +01fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003f +c00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00 +003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001 +fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc0 +0001fe00003fc00001fe00003fc00003ff00007fe00003ff00007fe0000fffc001fff800fffffc1f +ffff80fffffc1fffff80>} imagemask + } + 104 /G68 MSTT31c1f0 AddChar +/G72 [33.0 0.0 1.0 0.0 33.0 46.0] +/G72 { + 32 46 true [1 0 0 -1 -1.0 46.0] {<000e00f0007e03fc01fe07fe0ffe0ffe7ffe1ffffffe3fffc7fe3fff03fe71ff01fee0fe01fec07e +01ffc01c01ff800001ff000001ff000001fe000001fe000001fe000001fe000001fe000001fe0000 +01fe000001fe000001fe000001fe000001fe000001fe000001fe000001fe000001fe000001fe0000 +01fe000001fe000001fe000001fe000001fe000001fe000001fe000001fe000001fe000001fe0000 +01ff000003ff000003ff80000fffe000fffffe00fffffe00>} imagemask + } + 114 /G72 MSTT31c1f0 AddChar +%%EndResource + +1 7 SJ +586 758 2329 (Some installations need a mechanism to control allocation) 2329 SB +1 2 SJ +586 878 521 (of disk space) 521 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G71 [50.0 0.0 3.0 -21.0 49.0 46.0] +/G71 { + 46 67 true [1 0 0 -1 -3.0 46.0] {<00003fe00e000001fffc1e000007ffff7e00001fc07ffe00003f001ffe0000fc000ffe0001f80007 +fe0003f00003fe0007e00003fe0007e00001fe000fc00001fe001fc00001fe001f800001fe003f80 +0001fe003f800001fe003f800001fe007f000001fe007f000001fe007f000001fe007f000001fe00 +ff000001fe00ff000001fe00ff000001fe00ff000001fe00ff000001fe00ff000001fe00ff000001 +fe00ff800001fe00ff800001fe00ff800001fe00ff800001fe007fc00001fe007fc00001fe007fe0 +0001fe007fe00001fe003ff00003fe003ff80003fe001ffc0007fe001fff001dfe000fffc079fe00 +07fffff9fe0007fffff1fe0003ffffe1fe0001ffff81fe00007fff01fe00003ffc01fe000007f001 +fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe000000 +0001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe00 +00000001fe0000000001fe0000000003ff0000000003ff000000000fffc0000000fffffc000000ff +fffc>} imagemask + } + 113 /G71 MSTT31c1f0 AddChar +/G75 [50.0 0.0 1.0 -1.0 50.0 45.0] +/G75 { + 49 46 true [1 0 0 -1 -1.0 45.0] {<fffe001fffc000fffe001fffc0000ffe0001ffc00003fe00007fc00003fe00007fc00001fe00003f +c00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00 +003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001 +fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc0 +0001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe0000 +3fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe00003fc00001fe +00007fc00001ff0000ffc00000ff0001ffc00000ff8007bfe00000ffc00f3fe000007ff07e3ff180 +007ffffc3fff80003ffff83fff00001ffff03ff800000fffe03fe0000007ff803f00000001fc0038 +0000>} imagemask + } + 117 /G75 MSTT31c1f0 AddChar +/G77 [72.0 0.0 1.0 -1.0 73.0 45.0] +/G77 { + 72 46 true [1 0 0 -1 -1.0 45.0] {<ffffe01ffffc003fffffffe01ffffc003fff3fff0003fff00003fc0ffe0000ffe00000f007fe0000 +7fc00000e003fe00007fc00000e003fe00003fc00001c001fe00003fe000018001ff00001fe00003 +8001ff00001fe000038000ff00000ff000070000ff80000ff0000700007f80000ff8000700007fc0 +000ff8000e00007fc0001ffc000e00003fc0001ffc000e00003fe0003ffc001c00001fe0003bfe00 +1c00001ff00079fe001c00001ff00071ff003800000ff000f0ff003800000ff800e0ff0038000007 +f801e0ff8070000007fc01c07f8070000007fc03c07fc0f0000003fc03803fc0e0000003fe07803f +e0e0000001fe07003fe1e0000001fe0f001fe1c0000001ff0e001ff1c0000000ff1e000ff3c00000 +00ff9c000ffb800000007fbc0007fb800000007fb80007ff800000007ff80007ff000000003ff000 +03ff000000003ff00003ff000000001fe00001fe000000001fe00001fe000000001fc00001fc0000 +00000fc00000fc000000000f800000fc000000000780000078000000000700000078000000000700 +0000780000000002000000300000>} imagemask + } + 119 /G77 MSTT31c1f0 AddChar +%%EndResource + +586 1021 2192 (Disk quotas allow the administrator to set limits on the) 2192 SB + +%%BeginResource: font MSTT31c1f0 +/G62 [50.0 0.0 1.0 -1.0 47.0 70.0] +/G62 { + 46 71 true [1 0 0 -1 -1.0 70.0] {<000e00000000007e0000000003fe000000000ffe000000007ffe00000000fffe00000000c7fe0000 +000003fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe +0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe00000000 +01fe0000000001fe0000000001fe0000000001fe0000000001fe003f800001fe01ffe00001fe07ff +f80001fe0ffffe0001fe1fffff0001fe3fffff8001fe7fffff8001fefc0fffc001fff001ffe001ff +c000ffe001ff80007ff001ff00003ff001fe00001ff801fe00001ff801fe00000ff801fe00000ff8 +01fe000007fc01fe000007fc01fe000007fc01fe000003fc01fe000003fc01fe000003fc01fe0000 +03fc01fe000003fc01fe000003fc01fe000003fc01fe000003fc01fe000003f801fe000003f801fe +000003f801fe000003f801fe000007f001fe000007f001fe000007f001fe000007e001fe00000fc0 +01fe00000fc001fe00001f8001fe00001f0001fe00003e0001ff80007c0001ffc000f80000fff001 +f000003ffc0fe000000fffff80000001fffe000000003ff00000>} imagemask + } + 98 /G62 MSTT31c1f0 AddChar +/G2f [28.0 0.0 0.0 -1.0 28.0 70.0] +/G2f { + 28 71 true [1 0 0 -1 0.0 70.0] {<000000f0000001f0000001e0000001e0000003e0000003c0000003c0000007c00000078000000780 +00000f8000000f0000000f0000001f0000001e0000001e0000003e0000003c0000003c0000007c00 +00007800000078000000f8000000f0000000f0000001f0000001e0000001e0000003e0000003c000 +0003c0000007c0000007800000078000000f0000000f0000000f0000001e0000001e0000001e0000 +003c0000003c0000003c000000780000007800000078000000f0000000f0000000f0000001e00000 +01e0000001e0000003c0000003c0000003c000000780000007800000078000000f0000000f000000 +0f0000001e0000001e0000001e0000003c0000003c0000003c000000780000007800000078000000 +f0000000>} imagemask + } + 47 /G2f MSTT31c1f0 AddChar +/G3a [28.0 0.0 9.0 -1.0 20.0 46.0] +/G3a { + 11 47 true [1 0 0 -1 -9.0 46.0] {<1f003f807fc0ffe0ffe0ffe0ffe0ffe07fc03f801f00000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000001f003f807fc0ffe0 +ffe0ffe0ffe0ffe07fc03f801f00>} imagemask + } + 58 /G3a MSTT31c1f0 AddChar +%%EndResource + +2 5 SJ +586 1141 1589 (number of allocated blocks and/or files:) 1589 SB + +%%BeginResource: font MSTT31c1fd +/MSTT31c1fd [75.0 0 0 0 0 0] 53 -104 [-75.0 -75.0 75.0 75.0] [1 75 div 0 0 1 75 div 0 0] /MSTT31c1fd GreNewFont +%%EndResource + +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font + +%%BeginResource: font MSTT31c1fd +/G96 [38.0 0.0 -1.0 17.0 39.0 20.0] +/G96 { + 40 3 true [1 0 0 -1 1.0 20.0] {<ffffffffffffffffffffffffffffff>} imagemask + } + 150 /G96 MSTT31c1fd AddChar +%%EndResource + +623 1280 38 (\226) 38 SB + +%%BeginResource: font MSTT31c1fd +/G6c [21.0 0.0 3.0 0.0 19.0 52.0] +/G6c { + 16 52 true [1 0 0 -1 -3.0 52.0] {<00e003e00fe07fe0dfe00fe007e007e007e007e007e007e007e007e007e007e007e007e007e007e0 +07e007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e0 +07e007e007e007e007e007e007e007e007e00ff01ff8ffff>} imagemask + } + 108 /G6c MSTT31c1fd AddChar +/G69 [21.0 0.0 3.0 0.0 19.0 52.0] +/G69 { + 16 52 true [1 0 0 -1 -3.0 52.0] {<03c007e00ff00ff00ff00ff007e003c000000000000000000000000000000000000000e003e00fe0 +7fe0dfe00fe007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e007e0 +07e007e007e007e007e007e007e007e007e00ff01ff8ffff>} imagemask + } + 105 /G69 MSTT31c1fd AddChar +/G6d [57.0 0.0 1.0 0.0 57.0 35.0] +/G6d { + 56 35 true [1 0 0 -1 -1.0 35.0] {<00e00fc001f80003e07fe007fe000fe0fff81fff007fe3fff83fff80dfe783fc783fc00fee01fce0 +1fc007f800ffc00fc007f000ff000fe007e0007e0007e007e0007e0007e007e0007e0007e007e000 +7e0007e007e0007e0007e007e0007e0007e007e0007e0007e007e0007e0007e007e0007e0007e007 +e0007e0007e007e0007e0007e007e0007e0007e007e0007e0007e007e0007e0007e007e0007e0007 +e007e0007e0007e007e0007e0007e007e0007e0007e007e0007e0007e007e0007e0007e007e0007e +0007e007e0007e0007e007e0007e0007e007e0007e0007e00ff000ff000ff01ff801ff801ff8ffff +0ffff0ffff>} imagemask + } + 109 /G6d MSTT31c1fd AddChar +/G74 [21.0 0.0 0.0 -1.0 21.0 45.0] +/G74 { + 21 46 true [1 0 0 -1 0.0 45.0] {<00100000300000300000700000700000f00000f00001f00003f00007f0001ff0007ffff0fffff003 +f00003f00003f00003f00003f00003f00003f00003f00003f00003f00003f00003f00003f00003f0 +0003f00003f00003f00003f00003f00003f00003f00003f00003f00003f00003f00003f00003f018 +03f83001fc7001ffe000ffc000ff80003e00>} imagemask + } + 116 /G74 MSTT31c1fd AddChar +/G73 [29.0 0.0 4.0 -1.0 27.0 35.0] +/G73 { + 23 36 true [1 0 0 -1 -4.0 35.0] {<01fe0807fff81e03f83c00f8780078700038700038f00018f00018f80008fc0008fe00007f80007f +e0003ff8001ffe000fff0003ffc001ffe0007ff0001ff80007fc0001fc0000fe00007e80007e8000 +3ec0003ec0003ee0003cf0003cf80078fc00f0ff81e0ffff8083fe00>} imagemask + } + 115 /G73 MSTT31c1fd AddChar +/G20 [19.0 0.0 0.0 0.0 0.0 0.0] +/G20 { +} + 32 /G20 MSTT31c1fd AddChar +/G61 [33.0 0.0 3.0 -1.0 34.0 35.0] +/G61 { + 31 36 true [1 0 0 -1 -3.0 35.0] {<007fc00003fff80007c1fc001f007e003e003f003e003f007e001f807e001f807e001f807e001f80 +7e001f803c001f8000003f800001ff800007df80003f1f8000f81f8001e01f8007c01f800f801f80 +1f001f803e001f807e001f807c001f80fc001f80fc001f80fc001f80fc001f80fe003f80fe007f82 +7f00ff867f83dfce3fff1ffc3ffe1ff81ff80fe007e00780>} imagemask + } + 97 /G61 MSTT31c1fd AddChar +/G72 [25.0 0.0 1.0 0.0 25.0 35.0] +/G72 { + 24 35 true [1 0 0 -1 -1.0 35.0] {<00e07c03e0fe0fe1ff7fe3ffdfe7ff0fee7f07ec3e07f80e07f00007f00007e00007e00007e00007 +e00007e00007e00007e00007e00007e00007e00007e00007e00007e00007e00007e00007e00007e0 +0007e00007e00007e00007e00007f0000ff0001ffc00ffff00>} imagemask + } + 114 /G72 MSTT31c1fd AddChar +/G65 [33.0 0.0 3.0 -1.0 31.0 35.0] +/G65 { + 28 36 true [1 0 0 -1 -3.0 35.0] {<001fe000007ffc0001c1fe0003807f0007003f800e001fc01c001fe03c000fe038000fe038000ff0 +78000ff07ffffff07ffffff0f8000000f8000000f8000000f8000000f8000000fc000000fc000000 +fc000000fc000000fe000010fe0000307f0000307f8000607fc000603fe000e03ff001c01ffc07c0 +0fffff8007ffff0003fffe0001fffc0000fff800001fc000>} imagemask + } + 101 /G65 MSTT31c1fd AddChar +/G6e [38.0 0.0 1.0 0.0 37.0 35.0] +/G6e { + 36 35 true [1 0 0 -1 -1.0 35.0] {<00e01f800003e07fe0000fe0fff0007fe3fff800dfe783fc000fee01fc0007fc00fc0007f000fe00 +07e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +0ff000ff001ff801ff80ffff0ffff0>} imagemask + } + 110 /G6e MSTT31c1fd AddChar +/G67 [37.0 0.0 2.0 -16.0 36.0 35.0] +/G67 { + 34 51 true [1 0 0 -1 -2.0 35.0] {<000ff00000003ffc000000f83f000001f00fffc003e00fffc007c007e0000fc003f0000f8003f000 +0f8003f8001f8001f8001f8001f8001f8001f8001f8001f8001f8001f8001f8001f8001fc001f800 +0fc001f0000fc003f00007e003e00003e007c00001f007800000fc1f0000007ffe000000eff00000 +01c0000000038000000007000000000f000000000f000000001f800000001ffff000001ffffff800 +0ffffffe0007ffffff0003ffffff800307ffff800600000fc00e000001c01c000000c038000000c0 +38000000c07800000080f800000180fc00000300fe00000600ff80001c007ff000f8003ffffff000 +0fffffc00003ffff0000003ff00000>} imagemask + } + 103 /G67 MSTT31c1fd AddChar +/G64 [38.0 0.0 3.0 -1.0 37.0 52.0] +/G64 { + 34 53 true [1 0 0 -1 -3.0 52.0] {<0000003800000000f800000003f80000001ff800000037f800000003f800000001f800000001f800 +000001f800000001f800000001f800000001f800000001f800000001f800000001f800000001f800 +000001f800000fe1f800003ff9f80000f83df80001e01ff80003c00ff800078007f8000f0003f800 +1f0003f8001e0001f8003e0001f8003e0001f8007c0001f8007c0001f8007c0001f8007c0001f800 +fc0001f800fc0001f800fc0001f800fc0001f800fc0001f800fc0001f800fc0001f800fe0001f800 +fe0001f8007e0001f8007f0001f8007f0001f8003f8001f8003fc001f8001fe003f8001ff00ffc00 +0ffc1dfec007fff9ff8003fff1fc0000ffe1f000003f81c000>} imagemask + } + 100 /G64 MSTT31c1fd AddChar +/G6f [38.0 0.0 3.0 -1.0 35.0 35.0] +/G6f { + 32 36 true [1 0 0 -1 -3.0 35.0] {<000ff000003ffe0000f83f8003e01fc007c00fe0078007f00f0003f81f0003f81f0001fc3e0001fc +3e0000fe7e0000fe7e0000fe7e00007ffe00007ffe00007ffe00007ffe00007ffe00007ffe00007f +fe00007ffe00007fff00007e7f00007e7f00007e7f00007c3f80007c3f8000f81fc000f81fc000f0 +0fe001e007f003e003f8078001fe0f00007ffc00000ff000>} imagemask + } + 111 /G6f MSTT31c1fd AddChar +/G66 [24.0 0.0 2.0 0.0 32.0 52.0] +/G66 { + 30 52 true [1 0 0 -1 -2.0 52.0] {<00007f000001ffc000070ff0000e07f8001c03fc003c01fc007800fc007800fc00f8003800f80000 +00f8000001f8000001f8000001f8000001f8000001f8000001f8000001f80000fffffc00fffffc00 +01f8000001f8000001f8000001f8000001f8000001f8000001f8000001f8000001f8000001f80000 +01f8000001f8000001f8000001f8000001f8000001f8000001f8000001f8000001f8000001f80000 +01f8000001f8000001f8000001f8000001f8000001f8000001f8000001f8000003fc000007fc0000 +0fff0000fffff800>} imagemask + } + 102 /G66 MSTT31c1fd AddChar +/G79 [36.0 0.0 0.0 -16.0 36.0 34.0] +/G79 { + 36 50 true [1 0 0 -1 0.0 34.0] {<ffff003ff03ff80007c01ff00003800ff000030007f000070007f000060003f000060003f8000e00 +01f8000c0001fc000c0000fc00180000fe001800007e003800007f003000003f003000003f806000 +001f806000001fc0c000000fc0c000000fe0c0000007e180000007f180000003f300000003fb0000 +0001ff00000001fe00000000fe00000000fc000000007c0000000078000000003800000000380000 +00003000000000300000000060000000006000000000e000000000c000000000c000000001800000 +000380000000030000001f0f0000003ffe0000007ffe0000007ffc0000007ff80000003ff0000000 +3fe00000000f80000000>} imagemask + } + 121 /G79 MSTT31c1fd AddChar +/G62 [38.0 0.0 1.0 -1.0 35.0 52.0] +/G62 { + 34 53 true [1 0 0 -1 -1.0 52.0] {<00e000000003e00000000fe00000007fe0000000dfe00000000fe000000007e000000007e0000000 +07e000000007e000000007e000000007e000000007e000000007e000000007e000000007e0000000 +07e000000007e03f800007e0ffe00007e1fff00007e3fff80007e7fffc0007ef07fe0007fc01ff00 +07f800ff0007f0007f8007e0003f8007e0003f8007e0001f8007e0001fc007e0001fc007e0000fc0 +07e0000fc007e0000fc007e0000fc007e0000fc007e0000fc007e0000fc007e0000fc007e0000f80 +07e0000f8007e0001f8007e0001f0007e0001f0007e0001e0007e0003e0007e0003c0007e0007800 +07f800f00007fc01e00001ff078000003ffe00000007f80000>} imagemask + } + 98 /G62 MSTT31c1fd AddChar +%%EndResource + +5 7 SJ +717 1280 1226 (limits are managed on a file system basis) 1226 SB +623 1388 38 (\226) 38 SB + +%%BeginResource: font MSTT31c1fd +/G71 [38.0 0.0 3.0 -16.0 37.0 35.0] +/G71 { + 34 51 true [1 0 0 -1 -3.0 35.0] {<0007f81800003ffe780000f81ff80001e00ff80003c007f800078003f8000f0003f8001f0001f800 +1e0001f8003e0001f8003e0001f8007c0001f8007c0001f8007c0001f800fc0001f800fc0001f800 +fc0001f800fc0001f800fc0001f800fc0001f800fc0001f800fc0001f800fe0001f800fe0001f800 +fe0001f8007f0001f8007f0001f8007f8001f8003fc003f8003fe007f8001ff81df8000ffff9f800 +07fff1f80003ffe1f80001ff81f800007e01f800000001f800000001f800000001f800000001f800 +000001f800000001f800000001f800000001f800000001f800000001f800000001f800000001f800 +000003fc00000007fe0000003fffc0>} imagemask + } + 113 /G71 MSTT31c1fd AddChar +/G75 [38.0 0.0 1.0 -1.0 37.0 34.0] +/G75 { + 36 35 true [1 0 0 -1 -1.0 34.0] {<ffe00ffe001fe001fe000fe000fe0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e0007e0007e0007e0007e0007f000fe0003f003fe0003f8077f0003fc1e7fb001fffc7fe0 +00fff07f00007fe07c00001f807000>} imagemask + } + 117 /G75 MSTT31c1fd AddChar +/G63 [33.0 0.0 3.0 -1.0 31.0 35.0] +/G63 { + 28 36 true [1 0 0 -1 -3.0 35.0] {<000ff000007ffc0000f07f0003c03f8007801fc00f001fc01f000fe01e000fe03e000fe03e0007e0 +7c0003c07c0000007c000000fc000000fc000000fc000000fc000000fc000000fc000000fe000000 +fe000000fe000000ff0000107f0000307f0000307f8000607fc000603fe000c03ff001c01ffc0f80 +0fffff8007ffff0003fffe0001fffc0000fff000001f8000>} imagemask + } + 99 /G63 MSTT31c1fd AddChar +/G77 [53.0 0.0 1.0 -1.0 53.0 34.0] +/G77 { + 52 35 true [1 0 0 -1 -1.0 34.0] {<fffc0fffc03ff07ff003ff0007e01fe000fe0003800fe000fe0003000fe0007e00030007e0007e00 +060007e0003f00060007f0003f00060003f0003f000c0003f0003f800c0001f8003f800c0001f800 +7fc0180001fc006fc0180000fc00efc0180000fc00cfe0300000fe00c7e03000007e0187e0300000 +7e0183f06000003f0303f06000003f0303f8e000003f8601f8c000001f8601f8c000001f8c01fdc0 +00001fcc00fd8000000fd800fd8000000fd8007f80000007f8007f00000007f0007f00000007f000 +3e00000003e0003e00000003e0003e00000003c0001c00000001c0001c0000000180001c00000000 +8000080000>} imagemask + } + 119 /G77 MSTT31c1fd AddChar +/G68 [38.0 0.0 1.0 0.0 37.0 52.0] +/G68 { + 36 52 true [1 0 0 -1 -1.0 52.0] {<00e000000003e00000000fe00000007fe0000000dfe00000000fe000000007e000000007e0000000 +07e000000007e000000007e000000007e000000007e000000007e000000007e000000007e0000000 +07e000000007e01f800007e07fe00007e0fff00007e3fff80007e783f80007ee01fc0007fc00fc00 +07f000fe0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e0007e00 +07e0007e000ff000ff001ff801ff80ffff0ffff0>} imagemask + } + 104 /G68 MSTT31c1fd AddChar +/G70 [38.0 0.0 1.0 -16.0 35.0 35.0] +/G70 { + 34 51 true [1 0 0 -1 -1.0 35.0] {<00e01f800003e07fe0000fe1fff0007fe3fff800ffe7fffc000fef07fe0007ee01ff0007f800ff00 +07f0007f8007e0003f8007e0003f8007e0001f8007e0001fc007e0001fc007e0001fc007e0000fc0 +07e0000fc007e0000fc007e0000fc007e0000fc007e0000fc007e0000fc007e0000f8007e0000f80 +07e0000f8007e0001f0007e0001f0007e0001f0007e0003e0007f0003c0007f0007c0007f8007800 +07fc00f00007ff03e00007e7ff800007e1fe000007e000000007e000000007e000000007e0000000 +07e000000007e000000007e000000007e000000007e000000007e000000007e000000007e0000000 +0ff00000001ff8000000ffff000000>} imagemask + } + 112 /G70 MSTT31c1fd AddChar +%%EndResource + +717 1388 1558 (quotas can be associated with users and user groups) 1558 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G34 [29.0 0.0 1.0 0.0 26.0 40.0] +/G34 { + 25 40 true [1 0 0 -1 -1.0 40.0] {<0000f0000000f0000001f0000001f0000003f0000007f0000007f000000df000001df0000019f000 +0031f0000031f0000061f00000e1f00000c1f0000181f0000181f0000301f0000701f0000601f000 +0c01f0000c01f0001801f0003801f0003001f0006001f000e001f000ffffff80ffffff80ffffff80 +0001f0000001f0000001f0000001f0000001f0000001f0000001f0000001f0000001f0000001f000 +>} imagemask + } + 52 /G34 MSTT31c1bc AddChar +%%EndResource + +2919 2191 29 (4) 29 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d0439a4b687a9024e596c4b1dde5fe3f345cafae8cf4c808fb96646624e02e6ffc7fee976c6bc04297090beef82b38032beb8ee2f +6bc81681d15818312c65bab2e7a843bdd3f258a0a30ee0b1c119aff67bb748720cea1369ef4bc2b2aa5b4c1af425550815b3e5607df8333913f207b8e5750be8 +ea52046b1728bbe207ca2300df72213da0e76feaea3f072404ebb5a7d7c446ac0c712bebbc02a47962fbd614355b5948e7d659101d06ea214be3a60a4699f41f +ba51b6a14fd6436539f3f3f178ea676bf5eb0ccb02b42c86d0ea544cefcebaf0d98921a2ccdf71b977889a5a877dbe0dad197f68c7b9d48da8c3268038eb4550 +7174185a8934678b3172e281758f08f294af4f839c9cba87637bf400551254e6e21cda +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-6 3 SJ +256 284 1650 (Principles of disk quotas) 1650 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G67 [49.0 0.0 3.0 -21.0 47.0 46.0] +/G67 { + 44 67 true [1 0 0 -1 -3.0 46.0] {<0000ff8000000007fff80000001f81fe0000003e007ffff000fc003ffff001f8001ffff001f8001f +f00003f0000ff00007f0000ff80007e00007f8000fe00007f8000fe00007fc000fe00003fc001fe0 +0003fc001fe00003fc001fe00003fc001fe00003fc001fe00003fc001fe00003fc001fe00003fc00 +1ff00003f8000ff00003f8000ff00003f80007f80007f00007f80007e00003fc0007e00003fc000f +c00001fe001f8000007f003f0000003fc0fc0000001ffff000000038ff80000000700000000000e0 +0000000003e00000000007c00000000007c0000000000fc0000000001ff0000000001fffffc00000 +1ffffffff0001ffffffffe000fffffffff0007ffffffff8003ffffffffc000ffffffffe001c0ffff +ffe003c000001ff00780000001f00700000000f00f00000000701e00000000703e00000000703e00 +000000607e00000000e07e00000000e0ff00000001c0ff8000000380ffe000000f00fff800003e00 +7fff8003fc003ffffffff8001ffffffff00007ffffffc00001ffffff0000007ffff800000007ff80 +0000>} imagemask + } + 103 /G67 MSTT31c1f0 AddChar +%%EndResource + +4 9 SJ +586 614 2281 (Disk quotas can be associated with users and user groups) 2281 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 788 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G54 [61.0 0.0 3.0 0.0 59.0 67.0] +/G54 { + 56 67 true [1 0 0 -1 -3.0 67.0] {<7ffffffffffffe7ffffffffffffe7ffffffffffffe7f8001ff0003fe7e0001ff00007e7c0001ff00 +003e780001ff00001ef00001ff00000fe00001ff000007e00001ff000007e00001ff000007c00001 +ff000003c00001ff000003c00001ff000003000001ff000000000001ff000000000001ff00000000 +0001ff000000000001ff000000000001ff000000000001ff000000000001ff000000000001ff0000 +00000001ff000000000001ff000000000001ff000000000001ff000000000001ff000000000001ff +000000000001ff000000000001ff000000000001ff000000000001ff000000000001ff0000000000 +01ff000000000001ff000000000001ff000000000001ff000000000001ff000000000001ff000000 +000001ff000000000001ff000000000001ff000000000001ff000000000001ff000000000001ff00 +0000000001ff000000000001ff000000000001ff000000000001ff000000000001ff000000000001 +ff000000000001ff000000000001ff000000000001ff000000000001ff000000000001ff00000000 +0001ff000000000001ff000000000001ff000000000001ff000000000003ff800000000003ff8000 +00000007ffc0000000001ffff000000003ffffff80000003ffffff8000>} imagemask + } + 84 /G54 MSTT31c1f0 AddChar +/G79 [47.0 0.0 0.0 -21.0 47.0 45.0] +/G79 { + 47 66 true [1 0 0 -1 0.0 45.0] {<fffff8007ffefffff8007ffe3fff800007f00fff000003e007fe000003c007fe0000038003ff0000 +038001ff0000070001ff0000070000ff80000f0000ff80000e00007fc0000e00007fc0001c00003f +e0001c00003fe0003c00001ff0003800001ff0003800000ff0007000000ff80070000007f800f000 +0007fc00e0000003fc00e0000003fe01c0000001fe01c0000001ff01c0000000ff0380000000ff83 +80000000ff87800000007fc7000000007fc7000000003fee000000003fee000000001ffe00000000 +1ffc000000000ffc000000000ff80000000007f80000000007f80000000003f00000000003f00000 +000001e00000000001e00000000001e00000000001c00000000001c0000000000380000000000380 +000000000780000000000700000000000700000000000e00000000000e00000000001e0000000000 +1c00000000003c00000007c0780000001ff0f80000001ffff00000003ffff00000003fffe0000000 +3fffc00000003fff800000001fff000000001ffe000000000ff80000000003e000000000>} imagemask + } + 121 /G79 MSTT31c1f0 AddChar +%%EndResource + +5 10 SJ +586 758 2328 (They limit the number of blocks and the number of inodes) 2328 SB + +%%BeginResource: font MSTT31c1f0 +/G28 [33.0 0.0 4.0 -21.0 31.0 69.0] +/G28 { + 27 90 true [1 0 0 -1 -4.0 69.0] {<00000020000000e0000003c00000078000001e0000003c00000078000000f0000001e0000003c000 +00078000000f8000001f0000003e0000003e0000007c000000fc000000f8000001f8000003f80000 +03f0000007f0000007f000000fe000000fe000000fe000001fe000001fe000001fc000003fc00000 +3fc000003fc000007fc000007fc000007f8000007f8000007f8000007f800000ff800000ff800000 +ff800000ff800000ff800000ff800000ff800000ff800000ff800000ff800000ff800000ff800000 +ff800000ff8000007f8000007f8000007fc000007fc000007fc000007fc000003fc000003fc00000 +3fc000001fc000001fe000001fe000000fe000000fe0000007f0000007f0000007f0000003f00000 +03f8000001f8000000fc000000fc0000007c0000003e0000003f0000001f0000000f80000007c000 +0003c0000001e0000000f0000000780000003c0000000f0000000780000001c0000000e000000020 +>} imagemask + } + 40 /G28 MSTT31c1f0 AddChar +/G29 [33.0 0.0 2.0 -21.0 29.0 69.0] +/G29 { + 27 90 true [1 0 0 -1 -2.0 69.0] {<80000000e0000000780000003c0000001f0000000780000003c0000001e0000000f0000000780000 +007c0000003e0000001f0000001f8000000f80000007c0000007e0000003e0000003f0000003f800 +0001f8000001fc000001fc000001fc000000fe000000fe000000ff000000ff0000007f0000007f80 +00007f8000007f8000007fc000007fc000007fc000007fc000003fc000003fc000003fe000003fe0 +00003fe000003fe000003fe000003fe000003fe000003fe000003fe000003fe000003fe000003fe0 +00003fe000003fe000003fc000003fc000003fc000003fc000007fc000007fc000007f8000007f80 +00007f8000007f000000ff000000ff000000fe000000fe000000fe000001fc000001fc000001f800 +0003f8000003f0000003e0000007e0000007c000000f8000000f8000001f0000003e0000003c0000 +0078000000f0000001e0000003c00000078000000f0000003c00000078000000e000000080000000 +>} imagemask + } + 41 /G29 MSTT31c1f0 AddChar +%%EndResource + +4 7 SJ +586 878 1804 (\(files\) that a user/group is allowed to allocate) 1804 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G4c [59.0 0.0 2.0 0.0 57.0 67.0] +/G4c { + 55 67 true [1 0 0 -1 -2.0 67.0] {<fffffff8000000fffffff800000007fffe0000000001fff80000000000ffe00000000000ffe00000 +0000007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc0 +00000000007fc000000000007fc000000000007fc000000000007fc000000000007fc00000000000 +7fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc0000000 +00007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc000 +000000007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007f +c000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000 +007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc00000 +0000007fc000000000007fc000000000007fc000000000007fc000000006007fc00000000e007fc0 +0000000c007fc00000000c007fc00000001c007fc00000001c007fc000000038007fc00000003800 +7fc000000078007fc0000000f0007fc0000001f0007fc0000003f000ffe0000007f000ffe000001f +e001fff80000ffe007ffffffffffe0ffffffffffffc0ffffffffffffc0>} imagemask + } + 76 /G4c MSTT31c1f0 AddChar +%%EndResource + +586 1021 288 (Limits:) 288 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 1160 38 (\226) 38 SB +717 1160 402 (current usage) 402 SB +623 1268 38 (\226) 38 SB + +%%BeginResource: font MSTT31c1fd +/G3a [21.0 0.0 7.0 -1.0 15.0 35.0] +/G3a { + 8 36 true [1 0 0 -1 -7.0 35.0] {<3c7effffffff7e3c00000000000000000000000000000000000000003c7effffffff7e3c>} imagemask + } + 58 /G3a MSTT31c1fd AddChar +/G78 [37.0 0.0 0.0 0.0 37.0 34.0] +/G78 { + 37 34 true [1 0 0 -1 0.0 34.0] {<ffff01ffc01ffc007f000ff8003c0007f800380003f800300001fc00700000fe00600000fe00c000 +007f018000003f830000003fc70000001fee0000000fec00000007f800000007f000000003f80000 +0001fc00000001fe00000001fe000000037f000000063f8000000c3f8000001c1fc00000380fe000 +00300ff000006007f00000c003f80001c003fc00038001fc00030000fe00070000ff000f0000ff80 +1fc001ffe07ff007fff8>} imagemask + } + 120 /G78 MSTT31c1fd AddChar +/G6b [37.0 0.0 1.0 0.0 37.0 52.0] +/G6b { + 36 52 true [1 0 0 -1 -1.0 52.0] {<00e000000003e00000000fe00000007fe0000000dfe00000000fe000000007e000000007e0000000 +07e000000007e000000007e000000007e000000007e000000007e000000007e000000007e0000000 +07e000000007e000000007e007ffe007e003fe0007e001f00007e001e00007e001c00007e0030000 +07e006000007e00c000007e038000007e070000007e0e0000007e1c0000007e380000007e7800000 +07efc0000007ffe0000007efe0000007e7f0000007e3f8000007e3fc000007e1fe000007e0fe0000 +07e07f000007e03f800007e03fc00007e01fe00007e00fe00007e007f00007e003f80007e003fc00 +07e001fe000ff001ff801ff801fff0ffff07fff0>} imagemask + } + 107 /G6b MSTT31c1fd AddChar +/G2f [21.0 0.0 0.0 -1.0 21.0 52.0] +/G2f { + 21 53 true [1 0 0 -1 0.0 52.0] {<0000380000780000700000700000e00000e00000e00001c00001c00001c000038000038000038000 +0700000700000700000e00000e00000e00001c00001c00001c000038000038000038000070000070 +0000700000e00000e00000e00001c00001c00001c000038000038000038000070000070000070000 +0e00000e00000e00001c00001c00001c0000380000380000380000700000700000700000e00000>} imagemask + } + 47 /G2f MSTT31c1fd AddChar +%%EndResource + +717 1268 2212 (soft limit: maximal number of blocks/inodes that a user/group is expected) 2212 SB +-1 1 SJ +717 1359 220 (to need) 220 SB +623 1467 38 (\226) 38 SB +717 1467 2205 (hard limit: maximal number of blocks/inodes that a user/group is allowed) 2205 SB +-1 1 SJ +717 1557 311 (to allocate) 311 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G35 [29.0 0.0 3.0 0.0 25.0 39.0] +/G35 { + 22 39 true [1 0 0 -1 -3.0 39.0] {<00fffc00fff801fff801fff003fff00300000600000600000c00000c00001f80001ff0003ffc003f +fe007fff8003ffc0007fc0001fe00007f00003f00001f00000f80000f80000780000780000780000 +780000780000700000700000700000e00000c00001c0700380fc0f00fffc007ff8001fc000>} imagemask + } + 53 /G35 MSTT31c1bc AddChar +%%EndResource + +2919 2191 29 (5) 29 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d013dcfd52cf6001bd0d7663003bf0bea02713009112d390690aa8cec87224298d4c086f147a6b31276874f777b1552311010bf1a +02aa65d153b06e732c7e0ffde68b3179b32ebd2d3d8bc355078d5346e8a53371f430cca006c34facac0d84562ed903c711b1506f186956159070ec7f114ff4d3 +59e5ee8ff1d184226fed9ea73198dfc19f44a91fe1380a15adaabcc4c52aa3c0690bcddedd640992169f01e19541e67a31503a333d47c5bde2cf24604721b6f0 +be8540fe1805b6425f3999bf18b8b12287e1ba05c78f36d229d0 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +256 305 1695 (Principles of disk quotas \(2\)) 1695 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G57 [95.0 0.0 3.0 -1.0 94.0 67.0] +/G57 { + 91 68 true [1 0 0 -1 -3.0 67.0] {<ffffff03fffffe0000ffffe0ffffff03fffffe0000ffffe00ffff0007fffe000000fff0007ffe000 +1fff80000003fc0003ffc0000fff80000001f80001ffc00007ff00000001f80000ffc00007ff0000 +0001f00000ffc00003ff00000001f00000ffc00003ff80000001e000007fc00001ff80000001e000 +007fe00001ff80000001c000007fe00000ff80000003c000003fe00000ffc0000003c000003ff000 +00ffc00000038000001ff000007fc00000078000001ff000007fe00000078000001ff800007fe000 +00070000000ff800003fe000000f0000000ff800003ff000000f0000000ffc00003ff000000e0000 +0007fc00001ff000001e00000007fc00001ff800001c00000007fe00001ff800003c00000003fe00 +003ff800003c00000003fe00003ffc00003800000001ff00003ffc00007800000001ff00007ffc00 +007800000001ff00007ffe0000f000000000ff80007bfe0000f000000000ff80007bff0000e00000 +0000ffc000fbff0001e0000000007fc000f1ff0001e0000000007fc000f1ff8001c0000000007fe0 +01f1ff8003c0000000003fe001e0ff8003c0000000003fe001e0ffc00780000000001ff003e0ffc0 +0780000000001ff003c07fc00700000000001ff003c07fe00f00000000000ff803c03fe00f000000 +00000ff807c03fe00e00000000000ff807803ff01e000000000007fc07801ff01e000000000007fc +0f801ff03c000000000007fe0f001ff83c000000000003fe0f000ff838000000000003fe1f000ffc +78000000000001ff1e000ffc78000000000001ff1e0007fc70000000000001ff3e0007fef0000000 +000000ffbc0007fef0000000000000ffbc0003ffe0000000000000ffbc0003ffe00000000000007f +f80001ffc00000000000007ff80001ffc00000000000007ff80001ffc00000000000003ff80000ff +800000000000003ff00000ff800000000000001ff00000ff800000000000001ff000007f00000000 +0000001fe000007f000000000000000fe000007f000000000000000fe000003e000000000000000f +c000003e0000000000000007c000003c0000000000000007c000001c00000000000000078000001c +00000000000000038000000800000000>} imagemask + } + 87 /G57 MSTT31c1f0 AddChar +/G2c [25.0 0.0 5.0 -16.0 20.0 10.0] +/G2c { + 15 26 true [1 0 0 -1 -5.0 10.0] {<0f803fe07ff0fff8fffcfffcfffcfffe7ffe3ffe1f0e000e000e000e001c001c00180038007000e0 +01c003800f007c00f0008000>} imagemask + } + 44 /G2c MSTT31c1f0 AddChar +%%EndResource + +4 9 SJ +586 614 2101 (When the soft limit is reached, a warning message is) 2101 SB +586 734 283 (printed) 283 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 908 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G78 [51.0 0.0 1.0 0.0 49.0 45.0] +/G78 { + 48 45 true [1 0 0 -1 -1.0 45.0] {<ffffe007fff8ffffe007fff81fff8000ffc007ff00007f0003ff00007e0001ff00007c0000ff8000 +780000ffc000f000007fe001e000003fe001c000003ff003c000001ff8078000000ffc0f00000007 +fe1e00000007fe1c00000003ff3800000001fff800000000fff000000000ffe0000000007fe00000 +00003ff0000000001ff0000000001ff8000000001ffc000000003ffe000000003bfe0000000073ff +00000000e1ff80000001e0ff80000003c07fc0000007807fe0000007003ff000000e001ff000001c +001ff800003c000ffc0000780007fe0000700003fe0000f00003ff0001e00001ff8003e00000ffc0 +07e00000ffc00ff00000ffe01ff80003fff87fff001fffff7fff001fffff>} imagemask + } + 120 /G78 MSTT31c1f0 AddChar +%%EndResource + +6 9 SJ +586 878 2329 (The hard limit cannot be exceeded \(system calls return the) 2329 SB +2 1 SJ +586 998 218 (error ) 218 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +806 1002 360 (EDQUOT) 360 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1166 998 33 (\)) 33 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1171 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G47 [72.0 0.0 4.0 -1.0 71.0 68.0] +/G47 { + 67 69 true [1 0 0 -1 -4.0 68.0] {<0000000fff00030000000001fffff0030000000007fffffe03000000001ffc00ffc7000000007fc0 +001fff00000001ff000007ff80000003fe000001ff80000007f8000000ff8000000ff00000007f80 +00001fe00000003f8000003fc00000001f8000007f800000000f800000ff800000000f800001ff00 +00000007800001ff0000000007800003fe0000000003800007fc0000000003c00007fc0000000001 +c0000ffc0000000001c0000ff80000000000c0001ff80000000000c0001ff8000000000000003ff0 +000000000000003ff0000000000000003ff0000000000000007ff0000000000000007ff000000000 +0000007fe0000000000000007fe0000000000000007fe000000000000000ffe000000000000000ff +e00000007fffffe0ffe00000007fffffe0ffe000000003fffe00ffe000000000fff800ffe0000000 +007ff000ffe0000000007ff000ffe0000000003fe000ffe0000000003fe000ffe0000000003fe000 +fff0000000003fe000fff0000000003fe0007ff0000000003fe0007ff0000000003fe0007ff00000 +00003fe0007ff8000000003fe0003ff8000000003fe0003ff8000000003fe0001ffc000000003fe0 +001ffc000000003fe0001ffe000000003fe0000ffe000000003fe0000fff000000003fe00007ff00 +0000003fe00003ff800000003fe00003ff800000003fe00001ffc00000003fe00000ffe00000003f +e000007ff00000003fe000003ff80000003fe000001ffc0000003fe000000ffe0000003fe0000007 +ff8000003fe0000001ffc00000ffc00000007ff80007ff000000001fff003ffc0000000007ffffff +f00000000000ffffff00000000000007ffe0000000>} imagemask + } + 71 /G47 MSTT31c1f0 AddChar +%%EndResource + +2 1 SJ +586 1141 545 (Grace period:) 545 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 1280 38 (\226) 38 SB + +%%BeginResource: font MSTT31c1fd +/G37 [38.0 0.0 3.0 -1.0 35.0 50.0] +/G37 { + 32 51 true [1 0 0 -1 -3.0 50.0] {<07ffffff0fffffff0fffffff0ffffffe1ffffffe1ffffffe3ffffffc3e00003c3800007c70000078 +60000078400000f8c00000f0000000f0000001f0000001e0000001e0000003e0000003c0000003c0 +00000780000007800000078000000f0000000f0000000f0000001e0000001e0000001e0000003c00 +00003c0000003c000000780000007800000078000000f0000000f0000000f0000001e0000001e000 +0003e0000003c0000003c0000007c0000007800000078000000f8000000f0000000f0000001f0000 +001e0000>} imagemask + } + 55 /G37 MSTT31c1fd AddChar +%%EndResource + +2 3 SJ +717 1280 513 (7 days by default) 513 SB +623 1388 38 (\226) 38 SB + +%%BeginResource: font MSTT31c1fd +/G57 [70.0 0.0 2.0 -1.0 70.0 50.0] +/G57 { + 68 51 true [1 0 0 -1 -2.0 50.0] {<ffffc1ffffc007fff01ffe007ffc00007f800ffc001ff800003f0007f8000ff800001e0003f8000f +f800001c0003fc0007f800001c0003fc0007f80000180001fc0003f80000380001fc0003f8000038 +0001fe0003fc0000300000fe0001fc0000700000fe0001fc0000700000ff0001fe00006000007f00 +00fe0000e000007f0000fe0000e000007f8000ff0000c000003f8000ff0001c000003f8001ff0001 +c000003fc001ff80018000001fc001ff80038000001fc003ff80038000001fe0039fc0030000000f +e0039fc0070000000fe0079fe0070000000ff0070fe00600000007f0070fe00e00000007f0070ff0 +0e00000007f80e07f00c00000003f80e07f01c00000003f80e07f81c00000003fc1c03f818000000 +01fc1c03f83800000001fc1c03fc3800000001fe3801fc3000000000fe3801fc7000000000fe3801 +fe70000000007f7000fee0000000007f7000fee0000000007f70007fe0000000003fe0007fc00000 +00003fe0007fc0000000003fe0003fc0000000001fc0003f80000000001fc0003f80000000001fc0 +001f00000000000f80001f00000000000f80001f00000000000f80000e00000000000700000e0000 +0000000700000e000000000007000004000000>} imagemask + } + 87 /G57 MSTT31c1fd AddChar +/G76 [37.0 0.0 1.0 -1.0 36.0 34.0] +/G76 { + 35 35 true [1 0 0 -1 -1.0 34.0] {<ffff007fe03ff8000f800ff800070007f000060007f800060003f8000e0003f8000c0001f8001c00 +01fc00180001fc00180000fe00380000fe003000007e007000007f006000007f006000003f80e000 +003f80c000001f81c000001fc18000000fc18000000fe38000000fe300000007e300000007f70000 +0003f600000003fe00000003fc00000001fc00000001fc00000000f800000000f800000000f00000 +000070000000007000000000200000>} imagemask + } + 118 /G76 MSTT31c1fd AddChar +/G2c [19.0 0.0 3.0 -12.0 14.0 7.0] +/G2c { + 11 19 true [1 0 0 -1 -3.0 7.0] {<1e007f80ff80ffc0ffe0ffe07fe03c6000600060004000c000c0018003000e001800f0008000>} imagemask + } + 44 /G2c MSTT31c1fd AddChar +/G28 [25.0 0.0 3.0 -16.0 23.0 52.0] +/G28 { + 20 68 true [1 0 0 -1 -3.0 52.0] {<0000100000600000c0000380000600000e00001c0000380000700000f00001e00001e00003c00007 +c00007c0000f80000f80001f80001f80001f00003f00003f00003f00007f00007f00007e00007e00 +007e0000fe0000fe0000fe0000fe0000fe0000fe0000fe0000fe0000fe0000fe0000fe0000fe0000 +7e00007e00007f00007f00007f00003f00003f00003f00001f00001f80000f80000f80000f800007 +c00003c00003c00001e00000e00000f000007800003800001c00000e000007000003800000c00000 +60000010>} imagemask + } + 40 /G28 MSTT31c1fd AddChar +%%EndResource + +717 1388 2078 (When this period is over, the soft limit is treated as the hard limit \(no) 2078 SB + +%%BeginResource: font MSTT31c1fd +/G29 [25.0 0.0 2.0 -16.0 22.0 52.0] +/G29 { + 20 68 true [1 0 0 -1 -2.0 52.0] {<8000006000003000001c00000e000007000003800001c00001e00000f000007800007800003c0000 +3c00003e00001f00001f00001f80001f80000f80000fc0000fc0000fc0000fe0000fe0000fe00007 +e00007e00007f00007f00007f00007f00007f00007f00007f00007f00007f00007f00007f00007f0 +0007e00007e00007e0000fe0000fe0000fc0000fc0000fc0000f80001f80001f80001f00001f0000 +3e00003e00003c0000780000780000f00000e00001c0000380000700000600001c00003000006000 +00800000>} imagemask + } + 41 /G29 MSTT31c1fd AddChar +%%EndResource + +-3 3 SJ +717 1478 942 (blocks/inodes can be allocated\)) 942 SB +623 1587 38 (\226) 38 SB + +%%BeginResource: font MSTT31c1fd +/G54 [45.0 0.0 2.0 0.0 44.0 50.0] +/G54 { + 42 50 true [1 0 0 -1 -2.0 50.0] {<7fffffffff807fffffffff807c007f001f8078007f00078070007f000380e0007f0001c0c0007f00 +00c0c0007f0000c0c0007f0000c0c0007f0000c080007f00004000007f00000000007f0000000000 +7f00000000007f00000000007f00000000007f00000000007f00000000007f00000000007f000000 +00007f00000000007f00000000007f00000000007f00000000007f00000000007f00000000007f00 +000000007f00000000007f00000000007f00000000007f00000000007f00000000007f0000000000 +7f00000000007f00000000007f00000000007f00000000007f00000000007f00000000007f000000 +00007f00000000007f00000000007f00000000007f00000000007f00000000007f0000000000ff80 +00000000ff8000000003ffe00000003ffffe0000>} imagemask + } + 84 /G54 MSTT31c1fd AddChar +%%EndResource + +717 1587 1652 (The current usage must be reduced below the soft limit) 1652 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2919 2191 29 (6) 29 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +-12 3 SJ +256 284 2340 (Configuration of the quota-support) 2340 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G76 [50.0 0.0 1.0 -1.0 49.0 45.0] +/G76 { + 48 46 true [1 0 0 -1 -1.0 45.0] {<fffff8003ffffffff8003fff3fffc00003f80fff800001f003ff000001e003ff000001e001ff0000 +01c001ff000003c000ff8000038000ff80000380007f80000700007fc0000700003fc0000f00003f +e0000e00003fe0000e00001ff0001c00001ff0001c00000ff0003c00000ff80038000007f8003800 +0007fc0070000007fc0070000003fe00e0000003fe00e0000001fe01e0000001ff01c0000000ff01 +c0000000ff8380000000ff83800000007fc7800000007fc7000000003fc7000000003fee00000000 +1fee000000001ffe000000001ffc000000000ffc000000000ff80000000007f80000000007f80000 +000003f00000000003f00000000003e00000000001e00000000001c00000000000c00000>} imagemask + } + 118 /G76 MSTT31c1f0 AddChar +%%EndResource + +9 10 SJ +586 614 2351 (Disk quotas have been available as a kernel patch for years) 2351 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 788 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G42 [66.0 0.0 2.0 0.0 61.0 67.0] +/G42 { + 59 67 true [1 0 0 -1 -2.0 67.0] {<fffffffff0000000ffffffffff80000007fffffffff0000001fff800fffc000000ffc0001fff0000 +00ffc00007ff8000007fc00001ffc000007fc00000ffe000007fc000007ff000007fc000003ff800 +007fc000003ff800007fc000001ffc00007fc000001ffc00007fc000001ffc00007fc000000ffe00 +007fc000000ffe00007fc000000ffe00007fc000000ffe00007fc000000ffe00007fc000000ffe00 +007fc000000ffe00007fc000000ffe00007fc000001ffc00007fc000001ffc00007fc000001ffc00 +007fc000003ff800007fc000003ff000007fc000007ff000007fc00000ffe000007fc00003ffc000 +007fe0003fff0000007ffffffffe0000007ffffffff00000007ffffffffe0000007fc0007fffc000 +007fc00007fff000007fc00001fff800007fc000007ffc00007fc000001ffe00007fc000000fff00 +007fc0000007ff80007fc0000007ff80007fc0000003ffc0007fc0000001ffc0007fc0000001ffc0 +007fc0000001ffe0007fc0000000ffe0007fc0000000ffe0007fc0000000ffe0007fc0000000ffe0 +007fc0000000ffe0007fc0000000ffe0007fc0000000ffc0007fc0000001ffc0007fc0000001ffc0 +007fc0000001ff80007fc0000003ff80007fc0000007ff00007fc0000007ff00007fc000000ffe00 +007fc000003ffc0000ffc000007ff80000ffc00001fff00001fffe001fffc00007ffffffffff0000 +fffffffffffc0000ffffffffff000000>} imagemask + } + 66 /G42 MSTT31c1f0 AddChar +%%EndResource + +10 8 SJ +586 758 1973 (But they were not fully tested and contained bugs) 1973 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 932 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G41 [72.0 0.0 1.0 0.0 71.0 68.0] +/G41 { + 70 68 true [1 0 0 -1 -1.0 68.0] {<00000000100000000000000000380000000000000000380000000000000000780000000000000000 +7c0000000000000000fc0000000000000000fe0000000000000000fe0000000000000001fe000000 +0000000001ff0000000000000003ff0000000000000003ff8000000000000007ff80000000000000 +07ffc00000000000000fffc00000000000000f7fc00000000000000f7fe00000000000001e3fe000 +00000000001e3ff00000000000003c3ff00000000000003c1ff00000000000007c1ff80000000000 +00780ff8000000000000f80ffc000000000000f007fc000000000000f007fe000000000001e007fe +000000000001e003fe000000000003c003ff000000000003c001ff000000000007c001ff80000000 +00078001ff80000000000f8000ff80000000000f0000ffc0000000001f00007fc0000000001e0000 +7fe0000000001e00007fe0000000003c00003ff0000000003c00003ff0000000007c00001ff00000 +00007800001ff800000000f800000ff800000000f000000ffc00000001fffffffffc00000001ffff +fffffc00000001fffffffffe00000003c0000003fe00000003c0000003ff0000000780000003ff00 +00000780000001ff8000000f80000001ff8000000f00000000ff8000001f00000000ffc000001e00 +0000007fc000001e000000007fe000003c000000007fe000003c000000003ff000007c000000003f +f0000078000000003ff00000f8000000001ff80000f8000000001ffc0001f0000000001ffc0003f0 +000000001ffe0003f8000000001fff000ffc000000003fff803fff00000000ffffe0fffff000000f +fffffcfffff000000ffffffc>} imagemask + } + 65 /G41 MSTT31c1f0 AddChar +/G31 [50.0 0.0 11.0 0.0 37.0 68.0] +/G31 { + 26 68 true [1 0 0 -1 -11.0 68.0] {<0001c0000007c000001fc000007fc00001ffc00007ffc0001fffc0007fffc000ffffc000407fc000 +007fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000 +003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000 +003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000 +003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000 +003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000 +003fc000003fc000003fc000007fe000007fe00001fff8003fffffc03fffffc0>} imagemask + } + 49 /G31 MSTT31c1f0 AddChar +/G2e [25.0 0.0 7.0 -1.0 18.0 10.0] +/G2e { + 11 11 true [1 0 0 -1 -7.0 10.0] {<1f003f807fc0ffe0ffe0ffe0ffe0ffe07fc03f801f00>} imagemask + } + 46 /G2e MSTT31c1f0 AddChar +/G33 [50.0 0.0 4.0 -1.0 41.0 68.0] +/G33 { + 37 69 true [1 0 0 -1 -4.0 68.0] {<0003fe0000001fffc000003ffff00000fffff80001fffffc0003fffffe0007ffffff0007f01fff00 +0f8003ff801f0001ff801c0000ffc03800007fc03000003fc07000003fc02000003fc00000001fc0 +0000001fc00000001f800000001f800000001f000000001f000000001e000000003e000000003c00 +000000380000000070000000006000000000c0000000018000000003e00000000ff80000001ffc00 +0000fffe000003ffff00001fffff8000007fffc000000fffe0000003ffe0000001fff00000007ff0 +0000003ff00000001ff80000001ff80000000ff80000000ff800000007f800000007f800000007f8 +00000003f800000003f800000003f800000003f000000003f000000003f000000003e000000003e0 +00000007c000000007c00000000f800000000f800000001f003e00003e007f80007c00ffe001f800 +fffc07f000ffffffc0007fffff00003ffff8000007ff800000>} imagemask + } + 51 /G33 MSTT31c1f0 AddChar +/G34 [50.0 0.0 2.0 0.0 46.0 68.0] +/G34 { + 44 68 true [1 0 0 -1 -2.0 68.0] {<00000007e00000000007e0000000000fe0000000001fe0000000001fe0000000003fe0000000007f +e0000000007fe000000000ffe000000001ffe000000001dfe0000000039fe0000000079fe0000000 +071fe00000000e1fe00000001e1fe00000003c1fe0000000381fe0000000781fe0000000f01fe000 +0000e01fe0000001e01fe0000003c01fe0000003801fe0000007801fe000000f001fe000000e001f +e000001e001fe000003c001fe0000038001fe0000078001fe00000f0001fe00000f0001fe00001e0 +001fe00003c0001fe00003c0001fe0000780001fe0000f00001fe0000f00001fe0001e00001fe000 +3c00001fe0007c00001fe0007800001fe000fffffffffff0fffffffffff0fffffffffff0ffffffff +fff0fffffffffff0fffffffffff0fffffffffff00000001fe0000000001fe0000000001fe0000000 +001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe000 +0000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001fe0000000001f +e0000000001fe000>} imagemask + } + 52 /G34 MSTT31c1f0 AddChar +/G36 [50.0 0.0 4.0 -1.0 46.0 68.0] +/G36 { + 42 69 true [1 0 0 -1 -4.0 68.0] {<000000007f8000000007ff800000003ff800000000ff8000000003fc000000000ff0000000001fe0 +000000007f8000000000ff0000000001fe0000000003fc0000000007f8000000000ff0000000001f +e0000000003fc0000000007fc0000000007f8000000000ff0000000001ff0000000001fe00000000 +03fe0000000007fc0000000007fc000000000ff8000000000ff8000000001ff0000000001ff00ff8 +00001ff07fff00003fe1ffff80003fe7ffffe0003fff81fff0007ffe003ff8007ff8001ffc007fe0 +000ffe007fc00007fe00ffc00007ff00ffc00003ff00ffc00003ff80ff800001ff80ff800001ff80 +ff800000ff80ff800000ffc0ff800000ffc0ff800000ffc0ff8000007fc0ff8000007fc0ff800000 +7fc0ff8000007fc07f8000007fc07f8000007fc07fc000007fc07fc000007f803fc000007f803fc0 +00007f803fe000007f001fe000007f001fe00000fe000ff00000fe000ff00000fc0007f80001fc00 +03f80001f80001fc0003f00001fe0007e00000ff000fe000007f801f8000003fe07f0000000ffffe +00000003fff8000000007fc00000>} imagemask + } + 54 /G36 MSTT31c1f0 AddChar +%%EndResource + +5 8 SJ +586 902 2139 (A revised version has been integrated in Linux 1.3.46) 2139 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1075 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +4 4 SJ +586 1045 993 (To use quotas, you need:) 993 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 1184 38 (\226) 38 SB + +%%BeginResource: font MSTT31c1fd +/G31 [38.0 0.0 9.0 0.0 29.0 51.0] +/G31 { + 20 51 true [1 0 0 -1 -9.0 51.0] {<000c00007c0001fc0007fc001ffc007ffc00c3fc0003fc0001fc0001fc0001fc0001fc0001fc0001 +fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc +0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc00 +01fc0001fc0001fc0001fc0001fc0001fc0001fc0001fc0003fe0007ff007ffff0>} imagemask + } + 49 /G31 MSTT31c1fd AddChar +/G2e [19.0 0.0 5.0 -1.0 13.0 7.0] +/G2e { + 8 8 true [1 0 0 -1 -5.0 7.0] {<3c7effffffff7e3c>} imagemask + } + 46 /G2e MSTT31c1fd AddChar +/G33 [38.0 0.0 3.0 -1.0 31.0 51.0] +/G33 { + 28 52 true [1 0 0 -1 -3.0 51.0] {<001fc00000fff80001fffc0007fffe000fffff000f81ff801c007f8038003fc030001fc060001fc0 +00000fc000000fc000000fc000000f8000000f8000000f0000000f0000001e0000001c0000003800 +000070000000e0000001f8000007fe00003fff0000ffff800007ffc00001ffc000007fe000003fe0 +00001fe000000ff000000ff0000007f0000007f0000003f0000003f0000003f0000003f0000003e0 +000003e0000003e0000007c0000007c000000f8078000f00fe001e00ff003c00ffc0f8007fffe000 +3fff80000ffc0000>} imagemask + } + 51 /G33 MSTT31c1fd AddChar +/G34 [38.0 0.0 2.0 0.0 35.0 51.0] +/G34 { + 33 51 true [1 0 0 -1 -2.0 51.0] {<000007c00000000fc00000000fc00000001fc00000001fc00000003fc00000007fc00000007fc000 +0000dfc0000001dfc00000019fc00000039fc00000031fc00000061fc000000e1fc000000c1fc000 +001c1fc00000381fc00000301fc00000701fc00000601fc00000e01fc00001c01fc00001801fc000 +03801fc00003001fc00007001fc0000e001fc0000c001fc0001c001fc00038001fc00038001fc000 +70001fc00070001fc000ffffffff80ffffffff80ffffffff80ffffffff8000001fc00000001fc000 +00001fc00000001fc00000001fc00000001fc00000001fc00000001fc00000001fc00000001fc000 +00001fc00000001fc00000001fc000>} imagemask + } + 52 /G34 MSTT31c1fd AddChar +/G36 [38.0 0.0 3.0 -1.0 35.0 51.0] +/G36 { + 32 52 true [1 0 0 -1 -3.0 51.0] {<000000fe000007f000003f000000fc000001f8000007e000000fc000001f8000003f0000007e0000 +00fc000001fc000003f8000003f0000007f000000fe000000fe000001fe000001fc000003fc00000 +3f81fe003f8fff807fbfffe07ff83ff07fe00ff87f8007f8ff0003fcff0001feff0001fefe0001fe +fe0000fffe0000fffe0000fffe00007ffe00007ffe00007ffe00007f7e00007f7e00007f7f00007e +3f00007e3f00007e3f80007c1f8000fc0f8000f80fc001f007e001f003e003e001f007c000fc1f00 +003ffe00000ff000>} imagemask + } + 54 /G36 MSTT31c1fd AddChar +/G2b [42.0 0.0 1.0 5.0 40.0 44.0] +/G2b { + 39 39 true [1 0 0 -1 -1.0 44.0] {<00003800000000380000000038000000003800000000380000000038000000003800000000380000 +00003800000000380000000038000000003800000000380000000038000000003800000000380000 +00003800000000380000fffffffffefffffffffefffffffffe000038000000003800000000380000 +00003800000000380000000038000000003800000000380000000038000000003800000000380000 +0000380000000038000000003800000000380000000038000000003800000000380000>} imagemask + } + 43 /G2b MSTT31c1fd AddChar +/G93 [33.0 0.0 2.0 32.0 30.0 51.0] +/G93 { + 28 19 true [1 0 0 -1 -2.0 51.0] {<00800040038001c00e0007001c000c0010001800200010006000300040002000c0006000c0006000 +c0006000ef8077c0ffc07fe0ffe07ff0ffe07ff07fe03ff03fe01ff01fc00fe00f800780>} imagemask + } + 147 /G93 MSTT31c1fd AddChar +/G94 [33.0 0.0 2.0 32.0 30.0 51.0] +/G94 { + 28 19 true [1 0 0 -1 -2.0 51.0] {<1e001f007f003f80ff807fc0ffc07fe0ffe07fe0ffe07ff07fe03ff03ee01f700060003000600030 +006000300040002000c000600080004001800080070003800e00070038001c0020001000>} imagemask + } + 148 /G94 MSTT31c1fd AddChar +/G51 [54.0 0.0 3.0 -14.0 51.0 51.0] +/G51 { + 48 65 true [1 0 0 -1 -3.0 51.0] {<00001ff800000000ffff00000003f00fe000000f8003f000003f0000fc00007c00007e0000f80000 +3f0001f800001f8003f000000fc007e000000fe007e0000007f00fc0000007f01fc0000003f81fc0 +000003f83f80000003fc3f80000001fc7f80000001fe7f80000001fe7f00000001fe7f00000000fe +ff00000000ffff00000000ffff00000000ffff00000000ffff00000000ffff00000000ffff000000 +00ffff00000000ffff00000000ffff00000000ffff00000000ff7f00000000fe7f80000000fe7f80 +000001fe7f80000001fe3f80000001fc3f80000001fc3fc0000003fc1fc0000003f81fe0000003f0 +0fe0000007f007f0000007e007f000000fc003f800001fc001fc00001f8000fe00003f00007f0000 +fc00001f8001f8000007f00ff0000001ffffc00000007ffe000000001ffc000000000ffe00000000 +07fe0000000003ff0000000001ff8000000000ffc0000000003fc0000000001fe00000000007f000 +00000001fc00000000007e00000000001f800000000003f000000000001e>} imagemask + } + 81 /G51 MSTT31c1fd AddChar +%%EndResource + +717 1184 2057 (a recent \(1.3.46+\) kernel \(answer \223y\224 to \223Quota support\224 during the ) 2057 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +2774 1187 180 (make) 180 SB +717 1277 270 (config) 270 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +-1 1 SJ +987 1274 165 ( step\)) 165 SB +623 1383 38 (\226) 38 SB +-2 2 SJ +717 1383 545 (the quota utilities:) 545 SB + +%%BeginResource: font MSTT31c1fd +/Gbb [35.0 0.0 2.0 0.0 32.0 35.0] +/Gbb { + 30 35 true [1 0 0 -1 -2.0 35.0] {<c00180006000c0007000e00038007000380070001c0038001e003c000f001e000f001e0007800f00 +07c00f8003e007c003e007c001f003e001f803f000f801f000fc01f8007e00fc007c00f800fc01f8 +01f803f001f003e003e007c003e007c007c00f8007800f000f001e000f001e001e003c001c003800 +38007000380070007000e0006000c000c0018000>} imagemask + } + 187 /Gbb MSTT31c1fd AddChar +%%EndResource + +773 1491 35 (\273) 35 SB + +%%BeginResource: font MSTT31c1fd +/G4c [45.0 0.0 1.0 0.0 43.0 50.0] +/G4c { + 42 50 true [1 0 0 -1 -1.0 50.0] {<fffff80000000fff8000000003fe0000000003fe0000000001fc0000000001fc0000000001fc0000 +000001fc0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc +0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc00000000 +01fc0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc0000 +000001fc0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc0000000001fc +0000000001fc0000000001fc0000000001fc0000000001fc000000c001fc000001c001fc00000180 +01fc0000038001fc0000038001fc0000070001fc0000070001fc00000f0001fc00001e0003fe0000 +3e0003ff0001fe000ffffffffc00fffffffffc00>} imagemask + } + 76 /G4c MSTT31c1fd AddChar +/G50 [43.0 0.0 1.0 0.0 40.0 50.0] +/G50 { + 39 50 true [1 0 0 -1 -1.0 50.0] {<ffffffc0000ffffffc0003fe01ff0003fc003fc001fc001fe001fc000ff001fc0007f801fc0007f8 +01fc0003fc01fc0003fc01fc0001fe01fc0001fe01fc0001fe01fc0001fe01fc0001fe01fc0001fe +01fc0001fe01fc0003fc01fc0003fc01fc0003fc01fc0007f801fc000ff001fc001ff001fc003fc0 +01ff00ff8001fffffe0001fcfff00001fc00000001fc00000001fc00000001fc00000001fc000000 +01fc00000001fc00000001fc00000001fc00000001fc00000001fc00000001fc00000001fc000000 +01fc00000001fc00000001fc00000001fc00000001fc00000001fc00000003fe00000003fe000000 +0fff800000fffff80000>} imagemask + } + 80 /G50 MSTT31c1fd AddChar +/G45 [46.0 0.0 1.0 0.0 44.0 50.0] +/G45 { + 43 50 true [1 0 0 -1 -1.0 50.0] {<fffffffffc0007fffffffc0003fc0000fc0003fc00003c0001fc00001c0001fc00000e0001fc0000 +0e0001fc00000e0001fc00000e0001fc0000060001fc0000060001fc0000000001fc0000000001fc +0000000001fc0000000001fc0000000001fc0000800001fc0000800001fc0000800001fc00018000 +01fc0001800001fc0003800001fc000f800001ffffff800001ffffff800001fc000f800001fc0003 +800001fc0001800001fc0001800001fc0000800001fc0000800001fc0000800001fc0000000001fc +0000000001fc0000000001fc0000000001fc0000000001fc0000006001fc000000c001fc000000c0 +01fc000001c001fc0000018001fc0000038001fc0000078001fc0000070001fc00000f0003fc0000 +3f0003fe0000fe000ffffffffe00fffffffffe00>} imagemask + } + 69 /G45 MSTT31c1fd AddChar +/G4f [54.0 0.0 3.0 -1.0 51.0 51.0] +/G4f { + 48 52 true [1 0 0 -1 -3.0 51.0] {<00001ff800000000ffff80000003f00fe000000f8001f000003f0000fc00007e00007e0000fc0000 +3f0001f800001f8003f000000fc007e000000fe00fe0000007f00fc0000007f01fc0000003f81fc0 +000003f83f80000001fc3f80000001fc7f80000001fe7f80000001fe7f80000001fe7f00000000fe +ff00000000ffff00000000ffff00000000ffff00000000ffff00000000ffff00000000ffff000000 +00ffff00000000ffff00000000ffff00000000ffff00000000ffff00000000fe7f00000000fe7f80 +000000fe7f80000001fe7f80000001fc3f80000001fc3fc0000001fc1fc0000003f81fc0000003f8 +0fe0000003f00fe0000007e007f0000007e003f000000fc001f800001f8000fc00003f00007e0000 +7e00003f0000fc00001f8003f0000007f00fc0000001ffff000000001ff80000>} imagemask + } + 79 /G4f MSTT31c1fd AddChar +%%EndResource + +848 1491 24 (f) 25 SB +873 1491 59 (tp) 58 SB +931 1491 87 (://f) 88 SB +1019 1491 59 (tp) 58 SB +1077 1491 43 (.f) 44 SB +1121 1491 38 (u) 37 SB +1158 1491 135 (net.f) 136 SB +1294 1491 80 (i/p) 79 SB +1373 1491 76 (ub) 75 SB +1448 1491 66 (/L) 67 SB +1515 1491 59 (in) 58 SB +1573 1491 139 (ux/P) 138 SB +1711 1491 46 (E) 45 SB +1756 1491 54 (O) 55 SB +1811 1491 43 (P) 41 SB +1852 1491 45 (L) 46 SB +1898 1491 112 (E/L) 113 SB +2011 1491 21 (i) 20 SB +2031 1491 76 (nu) 75 SB +2106 1491 29 (s) 30 SB +2136 1491 21 (/) 20 SB +2156 1491 29 (s) 30 SB +2186 1491 38 (u) 37 SB +2223 1491 103 (bsy) 104 SB +2327 1491 83 (ste) 84 SB +2411 1491 57 (m) 58 SB +2469 1491 88 (s/q) 87 SB +2556 1491 76 (uo) 75 SB +2631 1491 54 (ta) 55 SB +773 1599 35 (\273) 35 SB +848 1599 24 (f) 25 SB +873 1599 59 (tp) 58 SB +931 1599 87 (://f) 88 SB +1019 1599 59 (tp) 58 SB +1077 1599 224 (.cistron) 223 SB +1300 1599 57 (.n) 56 SB +1356 1599 118 (l/pu) 117 SB +1473 1599 59 (b/) 58 SB +1531 1599 43 (P) 42 SB +1573 1599 109 (eop) 108 SB +1681 1599 54 (le) 55 SB +1736 1599 21 (/) 20 SB +1756 1599 57 (m) 59 SB +1815 1599 163 (vw/qu) 162 SB +1977 1599 92 (ota) 92 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G37 [29.0 0.0 2.0 0.0 25.0 39.0] +/G37 { + 23 39 true [1 0 0 -1 -2.0 39.0] {<0ffffe1ffffe1ffffe1ffffe3ffffc38001c60001c400038c0003880003800007000007000007000 +00e00000e00000e00001c00001c00001c0000380000380000380000700000700000700000e00000e +00000e00001c00001c00001c0000380000380000380000700000700000700000e00000e000>} imagemask + } + 55 /G37 MSTT31c1bc AddChar +%%EndResource + +2919 2191 29 (7) 29 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +-6 3 SJ +256 84 1853 (Administration of the quota) 1853 SB +256 284 149 (su) 148 SB +404 284 149 (bs) 148 SB +552 284 398 (ystem) 398 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 648 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d057ee26f8d6945ed4a734c986bacc9c4e9146c536d435a3f6fe0bdd7292c545882f15c502251ef625c374cd766ecd6c027e94c0d +02455a20a915ae7e602e4ce476c48af63ce8881e74c11919ef36f4173b1c5093a5c28b8b51817b3b2d6208d608bd4a83e1e281bccf58e2e3167313817edb8130 +3e3a3ed7fd80096a1582c85560de49313e80c9450fa16756be238e37e4e1e782239b6ef0c45e4d6a4990e6b587e1f1a8a85e38db96ba259d8b88453f687fa358 +5489f868f8cfb10e7ab8f3fe7b10d998cf8058e0ec33100415a1c7d9dcff19037c7b759645e8f5273270f67ab6adacb319ab +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-15 5 SJ +586 615 1756 (installing a kernel with quota support) 1756 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 817 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +-15 3 SJ +586 784 1288 (installing the quota utilities) 1288 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 985 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +-12 4 SJ +586 952 1732 (activating disk quotas on filesystems) 1732 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 1153 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d0007e93fb06c6a176f2b56dd99c207c01444802de9e7bcfa5f1fa63880cc63e67df2094a85d91cac055b75fb839d00387733a140 +30015b397949b626fa6b1885d027fa05dcf0eb8fe9dc385e89a67d0f95d954dc +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-16 4 SJ +586 1120 1669 (setting disk quotas for users/groups) 1669 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 1321 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +-9 3 SJ +586 1288 1114 (checking for disk usage) 1114 SB +32 0 0 88 88 0 0 0 71 /ZapfDingbats font +473 1489 69 (u) 69 SB +32 0 0 117 117 0 0 0 104 /MSTT31c1c9 font +-10 2 SJ +586 1456 1294 (checking quota consistency) 1294 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G38 [29.0 0.0 3.0 0.0 26.0 40.0] +/G38 { + 23 40 true [1 0 0 -1 -3.0 40.0] {<00fe0003ffc00f83e01f01f03e00f83c00783c007c7c007c7c007c7c007c7e007c7e00783f00f83f +80f03fc1e01fe3c00ff78007fe0003fc0001fe0000ff8003ffc0073fe00e0ff01e07f83c03f87c01 +fc7800fcf8007ef8007ef8003ef8003ef8003e78003c7c003c3e00783f00f01f83e007ffc001fe00 +>} imagemask + } + 56 /G38 MSTT31c1bc AddChar +%%EndResource + +2919 2191 29 (8) 29 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +-4 4 SJ +256 305 1789 (Installing the kernel and tools) 1789 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G4b [72.0 0.0 2.0 0.0 72.0 67.0] +/G4b { + 70 67 true [1 0 0 -1 -2.0 67.0] {<ffffffe003fffffc00ffffffe003fffffc0007fffc00001fffc00001fff000000fff000000ffe000 +000ffc000000ffe000000ff00000007fc000000fe00000007fc000001f800000007fc000001f0000 +00007fc000003e000000007fc000007c000000007fc00000f8000000007fc00001f0000000007fc0 +0003e0000000007fc00007c0000000007fc0000f80000000007fc0001f00000000007fc0003e0000 +0000007fc0007c00000000007fc000f800000000007fc001f000000000007fc003e000000000007f +c007c000000000007fc00f8000000000007fc01f0000000000007fc03e0000000000007fc07c0000 +000000007fc0f80000000000007fc1f00000000000007fc3e00000000000007fcfe0000000000000 +7fdff00000000000007ffff80000000000007ffffc0000000000007fdffe0000000000007fcfff00 +00000000007fc7ff8000000000007fc3ffc000000000007fc1ffe000000000007fc0fff000000000 +007fc07ff800000000007fc03ffc00000000007fc01fff00000000007fc00fff80000000007fc007 +ffc0000000007fc003ffe0000000007fc001fff0000000007fc000fff8000000007fc0007ffc0000 +00007fc0003ffe000000007fc0001fff000000007fc0000fff800000007fc00007ffc00000007fc0 +0003ffe00000007fc00001fff00000007fc00000fff80000007fc000003ffc0000007fc000001ffe +0000007fc000001fff0000007fc000000fffc000007fc0000007ffe00000ffe0000007fff00000ff +e0000007fffc0001fff000000fffff0007fffc00001fffffe0ffffffe000fffffffcffffffe000ff +fffffc>} imagemask + } + 75 /G4b MSTT31c1f0 AddChar +/G6a [28.0 0.0 -8.0 -21.0 18.0 70.0] +/G6a { + 26 91 true [1 0 0 -1 8.0 70.0] {<00003e0000007f000000ff800001ffc00001ffc00001ffc00001ffc00001ffc00000ff8000007f00 +00003e00000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000001c000000fc000007fc00001ffc0000fffc0001fffc0 +0018ffc000007fc000007fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc0 +00003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc0 +00003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc0 +00003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc000003fc0 +00003fc000003fc000003fc000003fc000003fc000003f8000003f8000003f8000003f8000003f00 +00003f0000003f003c003e007f003e00ff807c00ff807800ffc0f000fff1e0007fffc0003fff0000 +07f80000>} imagemask + } + 106 /G6a MSTT31c1f0 AddChar +/G93 [44.0 0.0 3.0 42.0 41.0 68.0] +/G93 { + 38 26 true [1 0 0 -1 -3.0 68.0] {<001000002000700000e001f00003c003c00007800700000e000e00001c001c000038001800007000 +3000006000700000e000600000c000600000c000e00001c000e00001c000e00001c000f3f001e7e0 +fff801fff0fffc01fff8fffe01fffc7ffe00fffc7ffe00fffc7ffe00fffc3ffc007ff81ffc003ff8 +0ff8001ff003e00007c0>} imagemask + } + 147 /G93 MSTT31c1f0 AddChar +/G94 [44.0 0.0 3.0 42.0 41.0 68.0] +/G94 { + 38 26 true [1 0 0 -1 -3.0 68.0] {<0f80001f003fe0007fc07ff000ffe07ff800fff0fffc01fff8fffc01fff8fffc01fff8fffe01fffc +7ffe00fffc3ffe007ffc1f9e003f3c000e00001c000e00001c000e00001c000c000018000c000018 +001c0000380018000030003800006000700000e000e00001c001c00003800780000f001f00003e00 +1c000038001000002000>} imagemask + } + 148 /G94 MSTT31c1f0 AddChar +/G51 [72.0 0.0 4.0 -19.0 68.0 68.0] +/G51 { + 64 87 true [1 0 0 -1 -4.0 68.0] {<0000001ffc000000000001ffffc0000000000ffffff8000000003fe00ffe00000000ff0001ff0000 +0003fc00007fc0000007f800001fe000000ff000000ff000001fe0000007f800003fc0000003fc00 +007f80000001fe0000ff00000001ff0001ff00000000ff8003fe000000007fc003fe000000007fc0 +07fc000000003fe00ffc000000003ff00ff8000000003ff01ff8000000001ff81ff8000000001ff8 +3ff0000000001ffc3ff0000000001ffc3ff0000000000ffc7ff0000000000ffe7ff0000000000ffe +7ff0000000000ffe7fe0000000000ffe7fe00000000007feffe00000000007ffffe00000000007ff +ffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ff +ffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ff +ffe00000000007ff7fe00000000007fe7ff00000000007fe7ff00000000007fe7ff0000000000ffe +7ff0000000000ffc3ff0000000000ffc3ff0000000000ffc3ff8000000000ff81ff8000000001ff8 +1ff8000000001ff00ffc000000001ff00ffc000000003fe007fc000000003fe007fe000000007fc0 +03fe000000007f8001ff00000000ff8000ff80000000ff00007f80000001fe00007fc0000003fc00 +001fe0000007f800000ff000000ff0000007f800001fe0000003fe00003f80000000ff8000ff0000 +00003fe00ffc000000000ffffff00000000003ffff800000000000ffff0000000000007fff800000 +0000003fff8000000000001fffc000000000000fffe0000000000007fff0000000000001fff00000 +00000000fff80000000000007ffc0000000000001ffe0000000000000fff00000000000003ff8000 +0000000000ffc00000000000003ff00000000000000ffc00000000000001ff000000000000003ff0 +00000000000007fe000000000000003e>} imagemask + } + 81 /G51 MSTT31c1f0 AddChar +%%EndResource + +6 7 SJ +586 614 2118 (Kernel: just answer \223y\224 to \223Quota support\224, compile,) 2118 SB +1 3 SJ +586 734 971 (install the kernel, reboot) 971 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 908 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1 3 SJ +586 878 689 (Tools: just type \223) 689 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +1 2 SJ +1277 882 1080 (make; make install) 1080 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1 2 SJ +2358 878 297 (\224 but ...) 297 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G45 [61.0 0.0 2.0 0.0 59.0 67.0] +/G45 { + 57 67 true [1 0 0 -1 -2.0 67.0] {<ffffffffffffe000ffffffffffffe00003ffffffffffe00001ffc000001fe00000ffc0000007e000 +00ffc0000003e000007fc0000001e000007fc0000000f000007fc0000000f000007fc00000007000 +007fc00000007000007fc00000007000007fc00000007000007fc00000003000007fc00000003000 +007fc00000000000007fc00000000000007fc00000000000007fc00000000000007fc00000000000 +007fc00000000000007fc00000000000007fc00000180000007fc00000180000007fc00000180000 +007fc00000380000007fc00000380000007fc00000380000007fc00000780000007fc00000f80000 +007fc00003f80000007ffffffff80000007ffffffff80000007ffffffff80000007fc00003f80000 +007fc00000f80000007fc00000780000007fc00000380000007fc00000380000007fc00000380000 +007fc00000180000007fc00000180000007fc00000180000007fc00000000000007fc00000000000 +007fc00000000000007fc00000000000007fc00000000000007fc00000000000007fc00000000000 +007fc00000000180007fc00000000300007fc00000000300007fc00000000700007fc00000000600 +007fc00000000e00007fc00000001e00007fc00000001c00007fc00000003c00007fc00000007c00 +007fc0000000f80000ffc0000001f80000ffe0000007f80001fff000003ff00007fffffffffff000 +fffffffffffff000ffffffffffffe000>} imagemask + } + 69 /G45 MSTT31c1f0 AddChar +/G32 [50.0 0.0 2.0 0.0 46.0 68.0] +/G32 { + 44 68 true [1 0 0 -1 -2.0 68.0] {<0000ff8000000007fff80000003ffffe0000007fffff000000ffffffc00001ffffffe00003ffffff +f00007fc03fff0000fe000fff8000f80003ffc001f00001ffc001e00000ffe003c000007fe003800 +0003fe0038000003ff0070000001ff0070000001ff0060000001ff0000000000ff0000000000ff00 +00000000ff0000000000ff0000000000fe0000000000fe0000000000fe0000000000fe0000000000 +fc0000000001fc0000000001f80000000001f80000000003f00000000003f00000000003e0000000 +0007c00000000007c0000000000f80000000001f00000000001f00000000003e00000000003c0000 +000000780000000000f00000000001f00000000001e00000000003c0000000000780000000000f00 +000000001e00000000003c0000000000780000000000f00000000001e00000000003c00000000007 +80000000000700000000000e00000000003c0000007000780000006000f0000000e001e0000003e0 +03c000001fc007ffffffffc00fffffffff801fffffffff803fffffffff807fffffffff00ffffffff +ff00ffffffffff00>} imagemask + } + 50 /G32 MSTT31c1f0 AddChar +%%EndResource + +6 8 SJ +586 1021 2024 (... you may want to include special Ext2fs support:) 2024 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +623 1163 45 (\226) 45 SB +717 1163 450 (quotacheck) 450 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font + +%%BeginResource: font MSTT31c1fd +/G32 [38.0 0.0 2.0 0.0 35.0 51.0] +/G32 { + 33 51 true [1 0 0 -1 -2.0 51.0] {<001ff00000007ffc000001ffff000003ffff800007ffffc0000fffffe0001fc0fff0001f003ff800 +3c000ff800380007f800300007fc00700003fc00600003fc00600001fc00000001fc00000001fc00 +000001fc00000001f800000001f800000001f800000001f000000003f000000003e000000003e000 +000007c000000007c00000000f800000000f000000001e000000003e000000003c00000000780000 +0000f000000001e000000001c0000000038000000007000000000e000000001c0000000038000000 +007000000000e000008001c000010003800003000700000f000ffffffe001ffffffe003ffffffe00 +7ffffffc00fffffffc00fffffffc00>} imagemask + } + 50 /G32 MSTT31c1fd AddChar +/G92 [25.0 0.0 7.0 32.0 18.0 51.0] +/G92 { + 11 19 true [1 0 0 -1 -7.0 51.0] {<3e007f00ff80ffc0ffe0ffe07fe03ee0006000600040004000c00180030006001c0038002000>} imagemask + } + 146 /G92 MSTT31c1fd AddChar +%%EndResource + +1 8 SJ +1167 1160 1478 ( uses the Ext2fs library written by Theodore Ts\222o) 1478 SB +623 1268 38 (\226) 38 SB +717 1268 921 (This is much faster than using ) 921 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1638 1271 405 (readdir\(\)) 405 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1412 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 1382 1036 (To enable Ext2fs support:) 1036 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 1521 38 (\226) 38 SB +717 1521 128 (add ) 128 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +845 1524 630 (-DEXT2_DIRECT ) 630 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1475 1521 78 (to ) 78 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1553 1524 270 (CFLAGS) 270 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 1629 38 (\226) 38 SB +717 1629 128 (add ) 128 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +845 1632 405 (-lext2fs ) 405 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1250 1629 78 (to ) 78 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1328 1632 315 (LDFLAGS) 315 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2919 2191 29 (9) 29 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d06220d6e2b623024556ea2a939cb367d2285f7b04631175ab33f2e59099e861b3f875c7fac9020d1ef6efbe9487d5c5b60b1182e +1d16965caac24d6041f6f39b7cd58549c9d14c1662f11e111e33b800e8ce1d96a9f15bc4ce0b7da824583f92dceeb4d299415c584f549bd2e98ffd8078fa1235 +c39cf7fa50fd5046a9ff05ab034b9277a9a7eec0341469664499fc5d03bb261786df4623ec9dbd2dfe7a56b7b2d3476013d5286fd827fa31f4b64ef3cbde3e63 +d1c8da84fbe462d36d55b82375491a6e16e964229cce8719aa830a4ea277345799016cd9bcca9a6daf9cb9ec5b10300d750aaea0d792e6d6d33efb3ef209261f +698d71fcb0172c34c6737c +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-5 5 SJ +256 305 2204 (Enabling disk quotas on file systems) 2204 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +7 7 SJ +586 614 1690 (Quotas are managed on a file system basis) 1690 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 788 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 758 1369 (Two fstab options control quotas: ) 1369 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +1955 762 480 (usrquota) 480 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +2435 758 169 ( and) 169 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 882 480 (grpquota) 480 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 1021 883 (Example of /etc/fstab:) 883 SB +32 0 0 67 67 0 0 0 57 /Courier-Bold /font9 ANSIFont font +586 1145 2280 (/dev/hda2 / ext2 defaults,rw 0 1) 2280 SB +586 1225 2280 (/dev/hdb2 /home ext2 defaults,rw,usrquota,grpquota 0 2) 2280 SB +586 1305 2280 (/dev/sda1 /usr/src ext2 default,usrquota 0 2) 2280 SB +586 1385 2280 (none /proc proc defaults,rw 0 0) 2280 SB +586 1465 2280 (/dev/hda3 none swap sw 0 0) 2280 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1596 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 1566 1042 (Quotas are activated with ) 1042 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +1628 1570 420 (quotaon) 420 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +2048 1566 28 (:) 28 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1690 1380 (/usr/sbin/quotaon -avug) 1380 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB + +%%BeginResource: font MSTT31c1bc +/G30 [29.0 0.0 2.0 0.0 26.0 40.0] +/G30 { + 24 40 true [1 0 0 -1 -2.0 40.0] {<007e0000ff8003c3c00780e00f00f00e00701e00781e003c3c003c3c003c7c003e7c001e7c001e78 +001ef8001ff8001ff8001ff8001ff8001ff8001ff8001ff8001ff8001ff8001ff8001ff8001f7800 +1e78001e7c003e7c003e3c003c3c003c3e00381e00780e00700f00f00781e003c3c001ff00007c00 +>} imagemask + } + 48 /G30 MSTT31c1bc AddChar +%%EndResource + +2890 2191 58 (10) 58 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +%%BeginResource: font MSTT31c1c9 +currentfile eexec +9e67edc6b858a3e762244b628fb7f6f6b82db3d80533f85f9af7ec02fa0992f446e47e7476690365d15488a3d0557140c554c35b60083b9bf344ec199d995ff7 +cd974526686a837538b7a59d07d53e21b3fa3313fbd1f7f7696e463c6e9f4dd81a178f4cd84a9c664c8ed3ec336fd6fb9e483f3302eeb5fe4637dfe6d10e7ba4 +f53e92bb2bbdcd0a388c0136f8906ca645dc0a64a817eca590cd187ecf50e06f833cc7154aaca53c69bc3b1326502d3bbeefe3c6ca245a19007872ec8da89685 +56eb3a6dfbb3acb8151d12382ee5a80c2afd576ac183cde8d7eab3e403805ee0e68a511f2d65ee2ed6124ccd69dfee6b3e8ceb1b0708a1183f6fb7e85a1f2038 +dbdf9ef86f77652226e8a4109784e077e9d3a78d5c34c01f0b4d377941e119ddace546b11dd90abf5f228925ffb99beaf6fd83aed87d08f3849c79e7acd19a06 +2022d0a0c0082055a16412d5e30b81adcb81bf0742acf8c198c2266ef5e1cf7b86096cc517bb37e3a9dc8d3733b4135c34ed46f4d1bc36446ef1bc30ed48e948 +a8612262f068a2e3119be1286861e7a0e5 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +cleartomark +%%EndResource +-4 2 SJ +256 305 1504 (Setting individual quotas) 1504 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G49 [31.0 0.0 2.0 0.0 29.0 67.0] +/G49 { + 27 67 true [1 0 0 -1 -2.0 67.0] {<ffffffe0ffffffe007fffc0001fff00000ffe00000ffe000007fc000007fc000007fc000007fc000 +007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000 +007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000 +007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000 +007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000 +007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000007fc000 +007fc00000ffe00000ffe00001fff00007fffc00ffffffe0ffffffe0>} imagemask + } + 73 /G49 MSTT31c1f0 AddChar +%%EndResource + +2 8 SJ +586 614 1680 (Individual disk quotas can be set with the ) 1680 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +2268 618 420 (edquota) 420 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +2688 614 181 ( tool) 181 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 788 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +6 9 SJ +586 758 2274 (The administrator can specify the soft and hard limits for) 2274 SB +1 1 SJ +586 878 263 (users \() 263 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +849 882 120 (-u) 120 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +2 3 SJ +969 878 556 (\) and groups \() 556 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +1527 882 120 (-g) 120 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1647 878 33 (\)) 33 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 1021 414 (Example \() 414 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +1000 1025 1080 (edquota -u dugenou) 1080 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +2080 1021 61 (\):) 61 SB +32 0 0 58 58 0 0 0 50 /Courier-Bold /font9 ANSIFont font +586 1144 840 (Quotas for user dugenou:) 840 SB +586 1214 2240 (/dev/hdb2: blocks in use: 16, limits \(soft = 5000, hard = 6000\) ) 2240 SB +773 1283 1960 ( inodes in use: 11, limits \(soft = 100, hard = 110\)) 1960 SB +586 1353 1995 (/dev/sda1: blocks in use: 0, limits \(soft = 0, hard = 0\) ) 1995 SB +773 1423 1785 ( inodes in use: 0, limits \(soft = 0, hard = 0\)) 1785 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1544 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +6 10 SJ +586 1514 2265 (edquota can also copy disk quotas from a user to another) 2265 SB +586 1634 172 (one:) 172 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1758 1800 (edquota -p prototype_user user) 1800 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (11) 58 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +-2 2 SJ +256 305 1244 (Checking disk usage) 1244 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1 1 SJ +586 614 180 (The ) 180 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +766 618 480 (repquota) 480 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 6 SJ +1246 614 1435 ( command prints a summary of disk) 1435 SB +586 734 254 (usage:) 254 SB +32 0 0 58 58 0 0 0 50 /Courier-Bold /font9 ANSIFont font +773 894 1645 (*** Report for user quotas on /dev/hdb2 \(/home\)) 1645 SB +1073 976 1505 ( Block limits File limits) 1505 SB +586 1046 2345 (User used soft hard grace used soft hard grace) 2345 SB +586 1116 2065 (root -- 19 0 0 2 0 0) 2065 SB +586 1185 2065 (bin -- 3 0 0 3 0 0) 2065 SB +586 1255 2065 (news -- 31691 0 0 11846 0 0) 2065 SB +586 1325 2065 (card -- 111498 0 0 8673 0 0) 2065 SB +586 1395 2065 (dugenou -- 16 5000 6000 11 100 110) 2065 SB +586 1465 2065 (melanie -- 6 5000 6000 7 100 110) 2065 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1586 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 9 SJ +586 1556 1961 (The quota command can also be used to print the) 1961 SB +586 1676 2013 (individual quota associated with a user or a group:) 2013 SB +32 0 0 58 58 0 0 0 50 /Courier-Bold /font9 ANSIFont font +586 1798 2030 (Disk quotas for user dugenou \(uid 1004\): ) 2030 SB +773 1868 2170 (Filesystem blocks quota limit grace files quota limit grace) 2170 SB +773 1938 1855 (/dev/hdb2 16 5000 6000 11 100 110) 1855 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (12) 58 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +-6 2 SJ +256 305 1690 (Checking quota consistency) 1690 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +9 9 SJ +586 614 2243 (Disk quota descriptors are kept in memory by the kernel) 2243 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 788 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +9 7 SJ +586 758 1810 (They are periodically written back to the disk) 1810 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 932 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +9 7 SJ +586 902 2182 (They can become corrupted after an unclean shutdown) 2182 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1075 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1049 600 (quotacheck) 600 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +4 6 SJ +1186 1045 1545 ( checks the consistency of disk quotas:) 1545 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1169 1560 (/usr/sbin/quotacheck -avug) 1560 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1339 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 1309 2266 (Be sure to compile the quota tools with Ext2fs support if) 2266 SB + +%%BeginResource: font MSTT31c1f0 +/G21 [33.0 0.0 11.0 -1.0 22.0 68.0] +/G21 { + 11 69 true [1 0 0 -1 -11.0 68.0] {<1f003f807fc07fc0ffe0ffe0ffe0ffe0ffe0ffe0ffe0ffe0ffe07fc07fc07fc07fc07fc07fc07fc0 +7fc07f807f807f803f803f803f803f803f803f003f003f003f003f001f001f001f001f001e001e00 +1e001e001e001e001e000e000c000c000c000c00000000000000000000000000000000001f003f80 +7fc0ffe0ffe0ffe0ffe0ffe07fc03f801f00>} imagemask + } + 33 /G21 MSTT31c1f0 AddChar +%%EndResource + +4 5 SJ +586 1429 910 (you want it to run fast!) 910 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (13) 58 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +-3 1 SJ +256 284 721 (Quota API) 721 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +5 8 SJ +586 614 1850 (A system call can be used to manipulate quota) 1850 SB +32 0 0 63 63 0 0 0 50 /ZapfDingbats font +473 779 50 (u) 50 SB +32 0 0 83 83 0 0 0 71 /Courier-Bold /font9 ANSIFont font +586 758 2250 (int quotactl \(int cmd, char *special, int id,) 2250 SB +586 858 650 (caddr_t addr\)) 650 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1008 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G43 [67.0 0.0 4.0 -1.0 63.0 68.0] +/G43 { + 59 69 true [1 0 0 -1 -4.0 68.0] {<0000001ffc000600000001ffffc00e0000000ffffff80e0000003ff803fe1e000000ffc0007ffe00 +0001ff00000ffe000007fc000007ff00000ff8000003ff00001fe0000001ff00003fc0000000ff00 +007fc00000007f0000ff800000003f0001ff000000001f0001ff000000001f0003fe000000000f00 +07fe000000000f0007fc0000000007000ffc0000000007800ff80000000003801ff8000000000380 +1ff80000000003803ff80000000001803ff00000000001803ff00000000000007ff0000000000000 +7ff00000000000007ff00000000000007fe00000000000007fe0000000000000ffe0000000000000 +ffe0000000000000ffe0000000000000ffe0000000000000ffe0000000000000ffe0000000000000 +ffe0000000000000ffe0000000000000ffe0000000000000ffe0000000000000ffe0000000000000 +ffe0000000000000ffe00000000000007fe00000000000007ff00000000000007ff0000000000000 +7ff00000000000003ff00000000000003ff80000000000003ff80000000000001ff8000000000000 +1ffc0000000000001ffc0000000000000ffc00000000004007fe0000000000e007ff0000000000c0 +03ff00000000018003ff80000000038001ffc0000000070000ffe00000000e00007ff00000001c00 +003ff80000003800001ffe000000f000000fff000003e0000007ffe0000fc0000001fffc007f8000 +00007ffffffe000000001ffffff80000000003ffffc000000000003ffc000000>} imagemask + } + 67 /G43 MSTT31c1f0 AddChar +%%EndResource + +586 978 509 (Commands: ) 509 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +1095 982 1260 (QCMD\(operation, type\)) 1260 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1152 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G4f [72.0 0.0 4.0 -1.0 68.0 68.0] +/G4f { + 64 69 true [1 0 0 -1 -4.0 68.0] {<0000001ffc000000000001ffffc0000000000ffffff8000000003fe00ffe00000000ff0000ff0000 +0001fc00003fc0000007f800001fe000000ff000000ff000001fe0000007f800003fc0000003fc00 +007f80000001fe0000ff00000000ff0001ff00000000ff8003fe000000007fc003fe000000007fc0 +07fc000000003fe00ffc000000003ff00ff8000000003ff01ff8000000001ff81ff8000000001ff8 +3ff8000000001ffc3ff0000000000ffc3ff0000000000ffc7ff0000000000ffe7ff0000000000ffe +7ff0000000000ffe7fe0000000000ffe7fe00000000007feffe00000000007ffffe00000000007ff +ffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ff +ffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ffffe00000000007ff +ffe00000000007ff7fe00000000007fe7ff00000000007fe7ff00000000007fe7ff0000000000ffe +7ff0000000000ffc3ff0000000000ffc3ff0000000000ffc3ff8000000000ff81ff8000000001ff8 +1ff8000000001ff80ffc000000001ff00ffc000000003fe007fc000000003fe007fe000000003fc0 +03fe000000007fc001ff00000000ff8000ff80000000ff0000ff80000001fe00007fc0000003fc00 +003fe0000007f800001ff000000ff0000007f800001fe0000003fe00007fc0000000ff0001ff0000 +00007fe00ffc000000001ffffff00000000003ffffc000000000003ff8000000>} imagemask + } + 79 /G4f MSTT31c1f0 AddChar +%%EndResource + +586 1122 466 (Operations:) 466 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +623 1263 45 (\226) 45 SB +717 1263 405 (Q_QUOTAON) 405 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1122 1260 38 (, ) 38 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1160 1263 450 (Q_QUOTAOFF) 450 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1610 1260 1128 (: activate or deactivate quota on a file) 1128 SB +717 1350 205 (system) 205 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +623 1462 45 (\226) 45 SB +717 1462 450 (Q_GETQUOTA) 450 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1167 1459 38 (, ) 38 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1205 1462 450 (Q_SETQUOTA) 450 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1655 1459 821 (: get or set usage and limits) 821 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +623 1570 45 (\226) 45 SB +717 1570 360 (Q_SETLIM) 360 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1077 1567 38 (, ) 38 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1115 1570 360 (Q_SETUSE) 360 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1475 1567 629 (: set limits and usage) 629 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +623 1678 45 (\226) 45 SB +717 1678 270 (Q_SYNC) 270 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +987 1675 791 (: write quotas back to disk) 791 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +623 1787 45 (\226) 45 SB +717 1787 450 (Q_GETSTATS) 450 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +1167 1784 408 (: get statistics) 408 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (14) 58 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +256 305 589 (Structure ) 589 SB +32 0 0 150 150 0 0 0 128 /Courier-Bold /font9 ANSIFont font +845 311 450 (dqblk) 450 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 618 840 (dqb_bhardlimit) 840 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1426 614 856 (: hard limit on blocks) 856 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 788 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 762 840 (dqb_bsoftlimit) 840 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1426 758 829 (: soft limit on blocks) 829 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 932 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 906 780 (dqb_curblocks) 780 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 3 SJ +1366 902 872 (: current blocks usage) 872 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1075 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1049 840 (dqb_ihardlimit) 840 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1426 1045 856 (: hard limit on inodes) 856 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1219 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1193 840 (dqb_isoftlimit) 840 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1426 1189 829 (: soft limit on inodes) 829 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1363 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1337 780 (dqb_curinodes) 780 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 3 SJ +1366 1333 872 (: current inodes usage) 872 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1507 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1481 540 (dqb_btime) 540 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 7 SJ +1126 1477 1794 (: grace period associated with the block limit) 1794 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1650 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1624 540 (dqb_inode) 540 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 7 SJ +1126 1620 1794 (: grace period associated with the inode limit) 1794 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (15) 58 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +-6 3 SJ +256 284 2038 (Implementation of disk quotas) 2038 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 614 1495 (Disk quotas are stored in quota files \() 1495 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +2081 618 600 (quota.user) 600 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +2681 614 169 ( and) 169 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 738 660 (quota.group) 660 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +5 7 SJ +1246 734 1430 (\) located in the root directory of file) 1430 SB +586 854 314 (systems) 314 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1028 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +586 998 1897 (Each quota file is seen as an array of structures ) 1897 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +2483 1002 360 (struct) 360 SB +586 1121 300 (dqblk) 300 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +4 7 SJ +886 1117 1685 (, that describe the current usage and limits) 1685 SB +3 4 SJ +586 1237 1247 (associated with users or groups) 1247 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1411 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +6 14 SJ +586 1381 2271 (The user id or group id is used as an index in the array to) 2271 SB +4 4 SJ +586 1501 1551 (access the appropriate quota descriptor) 1551 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (16) 58 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +-2 1 SJ +256 305 1064 (Quota descriptors) 1064 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +5 9 SJ +586 614 2336 (The kernel maintains a list of quota descriptors in memory) 2336 SB +586 734 33 (\() 33 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +619 738 720 (struct dquot) 720 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1339 734 33 (\)) 33 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 908 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1 6 SJ +586 878 1598 (The descriptors are stored in linked lists) 1598 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +4 5 SJ +586 1021 1765 (Inodes contain pointers on quota descriptors) 1765 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1195 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +6 7 SJ +586 1165 2341 (Quota operations are associated with mounted file systems) 2341 SB +586 1285 33 (\() 33 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +619 1289 1020 (struct superblock) 1020 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +1639 1285 33 (\)) 33 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (17) 58 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +-2 1 SJ +256 305 1031 (Quota operations) 1031 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 618 600 (initialize) 600 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +2 6 SJ +1186 614 1681 (: loads quota descriptors associated with a) 1681 SB +586 734 222 (inode) 222 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 908 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 882 240 (drop) 240 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +4 7 SJ +826 878 1910 (: frees quota descriptors associated with a inode) 1910 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1025 660 (alloc_block) 660 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 6 SJ +1246 1021 1630 (: checks for block allocation and updates) 1630 SB +586 1141 226 (usage) 226 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1315 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1289 660 (alloc_inode) 660 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 6 SJ +1246 1285 1630 (: checks for inode allocation and updates) 1630 SB +586 1405 226 (usage) 226 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1579 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1553 600 (free_block) 600 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +4 7 SJ +1186 1549 1737 (: updates usage when a block is deallocated) 1737 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1722 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1696 600 (free_inode) 600 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +3 6 SJ +1186 1692 1308 (: updates usage when an inode is) 1308 SB +586 1812 454 (deallocated) 454 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1986 59 (u) 59 SB +32 0 0 100 100 0 0 0 86 /Courier-Bold /font9 ANSIFont font +586 1960 480 (transfer) 480 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +6 8 SJ +1066 1956 1838 (: updates usages when a file owner is changed) 1838 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (18) 58 SB +32 0 0 150 150 0 0 0 134 /MSTT31c1c9 font +-6 3 SJ +256 305 1727 (Quota support in filesystems) 1727 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G4d [89.0 0.0 2.0 0.0 87.0 67.0] +/G4d { + 85 67 true [1 0 0 -1 -2.0 67.0] {<ffffc000000000000ffff8ffffe000000000001ffff80fffe000000000001fff0003fff000000000 +003ffc0001fff000000000003ff80000fff000000000007ff80000fff800000000007ff000007ff8 +0000000000fff000007ffc0000000000fff000007ffc0000000001fff000007ffe0000000001fff0 +00007ffe0000000003fff000007bff0000000003dff000007bff0000000007dff0000079ff800000 +00079ff0000079ff800000000f9ff0000078ffc00000000f1ff0000078ffc00000001f1ff0000078 +7fc00000001e1ff00000787fe00000003e1ff00000783fe00000003c1ff00000783ff00000007c1f +f00000783ff0000000781ff00000781ff8000000781ff00000781ff8000000f01ff00000780ffc00 +0000f01ff00000780ffc000001e01ff000007807fe000001e01ff000007807fe000003c01ff00000 +7803ff000003c01ff000007803ff000007801ff000007801ff000007801ff000007801ff80000f80 +1ff000007800ff80000f001ff000007800ffc0001f001ff000007800ffc0001e001ff0000078007f +e0003e001ff0000078007fe0003c001ff0000078003ff0007c001ff0000078003ff00078001ff000 +0078001ff800f8001ff0000078001ff800f0001ff0000078000ffc01f0001ff0000078000ffc01e0 +001ff00000780007fc03e0001ff00000780007fe03c0001ff00000780003fe03c0001ff000007800 +03ff0780001ff00000780003ff0780001ff00000780001ff8f00001ff00000780001ff8f00001ff0 +0000780000ffde00001ff00000780000ffde00001ff000007800007ffc00001ff000007800007ffc +00001ff000007800003ffc00001ff000007800003ff800001ff000007800001ff800001ff0000078 +00001ff000001ff000007800000ff000001ff000007800000fe000001ff00000fc00000fe000003f +f80000fc000007c000003ff80001fe000007c000007ffc0007ff800003800001ffff00fffffc0003 +80003ffffff8fffffc000100003ffffff8>} imagemask + } + 77 /G4d MSTT31c1f0 AddChar +%%EndResource + +586 614 2116 (Most of the quota implementation is contained in the) 2116 SB + +%%BeginResource: font MSTT31c1f0 +/G56 [72.0 0.0 1.0 -1.0 69.0 67.0] +/G56 { + 68 68 true [1 0 0 -1 -1.0 67.0] {<ffffffe00000fffff0ffffffe00000fffff01fffff0000001fffc003fff800000007ff0001fff000 +000003fe0000fff000000001fc00007ff000000001f800007ff000000001f800003ff000000001f0 +00003ff000000001e000001ff800000003e000001ff800000003e000001ff800000003c000000ffc +00000007c000000ffc0000000780000007fe0000000780000007fe0000000f80000003fe0000000f +00000003ff0000000f00000003ff0000001f00000001ff8000001e00000001ff8000003e00000000 +ffc000003c00000000ffc000003c000000007fc000007c000000007fe0000078000000007fe00000 +f8000000003ff00000f8000000003ff00000f0000000001ff80001f0000000001ff80001e0000000 +001ff80001e0000000000ffc0003e0000000000ffc0003c00000000007fe0007c00000000007fe00 +07c00000000003ff0007800000000003ff000f800000000003ff000f000000000001ff800f000000 +000001ff801f000000000000ffc01e000000000000ffc03e0000000000007fe03c0000000000007f +e03c0000000000007fe07c0000000000003ff0780000000000003ff0780000000000001ff8f80000 +000000001ff8f00000000000000ff9f00000000000000ffde00000000000000ffde0000000000000 +07ffe000000000000007ffc000000000000003ffc000000000000003ffc000000000000001ff8000 +000000000001ff8000000000000001ff0000000000000000ff0000000000000000ff000000000000 +00007e00000000000000007e00000000000000003e00000000000000003c00000000000000003c00 +000000000000001800000000>} imagemask + } + 86 /G56 MSTT31c1f0 AddChar +/G46 [55.0 0.0 2.0 0.0 51.0 67.0] +/G46 { + 49 67 true [1 0 0 -1 -2.0 67.0] {<ffffffffffff00ffffffffffff0007ffffffffff0001ffc00001ff0000ffc000007f0000ffc00000 +1f00007fc000000f00007fc000000f80007fc000000780007fc000000780007fc000000380007fc0 +00000380007fc000000380007fc000000180007fc000000180007fc000000000007fc00000000000 +7fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc0000300 +00007fc000030000007fc000030000007fc000070000007fc000070000007fc000070000007fc000 +0f0000007fc0001f0000007fc0007f0000007fffffff0000007fffffff0000007fffffff0000007f +c0003f0000007fc0001f0000007fc0000f0000007fc000070000007fc000070000007fc000030000 +007fc000030000007fc000030000007fc000030000007fc000000000007fc000000000007fc00000 +0000007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc0 +00000000007fc000000000007fc000000000007fc000000000007fc000000000007fc00000000000 +7fc000000000007fc000000000007fc000000000007fc00000000000ffe00000000000ffe0000000 +0001fff00000000007fffc00000000ffffffe0000000ffffffe0000000>} imagemask + } + 70 /G46 MSTT31c1f0 AddChar +%%EndResource + +4 3 SJ +586 734 1082 (Virtual File System \(VFS\):) 1082 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 873 38 (\226) 38 SB +717 873 997 (management of quota descriptors) 997 SB +623 981 38 (\226) 38 SB +-3 1 SJ +717 981 501 (quota operations) 501 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1124 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +8 7 SJ +586 1094 1845 (The file systems need a very minimal support:) 1845 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 1233 38 (\226) 38 SB +717 1233 1193 (when a block or inode is allocated, call ) 1193 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1910 1236 540 (alloc_block ) 540 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +2450 1233 63 (or) 63 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +717 1326 495 (alloc_inode) 495 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +623 1431 38 (\226) 38 SB +717 1431 1264 (when a block or inode is deallocated, call ) 1264 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +1981 1434 495 (free_block ) 495 SB +32 0 0 75 75 0 0 1 67 /MSTT31c1fd font +2476 1431 63 (or) 63 SB +32 0 0 75 75 0 0 0 64 /Courier-Bold /font9 ANSIFont font +717 1525 450 (free_inode) 450 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1665 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +6 7 SJ +586 1635 2005 (Currently, this support is integrated in Ext2fs only) 2005 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1809 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +6 9 SJ +586 1779 1913 (But it would be easy to integrate quotas in other) 1913 SB +586 1899 447 (filesystems) 447 SB +EJ RS +%%PageTrailer +SS +0 0 18 13 783 1169 300 SM +255 255 255 fC +/fm 256 def +3250 2250 88 49 B +1 F +n +1 lc +1 lj +0 0 0 pC +6 17 SP +gs 2857 2349 88 0 CB +-2765 499 M 8559 0 1 PP +S +n +gr +32 0 0 58 58 0 0 1 53 /MSTT31c1bc font +0 0 0 fC +25 8 SJ +153 2191 1278 (Third International Linux Conference - Berlin - May 96) 1278 SB +2890 2191 58 (19) 58 SB +32 0 0 167 167 0 0 0 150 /MSTT31c1c9 font +256 284 177 (Su) 176 SB +432 284 129 (m) 130 SB +562 284 343 (mary) 342 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 644 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +8 8 SJ +586 614 2122 (Finally, the quota patches have been integrated in the) 2122 SB +2 1 SJ +586 734 645 (standard kernel!) 645 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 908 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G30 [50.0 0.0 4.0 -1.0 46.0 68.0] +/G30 { + 42 69 true [1 0 0 -1 -4.0 68.0] {<00003f8000000001ffe000000007fff80000000fe0fc0000001f803f0000003f001f8000007e000f +c00000fc000fc00001f80007e00003f80007f00003f00003f00007f00003f80007f00001fc000fe0 +0001fc000fe00001fc001fe00001fe001fe00000fe001fe00000ff003fc00000ff003fc00000ff00 +3fc00000ff007fc00000ff807fc000007f807fc000007f807fc000007f807fc000007f807f800000 +7fc0ff8000007fc0ff8000007fc0ff8000007fc0ff8000007fc0ff8000007fc0ff8000007fc0ff80 +00007fc0ff8000007fc0ff8000007fc0ff8000007fc0ff8000007fc0ff8000007fc0ff8000007fc0 +ff8000007fc0ff8000007fc0ff8000007f807f8000007f807f8000007f807f800000ff807fc00000 +ff807fc00000ff803fc00000ff003fc00000ff003fc00000ff003fc00000ff001fe00001fe001fe0 +0001fe000fe00001fc000fe00001fc0007f00003f80007f00003f80003f00003f00003f80007f000 +01f80007e00000fc000fc00000fc001fc000007e003f8000003f007e0000001fc1fc00000007fff8 +00000003ffe0000000007f000000>} imagemask + } + 48 /G30 MSTT31c1f0 AddChar +%%EndResource + +5 9 SJ +586 878 1928 (They will be part of the next stable version \(2.0\)) 1928 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1051 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font + +%%BeginResource: font MSTT31c1f0 +/G50 [56.0 0.0 2.0 0.0 52.0 67.0] +/G50 { + 50 67 true [1 0 0 -1 -2.0 67.0] {<ffffffff000000fffffffff8000007fffffffe000001fff007ff800000ffc001ffe00000ffc0007f +f000007fc0003ff800007fc0001ffc00007fc0000ffe00007fc00007ff00007fc00007ff00007fc0 +0003ff80007fc00003ff80007fc00003ff80007fc00003ffc0007fc00001ffc0007fc00001ffc000 +7fc00001ffc0007fc00001ffc0007fc00001ffc0007fc00001ffc0007fc00001ffc0007fc00001ff +c0007fc00001ff80007fc00003ff80007fc00003ff80007fc00007ff00007fc00007ff00007fc000 +0ffe00007fc0000ffe00007fc0001ffc00007fc0007ff800007fc000fff000007ff803ffe000007f +ffffff8000007ffffffe0000007fc1ffe00000007fc000000000007fc000000000007fc000000000 +007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc00000 +0000007fc000000000007fc000000000007fc000000000007fc000000000007fc000000000007fc0 +00000000007fc000000000007fc000000000007fc000000000007fc000000000007fc00000000000 +7fc000000000007fc000000000007fc000000000007fc00000000000ffe00000000000ffe0000000 +0001fff00000000007fffc00000000ffffffe0000000ffffffe0000000>} imagemask + } + 80 /G50 MSTT31c1f0 AddChar +/G2a [50.0 0.0 7.0 29.0 41.0 70.0] +/G2a { + 34 41 true [1 0 0 -1 -7.0 70.0] {<0000e000000003f000000003f000000003f800000007f800000007f800000007f800000003f80000 +0003f000003c03f00f007e03f01f80ff81f03fc0ffc1e07fc0ffc1e0ffc07fe1e1ffc07ff0e3ff80 +1ff8c7fe0007fccff800007eff80000007f800000001e00000000ff80000007edf800007fccff800 +1ff8c7ff007ff0c3ff807fe1e1ff80ffc1e0ffc0ff81e07fc0ff03f03fc07e03f01f803c03f00f00 +0003f000000003f800000007f800000007f800000007f800000007f800000003f000000003f00000 +0000e00000>} imagemask + } + 42 /G2a MSTT31c1f0 AddChar +%%EndResource + +3 9 SJ +586 1021 2321 (The API and tools are compatible with *BSD \(the utilities) 2321 SB +2 2 SJ +586 1141 812 (come from 4.4BSD\)) 812 SB +32 0 0 75 75 0 0 0 60 /ZapfDingbats font +473 1315 59 (u) 59 SB +32 0 0 100 100 0 0 1 90 /MSTT31c1f0 font +7 10 SJ +586 1285 2232 (Most of the quota management is done in the VFS layer) 2232 SB +EJ RS +%%PageTrailer +%%Trailer +SVDoc restore +end +% TrueType font name key: +% MSTT31c1bc = 0c27DTimes New RomanF0000003a000001900000 +% MSTT31c1c9 = 0c27DTimes New RomanF00000000000001900000 +% MSTT31c1d6 = 0c27DTimes New RomanF000000000000019000ff +% MSTT31c1e3 = 0c27DMonotype SortsF00000058000001900000 +% MSTT31c1f0 = 0c27DTimes New RomanF00000064000001900000 +% MSTT31c1fd = 0c27DTimes New RomanF0000004b000001900000 +% MSTT31c20a = 0c27DMonotype SortsF0000004b000001900000 +% MSTT31c217 = 0c27DTimes New RomanF00000043000001900000 +% MSTT31c22e = 0c27DMonotype SortsF0000003f000001900000 +%%DocumentSuppliedResources: procset Win35Dict 3 1 +%%+ font MSTT31c1bc +%%+ font MSTT31c1c9 +%%+ font MSTT31c1d6 +%%+ font MSTT31c1f0 +%%+ font MSTT31c1fd + +%%DocumentNeededResources: font Courier-Bold +%%+ font ZapfDingbats + +%%EOF +grestore diff --git a/doc/quotas.ms b/doc/quotas.ms new file mode 100644 index 0000000..10e200c --- /dev/null +++ b/doc/quotas.ms @@ -0,0 +1,318 @@ +.\" Copyright (c) 1983 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)quotas.ms 6.3 (Berkeley) 4/17/91 +.\" +.EH 'SMM:4-%''Disc Quotas in a \s-2UNIX\s+2 Environment' +.OH 'Disc Quotas in a \s-2UNIX\s+2 Environment''SMM:4-%' +.ND 5th July, 1983 +.TL +Disc Quotas in a \s-2UNIX\s+2\s-3\u*\d\s0 Environment +.FS +* UNIX is a trademark of Bell Laboratories. +.FE +.AU +Robert Elz +.AI +Department of Computer Science +University of Melbourne, +Parkville, +Victoria, +Australia. +.AB +.PP +In most computing environments, disc space is not +infinite. +The disc quota system provides a mechanism +to control usage of disc space, on an +individual basis. +.PP +Quotas may be set for each individual user, on any, or +all filesystems. +.PP +The quota system will warn users when they +exceed their allotted limit, but allow some +extra space for current work. +Repeatedly remaining over quota at logout, +will cause a fatal over quota condition eventually. +.PP +The quota system is an optional part of +\s-2VMUNIX\s0 that may be included when the +system is configured. +.AE +.NH 1 +Users' view of disc quotas +.PP +To most users, disc quotas will either be of no concern, +or a fact of life that cannot be avoided. +The +\fIquota\fP\|(1) +command will provide information on any disc quotas +that may have been imposed upon a user. +.PP +There are two individual possible quotas that may be +imposed, usually if one is, both will be. +A limit can be set on the amount of space a user +can occupy, and there may be a limit on the number +of files (inodes) he can own. +.PP +.I Quota +provides information on the quotas that have +been set by the system administrators, in each +of these areas, and current usage. +.PP +There are four numbers for each limit, the current +usage, soft limit (quota), hard limit, and number +of remaining login warnings. +The soft limit is the number of 1K blocks (or files) +that the user is expected to remain below. +Each time the user's usage goes past this limit, +he will be warned. +The hard limit cannot be exceeded. +If a user's usage reaches this number, further +requests for space (or attempts to create a file) +will fail with an EDQUOT error, and the first time +this occurs, a message will be written to the user's +terminal. +Only one message will be output, until space occupied +is reduced below the limit, and reaches it again, +in order to avoid continual noise from those +programs that ignore write errors. +.PP +Whenever a user logs in with a usage greater than +his soft limit, he will be warned, and his login +warning count decremented. +When he logs in under quota, the counter is reset +to its maximum value (which is a system configuration +parameter, that is typically 3). +If the warning count should ever reach zero (caused +by three successive logins over quota), the +particular limit that has been exceeded will be treated +as if the hard limit has been reached, and no +more resources will be allocated to the user. +The \fBonly\fP way to reset this condition is +to reduce usage below quota, then log in again. +.NH 2 +Surviving when quota limit is reached +.PP +In most cases, the only way to recover from over +quota conditions, is to abort whatever activity was in progress +on the filesystem that has reached its limit, remove +sufficient files to bring the limit back below quota, +and retry the failed program. +.PP +However, if you are in the editor and a write fails +because of an over quota situation, that is not +a suitable course of action, as it is most likely +that initially attempting to write the file +will have truncated its previous contents, so should +the editor be aborted without correctly writing the +file not only will the recent changes be lost, but +possibly much, or even all, of the data +that previously existed. +.PP +There are several possible safe exits for a user +caught in this situation. +He may use the editor \fB!\fP shell escape command to +examine his file space, and remove surplus files. +Alternatively, using \fIcsh\fP, he may suspend the +editor, remove some files, then resume it. +A third possibility, is to write the file to +some other filesystem (perhaps to a file on /tmp) +where the user's quota has not been exceeded. +Then after rectifying the quota situation, +the file can be moved back to the filesystem +it belongs on. +.NH 1 +Administering the quota system +.PP +To set up and establish the disc quota system, +there are several steps necessary to be performed +by the system administrator. +.PP +First, the system must be configured to include +the disc quota sub-system. +This is done by including the line: +.DS +options QUOTA +.DE +in the system configuration file, then running +\fIconfig\fP\|(8) +followed by a system configuration\s-3\u*\d\s0. +.FS +* See also the document ``Building 4.2BSD UNIX Systems with Config''. +.FE +.PP +Second, a decision as to what filesystems need to have +quotas applied needs to be made. +Usually, only filesystems that house users' home directories, +or other user files, will need to be subjected to +the quota system, though it may also prove useful to +also include \fB/usr\fR. +If possible, \fB/tmp\fP should usually be free of quotas. +.PP +Having decided on which filesystems quotas need to be +set upon, the administrator should then allocate the +available space amongst the competing needs. How this +should be done is (way) beyond the scope of this document. +.PP +Then, the +\fIedquota\fP\|(8) +command can be used to actually set the limits desired upon +each user. Where a number of users are to be given the +same quotas (a common occurrence) the \fB\-p\fP switch +to edquota will allow this to be easily accomplished. +.PP +Once the quotas are set, ready to operate, the system +must be informed to enforce quotas on the desired filesystems. +This is accomplished with the +\fIquotaon\fP\|(8) +command. +.I Quotaon +will either enable quotas for a particular filesystem, or +with the \fB\-a\fP switch, will enable quotas for each +filesystem indicated in \fB/etc/fstab\fP as using quotas. +See +\fIfstab\fP\|(5) +for details. +Most sites using the quota system, will include the +line +.DS C +/etc/quotaon -a +.DE +in \fB/etc/rc.local\fP. +.PP +Should quotas need to be disabled, the +\fIquotaoff\fP(8) +command will do that, however, should the filesystem be +about to be dismounted, the +\fIumount\fP\|(8) +command will disable quotas immediately before the +filesystem is unmounted. +This is actually an effect of the +\fIumount\fP\|(2) +system call, and it guarantees that the quota system +will not be disabled if the umount would fail +because the filesystem is not idle. +.PP +Periodically (certainly after each reboot, and when quotas +are first enabled for a filesystem), the records retained +in the quota file should be checked for consistency with +the actual number of blocks and files allocated to +the user. +The +\fIquotacheck\fP\|(8) +command can be used to accomplish this. +It is not necessary to dismount the filesystem, or disable +the quota system to run this command, though on +active filesystems inaccurate results may occur. +This does no real harm in most cases, another run of +.I quotacheck +when the filesystem is idle will certainly correct any inaccuracy. +.PP +The super-user may use the +\fIquota\fP\|(1) +command to examine the usage and quotas of any user, and +the +\fIrepquota\fP\|(8) +command may be used to check the usages and limits for +all users on a filesystem. +.NH 1 +Some implementation detail. +.PP +Disc quota usage and information is stored in a file on the +filesystem that the quotas are to be applied to. +Conventionally, this file is \fBquotas\fR in the root of +the filesystem. +While this name is not known to the system in any way, +several of the user level utilities "know" it, and +choosing any other name would not be wise. +.PP +The data in the file comprises an array of structures, indexed +by uid, one structure for each user on the system (whether +the user has a quota on this filesystem or not). +If the uid space is sparse, then the file may have holes +in it, which would be lost by copying, so it is best to +avoid this. +.PP +The system is informed of the existence of the quota +file by the +\fIsetquota\fP\|(2) +system call. +It then reads the quota entries for each user currently +active, then for any files open owned by users who +are not currently active. +Each subsequent open of a file on the filesystem, will +be accompanied by a pairing with its quota information. +In most cases this information will be retained in core, +either because the user who owns the file is running some +process, because other files are open owned by the same +user, or because some file (perhaps this one) was recently +accessed. +In memory, the quota information is kept hashed by user-id +and filesystem, and retained in an LRU chain so recently +released data can be easily reclaimed. +Information about those users whose last process has +recently terminated is also retained in this way. +.PP +Each time a block is accessed or released, and each time an inode +is allocated or freed, the quota system gets told +about it, and in the case of allocations, gets the +opportunity to object. +.PP +Measurements have shown +that the quota code uses a very small percentage of the system +cpu time consumed in writing a new block to disc. +.NH 1 +Acknowledgments +.PP +The current disc quota system is loosely based upon a very +early scheme implemented at the University of New South +Wales, and Sydney University in the mid 70's. That system +implemented a single combined limit for both files and blocks +on all filesystems. +.PP +A later system was implemented at the University of Melbourne +by the author, but was not kept highly accurately, eg: +chown's (etc) did not affect quotas, nor did i/o to a file +other than one owned by the instigator. +.PP +The current system has been running (with only minor modifications) +since January 82 at Melbourne. +It is actually just a small part of a much broader resource +control scheme, which is capable of controlling almost +anything that is usually uncontrolled in unix. The rest +of this is, as yet, still in a state where it is far too +subject to change to be considered for distribution. +.PP +For the 4.2BSD release, much work has been done to clean +up and sanely incorporate the quota code by Sam Leffler and +Kirk McKusick at The University of California at Berkeley. diff --git a/doc/quotas.preformated b/doc/quotas.preformated new file mode 100644 index 0000000..e008aeb --- /dev/null +++ b/doc/quotas.preformated @@ -0,0 +1,330 @@ + + + + + + + + + + DDiisscc QQuuoottaass iinn aa UUNNIIXX** EEnnvviirroonnmmeenntt + + _R_o_b_e_r_t _E_l_z + Department of Computer Science + University of Melbourne, + Parkville, + Victoria, + Australia. + + + _A_B_S_T_R_A_C_T + + + + In most computing environments, disc space is + not infinite. The disc quota system provides a + mechanism to control usage of disc space, on an + individual basis. + + Quotas may be set for each individual user, + on any, or all filesystems. + + The quota system will warn users when they + exceed their allotted limit, but allow some extra + space for current work. Repeatedly remaining over + quota at logout, will cause a fatal over quota + condition eventually. + + The quota system is an optional part of VMU- + NIX that may be included when the system is con- + figured. + + + 11.. UUsseerrss'' vviieeww ooff ddiisscc qquuoottaass + + To most users, disc quotas will either be of no con- + cern, or a fact of life that cannot be avoided. The + _q_u_o_t_a(1) command will provide information on any disc quotas + that may have been imposed upon a user. + + There are two individual possible quotas that may be + imposed, usually if one is, both will be. A limit can be + set on the amount of space a user can occupy, and there may + be a limit on the number of files (inodes) he can own. + + _Q_u_o_t_a provides information on the quotas that have been + set by the system administrators, in each of these areas, + and current usage. + + ----------- + * UNIX is a trademark of Bell Laboratories. + + + + + + + + + + SMM:4-2 Disc Quotas in a UNIX Environment + + + There are four numbers for each limit, the current + usage, soft limit (quota), hard limit, and number of remain- + ing login warnings. The soft limit is the number of 1K + blocks (or files) that the user is expected to remain below. + Each time the user's usage goes past this limit, he will be + warned. The hard limit cannot be exceeded. If a user's + usage reaches this number, further requests for space (or + attempts to create a file) will fail with an EDQUOT error, + and the first time this occurs, a message will be written to + the user's terminal. Only one message will be output, until + space occupied is reduced below the limit, and reaches it + again, in order to avoid continual noise from those programs + that ignore write errors. + + Whenever a user logs in with a usage greater than his + soft limit, he will be warned, and his login warning count + decremented. When he logs in under quota, the counter is + reset to its maximum value (which is a system configuration + parameter, that is typically 3). If the warning count + should ever reach zero (caused by three successive logins + over quota), the particular limit that has been exceeded + will be treated as if the hard limit has been reached, and + no more resources will be allocated to the user. The oonnllyy + way to reset this condition is to reduce usage below quota, + then log in again. + + 11..11.. SSuurrvviivviinngg wwhheenn qquuoottaa lliimmiitt iiss rreeaacchheedd + + In most cases, the only way to recover from over quota + conditions, is to abort whatever activity was in progress on + the filesystem that has reached its limit, remove sufficient + files to bring the limit back below quota, and retry the + failed program. + + However, if you are in the editor and a write fails + because of an over quota situation, that is not a suitable + course of action, as it is most likely that initially + attempting to write the file will have truncated its previ- + ous contents, so should the editor be aborted without cor- + rectly writing the file not only will the recent changes be + lost, but possibly much, or even all, of the data that pre- + viously existed. + + There are several possible safe exits for a user caught + in this situation. He may use the editor !! shell escape + command to examine his file space, and remove surplus files. + Alternatively, using _c_s_h, he may suspend the editor, remove + some files, then resume it. A third possibility, is to + write the file to some other filesystem (perhaps to a file + on /tmp) where the user's quota has not been exceeded. Then + after rectifying the quota situation, the file can be moved + back to the filesystem it belongs on. + + + + + + + + + + + + Disc Quotas in a UNIX Environment SMM:4-3 + + + 22.. AAddmmiinniisstteerriinngg tthhee qquuoottaa ssyysstteemm + + To set up and establish the disc quota system, there + are several steps necessary to be performed by the system + administrator. + + First, the system must be configured to include the + disc quota sub-system. This is done by including the line: + + options QUOTA + + in the system configuration file, then running _c_o_n_f_i_g(8) + followed by a system configuration*. + + Second, a decision as to what filesystems need to have + quotas applied needs to be made. Usually, only filesystems + that house users' home directories, or other user files, + will need to be subjected to the quota system, though it may + also prove useful to also include //uussrr. If possible, //ttmmpp + should usually be free of quotas. + + Having decided on which filesystems quotas need to be + set upon, the administrator should then allocate the avail- + able space amongst the competing needs. How this should be + done is (way) beyond the scope of this document. + + Then, the _e_d_q_u_o_t_a(8) command can be used to actually + set the limits desired upon each user. Where a number of + users are to be given the same quotas (a common occurrence) + the --pp switch to edquota will allow this to be easily accom- + plished. + + Once the quotas are set, ready to operate, the system + must be informed to enforce quotas on the desired filesys- + tems. This is accomplished with the _q_u_o_t_a_o_n(8) command. + _Q_u_o_t_a_o_n will either enable quotas for a particular filesys- + tem, or with the --aa switch, will enable quotas for each + filesystem indicated in //eettcc//ffssttaabb as using quotas. See + _f_s_t_a_b(5) for details. Most sites using the quota system, + will include the line + + /etc/quotaon -a + + in //eettcc//rrcc..llooccaall. + + Should quotas need to be disabled, the _q_u_o_t_a_o_f_f(8) com- + mand will do that, however, should the filesystem be about + to be dismounted, the _u_m_o_u_n_t(8) command will disable quotas + immediately before the filesystem is unmounted. This is + actually an effect of the _u_m_o_u_n_t(2) system call, and it + guarantees that the quota system will not be disabled if the + ----------- + * See also the document ``Building 4.2BSD UNIX + Systems with Config''. + + + + + + + + + + SMM:4-4 Disc Quotas in a UNIX Environment + + + umount would fail because the filesystem is not idle. + + Periodically (certainly after each reboot, and when + quotas are first enabled for a filesystem), the records + retained in the quota file should be checked for consistency + with the actual number of blocks and files allocated to the + user. The _q_u_o_t_a_c_h_e_c_k(8) command can be used to accomplish + this. It is not necessary to dismount the filesystem, or + disable the quota system to run this command, though on + active filesystems inaccurate results may occur. This does + no real harm in most cases, another run of _q_u_o_t_a_c_h_e_c_k when + the filesystem is idle will certainly correct any inaccu- + racy. + + The super-user may use the _q_u_o_t_a(1) command to examine + the usage and quotas of any user, and the _r_e_p_q_u_o_t_a(8) com- + mand may be used to check the usages and limits for all + users on a filesystem. + + 33.. SSoommee iimmpplleemmeennttaattiioonn ddeettaaiill.. + + Disc quota usage and information is stored in a file on + the filesystem that the quotas are to be applied to. Con- + ventionally, this file is qquuoottaass in the root of the filesys- + tem. While this name is not known to the system in any way, + several of the user level utilities "know" it, and choosing + any other name would not be wise. + + The data in the file comprises an array of structures, + indexed by uid, one structure for each user on the system + (whether the user has a quota on this filesystem or not). + If the uid space is sparse, then the file may have holes in + it, which would be lost by copying, so it is best to avoid + this. + + The system is informed of the existence of the quota + file by the _s_e_t_q_u_o_t_a(2) system call. It then reads the + quota entries for each user currently active, then for any + files open owned by users who are not currently active. + Each subsequent open of a file on the filesystem, will be + accompanied by a pairing with its quota information. In + most cases this information will be retained in core, either + because the user who owns the file is running some process, + because other files are open owned by the same user, or + because some file (perhaps this one) was recently accessed. + In memory, the quota information is kept hashed by user-id + and filesystem, and retained in an LRU chain so recently + released data can be easily reclaimed. Information about + those users whose last process has recently terminated is + also retained in this way. + + Each time a block is accessed or released, and each + time an inode is allocated or freed, the quota system gets + told about it, and in the case of allocations, gets the + + + + + + + + + + Disc Quotas in a UNIX Environment SMM:4-5 + + + opportunity to object. + + Measurements have shown that the quota code uses a very + small percentage of the system cpu time consumed in writing + a new block to disc. + + 44.. AAcckknnoowwlleeddggmmeennttss + + The current disc quota system is loosely based upon a + very early scheme implemented at the University of New South + Wales, and Sydney University in the mid 70's. That system + implemented a single combined limit for both files and + blocks on all filesystems. + + A later system was implemented at the University of + Melbourne by the author, but was not kept highly accurately, + eg: chown's (etc) did not affect quotas, nor did i/o to a + file other than one owned by the instigator. + + The current system has been running (with only minor + modifications) since January 82 at Melbourne. It is actu- + ally just a small part of a much broader resource control + scheme, which is capable of controlling almost anything that + is usually uncontrolled in unix. The rest of this is, as + yet, still in a state where it is far too subject to change + to be considered for distribution. + + For the 4.2BSD release, much work has been done to + clean up and sanely incorporate the quota code by Sam Lef- + fler and Kirk McKusick at The University of California at + Berkeley. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/repquota(8).html b/doc/repquota(8).html new file mode 100644 index 0000000..dc3cf70 --- /dev/null +++ b/doc/repquota(8).html @@ -0,0 +1,68 @@ +<HTML> +<HEAD> +<TITLE>repquota(8) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +repquota - summarize quotas for a file system +<H1>SYNOPSIS</H1> +<B>repquota</B> +[ +<B>-vug</B> +] +<B>filesystem</B> +<BR> +<B>repquota</B> +[ +<B>-avug</B> +] +<H1>DESCRIPTION</H1> +<B>Repquota</B> +prints a summary of the disc usage and quotas for the specified file +systems. For each user the current number of files and amount of space +(in kilobytes) is printed, along with any quotas created with +<A HREF="edquota(8).html">edquota (8)</A> +. +<H1>OPTIONS</H1> +<UL> +<LI> +<B>-a</B> +<BR> +Report on all file systems indicated in +<B>/etc/fstab</B> +to be read-write with quotas. +<LI> +<B>-v</B> +<BR> +Report all quotas, even if there is no usage. +<LI> +<B>-g</B> +<BR> +Report quotas for groups. +<LI> +<B>-u</B> +<BR> +Report quotas for users. This is the default. +</UL> +<P> +Only the super-user may view quotas which are not their own. +<H1>FILES</H1> +<B>quota.user</B> + : located at the filesystem root with user quotas +<BR> +<B>quota.group</B> + : located at the filesystem root with group quotas +<BR> +<B>/etc/fstab</B> + : to find filesystem names and locations +<H1>SEE ALSO</H1> +<A HREF="quotactl(2).html">quotactl (2)</A>, +<A HREF="fstab(5).html">fstab (5)</A>, +<A HREF="edquota(8).html">edquota (8)</A>, +<A HREF="quotacheck(8).html">quotacheck (8)</A>, +<A HREF="quotaon(8).html">quotaon (8)</A> +</BODY> +</HTML> diff --git a/doc/rquotad(8).html b/doc/rquotad(8).html new file mode 100644 index 0000000..5c20a2f --- /dev/null +++ b/doc/rquotad(8).html @@ -0,0 +1,38 @@ +<HTML> +<HEAD> +<TITLE>rquotad(8) manualpage</TITLE> +<!-- OWNER_NAME="Marco van Wieringen, OpenWorld System Management" --> +<!-- OWNER_INFO="The OpenWorld Foundation, The Netherlands" --> +<LINK REV=MADE HREF="mailto:mvw@planets.elm.net"> +</HEAD> +<BODY> +<H1>NAME</H1> +rquotad, rpc.rquotad - remote quota server +<H1>SYNOPSIS</H1> +<B>rpc.rquotad</B> +<H1>DESCRIPTION</H1> +<B>rquotad</B> +is an +<B>rpc (3N)</B> +server which returns quotas for a user of a local file system +which is mounted by a remote machine over the +<B>NFS</B> +The results are used by +<A HREF="quota(1).html">quota (1)</A> +to display user quotas for remote file systems. +The +<B>rquotad</B> +daemon is normally started at boottime from the +<B>rc.net</B> +script +<H1>FILES</H1> +<B>quota.user</B> + : located at the filesystem root with user quotas +<BR> +<B>quota.group</B> + : located at the filesystem root with group quotas +<H1>SEE ALSO</H1> +<A HREF="quota(1).html">quota (1)</A>, +rpc (3N), nfs (4P), services (5) inetd (8C), +</BODY> +</HTML> diff --git a/dqblk_rpc.h b/dqblk_rpc.h new file mode 100644 index 0000000..f5a666a --- /dev/null +++ b/dqblk_rpc.h @@ -0,0 +1,20 @@ +/* + * Headerfile for rpc quotafile format + */ + +#ifndef _DQBLK_RPC_H +#define _DQBLK_RPC_H + +/* Values used for communication through network */ +#define Q_RPC_GETQUOTA 0x0300 /* get limits and usage */ +#define Q_RPC_SETQUOTA 0x0400 /* set limits and usage */ +#define Q_RPC_SETUSE 0x0500 /* set usage */ +#define Q_RPC_SETQLIM 0x0700 /* set limits */ + +#define RPC_DQBLK_SIZE_BITS 10 +#define RPC_DQBLK_SIZE (1 << RPC_DQBLK_SIZE_BITS) + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_rpc; + +#endif diff --git a/dqblk_v1.h b/dqblk_v1.h new file mode 100644 index 0000000..409a70c --- /dev/null +++ b/dqblk_v1.h @@ -0,0 +1,18 @@ +/* + * Headerfile for old quotafile format + */ + +#ifndef _DQBLK_V1_H +#define _DQBLK_V1_H + +/* Values of quota calls */ +#define Q_V1_RSQUASH 0x1000 +#define Q_V1_GETQUOTA 0x300 +#define Q_V1_SETQUOTA 0x400 + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_1; + +#endif diff --git a/dqblk_v2.h b/dqblk_v2.h new file mode 100644 index 0000000..56aaf5f --- /dev/null +++ b/dqblk_v2.h @@ -0,0 +1,36 @@ +/* + * + * Header file for disk format of new quotafile format + * + */ + +#ifndef _DQBLK_V2_H +#define _DQBLK_V2_H + +#include <sys/types.h> + +#define Q_V2_GETQUOTA 0x0D00 /* Get limits and usage */ +#define Q_V2_SETQUOTA 0x0E00 /* Set limits and usage */ +#define Q_V2_GETINFO 0x0900 /* Get information about quota */ +#define Q_V2_SETINFO 0x0A00 /* Set information about quota */ + +/* Structure for format specific information */ +struct v2_mem_dqinfo { + uint dqi_flags; /* Flags set in quotafile */ + uint dqi_blocks; /* Number of blocks in file */ + uint dqi_free_blk; /* Number of first free block in the list */ + uint dqi_free_entry; /* Number of first block with free entry in the list */ + uint dqi_used_entries; /* Number of entries in file - updated by scan_dquots */ + uint dqi_data_blocks; /* Number of data blocks in file - updated by scan_dquots */ +}; + +struct v2_mem_dqblk { + loff_t dqb_off; /* Offset of dquot in file */ +}; + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_2; + +#endif diff --git a/dqblk_xfs.h b/dqblk_xfs.h new file mode 100644 index 0000000..8b03d98 --- /dev/null +++ b/dqblk_xfs.h @@ -0,0 +1,25 @@ +/* + * Headerfile for XFS quota format + */ + +#ifndef _DQBLK_XFS_H +#define _DQBLK_XFS_H + +#include "quotaio_xfs.h" + +#define Q_XFS_QUOTAON Q_XQUOTAON +#define Q_XFS_QUOTAOFF Q_XQUOTAOFF +#define Q_XFS_GETQUOTA Q_XGETQUOTA +#define Q_XFS_SETQLIM Q_XSETQLIM +#define Q_XFS_GETQSTAT Q_XGETQSTAT +#define Q_XFS_QUOTARM Q_XQUOTARM + +#define xfs_mem_dqinfo fs_quota_stat +#define xfs_kern_dqblk fs_disk_quota + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_xfs; + +#endif diff --git a/edquota.8 b/edquota.8 new file mode 100644 index 0000000..e02218c --- /dev/null +++ b/edquota.8 @@ -0,0 +1,95 @@ +.TH EDQUOTA 8 +.SH NAME +edquota \- edit user quotas +.SH SYNOPSIS +.B edquota +[ +.B \-p +.I proto-user +] [ +.B \-ug +] +.IR name .\|.\|. +.LP +.B edquota +[ +.B \-r +] +[ +.B \-ug +] +.B \-t +.SH DESCRIPTION +.IX "edquota command" "" "\fLedquota\fP \(em edit user quotas" +.IX edit "user quotas \(em \fLedquota\fP" +.IX "user quotas" "edquota command" "" "\fLedquota\fP \(em edit user quotas" +.IX "disk quotas" "edquota command" "" "\fLedquota\fP \(em edit user quotas" +.IX "quotas" "edquota command" "" "\fLedquota\fP \(em edit user quotas" +.IX "filesystem" "edquota command" "" "\fLedquota\fP \(em edit user quotas" +.B edquota +is a quota editor. One or more users or groups may be specified on the command +line. For each user or group a temporary file is created with an +.SM ASCII +representation of the current disk quotas for that user or group and an editor +is then invoked on the file. The quotas may then be modified, new +quotas added, etc. Upon leaving the editor, +.B edquota +reads the temporary file and modifies the binary quota files to reflect +the changes made. +.LP +The editor invoked is +.BR vi (1) +unless either the +.SB EDITOR +or the +.SB VISUAL +environment variable specifies otherwise. +.LP +Only the super-user may edit quotas. +.SH OPTIONS +.TP +.B \-r +Edit also non-local quota use rpc.rquotad on remote server to set quota. +The +.B \-n +option is equivalent, and is maintained for backward compatibility. +.TP +.B \-u +Edit the user quota. This is the default. +.TP +.B \-g +Edit the group quota. +.TP +.B \-p +Duplicate the quotas of the prototypical user +specified for each user specified. This is the normal +mechanism used to initialize quotas for groups of users. +.TP +.B \-t +Edit the soft time limits for each filesystem. +If the time limits are zero, the default time limits in +.B <linux/quota.h> +are used. +Time units of seconds, minutes, hours, days, weeks, and months +are understood. +Time limits are printed in the greatest possible time unit such that +the value is greater than or equal to one. +.SH FILES +.PD 0 +.TP 20 +.B aquota.user or aquota.group +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP +.B quota.user or quota.group +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/mtab +mounted filesystems +.PD +.SH SEE ALSO +.BR quota (1), +.BR vi (1), +.BR quotactl (2), +.BR quotacheck (8), +.BR quotaon (8), +.BR repquota (8) diff --git a/edquota.c b/edquota.c new file mode 100644 index 0000000..7817750 --- /dev/null +++ b/edquota.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. All + * rights reserved. + * + * This code is derived from software contributed to Berkeley by Robert Elz at + * The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $" +#ident "$Copyright: All rights reserved. $" +#ident "$Id: edquota.c,v 1.1 2001/03/23 12:03:26 jkar8572 Exp $" + +/* + * Disk quota editor. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <paths.h> +#include <stdlib.h> + +#include "pot.h" +#include "quotaops.h" +#include "quotasys.h" +#include "quotaio.h" +#include "common.h" + +static char tmpfil[] = _PATH_TMP "EdP.aXXXXXX"; + +void usage(void) +{ +#if defined(RPC_SETQUOTA) + fprintf(stderr, "%s%s%s%s", + _("Usage:\tedquota [-r] [-u] [-F formatname] [-p username] username ...\n"), + _("\tedquota [-r] -g [-p groupname] groupname ...\n"), + _("\tedquota [-r] [-u] -t\n"), _("\tedquota [-r] -g -t\n")); +#else + fprintf(stderr, "%s%s%s%s", + _("Usage:\tedquota [-u] [-F formatname] [-p username] username ...\n"), + _("\tedquota -g [-p groupname] groupname ...\n"), + _("\tedquota [-u] -t\n"), _("\tedquota -g -t\n")); +#endif + fprintf(stderr, _("Bugs to: %s\n"), MY_EMAIL); + exit(1); +} + +int main(int argc, char **argv) +{ + struct dquot *q, *protoprivs, *curprivs, *pprivs, *cprivs; + long id, protoid; + int quotatype, tmpfd, ret; + char *protoname = NULL; + int tflag = 0, pflag = 0, rflag = 0, fmt = -1; + struct quota_handle **handles; + + gettexton(); + + if (argc < 2) + usage(); + + quotatype = USRQUOTA; +#if defined(RPC_SETQUOTA) + while ((ret = getopt(argc, argv, "ugrntVp:F:")) != EOF) { +#else + while ((ret = getopt(argc, argv, "ugtVp:F:")) != EOF) { +#endif + switch (ret) { + case 'p': + protoname = optarg; + pflag++; + break; + case 'g': + quotatype = GRPQUOTA; + break; +#if defined(RPC_SETQUOTA) + case 'n': + case 'r': + rflag++; + break; +#endif + case 'u': + quotatype = USRQUOTA; + break; + case 't': + tflag++; + break; + case 'F': + if ((fmt = name2fmt(optarg)) == QF_ERROR) /* Error? */ + exit(1); + break; + case 'V': + version(); + exit(0); + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (tflag && argc != 0) + usage(); + + handles = create_handle_list(0, NULL, quotatype, fmt, (rflag == 0)); + if (!handles[0]) { + dispose_handle_list(handles); + fputs(_("No filesystems with quota detected.\n"), stderr); + return 0; + } + if (pflag) { + protoid = name2id(protoname, quotatype); + protoprivs = getprivs(protoid, handles); + for (q = protoprivs; q; q = q->dq_next) { + q->dq_dqb.dqb_btime = 0; + q->dq_dqb.dqb_itime = 0; + } + while (argc-- > 0) { + id = name2id(*argv++, quotatype); + curprivs = getprivs(id, handles); + + for (pprivs = protoprivs, cprivs = curprivs; pprivs && cprivs; + pprivs = pprivs->dq_next, cprivs = cprivs->dq_next) { + if (strcmp(pprivs->dq_h->qh_quotadev, cprivs->dq_h->qh_quotadev)) + fprintf(stderr, _("fsname mismatch\n")); + else { + cprivs->dq_dqb.dqb_bsoftlimit = + pprivs->dq_dqb.dqb_bsoftlimit; + cprivs->dq_dqb.dqb_bhardlimit = + pprivs->dq_dqb.dqb_bhardlimit; + cprivs->dq_dqb.dqb_isoftlimit = + pprivs->dq_dqb.dqb_isoftlimit; + cprivs->dq_dqb.dqb_ihardlimit = + pprivs->dq_dqb.dqb_ihardlimit; + } + } + putprivs(curprivs); + } + dispose_handle_list(handles); + warn_new_kernel(fmt); + exit(0); + } + + umask(077); + tmpfd = mkstemp(tmpfil); + fchown(tmpfd, getuid(), getgid()); + if (tflag) { + writetimes(handles, tmpfd); + if (!editprivs(tmpfil) && (readtimes(handles, tmpfd) < 0)) + die(1, _("Failed to parse grace times file.\n")); + } + else { + for (; argc > 0; argc--, argv++) { + id = name2id(*argv, quotatype); + curprivs = getprivs(id, handles); + writeprivs(curprivs, tmpfd, *argv, quotatype); + if (!editprivs(tmpfil) && !readprivs(curprivs, tmpfd)) + putprivs(curprivs); + freeprivs(curprivs); + } + } + dispose_handle_list(handles); + warn_new_kernel(fmt); + + close(tmpfd); + unlink(tmpfil); + return 0; +} diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mntopt.h b/mntopt.h new file mode 100644 index 0000000..c09b35f --- /dev/null +++ b/mntopt.h @@ -0,0 +1,22 @@ +#ifndef _MNTOPT_H +#define _MNTOPT_H + +#include <mntent.h> + +/* filesystem type */ +#define MNTTYPE_EXT2 "ext2" /* 2nd Extended file system */ +#define MNTTYPE_EXT3 "ext3" /* ext2 + journaling */ +#define MNTTYPE_MINIX "minix" /* MINIX file system */ +#define MNTTYPE_UFS "ufs" /* UNIX file system */ +#define MNTTYPE_UDF "udf" /* OSTA UDF file system */ +#define MNTTYPE_REISER "reiser" /* Reiser file system */ +#define MNTTYPE_XFS "xfs" /* SGI XFS file system */ + +/* mount options */ +#define MNTOPT_NOQUOTA "noquota" /* don't enforce quota */ +#define MNTOPT_QUOTA "quota" /* enforce user quota */ +#define MNTOPT_USRQUOTA "usrquota" /* enforce user quota */ +#define MNTOPT_GRPQUOTA "grpquota" /* enforce group quota */ +#define MNTOPT_RSQUASH "rsquash" /* root as ordinary user */ + +#endif diff --git a/po/pl.po b/po/pl.po new file mode 100644 index 0000000..cbd31a6 --- /dev/null +++ b/po/pl.po @@ -0,0 +1,857 @@ +# polish translation for LinuxPL. +# i know that there are many mismatches, please inform me about them +# Copyright (C) 2000 Free Software Foundation, Inc. +# PAUL NIEWIADOMSKI <lilo@free.poltronic.net>, 2000. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: 1\n" +"POT-Creation-Date: 2000-07-19 17:30+0200\n" +"PO-Revision-Date: 2000-07-17 15:22+0200\n" +"Last-Translator: PAUL NIEWIADOMSKI <lilo@free.poltronic.net>\n" +"Language-Team: PL <PL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-2\n" +"Content-Transfer-Encoding: 8-BIT\n" + +#: edquota.c:81 quotaops.c:143 setquota.c:111 +#, c-format +msgid "%s: no such user\n" +msgstr "%s: nie ma takiego u¿ytkownika\n" + +#: edquota.c:86 quotaops.c:148 setquota.c:116 +#, c-format +msgid "%s: no such group\n" +msgstr "%s: nie ma takiej grupy\n" + +#: edquota.c:89 quotaops.c:151 setquota.c:119 +#, c-format +msgid "%d: unknown quota type\n" +msgstr "%d: nieznany typ limitu\n" + +#: edquota.c:162 +msgid "fsname mismatch\n" +msgstr "nieprawid³owa nazwa systemu plików\n" + +#: edquota.c:207 +msgid "Usage:\tedquota [-n] [-u] [-p username] username ...\n" +msgstr "U¿ycie:\tedquota [-n] [-u] [-p u¿ytkownik] u¿ytkownik ...\n" + +#: edquota.c:208 +msgid "\tedquota [-n] -g [-p groupname] groupname ...\n" +msgstr "\tedquota [-n] -g [-p grupa] grupa ...\n" + +#: edquota.c:209 +msgid "\tedquota [-n] [-u] -t\n" +msgstr "" + +#: edquota.c:209 +msgid "\tedquota [-n] -g -t\n" +msgstr "" + +#: edquota.c:212 +msgid "Usage:\tedquota [-u] [-p username] username ...\n" +msgstr "U¿ycie:\tedquota [-u] [-p u¿ytkownik] u¿ytkownik ...\n" + +#: edquota.c:213 +msgid "\tedquota -g [-p groupname] groupname ...\n" +msgstr "\tedquota -g [-p grupa] grupa ...\n" + +#: edquota.c:214 +msgid "\tedquota [-u] -t\n" +msgstr "" + +#: edquota.c:214 +msgid "\tedquota -g -t\n" +msgstr "" + +#: quota.c:81 +#, c-format +msgid "quota %s, with RPC and EXT2_DIRECT options.\n" +msgstr "quota %s, z opcjami RPC i EXT2_DIRECT.\n" + +#: quota.c:83 +#, c-format +msgid "quota %s, with RPC options.\n" +msgstr "quota %s, z opcjami RPC.\n" + +#: quota.c:87 +#, c-format +msgid "quota %s, with EXT2_DIRECT options.\n" +msgstr "quota %s, z opcjami EXT2_DIRECT.\n" + +#: quota.c:89 +#, c-format +msgid "quota %s, without special options.\n" +msgstr "quota %s, bez ¿adnych specjalnych opcji.\n" + +#: quota.c:169 +msgid "Usage: quota [-guqvV]" +msgstr "U¿ycie: quota [-guqvV]" + +#: quota.c:170 +msgid "\tquota [-qv] -u username ..." +msgstr "\tquota [-qv] -u u¿ytkownik ..." + +#: quota.c:171 +msgid "\tquota [-qv] -g groupname ..." +msgstr "\tquota [-qv] -g grupa ..." + +#: quota.c:185 +msgid "(no account)" +msgstr "(brak konta)" + +#: quota.c:190 quota.c:210 +#, c-format +msgid "quota: %s (uid %d): permission denied\n" +msgstr "quota: %s (uid %d): brak prawa dostêpu\n" + +#: quota.c:205 +#, c-format +msgid "quota: %s: unknown user\n" +msgstr "quota: %s: nieznany u¿ytkownik\n" + +#: quota.c:229 +msgid "(no entry)" +msgstr "(brak wpisu)" + +#: quota.c:242 quota.c:272 +#, c-format +msgid "quota: %s (gid %d): permission denied\n" +msgstr "quota: %s (gid %d): brak prawa dostêpu\n" + +#: quota.c:260 +#, c-format +msgid "quota: %s: unknown group\n" +msgstr "quota: %s: nieznana grupa\n" + +#: quota.c:301 +msgid "File limit reached on" +msgstr "Limit plików osi±gniêty na" + +#: quota.c:305 +msgid "In file grace period on" +msgstr "Okres pob³a¿liwo¶ci dla przekroczonego limitu plików na" + +#: quota.c:307 +msgid "Over file quota on" +msgstr "Limit plików przekroczony na" + +#: quota.c:311 +msgid "Block limit reached on" +msgstr "Limit bloków osi±gniêty na" + +#: quota.c:315 +msgid "In block grace period on" +msgstr "Okres pob³a¿liwo¶ci dla przekroczonego limitu bloków na" + +#: quota.c:317 +msgid "Over block quota on" +msgstr "Limit bloków przekroczony na" + +#: quota.c:366 quota.c:400 repquota.c:309 warnquota.c:150 +msgid "none" +msgstr "brak" + +#: quota.c:371 +#, c-format +msgid "Disk quotas for %s %s (%cid %d): %s\n" +msgstr "Limity dyskowe dla %s %s (%cid %d): %s\n" + +#: quota.c:375 +msgid "Filesystem" +msgstr "System plików" + +#: quota.c:376 +msgid "blocks" +msgstr "bloki" + +#: quota.c:377 quota.c:381 +msgid "quota" +msgstr "miêkki" + +#: quota.c:378 quota.c:382 +msgid "limit" +msgstr "twardy" + +#: quota.c:379 quota.c:383 +msgid "grace" +msgstr "pob³." + +#: quota.c:380 +msgid "files" +msgstr "pliki" + +#: quotacheck.c:111 warnquota.c:72 +msgid "Virtual memory exhausted\n" +msgstr "Brak wirtualnej pamiêci\n" + +#: quotacheck.c:146 +#, c-format +msgid "Adding dquot structure type %s for %d\n" +msgstr "Dodajê strukturê dquot typu %s dla %d\n" + +#: quotacheck.c:190 +msgid "" +"Usage:\n" +"\tquotacheck [-g] [-u] [-R] [-vd] -a\n" +msgstr "" +"U¿ycie:\n" +"\tquotacheck [-g] [-u] [-R] [-vd] -a\n" + +#: quotacheck.c:191 +msgid "\tquotacheck [-g] [-u] [-vd] filesys ...\n" +msgstr "\tquotacheck [-g] [-u] [-vd] systemplików ...\n" + +#: quotacheck.c:270 +#, c-format +msgid "%s: not found\n" +msgstr "nie znaleziono: %s\n" + +#: quotacheck.c:276 +#, c-format +msgid "Scanning %s [%s] " +msgstr "Skanujê %s [%s] " + +#: quotacheck.c:299 +msgid "done\n" +msgstr "zrobiono\n" + +#: quotacheck.c:301 +#, c-format +msgid "Checked %d directories and %d files\n" +msgstr "Sprawdzono %d katalogów i %d plików\n" + +#: quotacheck.c:304 +#, c-format +msgid "%s: not a directory\n" +msgstr "%s: nie jest katalogiem\n" + +#: quotacheck.c:319 quotaon.c:156 repquota.c:153 +#, c-format +msgid "%s not found in fstab\n" +msgstr "%s nie zosta³ znaleziony w fstab\n" + +#: quotacheck.c:322 +#, c-format +msgid "" +"Allocated %d bytes memory\n" +"Free'd %d bytes\n" +"Lost %d bytes\n" +msgstr "" +"Zaallokowano %d bajtów pamiêci\n" +"Zwolniono %d bajtów\n" +"Stracono %d bajtów\n" + +#: quotacheck.c:341 +#, c-format +msgid "quotacheck: error while opening %s\n" +msgstr "quotacheck: b³±d podczas otwierania %s\n" + +#: quotacheck.c:345 +msgid "in-use inode map" +msgstr "mapa u¿ywanych i-wêz³ów" + +#: quotacheck.c:346 +msgid "quotacheck: error while allocating inode file bitmap\n" +msgstr "quotacheck: b³±d podczas allokowania bitmapy i-wêz³ów plików\n" + +#: quotacheck.c:350 +msgid "directory inode map" +msgstr "mapa i-wêz³ów katalogów" + +#: quotacheck.c:351 +msgid "quotacheck: error while allocating inode directory bitmap\n" +msgstr "quotacheck: b³±d podczas allokowania bitmapy i-wêz³ów katalogów\n" + +#: quotacheck.c:356 +msgid "quotacheck: error while opening inode scan\n" +msgstr "quotacheck: b³±d podczas otwierania skanu i-wêz³ów\n" + +#: quotacheck.c:361 +msgid "quotacheck: error while starting inode scan\n" +msgstr "quotacheck: b³±d podczas uruchamiania skanu i-wêz³ów\n" + +#: quotacheck.c:368 +#, c-format +msgid "Found i_num %ld\n" +msgstr "Znaleziono i_num %ld\n" + +#: quotacheck.c:384 +msgid "Something weird while scanning\n" +msgstr "Co¶ dziwnego podczas skanowania\n" + +#: quotacheck.c:415 +#, c-format +msgid "Hmm, file `%s/%s' not found\n" +msgstr "Hmm, plik %s/%s nie zosta³ znaleziony\n" + +#: quotacheck.c:416 +msgid "" +"Guess you'd better run fsck first !\n" +"exiting...\n" +msgstr "" +"Ururchom najpierw fsck !\n" +"Koñczê...\n" + +#: quotacheck.c:443 +#, c-format +msgid "\tAdding %s size %d ino %d links %d\n" +msgstr "\tDodajê %s, o rozmiarze %d, iwêze³ %d, po³±czeñ %d\n" + +#: quotacheck.c:454 +msgid "Scanning stored directories from directory stack\n" +msgstr "Skanujê zapisane na stosie katalogi\n" + +#: quotacheck.c:459 +#, c-format +msgid "" +"popd %s\n" +"Entering directory %s\n" +msgstr "" +"popd %s\n" +"Wchodzê do katalogu %s\n" + +#: quotacheck.c:470 +#, c-format +msgid "Leaving %s\n" +msgstr "Opuszczam %s\n" + +#: quotacheck.c:482 +#, c-format +msgid "Adding hardlink for ino %d\n" +msgstr "Dodajê dowi±zanie na i-wêze³ %d\n" + +#: quotacheck.c:528 +#, c-format +msgid "Can't add dquot structure type %s for uid %d\n" +msgstr "Nie mogê dodaæ struktury dquot typu %s dla uid %d\n" + +#: quotacheck.c:558 +#, c-format +msgid "Adding blocks from hardlinks for %s %d\n" +msgstr "Dodajê bloki z dowi±zañ na %s %d\n" + +#: quotacheck.c:622 +#, c-format +msgid "Using quotafile %s\n" +msgstr "Korzystam z pliku limitów %s\n" + +#: quotacheck.c:628 +#, c-format +msgid "Updating in-core %s quotas\n" +msgstr "Aktualizujê wewnêtrzne limity typu %s\n" + +#: quotacheck.c:665 +#, c-format +msgid "%s %d: curinodes: %d curblocks: %d without hardlinks\n" +msgstr "%s %d: akt.iwêz³ów: %d akt.bloków: %d bez dowi±zañ\n" + +#: quotacheck.c:669 +#, c-format +msgid "%s %d: curinodes: %d curblocks: %d with hardlinks\n" +msgstr "%s %d: akt.iwêz³ów: %d akt.bloków: %d z dowi±zaniami\n" + +#: quotaon.c:86 +#, c-format +msgid "Name must be quotaon or quotaoff not %s\n" +msgstr "Nazw± musi byæ quotaon, lub quotaoff, nie %s\n" + +#: quotaon.c:163 +#, c-format +msgid "" +"Usage:\n" +"\t%s [-g] [-u] [-v] -a\n" +msgstr "" +"U¿ycie:\n" +"\t%s [-g] [-u] [-v] -a\n" + +#: quotaon.c:164 +#, c-format +msgid "\t%s [-g] [-u] [-v] filesys ...\n" +msgstr "\t%s [-g] [-u] [-v] systemplików ...\n" + +#: quotaon.c:177 +#, c-format +msgid "%s: %s quotas turned off\n" +msgstr "%s: %s limity wy³±czone\n" + +#: quotaon.c:182 +#, c-format +msgid "quotaon: using %s on " +msgstr "quotaon: u¿ywam %s dla " + +#: quotaon.c:187 +#, c-format +msgid "%s: %s quotas turned on\n" +msgstr "%s: %s limity w³±czone\n" + +#: quotaon.c:199 +msgid "quotaon: set root_squash on" +msgstr "quotaon: w³±czono root_squash" + +#: quotaon.c:205 +#, c-format +msgid "%s: %s root_squash turned off\n" +msgstr "%s: %s wy³±czono root_squash\n" + +#: quotaon.c:207 +#, c-format +msgid "%s: %s root_squash turned on\n" +msgstr "%s: %s w³±czono root_squash\n" + +#: quotaops.c:82 +msgid "day" +msgstr "dzieñ" + +#: quotaops.c:84 repquota.c:314 warnquota.c:155 +#, c-format +msgid "%d days" +msgstr "%d dni" + +#: quotaops.c:89 +msgid "hour" +msgstr "godzina" + +#: quotaops.c:91 +#, c-format +msgid "%d hours" +msgstr "%d godziny" + +#: quotaops.c:96 +msgid "minute" +msgstr "minuta" + +#: quotaops.c:98 +#, c-format +msgid "%d minutes" +msgstr "%d minuty" + +#: quotaops.c:103 +msgid "second" +msgstr "sekunda" + +#: quotaops.c:105 +#, c-format +msgid "%d seconds" +msgstr "%d sekundy" + +#: quotaops.c:124 +#, c-format +msgid "" +"%s: bad units, specify:\n" +" %s, %s, %s, or %s" +msgstr "" +"%s: z³e jednostki, podaj:\n" +" %s, %s, %s, lub %s" + +#: quotaops.c:182 +msgid "edquota: out of memory\n" +msgstr "edquota: brak pamiêci\n" + +#: quotaops.c:191 +msgid "Warning: Quotas are not compiled into this kernel\n" +msgstr "Uwaga: Quota nie jest wkompilowane w to j±dro\n" + +#: quotaops.c:315 +#, c-format +msgid "Disk quotas for %s %s (%cid %d):\n" +msgstr "Limity dla %s %s (%cid %d):\n" + +#: quotaops.c:319 +msgid "" +" Filesystem blocks soft hard inodes " +"soft hard\n" +msgstr "" +" System plików bloki miêkki twardy i-wêz³y " +"miêkki twardy\n" + +#: quotaops.c:332 +#, c-format +msgid "Quotas for %s %s:\n" +msgstr "Limity dla %s %s:\n" + +#: quotaops.c:334 +#, c-format +msgid "%s: %s %d, limits (soft = %d, hard = %d)\n" +msgstr "%s: %s %d, limity (miêkki = %d, twardy = %d)\n" + +#: quotaops.c:335 +msgid "blocks in use:" +msgstr "u¿ywanych bloków:" + +#: quotaops.c:339 +#, c-format +msgid "%s %d, limits (soft = %d, hard = %d)\n" +msgstr "%s %d, limity (miêkki = %d, twardy = %d)\n" + +#: quotaops.c:340 +msgid "\tinodes in use:" +msgstr "\tu¿ywanych iwêz³ów:" + +#: quotaops.c:367 quotaops.c:580 +msgid "Can't re-read temp file!!\n" +msgstr "Nie mogê odczytaæ pliku tymczasowego\n" + +#: quotaops.c:385 quotaops.c:596 +#, c-format +msgid "" +"bad format:\n" +"%s\n" +msgstr "" +"z³y format:\n" +"%s\n" + +#: quotaops.c:421 +#, c-format +msgid "%s: cannot change current block allocation\n" +msgstr "%s: nie mogê zmieniæ aktualnej allokacji bloków\n" + +#: quotaops.c:423 +#, c-format +msgid "%s: cannot change current inode allocation\n" +msgstr "%s: nie mogê zmieniæ aktualnej allokacji iwêz³ów\n" + +#: quotaops.c:434 quotaops.c:608 +#, c-format +msgid "%s: bad format\n" +msgstr "%s: z³y format\n" + +#: quotaops.c:438 quotaops.c:455 quotaops.c:462 quotaops.c:612 +#, c-format +msgid "%s: %s: bad format\n" +msgstr "%s: %s: z³y format\n" + +#: quotaops.c:443 +#, c-format +msgid " blocks in use: %d, limits (soft = %d, hard = %d)" +msgstr " u¿ywanych bloków: %d, limity (miêkki = %d, twardy = %d)" + +#: quotaops.c:446 quotaops.c:620 +#, c-format +msgid "%s:%s: bad format\n" +msgstr "%s:%s: z³y format\n" + +#: quotaops.c:459 +#, c-format +msgid "\tinodes in use: %d, limits (soft = %d, hard = %d)" +msgstr "\tu¿ywanych iwêz³ów: %d, limity (miêkki = %d, twardy = %d)" + +#: quotaops.c:499 +#, c-format +msgid "%s: cannot change current allocation\n" +msgstr "%s: nie mogê zmieniæ aktualnej allokacji\n" + +#: quotaops.c:537 quotaops.c:547 +#, c-format +msgid "Grace period before enforcing soft limits for %ss:\n" +msgstr "Okres pob³a¿liwo¶ci przed wymuszeniem miêkkich limitów dla %s:\n" + +#: quotaops.c:538 quotaops.c:546 +msgid "Time units may be: days, hours, minutes, or seconds\n" +msgstr "Jednostkami czasu mog± byæ: days, hours, minutes, seconds\n" + +#: quotaops.c:539 +msgid " Filesystem Block grace period Inode grace period\n" +msgstr "" +" System plików Pob³a¿liwo¶æ dla bloków Pob³a¿liwo¶æ dla iwêz³ów\n" + +#: quotaops.c:550 +#, c-format +msgid "%s: block grace period: %s, " +msgstr "%s: okres pob³a¿liwo¶ci dla bloków: %s," + +#: quotaops.c:552 +#, c-format +msgid "file grace period: %s\n" +msgstr "okres pob³a¿liwo¶ci dla plików: %s\n" + +#: quotaops.c:617 +#, c-format +msgid " block grace period: %d %s file grace period: %d %s" +msgstr "" +" okres pob³a¿liwo¶ci dla bloków: %d %s okres pob³a¿liwo¶ci dla plików: %d %s" + +#: quotastats.c:35 +#, c-format +msgid "Number of dquot lookups: %ld\n" +msgstr "Liczba poszukiwañ dquot: %ld\n" + +#: quotastats.c:36 +#, c-format +msgid "Number of dquot drops: %ld\n" +msgstr "Liczba zrzutów dquot: %ld\n" + +#: quotastats.c:37 +#, c-format +msgid "Number of still active inodes with quota : %ld\n" +msgstr "Liczba aktywnych iwêz³ów dla limitu: %ld\n" + +#: quotastats.c:39 +#, c-format +msgid "Number of dquot reads: %ld\n" +msgstr "Liczba odczytów dquot: %ld\n" + +#: quotastats.c:40 +#, c-format +msgid "Number of dquot writes: %ld\n" +msgstr "Liczba zapisów dquot: %ld\n" + +#: quotastats.c:41 +#, c-format +msgid "Number of quotafile syncs: %ld\n" +msgstr "Liczba synchronizacji pliku limitów: %ld\n" + +#: quotastats.c:42 +#, c-format +msgid "Number of dquot cache hits: %ld\n" +msgstr "Liczba trafieñ cache'u dquot: %ld\n" + +#: quotastats.c:43 +#, c-format +msgid "Number of allocated dquots: %ld\n" +msgstr "Liczba zaallokowanych struktur dquot: %ld\n" + +#: quotastats.c:44 +#, c-format +msgid "Number of free dquots: %ld\n" +msgstr "Liczba wolnych dquot: %ld\n" + +#: quotastats.c:45 +#, c-format +msgid "Number of in use dquot entries (user/group): %ld\n" +msgstr "Liczba u¿ywanych wpisów dquot (u¿ytkownik/grupa): %ld\n" + +#: repquota.c:159 +#, c-format +msgid "" +"Usage:\n" +"\t%s\n" +"\t%s\n" +msgstr "" +"U¿ycie:\n" +"\t%s\n" +"\t%s\n" + +#: repquota.c:160 +#, fuzzy +msgid "repquota [-v] [-g] [-u] -a" +msgstr "repquota [-v] [-g] [-u] systemplików ..." + +#: repquota.c:161 +msgid "repquota [-v] [-g] [-u] filesys ..." +msgstr "repquota [-v] [-g] [-u] systemplików ..." + +#: repquota.c:181 +msgid "*** Warning: Quotas are not compiled into this kernel\n" +msgstr "*** Uwaga: Quota nie s± wkompilowane w to j±dro\n" + +#: repquota.c:186 +#, c-format +msgid "*** Report for %s quotas on %s (%s)\n" +msgstr "*** Raport dla %s limitów na %s (%s)\n" + +#: repquota.c:203 +msgid " Block limits File limits\n" +msgstr " Limity bloków Limity plików\n" + +#: repquota.c:204 +msgid "" +"User used soft hard grace used soft hard grace\n" +msgstr "" +"U¿ytkownik u¿yw. miê. twa. pob. u¿yw. miê. twa. pob.\n" + +#: repquota.c:279 +msgid "out of memory for fileusage structures\n" +msgstr "brak p±miêci dla struktury wykorzystania systemu plików\n" + +#: rquota_svc.c:103 rquota_svc.c:182 +msgid "unable to free arguments" +msgstr "nie mogê usun±æ argumentów" + +#: rquota_svc.c:202 +msgid "cannot create udp service." +msgstr "nie mogê stworzyæ us³ugi udp." + +#: rquota_svc.c:206 +msgid "unable to register (RQUOTAPROG, RQUOTAVERS, udp)." +msgstr "nie mogê zarejestrowaæ (RQUOTAPROG, RQUOTAVERS, udp)." + +#: rquota_svc.c:210 +msgid "unable to register (RQUOTAPROG, EXT_RQUOTAVERS, udp)." +msgstr "nie mogê zarejestrowaæ (RQUOTAPROG, EXT_RQUOTAVERS, udp)." + +#: rquota_svc.c:216 +msgid "cannot create tcp service." +msgstr "nie mogê stworzyæ us³ugi tcp." + +#: rquota_svc.c:220 +msgid "unable to register (RQUOTAPROG, RQUOTAVERS, tcp)." +msgstr "nie mogê zarejestrowaæ (RQUOTAPROG, RQUOTAVERS, tcp)." + +#: rquota_svc.c:224 +msgid "unable to register (RQUOTAPROG, EXT_RQUOTAVERS, tcp)." +msgstr "nie mogê zarejestrowaæ (RQUOTAPROG, EXT_RQOUTAVERS, tcp)." + +#: rquota_svc.c:230 +msgid "svc_run returned" +msgstr "swc_run zwróci³o" + +#: set_limits_example.c:17 +#, c-format +msgid "copy_user_quota_limits: Failed to set userquota for uid %ld : %s\n" +msgstr "" +"copy_user_quota_limits: nie mogê ustawiæ limitów u¿ytkownika dla uid %ld : " +"%s\n" + +#: set_limits_example.c:23 +#, c-format +msgid "copy_user_quota_limits: Failed to get userquota for uid %ld : %s\n" +msgstr "" +"copy_user_quota_limits: nie mogê pobraæ limitów u¿ytkownika dla uid %ld : " +"%s\n" + +#: set_limits_example.c:38 +#, c-format +msgid "copy_group_quota_limits: Failed to set groupquota for uid %ld : %s\n" +msgstr "" +"copy_group_quota_limits: nie mogê ustawiæ limitów grupy dla uid %ld : %s\n" + +#: set_limits_example.c:44 +#, c-format +msgid "copy_group_quota_limits: Failed to get groupquota for uid %ld : %s\n" +msgstr "" +"copy_group_quota_limits: nie mogê odczytaæ limitór grupy dla uid %ld : %s\n" + +#: setquota.c:74 +msgid "" +"Usage:\n" +"\tsetquota [-u|-g] [-n] <username|groupname> <filesystem>\n" +"\t\t<block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit>\n" +"\tsetquota [-u|-g] [-n] <-p protousername|protogroupname> " +"<username|groupname> <filesystem>\n" +msgstr "" +"U¿ycie:\n" +"\tsetquota [-u|-g] [-n] <u¿ytkownik|grupa> <systemplików>\n" +"\t\t<bloki-miêkki> <bloki-twardy> <iwêz³umiêkki> <iwêz³ytwary>\n" +"\tsetquota [-u|-g] [-n] <-p u_prototyp|g_prototyp> <u¿ytkownik|grupa> " +"<systemplików>\n" + +#: setquota.c:79 +msgid "" +"Usage:\n" +"\tsetquota [-u|-g] <username|groupname> <filesystem>\n" +"\t\t<block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit>\n" +"\tsetquota [-u|-g] <-p protousername|protogroupname> <username|groupname> " +"<filesystem>\n" +msgstr "" +"U¿ycie:\n" +"\tsetquota [-u|-g] <u¿ytkownik|grupa> <systemplików>\n" +"\t\t<bloki-miêkki> <bloki-twardy> <iwêz³y-miêkki> <iwêz³y-twardy>\n" +"\tsetquota [-u|-g] <-p u_prototyp|g_prototyp> <u¿ytkownik|grupa> " +"<systemplików>\n" + +#: setquota.c:152 +msgid "setquota: permission denied\n" +msgstr "setquota: brak prawa dostêpu\n" + +#: setquota.c:180 +#, c-format +msgid "Unknown option -%c\n" +msgstr "Nieznana opcja -%c\n" + +#: setquota.c:193 +#, c-format +msgid "Unknown protoname %s for quotatype %s\n" +msgstr "Nieznany prototyp %s dla limity typu %s\n" + +#: setquota.c:213 setquota.c:231 +#, c-format +msgid "File system %s not found\n" +msgstr "Nie znaleziono system plików %s\n" + +#: setquota.c:252 +msgid "Invalid number: block-soft\n" +msgstr "Nieprawid³owa liczba: bloki-miêkki\n" + +#: setquota.c:260 +msgid "Invalid number: block-hard\n" +msgstr "Nieprawid³owa liczba: bloki-twardy\n" + +#: setquota.c:268 +msgid "Invalid number: inode-soft\n" +msgstr "Nieprawid³owa liczba: iwêz³y-miêkki\n" + +#: setquota.c:276 +msgid "Invalid number: inode-hard\n" +msgstr "Nieprawid³owa liczba: iwêz³y-twardy\n" + +#: setquota.c:293 +msgid "File system not found\n" +msgstr "Nie znaleziono system plików\n" + +#: warnquota.c:177 +msgid "/usr/lib/sendmail -t" +msgstr "" + +#: warnquota.c:178 warnquota.c:179 +msgid "support@localhost" +msgstr "" + +#: warnquota.c:180 +msgid "Disk Quota usage on system" +msgstr "Wykorzystanie limitów dyskowych" + +#: warnquota.c:182 +msgid "root" +msgstr "" + +#: warnquota.c:184 +msgid "" +"Hi,\n" +"\n" +"We noticed that you are in violation with the quotasystem\n" +"used on this system. We have found the following violations:\n" +msgstr "" +"Cze¶æ!\n" +"Zauwa¿yli¶my naruszenie zasad systemu limitowania przestrzeni dyskowej,\n" +"u¿ywanego na tym systemie. Znale¼li¶my nastêpuj±ce naruszenia:\n" + +#: warnquota.c:191 +msgid "" +"\n" +" Block limits File limits\n" +msgstr "" +"\n" +" Limity bloków Limity plików\n" + +#: warnquota.c:192 +msgid "" +"Filesystem used soft hard grace used soft hard grace\n" +msgstr "" +"System plików u¿yw. miêkkie twa. pob³. u¿yw. miê. twa. pob³.\n" + +#: warnquota.c:217 +msgid "" +"\n" +"We hope that you will cleanup before your grace period expires.\n" +"\n" +"Basically, this means that the system thinks you are using more disk space\n" +"on the above partition(s) than you are allowed. If you do not delete files\n" +"and get below your quota before the grace period expires, the system will\n" +"prevent you from creating new files.\n" +"\n" +"For additional assistance, please contact us at support@localhost or via\n" +"phone at (xxx) xxx-xxxx or (xxx) xxx-xxxx.\n" +msgstr "" +"\n" +"Mamy nadziejê, ¿e posprz±tasz przed up³yniêciem okresu pob³a¿liwo¶ci.\n" +"\n" +"Oznancza to, i¿ system uwa¿a, ¿e u¿ywasz, na podanych systemach plików,\n" +"wiêcej powierzchni, ni¿ jeste¶ upowa¿niony. Je¿eli nie posprz±tasz tak, aby\n" +"znale¼æ siê poni¿ej limitów przed up³yniêciem okresu pob³a¿liwo¶ci, system\n" +"zabroni Ci tworzyæ nowe pliki.\n" +"\n" +"Je¿eli chcesz dowiedzieæ siê wiêcej skontaktuj siê z nami: " +"support@localhost\n" @@ -0,0 +1,15 @@ +#include "pot.h" +#include <locale.h> + +/************************************************************************* + * if you want to turn off gettext without changing sources edit pot.h + *************************************************************************/ + +void gettexton(void) +{ +#ifdef __GETTEXT__ + setlocale(LC_ALL, ""); + bindtextdomain("quota", "/usr/share/locale"); + textdomain("quota"); +#endif +} @@ -0,0 +1,24 @@ +#ifndef _POT_H +#define _POT_H + +#define __GETTEXT__ +/*************************************************************************** + * if you want to turn off gettext without changing sources + * undefine __GETTEXT__ + ***************************************************************************/ + +#ifdef __GETTEXT__ + +#include <libintl.h> + +#define _(x) gettext((x)) + +void gettexton(void); + +#else + +#define _(x) (x) + +#endif + +#endif @@ -0,0 +1,45 @@ +.TH QUOT 8 +.SH NAME +quot \- summarize filesystem ownership +.SH SYNOPSIS +.nf +\f3quot\f1 [ \f3\-acfv\f1 ] [ filesystem... ] +.fi +.SH DESCRIPTION +.IR quot +displays the number of kilobytes in the named +.I filesystem +currently owned by each user. +.SH OPTIONS +.TP +.B \-a +Generate a report for all mounted filesystems giving the number of +kilobytes used by each user. +.TP +.B \-c +Display three columns giving file size in kilobytes, number of +files of that size, and cumulative total of kilobytes +in that size or smaller file. +The last row is used as an overflow +bucket and is the total of all files greater than 500 kilobytes. +.TP +.B \-f +Display count of kilobytes and number of files owned by each user. +.TP +.B \-v +Display three columns containing the number of kilobytes not accessed in +the last 30, 60, and 90 days. +.SH FILES +.PD 0 +.TP 20 +/etc/mtab +mounted filesystems +.TP +/etc/passwd +to get user names +.PD +.SH "SEE ALSO" +du(1), +ls(1). +.SH BUGS +Currently, only the XFS filesystem type is supported. @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. [SGI] + * All rights reserved. + * + * [Extensions to support XFS are copyright SGI] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $" +#ident "$Copyright: (c) 2000, 2001 Silicon Graphics, Inc. $" +#ident "$Copyright: All rights reserved. $" + +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <time.h> +#include <utmp.h> +#include <pwd.h> + +#include "pot.h" +#include "quot.h" +#include "common.h" +#include "mntopt.h" +#include "bylabel.h" + +#define TSIZE 500 +__uint64_t sizes[TSIZE]; +__uint64_t overflow; + +static int fflag; +static int cflag; +static int vflag; +static int aflag; +static char *progname; +static time_t now; + +static void mounttable(char *); +static char *username(uid_t); +static void report(void); + +static void usage(void) +{ + fprintf(stderr, _("Usage: %s [-acfvV] [filesystem...]\n"), progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int c; + + now = time(0); + progname = basename(argv[0]); + + while ((c = getopt(argc, argv, "acfvV")) != EOF) { + switch (c) { + case 'a': + aflag++; + break; + case 'c': + cflag++; + break; + case 'f': + fflag++; + break; + case 'v': + vflag++; + break; + case 'V': + version(); + exit(0); + default: + usage(); + } + } + if ((aflag && optind != argc) || (!aflag && optind == argc)) + usage(); + if (aflag) + mounttable(NULL); + else { + while (optind < argc) + mounttable(argv[optind++]); + } + return 0; +} + +static void mounttable(char *entry) +{ + struct mntent *mntp; + const char *dev; + FILE *mtab; + int doit; + + if ((mtab = setmntent(MOUNTED, "r")) == NULL) { + fprintf(stderr, _("%s: no " MOUNTED " file\n"), progname); + exit(1); + } + while ((mntp = getmntent(mtab)) != NULL) { + doit = 0; + dev = get_device_name(mntp->mnt_fsname); + if ((entry != NULL) && + (strcmp(entry, mntp->mnt_dir) != 0) && (strcmp(entry, dev) != 0)) { + free((char *)dev); + continue; + } + + /* Currently, only XFS is implemented... */ + if (strcmp(mntp->mnt_type, MNTTYPE_XFS) == 0) { + checkXFS(dev, mntp->mnt_dir); + doit = 1; + } + /* ...additional filesystems types here. */ + free((char *)dev); + + if (doit) + report(); + if (entry != NULL) { + entry = NULL; /* found, bail out */ + break; + } + } + if (entry != NULL) + fprintf(stderr, _("%s: cannot locate block device for %s\n"), progname, entry); + endmntent(mtab); +} + +static int qcmp(du_t * p1, du_t * p2) +{ + if (p1->blocks > p2->blocks) + return -1; + if (p1->blocks < p2->blocks) + return 1; + if (p1->uid > p2->uid) + return 1; + else if (p1->uid < p2->uid) + return -1; + return 0; +} + +static void report(void) +{ + int i; + du_t *dp; + + if (cflag) { + __uint64_t t = 0; + + for (i = 0; i < TSIZE - 1; i++) + if (sizes[i] > 0) { + t += sizes[i] * i; + printf(_("%d\t%llu\t%llu\n"), i, sizes[i], t); + } + printf(_("%d\t%llu\t%llu\n"), TSIZE - 1, sizes[TSIZE - 1], overflow + t); + return; + } + qsort(du, ndu, sizeof(du[0]), (int (*)(const void *, const void *))qcmp); + for (dp = du; dp < &du[ndu]; dp++) { + char *cp; + + if (dp->blocks == 0) + return; + printf(_("%8llu "), dp->blocks); + if (fflag) + printf(_("%8llu "), dp->nfiles); + if ((cp = username(dp->uid)) != NULL) + printf(_("%-8.8s"), cp); + else + printf(_("#%-7d"), dp->uid); + if (vflag) + printf(_(" %8llu %8llu %8llu"), + dp->blocks30, dp->blocks60, dp->blocks90); + putchar('\n'); + } +} + +static char *username(uid_t uid) +{ + register struct passwd *pw; + register uidcache_t *ncp; + static uidcache_t nc[NUID]; + static int entriesleft = NUID; + + /* check cache for name first */ + ncp = &nc[uid & UIDMASK]; + if (ncp->uid == uid && ncp->name[0]) + return ncp->name; + if (entriesleft) { + /* + * If we haven't gone through the passwd file then + * fill the cache while seaching for name. + * This lets us run through passwd serially. + */ + if (entriesleft == NUID) + setpwent(); + while (((pw = getpwent()) != NULL) && entriesleft) { + entriesleft--; + ncp = &nc[pw->pw_uid & UIDMASK]; + if (ncp->name[0] == '\0' || pw->pw_uid == uid) { + strncpy(ncp->name, pw->pw_name, UT_NAMESIZE); + ncp->uid = uid; + } + if (pw->pw_uid == uid) + return ncp->name; + } + endpwent(); + entriesleft = 0; + ncp = &nc[uid & UIDMASK]; + } + + /* Not cached - do it the slow way & insert into cache */ + if ((pw = getpwuid(uid)) == NULL) + return NULL; + strncpy(ncp->name, pw->pw_name, UT_NAMESIZE); + ncp->uid = uid; + return ncp->name; +} + +/* + * === XFS specific code follows === + */ + +static void acctXFS(xfs_bstat_t * p) +{ + register du_t *dp; + du_t **hp; + __uint64_t size; + + if ((p->bs_mode & S_IFMT) == 0) + return; + size = howmany((p->bs_blocks * p->bs_blksize), 0x400ULL); + + if (cflag) { + if (!(S_ISDIR(p->bs_mode) || S_ISREG(p->bs_mode))) + return; + if (size >= TSIZE) { + overflow += size; + size = TSIZE - 1; + } + sizes[(int)size]++; + return; + } + hp = &duhash[p->bs_uid % DUHASH]; + for (dp = *hp; dp; dp = dp->next) + if (dp->uid == p->bs_uid) + break; + if (dp == 0) { + if (ndu >= NDU) + return; + dp = &du[ndu++]; + dp->next = *hp; + *hp = dp; + dp->uid = p->bs_uid; + dp->nfiles = 0; + dp->blocks = 0; + dp->blocks30 = 0; + dp->blocks60 = 0; + dp->blocks90 = 0; + } + dp->blocks += size; + + if (now - p->bs_atime.tv_sec > 30 * SEC24HR) + dp->blocks30 += size; + if (now - p->bs_atime.tv_sec > 60 * SEC24HR) + dp->blocks60 += size; + if (now - p->bs_atime.tv_sec > 90 * SEC24HR) + dp->blocks90 += size; + dp->nfiles++; +} + +static void checkXFS(const char *file, char *fsdir) +{ + xfs_fsop_bulkreq_t bulkreq; + __s64 last = 0; + __s32 count; + int i; + int sts; + int fsfd; + du_t **dp; + xfs_bstat_t *buf; + + /* + * Initialize tables between checks; because of the qsort + * in report() the hash tables must be rebuilt each time. + */ + for (sts = 0; sts < TSIZE; sts++) + sizes[sts] = 0; + overflow = 0; + for (dp = duhash; dp < &duhash[DUHASH]; dp++) + *dp = 0; + ndu = 0; + + fsfd = open(fsdir, O_RDONLY); + if (fsfd < 0) { + fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, fsdir, strerror(errno)); + exit(1); + } + printf(_("%s (%s):\n"), file, fsdir); + sync(); + + buf = (xfs_bstat_t *) smalloc(NBSTAT * sizeof(xfs_bstat_t)); + memset(buf, 0, NBSTAT * sizeof(xfs_bstat_t)); + + bulkreq.lastip = &last; + bulkreq.icount = NBSTAT; + bulkreq.ubuffer = buf; + bulkreq.ocount = &count; + + while ((sts = ioctl(fsfd, XFS_IOC_FSBULKSTAT, &bulkreq)) == 0) { + if (count == 0) + break; + for (i = 0; i < count; i++) + acctXFS(&buf[i]); + } + if (sts < 0) { + fprintf(stderr, _("%s: XFS_IOC_FSBULKSTAT ioctl failed: %s\n"), + progname, strerror(errno)); + exit(1); + } + free(buf); + close(fsfd); +} @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. [SGI] + * All rights reserved. + * + * [Extensions to support XFS are copyright SGI] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define SEC24HR (60*60*24) /* seconds per day */ + +typedef struct { + uid_t uid; + char name[UT_NAMESIZE + 1]; +} uidcache_t; + +typedef struct du { + struct du *next; + __uint64_t blocks; + __uint64_t blocks30; + __uint64_t blocks60; + __uint64_t blocks90; + __uint64_t nfiles; + uid_t uid; +} du_t; + +#define NDU 60000 +#define DUHASH 8209 +static du_t du[NDU]; +static du_t *duhash[DUHASH]; +static int ndu; + +#define NUID 256 +#define UIDMASK (NUID-1) + +/* + * === Start XFS specific types and definitions === + */ +#include <linux/types.h> + +/* Structures returned from ioctl XFS_IOC_FSBULKSTAT */ +typedef struct xfs_bstime { + time_t tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} xfs_bstime_t; + +typedef struct xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + xfs_bstime_t bs_atime; /* access time */ + xfs_bstime_t bs_mtime; /* modify time */ + xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid; /* project id */ + unsigned char bs_pad[14]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} xfs_bstat_t; + +/* The user-level BulkStat Request interface structure. */ +typedef struct xfs_fsop_bulkreq { + __u64 *lastip; /* last inode # pointer */ + __s32 icount; /* count of entries in buffer */ + void *ubuffer; /* user buffer for inode desc. */ + __s32 *ocount; /* output count pointer */ +} xfs_fsop_bulkreq_t; + +#ifndef XFS_IOC_FSBULKSTAT +#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) +#endif + +#define NBSTAT 4069 /* XFS bulkstat inodes */ +static void checkXFS(const char *file, char *fsdir); + +/* + * === End of XFS specific types and definitions === + */ @@ -0,0 +1,100 @@ +.TH QUOTA 1 +.SH NAME +quota \- display disk usage and limits +.SH SYNOPSIS +quota [ +.B -n +] [ +.B -guv | q +] +.br +quota [ +.B -n +] [ +.B -uv | q +] user +.br +quota [ +.B -n +] [ +.B -gv | q +] group +.SH DESCRIPTION +.B Quota +displays users' disk usage and limits. +By default only the user quotas are printed. +.PP +.B Quota +reports the quotas of all the filesystems listed in +.B /etc/mtab. +For filesystems that are NFS-mounted a call to the rpc.rquotad on +the server machine is performed to get the information. +.SH OPTIONS +.TP +.B \-n +Print info on numeric arguments e.g. uids and gids instead of users and groups +.TP +.B \-g +Print group quotas for the group +of which the user is a member. +The optional +.TP +.B \-u +flag is equivalent to the default. +.TP +.B \-v +will display quotas on filesystems +where no storage is allocated. +.TP +.B -q +Print a more terse message, +containing only information +on filesystems where usage is over quota. +.LP +Specifying both +.B \-g +and +.B \-u +displays both the user quotas and the group quotas (for +the user). +.LP +Only the super-user may use the +.B \-u +flag and the optional +.B user +argument to view the limits of other users. +Non-super-users can use the the +.B \-g +flag and optional +.B group +argument to view only the limits of groups of which they are members. +.LP +The +.B \-q +flag takes precedence over the +.B \-v +flag. +.SH DIAGNOSTICS +If +.B quota +exits with a non-zero status, one or more filesystems +are over quota. +.SH FILES +.PD 0 +.TP 20 +.B aquota.user or aquota.group +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP 20 +.B quota.user or quota.group +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/mtab +default filesystems +.PD +.SH SEE ALSO +.BR quotactl (2), +.BR fstab (5), +.BR edquota (8), +.BR quotacheck (8), +.BR quotaon (8), +.BR repquota (8) @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. All + * rights reserved. + * + * This code is derived from software contributed to Berkeley by Robert Elz at + * The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $" +#ident "$Copyright: All rights reserved. $" +#ident "$Id: quota.c,v 1.1 2001/03/23 12:03:26 jkar8572 Exp $" + +/* + * Disk quota reporting program. + */ +#include <sys/types.h> +#include <getopt.h> +#include <stdio.h> +#include <pwd.h> +#include <grp.h> +#include <time.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#ifdef RPC +#include <rpc/rpc.h> +#include "rquota.h" +#endif + +#include "quota.h" +#include "quotaops.h" +#include "quotasys.h" +#include "pot.h" +#include "common.h" + +int qflag, vflag, fmt = -1; + +void usage(void); +void showquotas(int type, qid_t id); +void heading(int type, qid_t id, char *name, char *tag); + +int main(int argc, char **argv) +{ + int ngroups; + gid_t gidset[NGROUPS]; + int i, ret, gflag = 0, uflag = 0; + + gettexton(); + + while ((ret = getopt(argc, argv, "guqvVF:")) != EOF) { + switch (ret) { + case 'g': + gflag++; + break; + case 'u': + uflag++; + break; + case 'q': + qflag++; + break; + case 'v': + vflag++; + break; + case 'F': + if ((fmt = name2fmt(optarg)) == QF_ERROR) /* Error? */ + exit(1); + break; + case 'V': + version(); + exit(0); + default: + usage(); + } + } + argc -= optind; + argv += optind; + + warn_new_kernel(fmt); + if (!uflag && !gflag) + uflag++; + + if (argc == 0) { + if (uflag) + showquotas(USRQUOTA, getuid()); + if (gflag) { + ngroups = getgroups(NGROUPS, gidset); + if (ngroups < 0) + die(1, "quota: getgroups(): %s\n", strerror(errno)); + for (i = 0; i < ngroups; i++) + showquotas(GRPQUOTA, gidset[i]); + } + exit(0); + } + + if (uflag && gflag) + usage(); + + if (uflag) + for (; argc > 0; argc--, argv++) + showquotas(USRQUOTA, user2uid(*argv)); + else if (gflag) + for (; argc > 0; argc--, argv++) + showquotas(GRPQUOTA, group2gid(*argv)); + return 0; +} + +void usage(void) +{ + fprintf(stderr, "%s\n%s\n%s\n", + _("Usage: quota [-guqvV] [-F quotaformat]"), + _("\tquota [-qv] [-F quotaformat] -u username ..."), + _("\tquota [-qv] [-F quotaformat] -g groupname ...")); + fprintf(stderr, _("Bugs to: %s\n"), MY_EMAIL); + exit(1); +} + +void showquotas(int type, qid_t id) +{ + struct dquot *qlist, *q; + char *msgi, *msgb; + char timebuf[MAXTIMELEN]; + char name[MAXNAMELEN]; + struct quota_handle **handles; + int lines = 0; + time_t now; + + time(&now); + id2name(id, type, name); + handles = create_handle_list(0, NULL, type, fmt, 0); + qlist = getprivs(id, handles); + for (q = qlist; q; q = q->dq_next) { + if (!vflag && !q->dq_dqb.dqb_isoftlimit && !q->dq_dqb.dqb_ihardlimit + && !q->dq_dqb.dqb_bsoftlimit && !q->dq_dqb.dqb_bhardlimit) + continue; + msgi = NULL; + if (q->dq_dqb.dqb_ihardlimit && q->dq_dqb.dqb_curinodes >= q->dq_dqb.dqb_ihardlimit) + msgi = _("File limit reached on"); + else if (q->dq_dqb.dqb_isoftlimit + && q->dq_dqb.dqb_curinodes >= q->dq_dqb.dqb_isoftlimit) { + if (q->dq_dqb.dqb_itime > now) + msgi = _("In file grace period on"); + else + msgi = _("Over file quota on"); + } + msgb = NULL; + if (q->dq_dqb.dqb_bhardlimit + && toqb(q->dq_dqb.dqb_curspace) >= q->dq_dqb.dqb_bhardlimit) + msgb = _("Block limit reached on"); + else if (q->dq_dqb.dqb_bsoftlimit + && toqb(q->dq_dqb.dqb_curspace) >= q->dq_dqb.dqb_bsoftlimit) { + if (q->dq_dqb.dqb_btime > now) + msgb = _("In block grace period on"); + else + msgb = _("Over block quota on"); + } + if (qflag) { + if ((msgi || msgb) && !lines++) + heading(type, id, name, ""); + if (msgi) + printf("\t%s %s\n", msgi, q->dq_h->qh_quotadev); + if (msgb) + printf("\t%s %s\n", msgb, q->dq_h->qh_quotadev); + continue; + } + if (vflag || q->dq_dqb.dqb_curspace || q->dq_dqb.dqb_curinodes) { + if (!lines++) + heading(type, id, name, ""); + if (strlen(q->dq_h->qh_quotadev) > 15) + printf("%s\n%15s", q->dq_h->qh_quotadev, ""); + else + printf("%15s", q->dq_h->qh_quotadev); + if (msgb) + difftime2str(q->dq_dqb.dqb_btime, timebuf); + printf("%8Lu%c%7Lu%8Lu%8s", (long long)toqb(q->dq_dqb.dqb_curspace), + msgb ? '*' : ' ', (long long)q->dq_dqb.dqb_bsoftlimit, + (long long)q->dq_dqb.dqb_bhardlimit, msgb ? timebuf : ""); + if (msgi) + difftime2str(q->dq_dqb.dqb_itime, timebuf); + printf("%8Lu%c%7Lu%8Lu%8s\n", (long long)q->dq_dqb.dqb_curinodes, + msgi ? '*' : ' ', (long long)q->dq_dqb.dqb_isoftlimit, + (long long)q->dq_dqb.dqb_ihardlimit, msgi ? timebuf : ""); + continue; + } + } + if (!qflag && !lines) + heading(type, id, name, _("none")); + freeprivs(qlist); + dispose_handle_list(handles); +} + +void heading(int type, qid_t id, char *name, char *tag) +{ + printf(_("Disk quotas for %s %s (%cid %d): %s\n"), type2name(type), + name, *type2name(type), id, tag); + if (!qflag && !tag[0]) { + printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n", _("Filesystem"), + _("blocks"), _("quota"), _("limit"), _("grace"), + _("files"), _("quota"), _("limit"), _("grace")); + } +} @@ -0,0 +1,83 @@ +#ifndef _QUOTA_H +#define _QUOTA_H + +#include <sys/types.h> + +typedef u_int32_t qid_t; /* Type in which we store ids in memory */ +typedef u_int64_t qsize_t; /* Type in which we store size limitations */ + +#define MAXQUOTAS 2 +#define USRQUOTA 0 /* element used for user quotas */ +#define GRPQUOTA 1 /* element used for group quotas */ + +/* + * Definitions for the default names of the quotas files. + */ +#define INITQFNAMES { \ + "user", /* USRQUOTA */ \ + "group", /* GRPQUOTA */ \ + "undefined", \ +} + +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +/* Size of blocks in which are counted size limits in generic utility parts */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +/* Conversion routines from and to quota blocks */ +#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) +#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) + +/* + * Command definitions for the 'quotactl' system call. + * The commands are broken into a main command defined below + * and a subcommand that is used to convey the type of + * quota that is being manipulated (see above). + */ +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#define Q_QUOTAON 0x0100 /* enable quotas */ +#define Q_QUOTAOFF 0x0200 /* disable quotas */ +#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ +#define Q_GETSTATS 0x1100 /* get collected stats */ + +struct dqstats { + u_int32_t lookups; + u_int32_t drops; + u_int32_t reads; + u_int32_t writes; + u_int32_t cache_hits; + u_int32_t allocated_dquots; + u_int32_t free_dquots; + u_int32_t syncs; + u_int32_t version; +}; + +/* Ioctl for getting quota size */ +#include <sys/ioctl.h> +#ifndef FIOQSIZE + #if defined(__alpha__) || defined(__powerpc__) || defined(__sh__) || defined(__sparc__) || defined(__sparc64__) + #define FIOQSIZE _IOR('f', 128, loff_t) + #elif defined(__arm__) || defined(__mc68000__) || defined(__s390__) + #define FIOQSIZE 0x545E + #elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__ia64__) + #define FIOQSIZE 0x5460 + #elif defined(__mips__) || defined(__mips64__) + #define FIOQSIZE 0x6667 + #endif +#endif + + +long quotactl __P((int, const char *, qid_t, caddr_t)); + +#endif /* _QUOTA_ */ diff --git a/quotacheck.8 b/quotacheck.8 new file mode 100644 index 0000000..7270040 --- /dev/null +++ b/quotacheck.8 @@ -0,0 +1,94 @@ +.TH QUOTACHECK 8 +.SH NAME +quotacheck \- scan a filesystem for disk usages +.SH SYNOPSIS +.B quotacheck +[-g] [-u] [-v] -a +.br +.B quotacheck +[-g] [-u] [-v] filesys ... +.SH DESCRIPTION +.I Quotacheck +performs a filesystems scan for usage of files and directories, used +by either user or group. +XFS filesystems are ignored by +.IR quotacheck , +since the XFS quota system is journaled and therefore inherently consistent. +.PP +The output is the quota file for the corresponding filesystem. +By default the names for these files are: +.br +\- A user scan: +.I quota.user +.br +\- A group scan: +.I quota.group +.PP +The resulting file consists of a +.I struct dqblk +for each possible id up to the highest existing uid or gid and contains the +values for the disk file and block usage and possibly excess time for these +values. ( for definitions of +.I struct dqblk +see +.I \<linux/quota.h\> +) +.PP +.I Quotacheck +should be run each time the system boots and mounts non-valid filesystems. +This is most likely to happen after a system crash. +.PP +The speed of the scan decreases with the number of directories increasing. +The time needed doubles when disk usage is doubled as well. A 100 MB partition +used for 94% is scanned in 1 minute, the same partition used for 50% is +done in 25 seconds. +.SH OPTIONS +.TP +.B \-v +This way the program will give some useful information about what it is +doing, plus some fancy stuff. +.TP +.B \-d +This means debug. It will result in a lot of information which can be used +in debugging the program. The output is very verbose and the scan +will not be fast. +.TP +.B \-u +This flag tells the program to scan the disk and to count the files and +directories used by a certain uid. This is the default action. +.TP +.B \-g +This flag forces the program to count the files and directories +used by a certain gid. +.TP +.B \-a +Check all of the quotas for the filesystems mentioned in /etc/mtab. Both +user and group quotas are checked as indicated by the /etc/mtab options. +.TP +.B \-R +When used in conjunction with \fP\-a\fR, all filesystems except the root +filesystem are checked for quotas. +.SH NOTE +.I Quotacheck +should only be run as Super User. Non-privilidged users are presumably not allowed +to read all the directories on the given filesystem. +.SH "SEE ALSO" +quota(1), quotactl(2), fstab(5), quotaon(8), quotaoff(8), edquota(8), +repquota(8), fsck(8) +.SH FILES +.PD 0 +.TP 20 +.B aquota.user or aquota.group +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP 20 +.B quota.user or quota.group +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/mtab +default filesystems +.PD +.SH "AUTHOR" +Edvard Tuinder \<ed@elm.net\> +.br +Marco van Wieringen \<mvw@planets.elm.net\> + diff --git a/quotacheck.c b/quotacheck.c new file mode 100644 index 0000000..5ed85bd --- /dev/null +++ b/quotacheck.c @@ -0,0 +1,849 @@ +/* + * + * Utility to check disk quotas + * + * Some parts of this utility are copied from old quotacheck by + * Marco van Wieringen <mvw@planets.elm.net> and Edvard Tuinder <ed@elm.ent> + * + */ + +#ident "$Id: quotacheck.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $" + +#include <dirent.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <getopt.h> +#include <limits.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/statfs.h> +#include <sys/ioctl.h> +#include <sys/mount.h> + +#if defined(EXT2_DIRECT) +#include <linux/ext2_fs.h> +#include <ext2fs/ext2fs.h> +#endif + +#include "pot.h" +#include "common.h" +#include "quotaio.h" +#include "quotasys.h" +#include "mntopt.h" +#include "bylabel.h" +#include "quotacheck.h" + +#define LINKSHASHSIZE 16384 /* Size of hashtable for hardlinked inodes */ +#define DQUOTHASHSIZE 32768 /* Size of hashtable for dquots from file */ + +struct dlinks { + ino_t i_num; + struct dlinks *next; +}; + +struct dirs { + char *dir_name; + struct dirs *next; +}; + +#define BITS_SIZE 4 /* sizeof(bits) == 5 */ + +dev_t cur_dev; /* Device we are working on */ +int files_done, dirs_done; +int flags, fmt = -1; /* Options from command line; Quota format to use */ +int uwant, gwant, ucheck, gcheck; /* Does user want to check user/group quota; Do we check user/group quota? */ +char *mntpoint; /* Mountpoint to check */ +struct util_dqinfo old_info[MAXQUOTAS]; /* Loaded infos */ + +#ifdef DEBUG_MALLOC +size_t malloc_mem = 0; +size_t free_mem = 0; +#endif + +struct dquot *dquot_hash[MAXQUOTAS][DQUOTHASHSIZE]; +struct dlinks *links_hash[MAXQUOTAS][DQUOTHASHSIZE]; + +/* + * Ok check each memory allocation. + */ +void *xmalloc(size_t size) +{ + void *ptr; + +#ifdef DEBUG_MALLOC + malloc_mem += size; +#endif + ptr = malloc(size); + if (!ptr) + die(3, "Not enough memory.\n"); + memset(ptr, 0, size); + return (ptr); +} + +void debug(int df, char *fmtstr, ...) +{ + va_list args; + + if (!(flags & df)) + return; + va_start(args, fmtstr); + vfprintf(stderr, fmtstr, args); + va_end(args); +} + +/* Compute hashvalue for given inode number */ +static inline uint hash_ino(uint i_num) +{ + return ((i_num ^ (i_num << 16)) * 997) & (LINKSHASHSIZE - 1); +} + +/* + * Store a hardlinked inode as we don't want to count it more then once. + */ +static int store_dlinks(int type, ino_t i_num) +{ + struct dlinks *lptr; + uint hash = hash_ino(i_num); + + debug(FL_DEBUG, "Adding hardlink for ino %d\n", i_num); + + for (lptr = links_hash[type][hash]; lptr; lptr = lptr->next) + if (lptr->i_num == i_num) + return 1; + + lptr = (struct dlinks *)xmalloc(sizeof(struct dlinks)); + + lptr->i_num = i_num; + lptr->next = links_hash[type][hash]; + links_hash[type][hash] = lptr; + return 0; +} + +/* Hash given id */ +static inline uint hash_dquot(uint id) +{ + return ((id ^ (id << 16)) * 997) & (DQUOTHASHSIZE - 1); +} + +/* + * Do a lookup of a type of quota for a specific id. Use short cut with + * most recently used dquot struct pointer. + */ +struct dquot *lookup_dquot(qid_t id, int type) +{ + struct dquot *lptr; + uint hash = hash_dquot(id); + + for (lptr = dquot_hash[type][hash]; lptr != NODQUOT; lptr = lptr->dq_next) + if (lptr->dq_id == id) + return lptr; + return NODQUOT; +} + +/* + * Add a new dquot for a new id to the list. + */ +struct dquot *add_dquot(qid_t id, int type) +{ + struct dquot *lptr; + uint hash = hash_dquot(id); + + debug(FL_DEBUG, "Adding dquot structure type %s for %d\n", type2name(type), (int)id); + + lptr = (struct dquot *)xmalloc(sizeof(struct dquot)); + + lptr->dq_id = id; + lptr->dq_next = dquot_hash[type][hash]; + dquot_hash[type][hash] = lptr; + lptr->dq_dqb.dqb_btime = lptr->dq_dqb.dqb_itime = (time_t) 0; + + return lptr; +} + +/* + * Add a number of blocks and inodes to a quota. + */ +static void add_to_quota(int type, ino_t i_num, uid_t i_uid, gid_t i_gid, umode_t i_mode, + nlink_t i_nlink, loff_t i_space) +{ + qid_t wanted; + struct dquot *lptr; + + if (type == USRQUOTA) + wanted = i_uid; + else + wanted = i_gid; + + if ((lptr = lookup_dquot(wanted, type)) == NODQUOT) + lptr = add_dquot(wanted, type); + + if (i_nlink != 1) + if (store_dlinks(type, i_num)) /* Did we already count this inode? */ + return; + lptr->dq_dqb.dqb_curinodes++; + lptr->dq_dqb.dqb_curspace += i_space; +} + +/* + * Clean up all list from a previous run. + */ +static void remove_list(void) +{ + int cnt; + uint i; + struct dquot *dquot, *dquot_free; + struct dlinks *dlink, *dlink_free; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + for (i = 0; i < DQUOTHASHSIZE; i++) { + dquot = dquot_hash[cnt][i]; + while (dquot != NODQUOT) { + dquot_free = dquot; + dquot = dquot->dq_next; +#ifdef DEBUG_MALLOC + free_mem += sizeof(struct dquot); +#endif + free(dquot_free); + } + dquot_hash[cnt][i] = NODQUOT; + } + for (i = 0; i < LINKSHASHSIZE; i++) { + dlink = links_hash[cnt][i]; + while (dlink) { + dlink_free = dlink; + dlink = dlink->next; +#ifdef DEBUG_MALLOC + free_mem += sizeof(struct dlinks); +#endif + free(dlink_free); + } + links_hash[cnt][i] = NULL; + } + } +} + +/* Get size used by file */ +static loff_t getqsize(char *fname, struct stat *st) +{ + static char ioctl_fail_warn; + int fd; + loff_t size; + + if (S_ISLNK(st->st_mode)) /* There's no way to do ioctl() on links... */ + return st->st_blocks << 9; + if ((fd = open(fname, O_RDONLY)) == -1) + die(2, _("Can't open file %s: %s\n"), fname, strerror(errno)); + if (ioctl(fd, FIOQSIZE, &size) == -1) { + size = st->st_blocks << 9; + if (!ioctl_fail_warn) { + ioctl_fail_warn = 1; + fputs(_("Can't get exact used space... Results might be inaccurate.\n"), + stderr); + } + } + close(fd); + return size; +} + +/* + * Show a blitting cursor as means of visual progress indicator. + */ +static inline void blit(void) +{ + static short bitc = 0; + static const char bits[] = "|/-\\"; + + putc(bits[bitc], stdout); + putc('\b', stdout); + fflush(stdout); + bitc++; + bitc %= BITS_SIZE; +} + +static void parse_options(int argcnt, char **argstr) +{ + int ret; + char *slash = strrchr(argstr[0], '/'); + + if (slash) + slash++; + else + slash = argstr[0]; + + while ((ret = getopt(argcnt, argstr, "VhcvugidnfF:mMRa")) != EOF) { + switch (ret) { + case 'g': + gwant = 1; + break; + case 'u': + uwant = 1; + break; + case 'd': + flags |= FL_DEBUG; + setlinebuf(stderr); + break; + case 'v': + flags |= FL_VERBOSE; + break; + case 'f': + flags |= FL_FORCE; + break; + case 'i': + flags |= FL_INTERACTIVE; + break; + case 'n': + flags |= FL_GUESSDQ; + break; + case 'c': + flags |= FL_NEWFILE; + break; + case 'V': + version(); + exit(0); + case 'M': + flags |= FL_FORCEREMOUNT; + break; + case 'm': + flags |= FL_NOREMOUNT; + break; + case 'a': + flags |= FL_ALL; + break; + case 'R': + flags |= FL_NOROOT; + break; + case 'F': + if ((fmt = name2fmt(optarg)) == QF_ERROR) + exit(1); + break; + default: + usage: + printf(_ + ("Utility for checking and repairing quota files.\n%s [-gucfinvdmMR] -F <quota-format> filesystem|-a\n"), +slash); + printf(_("Bugs to %s\n"), MY_EMAIL); + exit(1); + } + } + if (!(uwant | gwant)) + uwant = 1; + if (argcnt == optind) { + fputs(_("Bad number of arguments.\n"), stderr); + goto usage; + } + if (fmt == -1) { + fputs(_("Quota format must be specified for scanning.\n"), stderr); + goto usage; + } + if (fmt == QF_XFS) { + fputs(_("XFS quota format needs no checking.\n"), stderr); + exit(0); + } + if (flags & FL_VERBOSE && flags & FL_DEBUG) + flags &= ~FL_VERBOSE; + if (!(flags & FL_ALL)) + mntpoint = argstr[optind]; + else + mntpoint = NULL; +} + +#if defined(EXT2_DIRECT) +static int ext2_direct_scan(char *device) +{ + ino_t i_num; + ext2_filsys fs; + errcode_t error; + ext2_inode_scan scan; + struct ext2_inode inode; + int inode_buffer_blocks = 0; + ext2fs_inode_bitmap inode_used_map; + ext2fs_inode_bitmap inode_dir_map; + + if ((error = ext2fs_open(device, 0, 0, 0, unix_io_manager, &fs))) { + fprintf(stderr, _("quotacheck: error (%d) while opening %s\n"), (int)error, device); + return -1; + } + + if ((error = ext2fs_allocate_inode_bitmap(fs, "in-use inode map", &inode_used_map))) { + fprintf(stderr, _("quotacheck: error (%d) while allocating inode file bitmap\n"), + (int)error); + return -1; + } + + if ((error = ext2fs_allocate_inode_bitmap(fs, "directory inode map", &inode_dir_map))) { + fprintf(stderr, + _("quotacheck: error (%d) while allocating inode directory bitmap\n"), + (int)error); + return -1; + } + + if ((error = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan))) { + fprintf(stderr, _("quotacheck: error (%d) while opening inode scan\n"), (int)error); + return -1; + } + + if ((error = ext2fs_get_next_inode(scan, &i_num, &inode))) { + fprintf(stderr, _("quotacheck: error (%d) while starting inode scan\n"), (int)error); + return -1; + } + + while (i_num) { + if (inode.i_links_count) { + debug(FL_DEBUG, _("Found i_num %ld\n"), i_num); + if (flags & FL_VERBOSE) + blit(); + if (ucheck) + add_to_quota(USRQUOTA, i_num, inode.i_uid, inode.i_gid, + inode.i_mode, inode.i_links_count, + inode.i_blocks << 9); + if (gcheck) + add_to_quota(GRPQUOTA, i_num, inode.i_uid, inode.i_gid, + inode.i_mode, inode.i_links_count, + inode.i_blocks << 9); + if (S_ISDIR(inode.i_mode)) + dirs_done++; + else + files_done++; + } + + if ((error = ext2fs_get_next_inode(scan, &i_num, &inode))) { + fprintf(stderr, _("Something weird happened while scanning. Error %d\n"), + (int)error); + return -1; + } + } + return 0; +} +#endif + +/* + * Scan a directory with the readdir systemcall. Stat the files and add the sizes + * of the files to the appropriate quotas. When we find a dir we recursivly call + * ourself to scan that dir. + */ +static int scan_dir(char *pathname) +{ + struct dirs *dir_stack = { (struct dirs *)NULL }; + struct dirs *new_dir; + struct dirent *de; + struct stat st; + loff_t qspace; + DIR *dp; + int ret; + + if ((dp = opendir(pathname)) == (DIR *) NULL) + die(2, "\nCan open directory %s: %s\n", pathname, strerror(errno)); + + chdir(pathname); + while ((de = readdir(dp)) != (struct dirent *)NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + if (flags & FL_VERBOSE) + blit(); + + if ((lstat(de->d_name, &st)) == -1) { + fprintf(stderr, + _ + ("lstat can't stat `%s/%s': %s\nGuess you'd better run fsck first !\nexiting...\n"), + pathname, de->d_name, strerror(errno)); + goto out; + } + + qspace = getqsize(de->d_name, &st); + if (ucheck) + add_to_quota(USRQUOTA, st.st_ino, st.st_uid, st.st_gid, st.st_mode, + st.st_nlink, qspace); + if (gcheck) + add_to_quota(GRPQUOTA, st.st_ino, st.st_uid, st.st_gid, st.st_mode, + st.st_nlink, qspace); + + if (S_ISDIR(st.st_mode)) { + if (st.st_dev != cur_dev) + continue; + /* + * Add this to the directory stack and check this later on. + */ + debug(FL_DEBUG, _("pushd %s/%s\n"), pathname, de->d_name); + new_dir = xmalloc(sizeof(struct dirs)); + + new_dir->dir_name = xmalloc(strlen(pathname) + strlen(de->d_name) + 2); + sprintf(new_dir->dir_name, "%s/%s", pathname, de->d_name); + new_dir->next = dir_stack; + dir_stack = new_dir; + } + else { + debug(FL_DEBUG, _("\tAdding %s size %d ino %d links %d\n"), de->d_name, + st.st_size, st.st_ino, st.st_nlink); + files_done++; + } + } + closedir(dp); + + /* + * Traverse the directory stack, and check it. + */ + debug(FL_DEBUG, "Scanning stored directories from directory stack\n"); + while (dir_stack != (struct dirs *)NULL) { + new_dir = dir_stack; + dir_stack = dir_stack->next; + debug(FL_DEBUG, _("popd %s\nEntering directory %s\n"), new_dir->dir_name, + new_dir->dir_name); + ret = scan_dir(new_dir->dir_name); + dirs_done++; +#ifdef DEBUG_MALLOC + free_mem += sizeof(struct dirs) + strlen(new_dir->dir_name) + 1; +#endif + free(new_dir->dir_name); + free(new_dir); + if (ret < 0) /* Error while scanning? */ + goto out; + } + debug(FL_DEBUG, _("Leaving %s\n"), pathname); + return 0; + out: + for (new_dir = dir_stack; new_dir; new_dir = dir_stack) { + dir_stack = dir_stack->next; +#ifdef DEBUG_MALLOC + free_mem += sizeof(struct dirs) + strlen(new_dir->dir_name) + 1; +#endif + free(new_dir->dir_name); + free(new_dir); + } + return -1; +} + +/* Ask user y/n question */ +int ask_yn(char *q, int def) +{ + char a[10]; /* Users answer */ + + printf("%s [%c]: ", q, def ? 'y' : 'n'); + fflush(stdout); + while (1) { + fgets(a, sizeof(a), stdin); + if (*a == '\n') + return def; + if (!strcasecmp(a, "y\n")) + return 1; + if (!strcasecmp(a, "n\n")) + return 0; + printf("Illegal answer. Please answer y/n: "); + fflush(stdout); + } +} + +/* Do checks and buffer quota file into memory */ +static int process_file(char *mnt_fsname, struct mntent *mnt, int type) +{ + char *qfname; + int fd, ret; + + debug(FL_DEBUG | FL_VERBOSE, _("Going to check %s quota file of %s\n"), type2name(type), + mnt->mnt_dir); + + if (kern_quota_on(mnt_fsname, type, (1 << fmt)) > 0) { /* Is quota enabled? */ + if (!(flags & FL_FORCE)) { + if (flags & FL_INTERACTIVE) { + printf(_ + ("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n"), +type2name(type), mnt->mnt_dir); + if (!ask_yn(_("Should I continue"), 0)) { + printf(_("As you wish... Canceling check of this file.\n")); + return -1; + } + } + else + die(6, + _ + ("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n\ +Please turn quotas off or use -f to force checking.\n"), + type2name(type), mnt->mnt_dir); + } + /* At least sync quotas so damage will be smaller */ + if (quotactl(QCMD(Q_SYNC, type), mnt_fsname, 0, NULL) < 0) + die(4, _("Error while syncing quotas: %s\n"), strerror(errno)); + } + + qfname = get_qf_name(mnt, type, fmt); + if (!qfname) { + fprintf(stderr, _("Can't get quotafile name for %s\n"), mnt_fsname); + return -1; + } + if ((fd = open(qfname, O_RDONLY)) < 0) { + fprintf(stderr, _("Can't open quotafile %s: %s\n"), qfname, strerror(errno)); + free(qfname); + return -1; + } + + memset(old_info + type, 0, sizeof(old_info[type])); + ret = 0; + switch (fmt) { + case QF_TOONEW: + fprintf(stderr, _("Too new quotafile format on %s\n"), mnt_fsname); + ret = -1; + break; + case QF_VFSOLD: + ret = v1_buffer_file(qfname, fd, type); + break; + case QF_VFSV0: + ret = v2_buffer_file(qfname, fd, type); + break; + } + free(qfname); + close(fd); + return ret; +} + +/* Backup old quotafile and rename new one to right name */ +static int rename_files(struct mntent *mnt, int type) +{ + char *filename, newfilename[PATH_MAX]; + struct stat st; + + if (!(filename = get_qf_name(mnt, type, fmt))) + die(2, _("Can't get name of old quotafile on %s.\n"), mnt->mnt_dir); + debug(FL_DEBUG | FL_VERBOSE, _("Data dumped.\nRenaming old quotafile to %s~\n"), filename); + if (stat(filename, &st) < 0) { /* File doesn't exist? */ + if (errno == ENOENT) { + debug(FL_DEBUG | FL_VERBOSE, _("Old file not found.\n")); + goto rename_new; + } + fprintf(stderr, _("Error while searching for old quota file %s: %s\n"), filename, + strerror(errno)); + free(filename); + return -1; + } + /* Backup old file */ + strcpy(newfilename, filename); + /* Make backingup safe */ + sstrncat(newfilename, "~", PATH_MAX); + if (newfilename[strlen(newfilename) - 1] != '~') + die(8, _("Name of quota file too long. Contact %s.\n"), MY_EMAIL); + if (rename(filename, newfilename) < 0) { + fprintf(stderr, _("Can't rename old quotafile %s to %s: %s\n"), filename, + newfilename, strerror(errno)); + free(filename); + return -1; + } + debug(FL_DEBUG | FL_VERBOSE, _("Renaming new quotafile\n")); + rename_new: + /* Rename new file to right name */ + strcpy(newfilename, filename); + sstrncat(newfilename, ".new", PATH_MAX); + if (rename(newfilename, filename) < 0) { + fprintf(stderr, _("Can't rename new quotafile %s to name %s: %s\n"), newfilename, + filename, strerror(errno)); + free(filename); + return -1; + } + free(filename); + return 0; +} + +/* + * Dump the quota info that we have in memory now to the appropriate + * quota file. As quotafiles doesn't account to quotas we don't have to + * bother about accounting new blocks for quota file + */ +static int dump_to_file(char *mnt_fsname, struct mntent *mnt, int type) +{ + struct dquot *dquot; + uint i; + struct quota_handle *h; + + debug(FL_DEBUG | FL_VERBOSE, _("Dumping gathered data for %ss.\n"), type2name(type)); + if (!(h = new_io(mnt, type, fmt))) { + fprintf(stderr, _("Can't initialize IO on new quotafile: %s\n"), strerror(errno)); + return -1; + } + memcpy(&h->qh_info, old_info + type, sizeof(h->qh_info)); + mark_quotafile_info_dirty(h); + for (i = 0; i < DQUOTHASHSIZE; i++) + for (dquot = dquot_hash[type][i]; dquot; dquot = dquot->dq_next) { + dquot->dq_h = h; + /* Unset grace times if limit is not exceeded; if limit is not set, clear times too... */ + if (dquot->dq_dqb.dqb_bsoftlimit > toqb(dquot->dq_dqb.dqb_curspace)) + dquot->dq_dqb.dqb_btime = 0; + if (dquot->dq_dqb.dqb_isoftlimit > dquot->dq_dqb.dqb_curinodes) + dquot->dq_dqb.dqb_itime = 0; + h->qh_ops->commit_dquot(dquot); + } + if (end_io(h) < 0) { + fprintf(stderr, _("Can't finish IO on new quotafile: %s\n"), strerror(errno)); + return -1; + } + if (rename_files(mnt, type) < 0) + return -1; + if (fmt == kern_quota_on(mnt_fsname, type, 1 << fmt)) { /* Quota turned on? */ + char *filename; + + filename = get_qf_name(mnt, type, fmt); + if (quotactl(QCMD(Q_QUOTAOFF, type), mnt_fsname, 0, NULL) + || quotactl(QCMD(Q_QUOTAON, type), mnt_fsname, 0, filename)) + fprintf(stderr, + _ + ("Can't turn %s quotas on %s off and on: %s\nKernel won't know about changes quotacheck did.\n"), + type2name(type), mnt_fsname, strerror(errno)); + free(filename); + } + return 0; +} + +static void check_dir(char *mnt_fsname, struct mntent *mnt) +{ + struct stat st; + int remounted = 0; + loff_t qspace; + + if (lstat(mnt->mnt_dir, &st) < 0) + die(2, _("Can't stat mountpoint %s: %s\n"), mnt, strerror(errno)); + if (!S_ISDIR(st.st_mode)) + die(2, _("Mountpoint %s isn't directory?!\n"), mnt); + qspace = getqsize(mnt->mnt_dir, &st); + cur_dev = st.st_dev; + files_done = dirs_done = 0; + if (ucheck) { + if (process_file(mnt_fsname, mnt, USRQUOTA) >= 0) + add_to_quota(USRQUOTA, st.st_ino, st.st_uid, st.st_gid, st.st_mode, + st.st_nlink, qspace); + else + ucheck = 0; + } + if (gcheck) { + if (process_file(mnt_fsname, mnt, GRPQUOTA) >= 0) + add_to_quota(GRPQUOTA, st.st_ino, st.st_uid, st.st_gid, st.st_mode, + st.st_nlink, qspace); + else + gcheck = 0; + } + if (!ucheck && !gcheck) /* Nothing to check? */ + return; + if (!(flags & FL_NOREMOUNT)) { + /* Now we try to remount fs read-only to prevent races when scanning filesystem */ + if (mount + (NULL, mnt->mnt_dir, mnt->mnt_type, MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, + NULL) < 0 && !(flags & FL_FORCEREMOUNT)) { + if (flags & FL_INTERACTIVE) { + printf(_ + ("Can't remount filesystem mounted on %s read-only. Counted values might not be right.\n"), +mnt->mnt_dir); + if (!ask_yn(_("Should I continue"), 0)) { + printf(_("As you wish... Canceling check of this file.\n")); + goto out; + } + } + else { + fprintf(stderr, + _ + ("Can't remount filesystem mounted on %s read-only so counted values might not be right.\n\ +Please stop all programs writing to filesystem or use -F flag to force checking.\n"), + mnt->mnt_dir); + goto out; + } + } + else + remounted = 1; + debug(FL_DEBUG | FL_VERBOSE, _("Filesystem remounted RO\n")); + } + debug(FL_VERBOSE, _("Scanning %s [%s] "), mnt_fsname, mnt->mnt_dir); +#if defined(EXT2_DIRECT) + if (!strcmp(mnt->mnt_type, MNTTYPE_EXT2) || !strcmp(mnt->mnt_type, MNTTYPE_EXT3)) { + if (ext2_direct_scan(mnt->mnt_dir) < 0) + goto out; + } + else if (mnt_fsname) { +#else + if (mnt->mnt_dir) { +#endif + if (scan_dir(mnt->mnt_dir) < 0) + goto out; + } + dirs_done++; + if (flags & FL_VERBOSE) + fputs(_("done\n"), stderr); + debug(FL_DEBUG | FL_VERBOSE, _("Checked %d directories and %d files\n"), dirs_done, + files_done); + if (remounted) { + if (mount(NULL, mnt->mnt_dir, mnt->mnt_type, MS_MGC_VAL | MS_REMOUNT, NULL) < 0) + die(4, + _ + ("Can't remount filesystem %s read-write. Can't write new quota files.\n"), + mnt->mnt_dir); + debug(FL_DEBUG | FL_VERBOSE, _("Filesystem remounted RW.\n")); + } + if (ucheck) + dump_to_file(mnt_fsname, mnt, USRQUOTA); + if (gcheck) + dump_to_file(mnt_fsname, mnt, GRPQUOTA); + out: + remove_list(); +} + +static void check_all(void) +{ + FILE *mntf; + struct mntent *mnt; + const char *mnt_fslabel; + char *devlist[MAXMNTPOINTS]; + int gotmnt = 0, i; + + if (!(mntf = setmntent(MOUNTED, "r"))) + die(2, _("Can't open %s: %s\n"), MOUNTED, strerror(errno)); + while ((mnt = getmntent(mntf))) { + if (gotmnt == MAXMNTPOINTS) + die(3, _("Too many mountpoints. Please report to: %s\n"), MY_EMAIL); + if (!(devlist[gotmnt] = (char *)get_device_name(mnt->mnt_fsname))) + continue; + for (i = 0; i < gotmnt && strcmp(devlist[i], devlist[gotmnt]); i++); + /* We already have this mountpoint? */ + if (i < gotmnt) + continue; + gotmnt++; + if ((mnt_fslabel = strchr(mnt->mnt_fsname, '='))) + mnt_fslabel++; + else + mnt_fslabel = devlist[gotmnt - 1]; + if ((flags & FL_ALL && (!(flags & FL_NOROOT) || strcmp(mnt->mnt_dir, "/"))) || + !strcmp(mntpoint, devlist[gotmnt - 1]) || !strcmp(mntpoint, mnt->mnt_dir)) { + if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { + debug(FL_DEBUG | FL_VERBOSE, _("Skipping %s [%s]\n"), mnt_fslabel, + mnt->mnt_dir); + continue; + } + if (uwant && hasquota(mnt, USRQUOTA)) + ucheck = 1; + else + ucheck = 0; + if (gwant && hasquota(mnt, GRPQUOTA)) + gcheck = 1; + else + gcheck = 0; + check_dir(devlist[gotmnt - 1], mnt); + } + } + endmntent(mntf); + if (!(flags & FL_ALL) && !gotmnt) + die(1, _("Can't find mountpoint %s.\n"), mntpoint); + for (i = 0; i < gotmnt; i++) + free(devlist[i]); +} + +int main(int argcnt, char **argstr) +{ + gettexton(); + parse_options(argcnt, argstr); + warn_new_kernel(fmt); + + check_all(); +#ifdef DEBUG_MALLOC + fprintf(stderr, _("Allocated %d bytes memory\nFree'd %d bytes\nLost %d bytes\n"), + malloc_mem, free_mem, malloc_mem - free_mem); +#endif + return 0; +} diff --git a/quotacheck.h b/quotacheck.h new file mode 100644 index 0000000..a20efb3 --- /dev/null +++ b/quotacheck.h @@ -0,0 +1,44 @@ +/* + * + * Header file for quota checking utilities + * + */ + +#ifndef _QUOTACHECK_H +#define _QUOTACHECK_H + +#include <sys/types.h> + +#include "quota.h" +#include "quotaio.h" + +#define NODQUOT ((struct dquot *)NULL) + +#define FL_FORCE 1 /* Force check even if quota enabled */ +#define FL_VERBOSE 2 /* Have verbose input */ +#define FL_DEBUG 4 /* Have very verbose input */ +#define FL_INTERACTIVE 8 /* Ask questions when needed */ +#define FL_GUESSDQ 16 /* When more structures for same user found, use the first */ +#define FL_NEWFILE 32 /* Don't try to read old file. Just create new one. */ +#define FL_FORCEREMOUNT 64 /* Force check even when remounting RO fails */ +#define FL_NOREMOUNT 128 /* Don't try to remount filesystem RO */ +#define FL_ALL 256 /* Scan all mountpoints with quota? */ +#define FL_NOROOT 512 /* Scan all mountpoints except root */ + +extern int flags; /* Options from command line */ +extern struct util_dqinfo old_info[MAXQUOTAS]; /* Loaded info from file */ + +#ifdef DEBUG_MALLOC +extern size_t malloc_mem = 0; +extern size_t free_mem = 0; +#endif + +void *xmalloc(size_t size); +void debug(int df, char *fmtstr, ...); +int ask_yn(char *q, int def); +struct dquot *lookup_dquot(qid_t id, int type); +struct dquot *add_dquot(qid_t id, int type); +int v2_buffer_file(char *filename, int fd, int type); +int v1_buffer_file(char *filename, int fd, int type); + +#endif diff --git a/quotacheck_v1.c b/quotacheck_v1.c new file mode 100644 index 0000000..db21c94 --- /dev/null +++ b/quotacheck_v1.c @@ -0,0 +1,83 @@ +/* + * + * Checking routines for old VFS quota format + * + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "pot.h" +#include "common.h" +#include "quotaio.h" +#include "quotaio_v1.h" +#include "quotacheck.h" + +/* Load all other dquot structures */ +static void load_dquots(char *filename, int fd, int type) +{ + struct v1_disk_dqblk ddqblk; + struct util_dqblk *udq; + struct dquot *dquot; + int err; + qid_t id = 0; + + lseek(fd, 0, SEEK_SET); + while ((err = read(fd, &ddqblk, sizeof(ddqblk)))) { + if (err < 0) + die(1, _("Can't read entry for id %u from quotafile %s: %s\n"), (uint) id, + filename, strerror(errno)); + if (err != sizeof(ddqblk)) { + fprintf(stderr, _("Entry for id %u is truncated.\n"), (uint) id); + break; + } + dquot = add_dquot(id, type); + udq = &dquot->dq_dqb; + udq->dqb_bhardlimit = ddqblk.dqb_bhardlimit; + udq->dqb_bsoftlimit = ddqblk.dqb_bsoftlimit; + udq->dqb_ihardlimit = ddqblk.dqb_ihardlimit; + udq->dqb_isoftlimit = ddqblk.dqb_isoftlimit; + udq->dqb_btime = ddqblk.dqb_btime; + udq->dqb_itime = ddqblk.dqb_itime; + id++; + } +} + +/* Load first structure - get grace times */ +static int check_info(char *filename, int fd, int type) +{ + struct v1_disk_dqblk ddqblk; + int err; + + debug(FL_DEBUG, _("Loading first quota entry with grace times.\n")); + lseek(fd, 0, SEEK_SET); + err = read(fd, &ddqblk, sizeof(ddqblk)); + if (err < 0) + die(1, _("Can't read first entry from quotafile %s: %s\n"), filename, + strerror(errno)); + if (err != sizeof(ddqblk)) { + fprintf(stderr, + _ + ("WARNING: Quotafile %s was probably truncated. Can't save quota settings...\n"), + filename); + return -1; + } + old_info[type].dqi_bgrace = ddqblk.dqb_btime; + old_info[type].dqi_igrace = ddqblk.dqb_itime; + debug(FL_DEBUG, _("First entry loaded.\n")); + return 0; +} + +int v1_buffer_file(char *filename, int fd, int type) +{ + old_info[type].dqi_bgrace = MAX_DQ_TIME; + old_info[type].dqi_igrace = MAX_IQ_TIME; + if (flags & FL_NEWFILE) + return 0; + if (check_info(filename, fd, type) < 0) + return 0; + load_dquots(filename, fd, type); + return 0; +} diff --git a/quotacheck_v2.c b/quotacheck_v2.c new file mode 100644 index 0000000..31a558f --- /dev/null +++ b/quotacheck_v2.c @@ -0,0 +1,344 @@ +/* + * + * Checking routines for new VFS quota format + * + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <asm/byteorder.h> + +#include "pot.h" +#include "common.h" +#include "quota.h" +#include "quotaio.h" +#include "quotaio_v2.h" +#include "quotacheck.h" + +#define getdqbuf() smalloc(V2_DQBLKSIZE) +#define freedqbuf(buf) free(buf) + +#define SET_BLK(blk) (blkbmp[(blk) >> 3] |= 1 << ((blk) & 7)) +#define GET_BLK(blk) (blkbmp[(blk) >> 3] & (1 << ((blk) & 7))) + +typedef char *dqbuf_t; + +static const int magics[MAXQUOTAS] = INITQMAGICS; /* Magics we should look for */ +static const int known_versions[MAXQUOTAS] = INITKNOWNVERSIONS; /* Versions we accept */ +static char *blkbmp; /* Bitmap of checked blocks */ + +static int check_blkref(uint blk, uint blocks) +{ + if (blk >= blocks) + return -1; + if (blk && blk < V2_DQTREEOFF) + return -1; + return 0; +} + +/* Load and check basic info about quotas */ +static int check_info(char *filename, int fd, int type) +{ + struct v2_disk_dqinfo dinfo; + uint blocks, dflags, freeblk, freeent; + off_t filesize; + int err; + + debug(FL_VERBOSE, _("Checking quotafile info...\n")); + lseek(fd, V2_DQINFOOFF, SEEK_SET); + err = read(fd, &dinfo, sizeof(struct v2_disk_dqinfo)); + + if (err < 0) { + fprintf(stderr, _("Can't read info from quota file %s: %s\n"), filename, strerror(errno)); + return -1; + } + if (err != sizeof(struct v2_disk_dqinfo)) { + fprintf(stderr, _("WARNING: Quota file %s was probably truncated. Can't save quota settings...\n"), + filename); + return -1; + } + + blocks = __le32_to_cpu(dinfo.dqi_blocks); + freeblk = __le32_to_cpu(dinfo.dqi_free_blk); + freeent = __le32_to_cpu(dinfo.dqi_free_entry); + dflags = __le32_to_cpu(dinfo.dqi_flags); + filesize = lseek(fd, 0, SEEK_END); + if (check_blkref(freeblk, blocks) < 0 || dflags & ~V2_DQF_MASK || + check_blkref(freeent, blocks) < 0 || (filesize + V2_DQBLKSIZE - 1) >> V2_DQBLKSIZE_BITS != blocks) { + fprintf(stderr, _("WARNING: Quota file info was corrupted.\n")); + debug(FL_DEBUG, _("Size of file: %lu\nBlocks: %u Free block: %u Block with free entry: %u Flags: %x\n"), + (unsigned long)filesize, blocks, freeblk, freeent, dflags); + old_info[type].dqi_bgrace = MAX_DQ_TIME; + old_info[type].dqi_igrace = MAX_IQ_TIME; + old_info[type].u.v2_mdqi.dqi_blocks = + (filesize + V2_DQBLKSIZE - 1) >> V2_DQBLKSIZE_BITS; + old_info[type].u.v2_mdqi.dqi_flags = 0; + printf(_("Setting grace times and other flags to default values.\nAssuming number of blocks is %u.\n"), + old_info[type].u.v2_mdqi.dqi_blocks); + } + else { + old_info[type].dqi_bgrace = __le32_to_cpu(dinfo.dqi_bgrace); + old_info[type].dqi_igrace = __le32_to_cpu(dinfo.dqi_igrace); + old_info[type].u.v2_mdqi.dqi_blocks = blocks; + old_info[type].u.v2_mdqi.dqi_flags = dflags; + } + old_info[type].u.v2_mdqi.dqi_free_blk = old_info[type].u.v2_mdqi.dqi_free_entry = 0; /* This won't be needed */ + debug(FL_DEBUG, _("File info done.\n")); + return 0; +} + +/* Print error message */ +static void blk_corrupted(int *corrupted, uint * lblk, uint blk, char *fmtstr, ...) +{ + va_list args; + + if (!*corrupted) { + if (!(flags & (FL_VERBOSE | FL_DEBUG))) + fprintf(stderr, _("Corrupted blocks: ")); + } + if (flags & (FL_VERBOSE | FL_DEBUG)) { + va_start(args, fmtstr); + fprintf(stderr, _("Block %u: "), blk); + vfprintf(stderr, fmtstr, args); + fputc('\n', stderr); + va_end(args); + } + else if (*lblk != blk) { + if (!*corrupted) + fprintf(stderr, "%u", blk); + else + fprintf(stderr, ", %u", blk); + } + *corrupted = 1; + *lblk = blk; + fflush(stderr); +} + +/* Convert dist quota format to utility one - copy just needed fields */ +static inline void disk2utildqblk(struct util_dqblk *u, struct v2_disk_dqblk *d) +{ + u->dqb_ihardlimit = __le32_to_cpu(d->dqb_ihardlimit); + u->dqb_isoftlimit = __le32_to_cpu(d->dqb_isoftlimit); + u->dqb_bhardlimit = __le32_to_cpu(d->dqb_bhardlimit); + u->dqb_bsoftlimit = __le32_to_cpu(d->dqb_bsoftlimit); + u->dqb_itime = __le64_to_cpu(d->dqb_itime); + u->dqb_btime = __le64_to_cpu(d->dqb_btime); +} + +/* Check whether given dquot is empty */ +static int empty_dquot(struct v2_disk_dqblk *d) +{ + static struct v2_disk_dqblk fakedq; + + return !memcmp(&fakedq, d, sizeof(fakedq)); +} + +/* Put one entry info memory */ +static int buffer_entry(dqbuf_t buf, uint blk, int *corrupted, uint * lblk, int cnt, int type) +{ + struct util_dqblk mdq, *fdq; + qid_t id; + struct dquot *cd; + + disk2utildqblk(&mdq, ((struct v2_disk_dqblk *)(((char *)buf) + sizeof(struct v2_disk_dqdbheader))) + cnt); + id = __le32_to_cpu(((struct v2_disk_dqblk *)(((char *)buf) + sizeof(struct v2_disk_dqdbheader)))[cnt].dqb_id); + cd = lookup_dquot(id, type); + if (cd != NODQUOT) { + fdq = &cd->dq_dqb; + if (mdq.dqb_bhardlimit != fdq->dqb_bhardlimit + || mdq.dqb_bsoftlimit != fdq->dqb_bsoftlimit + || mdq.dqb_ihardlimit != fdq->dqb_ihardlimit + || mdq.dqb_isoftlimit != fdq->dqb_isoftlimit) { + blk_corrupted(corrupted, lblk, blk, _("Duplicated entries.")); + if (flags & FL_GUESSDQ) { + if (!(flags & (FL_DEBUG | FL_VERBOSE))) + fputc('\n', stderr); + fprintf(stderr, _("Found more structures for ID %u. Using values: BHARD: %Ld BSOFT: %Ld IHARD: %Ld ISOFT: %Ld\n"), + (uint) id, (long long)fdq->dqb_bhardlimit, (long long)fdq->dqb_bsoftlimit, + (long long)fdq->dqb_ihardlimit, (long long)fdq->dqb_isoftlimit); + return 0; + } + else if (flags & FL_INTERACTIVE) { + fprintf(stderr, _("\nFound more structures for ID %u. Values: BHARD: %Ld/%Ld BSOFT: %Ld/%Ld IHARD: %Ld/%Ld ISOFT: %Ld/%Ld\n"), + (uint) id, (long long)fdq->dqb_bhardlimit, (long long)mdq.dqb_bhardlimit, + (long long)fdq->dqb_bsoftlimit, (long long)mdq.dqb_bsoftlimit, + (long long)fdq->dqb_ihardlimit, (long long)mdq.dqb_ihardlimit, + (long long)fdq->dqb_isoftlimit, (long long)mdq.dqb_isoftlimit); + if (ask_yn(_("Should I use new values"), 0)) { + fdq->dqb_bhardlimit = mdq.dqb_bhardlimit; + fdq->dqb_bsoftlimit = mdq.dqb_bsoftlimit; + fdq->dqb_ihardlimit = mdq.dqb_ihardlimit; + fdq->dqb_isoftlimit = mdq.dqb_isoftlimit; + fdq->dqb_btime = mdq.dqb_btime; + fdq->dqb_itime = mdq.dqb_itime; + } + } + else { + fprintf(stderr, _("ID %u has more structures. User intervention needed (use -i for interactive mode or -n for automatic answer).\n"), + (uint) id); + return -1; + } + } + else if (mdq.dqb_itime != fdq->dqb_itime || mdq.dqb_btime != fdq->dqb_btime) { + if (fdq->dqb_btime < mdq.dqb_btime) + fdq->dqb_btime = mdq.dqb_btime; + if (fdq->dqb_itime < mdq.dqb_itime) + fdq->dqb_itime = mdq.dqb_itime; + } + } + else { + cd = add_dquot(id, type); + fdq = &cd->dq_dqb; + fdq->dqb_bhardlimit = mdq.dqb_bhardlimit; + fdq->dqb_bsoftlimit = mdq.dqb_bsoftlimit; + fdq->dqb_ihardlimit = mdq.dqb_ihardlimit; + fdq->dqb_isoftlimit = mdq.dqb_isoftlimit; + fdq->dqb_btime = mdq.dqb_btime; + fdq->dqb_itime = mdq.dqb_itime; + } + return 0; +} + +static void check_read_blk(int fd, uint blk, dqbuf_t buf) +{ + size_t rd; + + lseek(fd, blk << V2_DQBLKSIZE_BITS, SEEK_SET); + rd = read(fd, buf, V2_DQBLKSIZE); + if (rd < 0) + die(2, _("Can't read block %u: %s\n"), blk, strerror(errno)); + if (rd != V2_DQBLKSIZE) { + debug(FL_VERBOSE | FL_DEBUG, _("Block %u is truncated.\n"), blk); + memset(buf + rd, 0, V2_DQBLKSIZE - rd); + } +} + +static int check_tree_ref(uint blk, uint ref, uint blocks, int check_use, uint * corrupted, + uint * lblk) +{ + if (check_blkref(ref, blocks) < 0) + blk_corrupted(corrupted, lblk, blk, _("Reference to illegal block %u"), ref); + if (!ref) + return 0; + if (!check_use || !GET_BLK(ref)) + return 0; + blk_corrupted(corrupted, lblk, blk, _("Block %u in tree referenced twice"), ref); + return -1; +} + +/* Check block with structures */ +static int check_data_blk(int fd, uint blk, int type, uint blocks, uint * corrupted, uint * lblk) +{ + dqbuf_t buf = getdqbuf(); + struct v2_disk_dqdbheader *head = (struct v2_disk_dqdbheader *)buf; + int i; + struct v2_disk_dqblk *dd = (struct v2_disk_dqblk *)(head + 1); + + SET_BLK(blk); + check_read_blk(fd, blk, buf); + if (check_blkref(__le32_to_cpu(head->dqdh_next_free), blocks) < 0) + blk_corrupted(corrupted, lblk, blk, _("Illegal free block reference to block %u"), + __le32_to_cpu(head->dqdh_next_free)); + if (__le16_to_cpu(head->dqdh_entries) > V2_DQSTRINBLK) + blk_corrupted(corrupted, lblk, blk, _("Corrupted number of used entries (%u)"), + (uint) __le16_to_cpu(head->dqdh_entries)); + for (i = 0; i < V2_DQSTRINBLK; i++) + if (!empty_dquot(dd + i)) + if (buffer_entry(buf, blk, corrupted, lblk, i, type) < 0) { + freedqbuf(buf); + return -1; + } + freedqbuf(buf); + return 0; +} + +/* Check one tree block */ +static int check_tree_blk(int fd, uint blk, int depth, int type, uint blocks, uint * corrupted, + uint * lblk) +{ + dqbuf_t buf = getdqbuf(); + u_int32_t *r = (u_int32_t *) buf; + int i; + + SET_BLK(blk); + check_read_blk(fd, blk, buf); + for (i = 0; i < V2_DQBLKSIZE >> 2; i++) + if (depth < V2_DQTREEDEPTH - 1) { + if (check_tree_ref(blk, __le32_to_cpu(r[i]), blocks, 1, corrupted, lblk) >= 0 && + __le32_to_cpu(r[i])) /* Isn't block OK? */ + if (check_tree_blk(fd, __le32_to_cpu(r[i]), depth + 1, type, blocks, corrupted, lblk) < 0) { + freedqbuf(buf); + return -1; + } + } + else if (check_tree_ref(blk, __le32_to_cpu(r[i]), blocks, 0, corrupted, lblk) >= 0 && __le32_to_cpu(r[i])) + if (check_data_blk(fd, __le32_to_cpu(r[i]), type, blocks, corrupted, lblk) < 0) { + freedqbuf(buf); + return -1; + } + freedqbuf(buf); + return 0; +} + +/* Check basic header */ +static int check_header(char *filename, int fd, int type) +{ + int err; + struct v2_disk_dqheader head; + + debug(FL_DEBUG, _("Checking quotafile headers...\n")); + lseek(fd, 0, SEEK_SET); + err = read(fd, &head, sizeof(head)); + if (err < 0) + die(1, _("Can't read header from quotafile %s: %s\n"), filename, strerror(errno)); + if (err != sizeof(head)) { + fprintf(stderr, _("WARNING: Quotafile %s was probably truncated. Can't save quota settings...\n"), + filename); + return -1; + } + if (__le32_to_cpu(head.dqh_magic) != magics[type] || __le32_to_cpu(head.dqh_version) > known_versions[type]) + fprintf(stderr, _("WARNING: Quota file %s has corrupted headers\n"), filename); + debug(FL_DEBUG, _("Headers checked.\n")); + return 0; +} + +/* Load data from file to memory */ +int v2_buffer_file(char *filename, int fd, int type) +{ + uint blocks, lastblk = 0; + int corrupted = 0, ret = 0; + + old_info[type].dqi_bgrace = MAX_DQ_TIME; + old_info[type].dqi_igrace = MAX_IQ_TIME; + if (flags & FL_NEWFILE) + return 0; + if (check_header(filename, fd, type) < 0) + return 0; + if (check_info(filename, fd, type) < 0) + return 0; + debug(FL_DEBUG | FL_VERBOSE, _("Headers of file %s checked. Going to load data...\n"), + filename); + blocks = old_info[type].u.v2_mdqi.dqi_blocks; + blkbmp = xmalloc((blocks + 7) >> 3); + memset(blkbmp, 0, (blocks + 7) >> 3); + if (check_tree_ref(0, V2_DQTREEOFF, blocks, 1, &corrupted, &lastblk) >= 0) + ret = check_tree_blk(fd, V2_DQTREEOFF, 0, type, blocks, &corrupted, &lastblk); + else + fprintf(stderr, _("Can't gather quota data. Tree root node corrupted.\n")); +#ifdef DEBUG_MALLOC + free_mem += (blocks + 7) >> 3; +#endif + free(blkbmp); + if (corrupted) { + if (!(flags & (FL_VERBOSE | FL_DEBUG))) + fputc('\n', stderr); + fprintf(stderr, _("WARNING: Some data might be changed due to corruption.\n")); + } + else + debug(FL_DEBUG | FL_VERBOSE, _("Not found any corrupted blocks. Congratulations.\n")); + return ret; +} diff --git a/quotactl.2 b/quotactl.2 new file mode 100644 index 0000000..006c86e --- /dev/null +++ b/quotactl.2 @@ -0,0 +1,231 @@ +.TH QUOTACTL 2 +.SH NAME +quotactl \- manipulate disk quotas +.SH SYNOPSIS +.nf +.B #include <linux/quota.h> +.B #include <linux/xqm.h> +.LP +.B int quotactl(int cmd, char \(**special, int uid, caddr_t addr) +.fi +.SH DESCRIPTION +.LP +.IX "filesystem" "quotactl() disk quotas" "" "\fLquotactl()\fP \(em disk quotas" +.IX "quotactl() disk quotas" "" "\fLquotactl()\fP \(em disk quotas" +.IX "disk quotas quotactl()" "" "disk quotas \(em \fLquotactl()\fP" +.LP +The +.B quotactl(\|) +call manipulates disk quotas. +.I cmd +indicates a command to be applied to +.SM UID +.IR id +or +.SM GID +.IR id . +To set the type of quota use the +.IR "QCMD(cmd, type)" +macro. +.I special +is a pointer to a null-terminated string containing the path +name of the block special device for the filesystem being manipulated. +.I addr +is the address of an optional, command specific, data structure +which is copied in or out of the system. The interpretation of +.I addr +is given with each command below. +.TP 15 +.SB Q_QUOTAON +Turn on quotas for a filesystem. +.I addr +points to the path name of file containing the quotas for the filesystem. +The quota file must exist; it is normally created with the +.BR quotacheck (8) +program. This call is restricted to the super-user. +.TP +.SB Q_QUOTAOFF +Turn off quotas for a filesystem. +.I addr +and +.I uid +are ignored. +This call is restricted to the super-user. +.TP +.SB Q_GETQUOTA +Get disk quota limits and current usage for user or group +.IR id . +.I addr +is a pointer to a +.B dqblk +structure (defined in +.BR <linux/quota.h> ). +Only the super-user may get the quotas of a user other than himself. +.TP +.SB Q_SETQUOTA +Set disk quota limits and current usage for user or group +.IR id . +.I addr +is a pointer to a +.B dqblk +structure (defined in +.BR <linux/quota.h> ). +This call is restricted to the super-user. +.TP +.SB Q_SETQLIM +Set disk quota limits for user or group +.IR id . +.I addr +is a pointer to a +.B dqblk +structure (defined in +.BR <linux/quota.h> ). +This call is restricted to the super-user. +.TP +.SB Q_SYNC +Update the on-disk copy of quota usages for a filesystem. +If +.I special +is null then all filesystems with active quotas are sync'ed. +.I addr +and +.I uid +are ignored. +.PP +For XFS filesystems making use of the XFS Quota Manager (XQM), the +above commands are bypassed and the following commands are used: +.TP 15 +.SB Q_XQUOTAON +Turn on quotas for an XFS filesystem. +XFS provides the ability to turn on/off quota limit enforcement +with quota accounting. +Therefore, XFS expects the addr to be a pointer to an unsigned int +that contains either the flags XFS_QUOTA_UDQ_ACCT and/or +XFS_QUOTA_UDQ_ENFD (for user quota), or XFS_QUOTA_GDQ_ACCT and/or +XFS_QUOTA_GDQ_ENFD (for group quota), as defined in +.BR <linux/xqm.h> . +This call is restricted to the superuser. +.TP +.SB Q_XQUOTAOFF +Turn off quotas for an XFS filesystem. +As in Q_QUOTAON, XFS filesystems expect a pointer to an unsigned int +that specifies whether quota accounting and/or limit enforcement need +to be turned off. +This call is restricted to the superuser. +.TP +.SB Q_XGETQUOTA +Get disk quota limits and current usage for user +.IR uid . +.I addr +is a pointer to a +.B fs_disk_quota +structure (defined in +.BR <linux/xqm.h> ). +Only the superuser may get the quotas of a user other than himself. +.TP +.SB Q_XSETQLIM +Set disk quota limits for user +.IR uid . +.I addr +is a pointer to a +.B fs_disk_quota +structure (defined in +.BR <linux/xqm.h> ). +This call is restricted to the superuser. +.TP +.SB Q_XGETQSTAT +Returns a +.B fs_quota_stat +structure containing XFS filesystem specific quota information. +This is useful in finding out how much space is spent to store quota +information, and also to get quotaon/off status of a given local XFS +filesystem. +.TP +.SB Q_XQUOTARM +Free the disk space taken by disk quotas. +Quotas must have already been turned off. +.PP +There is no command equivalent to +.B Q_SYNC +for XFS since +.IR sync (1) +writes quota information to disk (in addition to the other filesystem +metadata it writes out). +.SH RETURN VALUES +.LP +.B quotactl(\|) +returns: +.TP +0 +on success. +.TP +\-1 +on failure and sets +.B errno +to indicate the error. +.SH ERRORS +.TP 15 +.SM EFAULT +.I addr +or +.I special +are invalid. +.TP +.SM EINVAL +The kernel has not been compiled with the +.SB QUOTA +option. +.IP +.I cmd +is invalid. +.TP +.SM ENOENT +The file specified by +.I special +or +.I addr +does not exist. +.TP +.SM ENOTBLK +.I special +is not a block device. +.TP +.SM EPERM +The call is privileged and the caller was not the super-user. +.TP +.SM ESRCH +No disc quota is found for the indicated user. +.IP +Quotas have not been turned on for this filesystem. +.TP +.SM EUSERS +The quota table is full. +.LP +If +.I cmd +is +.BR \s-1Q_QUOTAON\s0 , +.B quotactl(\|) +may set errno to: +.TP 15 +.SM EACCES +The quota file pointed to by +.I addr +exists but is not a regular file. +.IP +The quota file pointed to by +.I addr +exists but is not on the +filesystem pointed to by +.IR special . +.TP +.SM EBUSY +.SB Q_QUOTAON +attempted while another +.SB Q_QUOTAON +has already taken place. +.SH "SEE ALSO" +.BR quota (1), +.BR getrlimit (2), +.BR quotacheck (8), +.BR quotaon (8) diff --git a/quotaio.c b/quotaio.c new file mode 100644 index 0000000..0a1927d --- /dev/null +++ b/quotaio.c @@ -0,0 +1,238 @@ +/* + * + * Generic IO operations on quotafiles + * + */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> + +#include "pot.h" +#include "bylabel.h" +#include "common.h" +#include "quotasys.h" +#include "quotaio.h" + +#include "dqblk_v1.h" +#include "dqblk_v2.h" +#include "dqblk_rpc.h" +#include "dqblk_xfs.h" + +static int file_magics[] = INITQMAGICS; +static int known_versions[] = INITKNOWNVERSIONS; + +/* Header in all newer quotafiles */ +struct disk_dqheader { + u_int32_t dqh_magic; + u_int32_t dqh_version; +} __attribute__ ((packed)); + +/* + * Detect quotafile format + */ +int detect_qf_format(int fd, int type) +{ + struct disk_dqheader head; + int ret; + + if ((ret = read(fd, &head, sizeof(head))) < 0) + die(2, _("Error while reading from quotafile: %s\n"), strerror(errno)); + if (ret != sizeof(head) || head.dqh_magic != file_magics[type]) /* Short file? Probably old format */ + return QF_VFSOLD; + if (head.dqh_version > known_versions[type]) /* Too new format? */ + return QF_TOONEW; + return QF_VFSV0; +} + +/* + * Detect quota format and initialize quota IO + */ +struct quota_handle *init_io(struct mntent *mnt, int type, int fmt) +{ + char *qfname = NULL; + int fd = -1, kernfmt; + struct quota_handle *h = smalloc(sizeof(struct quota_handle)); + const char *mnt_fsname = NULL; + + if (!hasquota(mnt, type)) + goto out_handle; + if (!(mnt_fsname = get_device_name(mnt->mnt_fsname))) + goto out_handle; + h->qh_io_flags = 0; + h->qh_type = type; + sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev)); + free((char *)mnt_fsname); + if (!strcmp(mnt->mnt_type, MNTTYPE_NFS)) { /* NFS filesystem? */ + if (fmt != -1 && fmt != QF_RPC) { /* User wanted some other format? */ + fprintf(stderr, _("Only RPC quota format is allowed on NFS filesystem.\n")); + goto out_handle; + } +#ifdef RPC + h->qh_fd = -1; + h->qh_fmt = QF_RPC; + h->qh_ops = "afile_ops_rpc; + return h; +#else + fprintf(stderr, _("RPC quota format not compiled.\n")); + goto out_handle; +#endif + } + + if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { + h->qh_fd = -1; + h->qh_fmt = QF_XFS; + h->qh_ops = "afile_ops_xfs; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops->init_io(h); + return h; + } + kernfmt = kern_quota_format(); /* Check kernel quota format */ + if (kernfmt > 0 && (fmt == -1 || (1 << fmt) & kernfmt) && /* Quota compiled and desired format available? */ + /* Quota turned on? */ + (kernfmt = kern_quota_on(h->qh_quotadev, type, fmt == -1 ? kernfmt : (1 << fmt))) != -1) { + h->qh_io_flags |= IOFL_QUOTAON; + fmt = kernfmt; /* Default is kernel used format */ + } + if (!(qfname = get_qf_name(mnt, type, fmt))) { + fprintf(stderr, _("Can't get quotafile name.\n")); + goto out_handle; + } + if (qfname[0]) { /* Has format any quotafile to open? */ + /* We still need to open file for operations like 'repquota' */ + if ((fd = open(qfname, O_RDWR)) < 0) { + fprintf(stderr, _("Can't open quotafile %s: %s\n"), qfname, + strerror(errno)); + goto out_handle; + } + flock(fd, LOCK_EX); + /* Init handle */ + h->qh_fd = fd; + + /* Check file format */ + h->qh_fmt = detect_qf_format(fd, type); + if (h->qh_fmt == -2) { + fprintf(stderr, _("Quotafile format too new in %s\n"), qfname); + goto out_lock; + } + if (fmt != -1 && h->qh_fmt != fmt) { + fprintf(stderr, + _ + ("Quotafile format detected differs from the specified one (or the one kernel uses on the file).\n")); + goto out_handle; + } + } + else { + h->qh_fd = -1; + h->qh_fmt = fmt; + } + + if (h->qh_fmt == QF_VFSOLD) + h->qh_ops = "afile_ops_1; + else if (h->qh_fmt == QF_VFSV0) + h->qh_ops = "afile_ops_2; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + + if (h->qh_ops->init_io && h->qh_ops->init_io(h) < 0) + goto out_lock; + return h; + out_lock: + if (fd != -1) + flock(fd, LOCK_UN); + out_handle: + if (qfname) + free(qfname); + free(h); + return NULL; +} + +/* + * Create new quotafile of specified format on given filesystem + */ +struct quota_handle *new_io(struct mntent *mnt, int type, int fmt) +{ + char *qfname; + int fd; + struct quota_handle *h; + const char *mnt_fsname; + char namebuf[PATH_MAX]; + + if (fmt == -1) + fmt = QF_VFSV0; /* Use the newest format */ + else if (fmt == QF_RPC || fmt == QF_XFS) { + fprintf(stderr, _("Creation of %s quota format is not supported.\n"), + fmt == QF_RPC ? "RPC" : "XFS"); + return NULL; + } + if (!hasquota(mnt, type) || !(qfname = get_qf_name(mnt, type, fmt))) + return NULL; + sstrncpy(namebuf, qfname, PATH_MAX); + sstrncat(namebuf, ".new", PATH_MAX); + free(qfname); + if ((fd = open(namebuf, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0) { + fprintf(stderr, _("Can't create new quotafile %s: %s\n"), namebuf, strerror(errno)); + return NULL; + } + if (!(mnt_fsname = get_device_name(mnt->mnt_fsname))) + goto out_fd; + h = smalloc(sizeof(struct quota_handle)); + + h->qh_fd = fd; + h->qh_io_flags = 0; + sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev)); + free((char *)mnt_fsname); + h->qh_type = type; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + if (fmt == QF_VFSOLD) + h->qh_ops = "afile_ops_1; + else + h->qh_ops = "afile_ops_2; + + flock(fd, LOCK_EX); + if (h->qh_ops->new_io && h->qh_ops->new_io(h) < 0) { + flock(fd, LOCK_UN); + free(h); + goto out_fd; + } + return h; + out_fd: + close(fd); + return NULL; +} + +/* + * Close quotafile and release handle + */ +int end_io(struct quota_handle *h) +{ + int ret; + + if (h->qh_io_flags & IOFL_INFODIRTY) { + if (h->qh_ops->write_info && (ret = h->qh_ops->write_info(h)) >= 0) + return ret; + h->qh_io_flags &= ~IOFL_INFODIRTY; + } + if (h->qh_ops->end_io && (ret = h->qh_ops->end_io(h)) >= 0) + return ret; + flock(h->qh_fd, LOCK_UN); + close(h->qh_fd); + free(h); + return 0; +} + +/* + * Create empty quota structure + */ +struct dquot *get_empty_dquot(void) +{ + struct dquot *dquot = smalloc(sizeof(struct dquot)); + + memset(dquot, 0, sizeof(*dquot)); + dquot->dq_id = -1; + return dquot; +} diff --git a/quotaio.h b/quotaio.h new file mode 100644 index 0000000..f5d790c --- /dev/null +++ b/quotaio.h @@ -0,0 +1,141 @@ +/* + * + * Header of IO operations for quota utilities + * + */ + +#ifndef _QUOTAIO_H +#define _QUOTAIO_H + +#include <limits.h> +#include <sys/types.h> + +#include "quota.h" +#include "mntopt.h" +#include "dqblk_v1.h" +#include "dqblk_v2.h" +#include "dqblk_rpc.h" +#include "dqblk_xfs.h" + +/* Latest known versions */ +#define INITKNOWNVERSIONS {\ + 0,\ + 0\ +} + +#define QUOTAFORMATS 4 + +#define INITQFBASENAMES {\ + "quota",\ + "aquota",\ + "",\ + ""\ +} + +/* Values for format handling */ +#define QF_TOONEW -2 /* Quota format is too new to handle */ +#define QF_ERROR -1 /* There was error while detecting format (maybe unknown format...) */ +#define QF_VFSOLD 0 /* Old quota format */ +#define QF_VFSV0 1 /* New quota format - version 0 */ +#define QF_RPC 2 /* RPC should be used on given filesystem */ +#define QF_XFS 3 /* XFS quota format */ + +/* + * Definitions for disk quotas imposed on the average user + * (big brother finally hits Linux). + * + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). The timer is started when the user crosses + * their soft limit, it is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +#define IOFL_QUOTAON 0x01 /* Is quota enabled in kernel? */ +#define IOFL_INFODIRTY 0x02 /* Did info change? */ + +struct quotafile_ops; + +/* Generic information about quotafile */ +struct util_dqinfo { + time_t dqi_bgrace; /* Block grace time for given quotafile */ + time_t dqi_igrace; /* Inode grace time for given quotafile */ + union { + struct v2_mem_dqinfo v2_mdqi; + struct xfs_mem_dqinfo xfs_mdqi; + } u; /* Format specific info about quotafile */ +}; + +/* Structure for one opened quota file */ +struct quota_handle { + int qh_fd; /* Handle of file (-1 when IOFL_QUOTAON) */ + int qh_io_flags; /* IO flags for file */ + char qh_quotadev[PATH_MAX]; /* Device file is for */ + int qh_type; /* Type of quotafile */ + int qh_fmt; /* Quotafile format */ + struct quotafile_ops *qh_ops; /* Operations on quotafile */ + struct util_dqinfo qh_info; /* Generic quotafile info */ +}; + +/* Utility quota block */ +struct util_dqblk { + qsize_t dqb_ihardlimit; + qsize_t dqb_isoftlimit; + qsize_t dqb_curinodes; + qsize_t dqb_bhardlimit; + qsize_t dqb_bsoftlimit; + qsize_t dqb_curspace; + time_t dqb_btime; + time_t dqb_itime; + union { + struct v2_mem_dqblk v2_mdqb; + } u; /* Format specific dquot information */ +}; + +#define DQ_FOUND 0x01 /* Dquot was found in the edquotas file */ + +/* Structure for one loaded quota */ +struct dquot { + struct dquot *dq_next; /* Pointer to next dquot in the list */ + qid_t dq_id; /* ID dquot belongs to */ + int dq_flags; /* Some flags for utils */ + struct quota_handle *dq_h; /* Handle of quotafile dquot belongs to */ + struct util_dqblk dq_dqb; /* Parsed data of dquot */ +}; + +/* Structure of quotafile operations */ +struct quotafile_ops { + int (*init_io) (struct quota_handle * h); /* Open quotafile */ + int (*new_io) (struct quota_handle * h); /* Create new quotafile */ + int (*end_io) (struct quota_handle * h); /* Write all changes and close quotafile */ + int (*write_info) (struct quota_handle * h); /* Write info about quotafile */ + struct dquot *(*read_dquot) (struct quota_handle * h, qid_t id); /* Read dquot into memory */ + int (*commit_dquot) (struct dquot * dquot); /* Write given dquot to disk */ + int (*scan_dquots) (struct quota_handle * h, int (*process_dquot) (struct dquot * dquot)); /* Scan quotafile and call callback on every structure */ + int (*report) (struct quota_handle * h, int verbose); /* Function called after 'repquota' to print format specific file information */ +}; + +static inline void mark_quotafile_info_dirty(struct quota_handle *h) +{ + h->qh_io_flags |= IOFL_INFODIRTY; +} + +#define QIO_ENABLED(h) ((h)->qh_io_flags & IOFL_QUOTAON) + +/* Detect format of given quotafile */ +int detect_qf_format(int fd, int type); + +/* Check quota format used on specified medium and initialize it */ +struct quota_handle *init_io(struct mntent *mnt, int type, int fmt); + +/* Create new quotafile of specified format on given filesystem */ +struct quota_handle *new_io(struct mntent *mnt, int type, int fmt); + +/* Close quotafile */ +int end_io(struct quota_handle *h); + +/* Get empty quota structure */ +struct dquot *get_empty_dquot(void); + +#endif /* _QUOTAIO_H */ diff --git a/quotaio_rpc.c b/quotaio_rpc.c new file mode 100644 index 0000000..0e33390 --- /dev/null +++ b/quotaio_rpc.c @@ -0,0 +1,55 @@ +/* + * quotaio_rpc.c - quota IO operations for RPC (just wrappers for RPC calls) + */ + +#include <stdio.h> +#include <sys/types.h> + +#include "quotaio.h" +#include "dqblk_rpc.h" +#include "rquota_client.h" + +static struct dquot *rpc_read_dquot(struct quota_handle *h, qid_t id); +static int rpc_commit_dquot(struct dquot *dquot); + +struct quotafile_ops quotafile_ops_rpc = { + NULL, /* init_io */ + NULL, /* new_io */ + NULL, /* end_io */ + NULL, /* write_info */ + rpc_read_dquot, + rpc_commit_dquot, + NULL /* scan_dquots */ +}; + +/* + * Read a dqblk struct from RPC server - just wrapper function. + */ +static struct dquot *rpc_read_dquot(struct quota_handle *h, qid_t id) +{ +#ifdef RPC + struct dquot *dquot = get_empty_dquot(); + + dquot->dq_id = id; + dquot->dq_h = h; + rpc_rquota_get(dquot); + return dquot; +#else + errno = ENOTSUP; + return NULL; +#endif +} + +/* + * Write a dqblk struct to RPC server - just wrapper function. + */ +static int rpc_commit_dquot(struct dquot *dquot) +{ +#ifdef RPC + rpc_rquota_set(QCMD(Q_RPC_SETQUOTA, dquot->dq_h->qh_type), dquot); + return 0; +#else + errno = ENOTSUP; + return -1; +#endif +} diff --git a/quotaio_v1.c b/quotaio_v1.c new file mode 100644 index 0000000..e09dc2f --- /dev/null +++ b/quotaio_v1.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. All + * rights reserved. + * + * This code is derived from software contributed to Berkeley by Robert Elz at + * The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $" +#ident "$Copyright: All rights reserved. $" +#ident "$Id: quotaio_v1.c,v 1.1 2001/03/23 12:03:28 jkar8572 Exp $" + +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +#include "pot.h" +#include "common.h" +#include "quotaio_v1.h" +#include "dqblk_v1.h" +#include "quotaio.h" + +static int v1_init_io(struct quota_handle *h); +static int v1_new_io(struct quota_handle *h); +static int v1_write_info(struct quota_handle *h); +static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id); +static int v1_commit_dquot(struct dquot *dquot); +static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot * dquot)); + +struct quotafile_ops quotafile_ops_1 = { + v1_init_io, + v1_new_io, + NULL, /* end_io */ + v1_write_info, + v1_read_dquot, + v1_commit_dquot, + v1_scan_dquots, + NULL /* report */ +}; + +/* + * Copy dquot from disk to memory + */ +static inline void v1_disk2memdqblk(struct util_dqblk *m, struct v1_disk_dqblk *d) +{ + m->dqb_ihardlimit = d->dqb_ihardlimit; + m->dqb_isoftlimit = d->dqb_isoftlimit; + m->dqb_bhardlimit = d->dqb_bhardlimit; + m->dqb_bsoftlimit = d->dqb_bsoftlimit; + m->dqb_curinodes = d->dqb_curinodes; + m->dqb_curspace = d->dqb_curblocks * V1_DQBLK_SIZE; + m->dqb_itime = d->dqb_itime; + m->dqb_btime = d->dqb_btime; +} + +/* + * Copy dquot from memory to disk + */ +static inline void v1_mem2diskdqblk(struct v1_disk_dqblk *d, struct util_dqblk *m) +{ + d->dqb_ihardlimit = m->dqb_ihardlimit; + d->dqb_isoftlimit = m->dqb_isoftlimit; + d->dqb_bhardlimit = m->dqb_bhardlimit; + d->dqb_bsoftlimit = m->dqb_bsoftlimit; + d->dqb_curinodes = m->dqb_curinodes; + d->dqb_curblocks = m->dqb_curspace >> V1_DQBLK_SIZE_BITS; + d->dqb_itime = m->dqb_itime; + d->dqb_btime = m->dqb_btime; +} + +/* Convert kernel quotablock format to utility one */ +static inline void v1_kern2utildqblk(struct util_dqblk *u, struct v1_kern_dqblk *k) +{ + u->dqb_ihardlimit = k->dqb_ihardlimit; + u->dqb_isoftlimit = k->dqb_isoftlimit; + u->dqb_bhardlimit = k->dqb_bhardlimit; + u->dqb_bsoftlimit = k->dqb_bsoftlimit; + u->dqb_curinodes = k->dqb_curinodes; + u->dqb_curspace = k->dqb_curblocks << V1_DQBLK_SIZE_BITS; + u->dqb_itime = k->dqb_itime; + u->dqb_btime = k->dqb_btime; +} + +/* Convert utility quotablock format to kernel one */ +static inline void v1_util2kerndqblk(struct v1_kern_dqblk *k, struct util_dqblk *u) +{ + k->dqb_ihardlimit = u->dqb_ihardlimit; + k->dqb_isoftlimit = u->dqb_isoftlimit; + k->dqb_bhardlimit = u->dqb_bhardlimit; + k->dqb_bsoftlimit = u->dqb_bsoftlimit; + k->dqb_curinodes = u->dqb_curinodes; + k->dqb_curblocks = (u->dqb_curspace + V1_DQBLK_SIZE - 1) >> V1_DQBLK_SIZE_BITS; + k->dqb_itime = u->dqb_itime; + k->dqb_btime = u->dqb_btime; +} + +/* + * Open quotafile + */ +static int v1_init_io(struct quota_handle *h) +{ + if (QIO_ENABLED(h)) { + struct v1_kern_dqblk kdqblk; + + if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < + 0) return -1; + h->qh_info.dqi_bgrace = kdqblk.dqb_btime; + h->qh_info.dqi_igrace = kdqblk.dqb_itime; + } + else { + struct v1_disk_dqblk ddqblk; + + lseek(h->qh_fd, 0, SEEK_SET); + if (read(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk)) + return -1; + h->qh_info.dqi_bgrace = ddqblk.dqb_btime; + h->qh_info.dqi_igrace = ddqblk.dqb_itime; + } + return 0; +} + +/* + * Initialize new quotafile + */ +static int v1_new_io(struct quota_handle *h) +{ + struct v1_disk_dqblk ddqblk; + + /* Write at least roots dquot with grace times */ + memset(&ddqblk, 0, sizeof(ddqblk)); + ddqblk.dqb_btime = MAX_DQ_TIME; + ddqblk.dqb_itime = MAX_IQ_TIME; + h->qh_info.dqi_bgrace = MAX_DQ_TIME; + h->qh_info.dqi_igrace = MAX_IQ_TIME; + lseek(h->qh_fd, 0, SEEK_SET); + if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk)) + return -1; + return 0; +} + +/* + * Write information (grace times to file) + */ +static int v1_write_info(struct quota_handle *h) +{ + if (QIO_ENABLED(h)) { + struct v1_kern_dqblk kdqblk; + + if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < + 0) return -1; + kdqblk.dqb_btime = h->qh_info.dqi_bgrace; + kdqblk.dqb_itime = h->qh_info.dqi_igrace; + if (quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < + 0) return -1; + } + else { + struct v1_disk_dqblk ddqblk; + + lseek(h->qh_fd, 0, SEEK_SET); + if (read(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk)) + return -1; + ddqblk.dqb_btime = h->qh_info.dqi_bgrace; + ddqblk.dqb_itime = h->qh_info.dqi_igrace; + lseek(h->qh_fd, 0, SEEK_SET); + if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk)) + return -1; + } + return 0; +} + +/* + * Read a dqblk struct from the quotafile. + * User can use 'errno' to detect error. + */ +static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id) +{ + struct v1_disk_dqblk ddqblk; + struct dquot *dquot = get_empty_dquot(); + + dquot->dq_id = id; + dquot->dq_h = h; + if (QIO_ENABLED(h)) { /* Does kernel use the file? */ + struct v1_kern_dqblk kdqblk; + + if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < + 0) { + free(dquot); + return NULL; + } + v1_kern2utildqblk(&dquot->dq_dqb, &kdqblk); + } + else { + lseek(h->qh_fd, (long)V1_DQOFF(id), SEEK_SET); + switch (read(h->qh_fd, &ddqblk, sizeof(ddqblk))) { + case 0: /* EOF */ + /* + * Convert implicit 0 quota (EOF) into an + * explicit one (zero'ed dqblk) + */ + memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); + + break; + case sizeof(struct v1_disk_dqblk): /* OK */ + v1_disk2memdqblk(&dquot->dq_dqb, &ddqblk); + + break; + default: /* ERROR */ + free(dquot); + return NULL; + } + } + return dquot; +} + +/* + * Write a dqblk struct to the quotafile. + * User can process use 'errno' to detect error + */ +static int v1_commit_dquot(struct dquot *dquot) +{ + struct v1_disk_dqblk ddqblk; + struct quota_handle *h = dquot->dq_h; + + if (QIO_ENABLED(h)) { /* Kernel uses same file? */ + struct v1_kern_dqblk kdqblk; + + v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb); + if (quotactl + (QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, dquot->dq_id, + (void *)&kdqblk) < 0) + return -1; + } + else { + v1_mem2diskdqblk(&ddqblk, &dquot->dq_dqb); + lseek(h->qh_fd, (long)V1_DQOFF(dquot->dq_id), SEEK_SET); + if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk)) + return -1; + } + return 0; +} + +/* + * Scan all dquots in file and call callback on each + */ +static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot * dquot)) +{ + int rd; + struct v1_disk_dqblk ddqblk; + struct dquot *dquot = get_empty_dquot(); + qid_t id = 0; + + if (QIO_ENABLED(h)) /* Kernel uses same file? */ + if (quotactl(QCMD(Q_SYNC, h->qh_type), h->qh_quotadev, 0, NULL) < 0) + die(4, _("Can't sync quotas on device %s: %s\n"), h->qh_quotadev, + strerror(errno)); + memset(dquot, 0, sizeof(*dquot)); + dquot->dq_h = h; + lseek(h->qh_fd, 0, SEEK_SET); + while ((rd = read(h->qh_fd, &ddqblk, sizeof(ddqblk))) == sizeof(ddqblk)) { + if ( + (ddqblk.dqb_ihardlimit | ddqblk.dqb_isoftlimit | ddqblk.dqb_bhardlimit | ddqblk. + dqb_bsoftlimit | ddqblk.dqb_curblocks | ddqblk.dqb_curinodes | ddqblk. + dqb_itime | ddqblk.dqb_btime) == 0) + continue; + v1_disk2memdqblk(&dquot->dq_dqb, &ddqblk); + dquot->dq_id = id++; + if ((rd = process_dquot(dquot)) < 0) { + free(dquot); + return rd; + } + } + if (!rd) /* EOF? */ + return 0; + return -1; /* Some read error... */ +} diff --git a/quotaio_v1.h b/quotaio_v1.h new file mode 100644 index 0000000..f36ed63 --- /dev/null +++ b/quotaio_v1.h @@ -0,0 +1,39 @@ +/* + * Headerfile for old quotafile format + */ + +#ifndef _QUOTAIO_V1_H +#define _QUOTAIO_V1_H + +#include <sys/types.h> + +#define V1_DQBLK_SIZE_BITS 10 +#define V1_DQBLK_SIZE (1 << V1_DQBLK_SIZE_BITS) /* Size of one quota block in bytes in old format */ + +#define V1_DQOFF(__id) ((loff_t) ((__id) * sizeof(struct v1_disk_dqblk))) + +/* Structure of quota on disk */ +struct v1_disk_dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +} __attribute__ ((packed)); + +/* Structure used for communication with kernel */ +struct v1_kern_dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +}; + +#endif diff --git a/quotaio_v2.c b/quotaio_v2.c new file mode 100644 index 0000000..f200b3a --- /dev/null +++ b/quotaio_v2.c @@ -0,0 +1,734 @@ +/* + * Implementation of new quotafile format + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <asm/byteorder.h> + +#include "pot.h" +#include "common.h" +#include "quotaio_v2.h" +#include "dqblk_v2.h" +#include "quotaio.h" + +typedef char *dqbuf_t; + +static int v2_init_io(struct quota_handle *h); +static int v2_new_io(struct quota_handle *h); +static int v2_write_info(struct quota_handle *h); +static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); +static int v2_commit_dquot(struct dquot *dquot); +static int v2_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot * dquot)); +static int v2_report(struct quota_handle *h, int verbose); + +struct quotafile_ops quotafile_ops_2 = { + v2_init_io, + v2_new_io, + NULL, /* end_io */ + v2_write_info, + v2_read_dquot, + v2_commit_dquot, + v2_scan_dquots, + v2_report +}; + +#define getdqbuf() smalloc(V2_DQBLKSIZE) +#define freedqbuf(buf) free(buf) + +/* + * Copy dquot from disk to memory + */ +static inline void v2_disk2memdqblk(struct util_dqblk *m, struct v2_disk_dqblk *d) +{ + m->dqb_ihardlimit = __le32_to_cpu(d->dqb_ihardlimit); + m->dqb_isoftlimit = __le32_to_cpu(d->dqb_isoftlimit); + m->dqb_bhardlimit = __le32_to_cpu(d->dqb_bhardlimit); + m->dqb_bsoftlimit = __le32_to_cpu(d->dqb_bsoftlimit); + m->dqb_curinodes = __le32_to_cpu(d->dqb_curinodes); + m->dqb_curspace = __le64_to_cpu(d->dqb_curspace); + m->dqb_itime = __le64_to_cpu(d->dqb_itime); + m->dqb_btime = __le64_to_cpu(d->dqb_btime); +} + +/* + * Copy dquot from memory to disk + */ +static inline void v2_mem2diskdqblk(struct v2_disk_dqblk *d, struct util_dqblk *m) +{ + d->dqb_ihardlimit = __cpu_to_le32(m->dqb_ihardlimit); + d->dqb_isoftlimit = __cpu_to_le32(m->dqb_isoftlimit); + d->dqb_bhardlimit = __cpu_to_le32(m->dqb_bhardlimit); + d->dqb_bsoftlimit = __cpu_to_le32(m->dqb_bsoftlimit); + d->dqb_curinodes = __cpu_to_le32(m->dqb_curinodes); + d->dqb_curspace = __cpu_to_le64(m->dqb_curspace); + d->dqb_itime = __cpu_to_le64(m->dqb_itime); + d->dqb_btime = __cpu_to_le64(m->dqb_btime); +} + +/* + * Copy dqinfo from disk to memory + */ +static inline void v2_disk2memdqinfo(struct util_dqinfo *m, struct v2_disk_dqinfo *d) +{ + m->dqi_bgrace = __le32_to_cpu(d->dqi_bgrace); + m->dqi_igrace = __le32_to_cpu(d->dqi_igrace); + m->u.v2_mdqi.dqi_flags = __le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; + m->u.v2_mdqi.dqi_blocks = __le32_to_cpu(d->dqi_blocks); + m->u.v2_mdqi.dqi_free_blk = __le32_to_cpu(d->dqi_free_blk); + m->u.v2_mdqi.dqi_free_entry = __le32_to_cpu(d->dqi_free_entry); +} + +/* + * Copy dqinfo from memory to disk + */ +static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, struct util_dqinfo *m) +{ + d->dqi_bgrace = __cpu_to_le32(m->dqi_bgrace); + d->dqi_igrace = __cpu_to_le32(m->dqi_igrace); + d->dqi_flags = __cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); + d->dqi_blocks = __cpu_to_le32(m->u.v2_mdqi.dqi_blocks); + d->dqi_free_blk = __cpu_to_le32(m->u.v2_mdqi.dqi_free_blk); + d->dqi_free_entry = __cpu_to_le32(m->u.v2_mdqi.dqi_free_entry); +} + +/* Convert kernel quotablock format to utility one */ +static inline void v2_kern2utildqblk(struct util_dqblk *u, struct v2_kern_dqblk *k) +{ + u->dqb_ihardlimit = k->dqb_ihardlimit; + u->dqb_isoftlimit = k->dqb_isoftlimit; + u->dqb_bhardlimit = k->dqb_bhardlimit; + u->dqb_bsoftlimit = k->dqb_bsoftlimit; + u->dqb_curinodes = k->dqb_curinodes; + u->dqb_curspace = k->dqb_curspace; + u->dqb_itime = k->dqb_itime; + u->dqb_btime = k->dqb_btime; +} + +/* Convert utility quotablock format to kernel one */ +static inline void v2_util2kerndqblk(struct v2_kern_dqblk *k, struct util_dqblk *u) +{ + k->dqb_ihardlimit = u->dqb_ihardlimit; + k->dqb_isoftlimit = u->dqb_isoftlimit; + k->dqb_bhardlimit = u->dqb_bhardlimit; + k->dqb_bsoftlimit = u->dqb_bsoftlimit; + k->dqb_curinodes = u->dqb_curinodes; + k->dqb_curspace = u->dqb_curspace; + k->dqb_itime = u->dqb_itime; + k->dqb_btime = u->dqb_btime; +} + +/* Is given dquot empty? */ +static int empty_dquot(struct v2_disk_dqblk *d) +{ + static struct v2_disk_dqblk fakedquot; + + return !memcmp(d, &fakedquot, sizeof(fakedquot)); +} + +/* + * Open quotafile + */ +static int v2_init_io(struct quota_handle *h) +{ + if (QIO_ENABLED(h)) { + struct v2_kern_dqinfo kdqinfo; + + if (quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < + 0) return -1; + h->qh_info.dqi_bgrace = kdqinfo.dqi_bgrace; + h->qh_info.dqi_igrace = kdqinfo.dqi_igrace; + h->qh_info.u.v2_mdqi.dqi_flags = kdqinfo.dqi_flags; + h->qh_info.u.v2_mdqi.dqi_blocks = kdqinfo.dqi_blocks; + h->qh_info.u.v2_mdqi.dqi_free_blk = kdqinfo.dqi_free_blk; + h->qh_info.u.v2_mdqi.dqi_free_entry = kdqinfo.dqi_free_entry; + } + else { + struct v2_disk_dqinfo ddqinfo; + + lseek(h->qh_fd, V2_DQINFOOFF, SEEK_SET); + if (read(h->qh_fd, &ddqinfo, sizeof(ddqinfo)) != sizeof(ddqinfo)) + return -1; + v2_disk2memdqinfo(&h->qh_info, &ddqinfo); + } + return 0; +} + +/* + * Initialize new quotafile + */ +static int v2_new_io(struct quota_handle *h) +{ + int file_magics[] = INITQMAGICS; + int known_versions[] = INIT_V2_VERSIONS; + struct v2_disk_dqheader ddqheader; + struct v2_disk_dqinfo ddqinfo; + + /* Write basic quota header */ + ddqheader.dqh_magic = __cpu_to_le32(file_magics[h->qh_type]); + ddqheader.dqh_version = __cpu_to_le32(known_versions[h->qh_type]); + lseek(h->qh_fd, 0, SEEK_SET); + if (write(h->qh_fd, &ddqheader, sizeof(ddqheader)) != sizeof(ddqheader)) + return -1; + /* Write information about quotafile */ + h->qh_info.dqi_bgrace = MAX_DQ_TIME; + h->qh_info.dqi_igrace = MAX_IQ_TIME; + h->qh_info.u.v2_mdqi.dqi_flags = 0; + h->qh_info.u.v2_mdqi.dqi_blocks = V2_DQTREEOFF + 1; + h->qh_info.u.v2_mdqi.dqi_free_blk = 0; + h->qh_info.u.v2_mdqi.dqi_free_entry = 0; + v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); + lseek(h->qh_fd, V2_DQINFOOFF, SEEK_SET); + if (write(h->qh_fd, &ddqinfo, sizeof(ddqinfo)) != sizeof(ddqinfo)) + return -1; + return 0; +} + +/* + * Write information (grace times to file) + */ +static int v2_write_info(struct quota_handle *h) +{ + if (QIO_ENABLED(h)) { + struct v2_kern_dqinfo kdqinfo; + + kdqinfo.dqi_bgrace = h->qh_info.dqi_bgrace; + kdqinfo.dqi_igrace = h->qh_info.dqi_igrace; + kdqinfo.dqi_flags = h->qh_info.u.v2_mdqi.dqi_flags; + kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_blocks; + kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_free_blk; + kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_free_entry; + if (quotactl(QCMD(Q_V2_SETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < + 0) return -1; + } + else { + struct v2_disk_dqinfo ddqinfo; + + v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); + lseek(h->qh_fd, V2_DQINFOOFF, SEEK_SET); + if (write(h->qh_fd, &ddqinfo, sizeof(ddqinfo)) != sizeof(ddqinfo)) + return -1; + } + return 0; +} + +/* Read given block */ +static void read_blk(struct quota_handle *h, uint blk, dqbuf_t buf) +{ + int err; + + lseek(h->qh_fd, blk << V2_DQBLKSIZE_BITS, SEEK_SET); + err = read(h->qh_fd, buf, V2_DQBLKSIZE); + if (err < 0) + die(2, "Can't read block %u: %s\n", blk, strerror(errno)); + else if (err != V2_DQBLKSIZE) + memset(buf + err, 0, V2_DQBLKSIZE - err); +} + +/* Write block */ +static int write_blk(struct quota_handle *h, uint blk, dqbuf_t buf) +{ + int err; + + lseek(h->qh_fd, blk << V2_DQBLKSIZE_BITS, SEEK_SET); + err = write(h->qh_fd, buf, V2_DQBLKSIZE); + if (err < 0 && errno != ENOSPC) + die(2, "Can't write block (%u): %s\n", blk, strerror(errno)); + if (err != V2_DQBLKSIZE) + return -ENOSPC; + return 0; +} + +/* Get free block in file (either from free list or create new one) */ +static int get_free_dqblk(struct quota_handle *h) +{ + dqbuf_t buf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi; + int blk; + + if (info->dqi_free_blk) { + blk = info->dqi_free_blk; + read_blk(h, blk, buf); + info->dqi_free_blk = __le32_to_cpu(dh->dqdh_next_free); + } + else { + memset(buf, 0, V2_DQBLKSIZE); + if (write_blk(h, info->dqi_blocks, buf) < 0) { /* Assure block allocation... */ + freedqbuf(buf); + fprintf(stderr, "Can't allocate new quota block (out of disk space).\n"); + return -ENOSPC; + } + blk = info->dqi_blocks++; + } + mark_quotafile_info_dirty(h); + freedqbuf(buf); + return blk; +} + +/* Put given block to free list */ +static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, uint blk) +{ + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi; + + dh->dqdh_next_free = __cpu_to_le32(info->dqi_free_blk); + dh->dqdh_prev_free = __cpu_to_le32(0); + dh->dqdh_entries = __cpu_to_le16(0); + info->dqi_free_blk = blk; + mark_quotafile_info_dirty(h); + write_blk(h, blk, buf); +} + +/* Remove given block from the list of blocks with free entries */ +static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + uint nextblk = __le32_to_cpu(dh->dqdh_next_free), prevblk = + + __le32_to_cpu(dh->dqdh_prev_free); + + if (nextblk) { + read_blk(h, nextblk, tmpbuf); + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; + write_blk(h, nextblk, tmpbuf); + } + if (prevblk) { + read_blk(h, prevblk, tmpbuf); + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; + write_blk(h, prevblk, tmpbuf); + } + else { + h->qh_info.u.v2_mdqi.dqi_free_entry = nextblk; + mark_quotafile_info_dirty(h); + } + freedqbuf(tmpbuf); + dh->dqdh_next_free = dh->dqdh_prev_free = __cpu_to_le32(0); + write_blk(h, blk, buf); /* No matter whether write succeeds block is out of list */ +} + +/* Insert given block to the beginning of list with free entries */ +static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi; + + dh->dqdh_next_free = __cpu_to_le32(info->dqi_free_entry); + dh->dqdh_prev_free = __cpu_to_le32(0); + write_blk(h, blk, buf); + if (info->dqi_free_entry) { + read_blk(h, info->dqi_free_entry, tmpbuf); + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = __cpu_to_le32(blk); + write_blk(h, info->dqi_free_entry, tmpbuf); + } + freedqbuf(tmpbuf); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); +} + +/* Find space for dquot */ +static uint find_free_dqentry(struct quota_handle *h, struct dquot *dquot, int *err) +{ + int blk, i; + struct v2_disk_dqdbheader *dh; + struct v2_disk_dqblk *ddquot; + struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi; + dqbuf_t buf; + + *err = 0; + buf = getdqbuf(); + dh = (struct v2_disk_dqdbheader *)buf; + ddquot = V2_GETENTRIES(buf); + if (info->dqi_free_entry) { + blk = info->dqi_free_entry; + read_blk(h, blk, buf); + } + else { + blk = get_free_dqblk(h); + if (blk < 0) { + freedqbuf(buf); + *err = blk; + return 0; + } + memset(buf, 0, V2_DQBLKSIZE); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); + } + if (__le16_to_cpu(dh->dqdh_entries) + 1 >= V2_DQSTRINBLK) /* Block will be full? */ + remove_free_dqentry(h, buf, blk); + dh->dqdh_entries = __cpu_to_le16(__le16_to_cpu(dh->dqdh_entries) + 1); + /* Find free structure in block */ + for (i = 0; i < V2_DQSTRINBLK && !empty_dquot(ddquot + i); i++); + if (i == V2_DQSTRINBLK) + die(2, "find_free_dqentry(): Data block full but it shouldn't.\n"); + write_blk(h, blk, buf); + dquot->dq_dqb.u.v2_mdqb.dqb_off = + (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + + + i * sizeof(struct v2_disk_dqblk); + freedqbuf(buf); + return blk; +} + +/* Insert reference to structure into the trie */ +static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, uint * treeblk, int depth) +{ + dqbuf_t buf; + int newson = 0, newact = 0; + u_int32_t *ref; + uint newblk; + int ret = 0; + + buf = getdqbuf(); + if (!*treeblk) { + ret = get_free_dqblk(h); + if (ret < 0) + goto out_buf; + *treeblk = ret; + memset(buf, 0, V2_DQBLKSIZE); + newact = 1; + } + else + read_blk(h, *treeblk, buf); + ref = (u_int32_t *) buf; + newblk = __le32_to_cpu(ref[V2_GETIDINDEX(dquot->dq_id, depth)]); + if (!newblk) + newson = 1; + if (depth == V2_DQTREEDEPTH - 1) { + if (newblk) + die(2, "Inserting already present quota entry (block %u).\n", + ref[V2_GETIDINDEX(dquot->dq_id, depth)]); + newblk = find_free_dqentry(h, dquot, &ret); + } + else + ret = do_insert_tree(h, dquot, &newblk, depth + 1); + if (newson && ret >= 0) { + ref[V2_GETIDINDEX(dquot->dq_id, depth)] = __cpu_to_le32(newblk); + write_blk(h, *treeblk, buf); + } + else if (newact && ret < 0) + put_free_dqblk(h, buf, *treeblk); + out_buf: + freedqbuf(buf); + return ret; +} + +/* Wrapper for inserting quota structure into tree */ +static inline void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) +{ + int tmp = V2_DQTREEOFF; + + if (do_insert_tree(h, dquot, &tmp, 0) < 0) + die(2, "Can't write quota (id %u): %s\n", (uint) dquot->dq_id, strerror(errno)); +} + +/* Write dquot to file */ +static void v2_write_dquot(struct dquot *dquot) +{ + ssize_t ret; + struct v2_disk_dqblk ddquot; + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) + dq_insert_tree(dquot->dq_h, dquot); + lseek(dquot->dq_h->qh_fd, dquot->dq_dqb.u.v2_mdqb.dqb_off, SEEK_SET); + v2_mem2diskdqblk(&ddquot, &dquot->dq_dqb); + ddquot.dqb_id = __cpu_to_le32(dquot->dq_id); + ret = write(dquot->dq_h->qh_fd, (char *)&ddquot, sizeof(struct v2_disk_dqblk)); + if (ret != sizeof(struct v2_disk_dqblk)) { + if (ret > 0) + errno = ENOSPC; + die(2, "Quota write failed (id %u): %s\n", (uint) dquot->dq_id, strerror(errno)); + } +} + +/* Free dquot entry in data block */ +static void free_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk) +{ + struct v2_disk_dqdbheader *dh; + dqbuf_t buf = getdqbuf(); + + if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> V2_DQBLKSIZE_BITS != blk) + die(2, "Quota structure has offset to other block (%u) than it should (%u).\n", blk, + (uint) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> V2_DQBLKSIZE_BITS)); + read_blk(h, blk, buf); + dh = (struct v2_disk_dqdbheader *)buf; + dh->dqdh_entries = __cpu_to_le16(__le16_to_cpu(dh->dqdh_entries) - 1); + if (!__le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ + remove_free_dqentry(h, buf, blk); + put_free_dqblk(h, buf, blk); + } + else { + memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & ((1 << V2_DQBLKSIZE_BITS) - 1)), 0, + sizeof(struct v2_disk_dqblk)); + + if (__le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK - 1) /* First free entry? */ + insert_free_dqentry(h, buf, blk); /* This will also write data block */ + else + write_blk(h, blk, buf); + } + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + freedqbuf(buf); +} + +/* Remove reference to dquot from tree */ +static void remove_tree(struct quota_handle *h, struct dquot *dquot, uint * blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + uint newblk; + u_int32_t *ref = (u_int32_t *) buf; + + read_blk(h, *blk, buf); + newblk = __le32_to_cpu(ref[V2_GETIDINDEX(dquot->dq_id, depth)]); + if (depth == V2_DQTREEDEPTH - 1) { + free_dqentry(h, dquot, newblk); + newblk = 0; + } + else + remove_tree(h, dquot, &newblk, depth + 1); + if (!newblk) { + int i; + + ref[V2_GETIDINDEX(dquot->dq_id, depth)] = __cpu_to_le32(0); + for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */ + if (i == V2_DQBLKSIZE) { + put_free_dqblk(h, buf, *blk); + *blk = 0; + } + else + write_blk(h, *blk, buf); + } + freedqbuf(buf); +} + +/* Delete dquot from tree */ +static void v2_delete_dquot(struct dquot *dquot) +{ + uint tmp = V2_DQTREEOFF; + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ + return; + remove_tree(dquot->dq_h, dquot, &tmp, 0); +} + +/* Find entry in block */ +static loff_t find_block_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk) +{ + dqbuf_t buf = getdqbuf(); + int i; + struct v2_disk_dqblk *ddquot = V2_GETENTRIES(buf); + + read_blk(h, blk, buf); + if (dquot->dq_id) + for (i = 0; i < V2_DQSTRINBLK && __le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; + i++); + else { /* ID 0 as a bit more complicated searching... */ + for (i = 0; i < V2_DQSTRINBLK; i++) + if (!__le32_to_cpu(ddquot[i].dqb_id) && !empty_dquot(ddquot + i)) + break; + } + if (i == V2_DQSTRINBLK) + die(2, "Quota for id %u referenced but not present.\n", dquot->dq_id); + freedqbuf(buf); + return (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + + + i * sizeof(struct v2_disk_dqblk); +} + +/* Find entry for given id in the tree */ +static loff_t find_tree_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + u_int32_t *ref = (u_int32_t *) buf; + + read_blk(h, blk, buf); + ret = 0; + blk = __le32_to_cpu(ref[V2_GETIDINDEX(dquot->dq_id, depth)]); + if (!blk) /* No reference? */ + goto out_buf; + if (depth < V2_DQTREEDEPTH - 1) + ret = find_tree_dqentry(h, dquot, blk, depth + 1); + else + ret = find_block_dqentry(h, dquot, blk); + out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree - wrapper function */ +static inline loff_t find_dqentry(struct quota_handle *h, struct dquot *dquot) +{ + return find_tree_dqentry(h, dquot, V2_DQTREEOFF, 0); +} + +/* + * Read dquot (either from disk or from kernel) + * User can use errno to detect error when NULL is returned + */ +static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) +{ + loff_t offset; + ssize_t ret; + struct v2_disk_dqblk ddquot; + struct dquot *dquot = get_empty_dquot(); + + dquot->dq_id = id; + dquot->dq_h = h; + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); + + if (QIO_ENABLED(h)) { + struct v2_kern_dqblk kdqblk; + + if (quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < + 0) { + free(dquot); + return NULL; + } + v2_kern2utildqblk(&dquot->dq_dqb, &kdqblk); + return dquot; + } + offset = find_dqentry(h, dquot); + if (offset > 0) { + dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; + lseek(h->qh_fd, offset, SEEK_SET); + ret = read(h->qh_fd, (char *)&ddquot, sizeof(struct v2_disk_dqblk)); + if (ret != sizeof(struct v2_disk_dqblk)) { + if (ret > 0) + errno = EIO; + die(2, "Can't read quota structure for id %u: %s\n", dquot->dq_id, + strerror(errno)); + } + v2_disk2memdqblk(&dquot->dq_dqb, &ddquot); + } + return dquot; +} + +/* + * Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... + * User can process use 'errno' to detect error + */ +static int v2_commit_dquot(struct dquot *dquot) +{ + struct util_dqblk *b = &dquot->dq_dqb; + + if (QIO_ENABLED(dquot->dq_h)) { + struct v2_kern_dqblk kdqblk; + + v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb); + if (quotactl + (QCMD(Q_V2_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, + dquot->dq_id, (void *)&kdqblk) < 0) + return -1; + } + if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && !b->dqb_isoftlimit + && !b->dqb_bhardlimit && !b->dqb_ihardlimit) + v2_delete_dquot(dquot); + else + v2_write_dquot(dquot); + return 0; +} + +/* + * Scan all dquots in file and call callback on each + */ +#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) +#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) + +static int report_block(struct dquot *dquot, uint blk, char *bitmap, + int (*process_dquot) (struct dquot *)) +{ + dqbuf_t buf = getdqbuf(); + struct v2_disk_dqdbheader *dh; + struct v2_disk_dqblk *ddata; + int entries, i; + + set_bit(bitmap, blk); + read_blk(dquot->dq_h, blk, buf); + dh = (struct v2_disk_dqdbheader *)buf; + ddata = V2_GETENTRIES(buf); + entries = __le16_to_cpu(dh->dqdh_entries); + for (i = 0; i < V2_DQSTRINBLK; i++) + if (!empty_dquot(ddata + i)) { + v2_disk2memdqblk(&dquot->dq_dqb, ddata + i); + dquot->dq_id = __le32_to_cpu(ddata[i].dqb_id); + if (process_dquot(dquot) < 0) + break; + } + freedqbuf(buf); + return entries; +} + +static int report_tree(struct dquot *dquot, uint blk, int depth, char *bitmap, + int (*process_dquot) (struct dquot *)) +{ + int entries = 0, i; + dqbuf_t buf = getdqbuf(); + u_int32_t *ref = (u_int32_t *) buf; + + read_blk(dquot->dq_h, blk, buf); + if (depth == V2_DQTREEDEPTH - 1) { + for (i = 0; i < V2_DQBLKSIZE >> 2; i++) { + blk = __le32_to_cpu(ref[i]); + if (blk && !get_bit(bitmap, blk)) + entries += report_block(dquot, blk, bitmap, process_dquot); + } + } + else { + for (i = 0; i < V2_DQBLKSIZE >> 2; i++) + if ((blk = __le32_to_cpu(ref[i]))) + entries += + report_tree(dquot, blk, depth + 1, bitmap, process_dquot); + } + freedqbuf(buf); + return entries; +} + +static uint find_set_bits(char *bmp, int blocks) +{ + uint i, used = 0; + + for (i = 0; i < blocks; i++) + if (get_bit(bmp, i)) + used++; + return used; +} + +static int v2_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot * dquot)) +{ + char *bitmap; + struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi; + struct dquot *dquot = get_empty_dquot(); + + if (QIO_ENABLED(h)) /* Kernel uses same file? */ + if (quotactl(QCMD(Q_SYNC, h->qh_type), h->qh_quotadev, 0, NULL) < 0) + die(4, _("Can't sync quotas on device %s: %s\n"), h->qh_quotadev, + strerror(errno)); + dquot->dq_h = h; + bitmap = smalloc((info->dqi_blocks + 7) >> 3); + memset(bitmap, 0, (info->dqi_blocks + 7) >> 3); + info->dqi_used_entries = report_tree(dquot, V2_DQTREEOFF, 0, bitmap, process_dquot); + info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); + free(bitmap); + free(dquot); + return 0; +} + +/* Report information about quotafile */ +static int v2_report(struct quota_handle *h, int verbose) +{ + struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi; + + if (verbose) + printf + ("Statistics:\nTotal blocks: %u\nData blocks: %u\nEntries: %u\nUsed average: %f\n", + info->dqi_blocks, info->dqi_data_blocks, info->dqi_used_entries, + ((float)info->dqi_used_entries) / info->dqi_data_blocks); + return 0; +} diff --git a/quotaio_v2.h b/quotaio_v2.h new file mode 100644 index 0000000..2657343 --- /dev/null +++ b/quotaio_v2.h @@ -0,0 +1,88 @@ +/* + * + * Header file for disk format of new quotafile format + * + */ + +#ifndef _QUOTAIO_V2_H +#define _QUOTAIO_V2_H + +#include <sys/types.h> +#include "quota.h" + +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ +#define V2_DQBLKSIZE_BITS 10 +#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ +#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */ +#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ +#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ +#define V2_GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) +#define V2_GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)(buf)) + sizeof(struct v2_disk_dqdbheader))) +#define INIT_V2_VERSIONS { 0, 0} + +struct v2_disk_dqheader { + u_int32_t dqh_magic; /* Magic number identifying file */ + u_int32_t dqh_version; /* File version */ +} __attribute__ ((packed)); + +/* Flags for version specific files */ +#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + u_int32_t dqi_bgrace; /* Time before block soft limit becomes hard limit */ + u_int32_t dqi_igrace; /* Time before inode soft limit becomes hard limit */ + u_int32_t dqi_flags; /* Flags for quotafile (DQF_*) */ + u_int32_t dqi_blocks; /* Number of blocks in file */ + u_int32_t dqi_free_blk; /* Number of first free block in the list */ + u_int32_t dqi_free_entry; /* Number of block with at least one free entry */ +} __attribute__ ((packed)); + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes so + * there will be space for exactly 18 quota-entries in a block + */ +struct v2_disk_dqdbheader { + u_int32_t dqdh_next_free; /* Number of next block with free entry */ + u_int32_t dqdh_prev_free; /* Number of previous block with free entry */ + u_int16_t dqdh_entries; /* Number of valid entries in block */ + u_int16_t dqdh_pad1; + u_int32_t dqdh_pad2; +} __attribute__ ((packed)); + +/* Structure of quota for one user on disk */ +struct v2_disk_dqblk { + u_int32_t dqb_id; /* id this quota applies to */ + u_int32_t dqb_ihardlimit; /* absolute limit on allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + u_int32_t dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ + u_int64_t dqb_curspace; /* current space occupied (in bytes) */ + u_int64_t dqb_btime; /* time limit for excessive disk use */ + u_int64_t dqb_itime; /* time limit for excessive inode use */ +} __attribute__ ((packed)); + +/* Structure of quota for communication with kernel */ +struct v2_kern_dqblk { + unsigned int dqb_ihardlimit; + unsigned int dqb_isoftlimit; + unsigned int dqb_curinodes; + unsigned int dqb_bhardlimit; + unsigned int dqb_bsoftlimit; + qsize_t dqb_curspace; + time_t dqb_btime; + time_t dqb_itime; +}; + +/* Structure of quotafile info for communication with kernel */ +struct v2_kern_dqinfo { + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + unsigned int dqi_flags; + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +#endif diff --git a/quotaio_xfs.c b/quotaio_xfs.c new file mode 100644 index 0000000..dc20f55 --- /dev/null +++ b/quotaio_xfs.c @@ -0,0 +1,277 @@ +/* + * Implementation of XFS quota manager. + */ + +#ident "Copyright (c) 2001 Silicon Graphics, Inc." + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> + +#include "pot.h" +#include "common.h" +#include "bylabel.h" +#include "quotaio.h" +#include "quotasys.h" +#include "dqblk_xfs.h" + +static int xfs_init_io(struct quota_handle *h); +static int xfs_write_info(struct quota_handle *h); +static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id); +static int xfs_commit_dquot(struct dquot *dquot); +static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot * dquot)); +static int xfs_report(struct quota_handle *h, int verbose); + +struct quotafile_ops quotafile_ops_xfs = { + xfs_init_io, + NULL, /* new_io */ + NULL, /* end_io */ + xfs_write_info, + xfs_read_dquot, + xfs_commit_dquot, + xfs_scan_dquots, + xfs_report +}; + +/* + * Convert XFS kernel quota format to utility format + */ +static inline void xfs_kern2utildqblk(struct util_dqblk *u, struct xfs_kern_dqblk * k) +{ + u->dqb_ihardlimit = k->d_ino_hardlimit; + u->dqb_isoftlimit = k->d_ino_softlimit; + u->dqb_bhardlimit = k->d_blk_hardlimit >> 1; + u->dqb_bsoftlimit = k->d_blk_softlimit >> 1; + u->dqb_curinodes = k->d_icount; + u->dqb_curspace = k->d_bcount << 9; + u->dqb_itime = k->d_itimer; + u->dqb_btime = k->d_btimer; +} + +/* + * Convert utility quota format to XFS kernel format + */ +static inline void xfs_util2kerndqblk(struct xfs_kern_dqblk *k, struct util_dqblk *u) +{ + memset(k, 0, sizeof(struct xfs_kern_dqblk)); + k->d_ino_hardlimit = u->dqb_ihardlimit; + k->d_ino_softlimit = u->dqb_isoftlimit; + k->d_blk_hardlimit = u->dqb_bhardlimit << 1; + k->d_blk_softlimit = u->dqb_bsoftlimit << 1; + k->d_icount = u->dqb_curinodes; + k->d_bcount = u->dqb_curspace >> 9; + k->d_itimer = u->dqb_itime; + k->d_btimer = u->dqb_btime; +} + +/* + * Initialize quota information + */ +static int xfs_init_io(struct quota_handle *h) +{ + struct xfs_mem_dqinfo info; + int qcmd; + + qcmd = QCMD(Q_XFS_GETQSTAT, 0); + memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); + if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&info) < 0) + return -1; + h->qh_info.dqi_bgrace = info.qs_btimelimit; + h->qh_info.dqi_igrace = info.qs_itimelimit; + h->qh_info.u.xfs_mdqi = info; + return 0; +} + +/* + * Write information (grace times) + */ +static int xfs_write_info(struct quota_handle *h) +{ + struct xfs_kern_dqblk xdqblk; + int qcmd; + + memset(&xdqblk, 0, sizeof(struct xfs_kern_dqblk)); + + xdqblk.d_btimer = h->qh_info.dqi_bgrace; + xdqblk.d_itimer = h->qh_info.dqi_igrace; + xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK; + qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); + if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&xdqblk) < 0) + return -1; + return 0; +} + +/* + * Read a dqblk struct from the quota manager + */ +static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id) +{ + struct dquot *dquot = get_empty_dquot(); + struct xfs_kern_dqblk xdqblk; + int qcmd; + + dquot->dq_id = id; + dquot->dq_h = h; + qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type); + if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) { + ; + } + else { + xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk); + return dquot; + } + free(dquot); + return NULL; +} + +/* + * Write a dqblk struct to the XFS quota manager + */ +static int xfs_commit_dquot(struct dquot *dquot) +{ + struct quota_handle *h = dquot->dq_h; + struct xfs_kern_dqblk xdqblk; + qid_t id = dquot->dq_id; + int qcmd; + + xfs_util2kerndqblk(&xdqblk, &dquot->dq_dqb); + xdqblk.d_fieldmask |= FS_DQ_LIMIT_MASK; + qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); + if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) { + ; + } + else { + return 0; + } + return -1; +} + +/* + * xfs_scan_dquots helper - processes a single dquot + */ +static int xfs_scan_dquot(struct quota_handle *h, + struct xfs_kern_dqblk *d, + struct dquot *dq, int (*process_dquot) (struct dquot * dquot)) +{ + int qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type); + + memset(d, 0, sizeof(struct xfs_kern_dqblk)); + + if (quotactl(qcmd, h->qh_quotadev, dq->dq_id, (void *)d) < 0) { + return 0; + } + if (d->d_blk_hardlimit == 0 && + d->d_blk_softlimit == 0 && + d->d_ino_hardlimit == 0 && + d->d_ino_softlimit == 0 && d->d_bcount == 0 && d->d_icount == 0) return 0; + xfs_kern2utildqblk(&dq->dq_dqb, d); + return process_dquot(dq); +} + +/* + * Scan all known dquots and call callback on each + */ +static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot * dquot)) +{ + struct dquot *dq; + struct xfs_kern_dqblk d; + int rd = 0; + + dq = get_empty_dquot(); + dq->dq_h = h; + if (h->qh_type == USRQUOTA) { + struct passwd *usr; + + setpwent(); + while ((usr = getpwent()) != NULL) { + dq->dq_id = usr->pw_uid; + if ((rd = xfs_scan_dquot(h, &d, dq, process_dquot)) < 0) + break; + } + endpwent(); + } + else { /* GRPQUOTA */ + struct group *grp; + + setgrent(); + while ((grp = getgrent()) != NULL) { + dq->dq_id = grp->gr_gid; + if ((rd = xfs_scan_dquot(h, &d, dq, process_dquot)) < 0) + break; + } + endgrent(); + } + + free(dq); + return rd; +} + +/* + * Report information about XFS quota on given filesystem + */ +static int xfs_report(struct quota_handle *h, int verbose) +{ + u_int16_t sbflags; + struct xfs_mem_dqinfo *info = &h->qh_info.u.xfs_mdqi; + + if (!verbose) + return 0; + + /* quotaon/off flags */ + printf(_("*** Status for %s quotas on device %s\n"), type2name(h->qh_type), h->qh_quotadev); + +#define XQM_ON(flag) ((info->qs_flags & (flag)) ? _("ON") : _("OFF")) + if (h->qh_type == USRQUOTA) { + printf(_("Accounting: %s Enforcement: %s\n"), + XQM_ON(XFS_QUOTA_UDQ_ACCT), XQM_ON(XFS_QUOTA_UDQ_ENFD)); + } + else { /* qh_type == USRQUOTA */ + printf(_("Accounting: %s Enforcement: %s\n"), + XQM_ON(XFS_QUOTA_GDQ_ACCT), XQM_ON(XFS_QUOTA_GDQ_ENFD)); + } +#undef XQM_ON + + /* + * If this is the root file system, it is possible that quotas are + * on ondisk, but not incore. Those flags will be in the HI 8 bits. + */ +#define XQM_ONDISK(flag) ((sbflags & (flag)) ? _("ON") : _("OFF")) + if ((sbflags = (info->qs_flags & 0xff00) >> 8) != 0) { + if (h->qh_type == USRQUOTA) { + printf(_("Accounting [ondisk]: %s " + "Enforcement [ondisk]: %s\n"), + XQM_ONDISK(XFS_QUOTA_UDQ_ACCT), XQM_ONDISK(XFS_QUOTA_UDQ_ENFD)); + } + else { /* qh_type == USRQUOTA */ + printf(_("Accounting [ondisk]: %s " + "Enforcement [ondisk]: %s\n"), + XQM_ONDISK(XFS_QUOTA_GDQ_ACCT), XQM_ONDISK(XFS_QUOTA_GDQ_ENFD)); + } +#undef XQM_ONDISK + } + + /* user and group quota file status information */ + if (h->qh_type == USRQUOTA) { + if (info->qs_uquota.qfs_ino == -1 || info->qs_uquota.qfs_ino == 0) + printf(_("Inode: none\n")); + else + printf(_("Inode: #%Lu (%Lu blocks, %u extents)\n"), + (unsigned long long)info->qs_uquota.qfs_ino, + (unsigned long long)info->qs_uquota.qfs_nblks, + info->qs_uquota.qfs_nextents); + } + else { /* qh_type == GRPQUOTA */ + if (info->qs_gquota.qfs_ino == -1) + printf(_("Inode: none\n")); + else + printf(_("Inode: #%Lu (%Lu blocks, %u extents)\n"), + (unsigned long long)info->qs_gquota.qfs_ino, + (unsigned long long)info->qs_gquota.qfs_nblks, + info->qs_gquota.qfs_nextents); + } + return 0; +} diff --git a/quotaio_xfs.h b/quotaio_xfs.h new file mode 100644 index 0000000..e854452 --- /dev/null +++ b/quotaio_xfs.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _QUOTAIO_XFS_H +#define _QUOTAIO_XFS_H + +#include <linux/types.h> + +#define XQM_CMD(cmd) ( ('X'<<8)+(cmd) ) +#define IS_XQM_CMD(cmd) ( ((int)(cmd)>>8) == 'X' ) + +/* + * Disk quota - quotactl(2) commands for XFS Quota Manager (XQM). + */ +#define Q_XQUOTAON XQM_CMD(0x1) /* enable quota accounting/enforcement */ +#define Q_XQUOTAOFF XQM_CMD(0x2) /* disable quota accounting/enforcement */ +#define Q_XGETQUOTA XQM_CMD(0x3) /* get disk limits & usage */ +#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits only */ +#define Q_XGETQSTAT XQM_CMD(0x5) /* returns fs_quota_stat_t struct */ +#define Q_XQUOTARM XQM_CMD(0x6) /* free quota files' space */ + +/* + * fs_disk_quota structure: + * + * This contains the current quota information regarding a user/proj/group. + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of + * 512 bytes. + */ +#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ +typedef struct fs_disk_quota { + __s8 d_version; /* version of this structure */ + __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ + __u16 d_fieldmask; /* field specifier */ + __u32 d_id; /* user, project, or group ID */ + __u64 d_blk_hardlimit; /* absolute limit on disk blks */ + __u64 d_blk_softlimit; /* preferred limit on disk blks */ + __u64 d_ino_hardlimit; /* maximum # allocated inodes */ + __u64 d_ino_softlimit; /* preferred inode limit */ + __u64 d_bcount; /* # disk blocks owned by the user */ + __u64 d_icount; /* # inodes owned by the user */ + __s32 d_itimer; /* zero if within inode limits */ + /* if not, we refuse service */ + __s32 d_btimer; /* similar to above; for disk blocks */ + __u16 d_iwarns; /* # warnings issued wrt num inodes */ + __u16 d_bwarns; /* # warnings issued wrt disk blocks */ + __s32 d_padding2; /* padding2 - for future use */ + __u64 d_rtb_hardlimit; /* absolute limit on realtime blks */ + __u64 d_rtb_softlimit; /* preferred limit on RT disk blks */ + __u64 d_rtbcount; /* # realtime blocks owned */ + __s32 d_rtbtimer; /* similar to above; for RT disk blks */ + __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ + __s16 d_padding3; /* padding3 - for future use */ + char d_padding4[8]; /* yet more padding */ +} fs_disk_quota_t; + +/* + * These fields are sent to Q_XSETQLIM to specify fields that need to change. + */ +#define FS_DQ_ISOFT (1<<0) +#define FS_DQ_IHARD (1<<1) +#define FS_DQ_BSOFT (1<<2) +#define FS_DQ_BHARD (1<<3) +#define FS_DQ_RTBSOFT (1<<4) +#define FS_DQ_RTBHARD (1<<5) +#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ + FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) +/* + * These timers can only be set in super user's dquot. For others, timers are + * automatically started and stopped. Superusers timer values set the limits + * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values + * defined below are used. + * These values also apply only to the d_fieldmask field for Q_XSETQLIM. + */ +#define FS_DQ_BTIMER (1<<6) +#define FS_DQ_ITIMER (1<<7) +#define FS_DQ_RTBTIMER (1<<8) +#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). These may be modified by the quotactl(2) + * system call with the Q_XSETQLIM command. + */ +#define DQ_FTIMELIMIT (7 * 24*60*60) /* 1 week */ +#define DQ_BTIMELIMIT (7 * 24*60*60) /* 1 week */ + +/* + * Various flags related to quotactl(2). Only relevant to XFS filesystems. + */ +#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ +#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ +#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ +#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ + +#define XFS_USER_QUOTA (1<<0) /* user quota type */ +#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ +#define XFS_GROUP_QUOTA (1<<2) /* group quota type */ + +/* + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. + * Provides a centralized way to get meta infomation about the quota subsystem. + * eg. space taken up for user and group quotas, number of dquots currently + * incore. + */ +#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ + +/* + * Some basic infomation about 'quota files'. + */ +typedef struct fs_qfilestat { + __u64 qfs_ino; /* inode number */ + __u64 qfs_nblks; /* number of BBs 512-byte-blks */ + __u32 qfs_nextents; /* number of extents */ +} fs_qfilestat_t; + +typedef struct fs_quota_stat { + __s8 qs_version; /* version number for future changes */ + __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ + __s8 qs_pad; /* unused */ + fs_qfilestat_t qs_uquota; /* user quota storage information */ + fs_qfilestat_t qs_gquota; /* group quota storage information */ + __u32 qs_incoredqs; /* number of dquots incore */ + __s32 qs_btimelimit; /* limit for blks timer */ + __s32 qs_itimelimit; /* limit for inodes timer */ + __s32 qs_rtbtimelimit; /* limit for rt blks timer */ + __u16 qs_bwarnlimit; /* limit for num warnings */ + __u16 qs_iwarnlimit; /* limit for num warnings */ +} fs_quota_stat_t; + +#endif /* _QUOTAIO_XFS_H */ diff --git a/quotaon.8 b/quotaon.8 new file mode 100644 index 0000000..c243763 --- /dev/null +++ b/quotaon.8 @@ -0,0 +1,168 @@ +.TH QUOTAON 8 +.UC 4 +.SH NAME +quotaon, quotaoff \- turn filesystem quotas on and off +.SH SYNOPSIS +.B /usr/sbin/quotaon +[ +.B \-vug +] +.IR filesystem .\|.\|. +.br +.B /usr/sbin/quotaon +[ +.B \-avug +] +.LP +.B /usr/sbin/quotaoff +[ +.B \-vugdo +] +[ +.B \-x +.I state +] +.IR filesystem .\|.\|. +.br +.B /usr/sbin/quotaoff +[ +.B \-avugdo +] +.SH DESCRIPTION +.SS quotaon +.IX "quotaon command" "" "\fLquotaon\fP \(em turn filesystem quotas on" +.IX "user quotas" "quotaon command" "" "\fLquotaon\fP \(em turn filesystem quotas on" +.IX "disk quotas" "quotaon command" "" "\fLquotaon\fP \(em turn filesystem quotas on" +.IX "quotas" "quotaon command" "" "\fLquotaon\fP \(em turn filesystem quotas on" +.IX "filesystem" "quotaon command" "" "\fLquotaon\fP \(em turn filesystem quotas on" +.LP +.B quotaon +announces to the system that disk quotas should be enabled on one or +more filesystems. The filesystem quota files must be present in the root +directory of the specified filesystem and be named either +.IR aquota.user +(for version 2 user quota), +.IR quota.user +(for version 1 user quota), +.IR aquota.group +(for version 2 group quota), or +.IR quota.group +(for version 1 group quota). +.PP +XFS filesystems are a special case - XFS considers quota +information as filesystem metadata and uses journaling to provide +a higher level guarantee of consistency. +There are two components to the XFS disk quota system: +accounting and limit enforcement. +Except in the case of the root filesystem, XFS filesystems require +that quota accounting be turned on at mount time. +It is possible to enable and disable limit enforcement on any XFS +filesystem after quota accounting is already turned on. +The default is to turn on both accounting and enforcement. +.PP +The XFS quota implementation does not maintain quota information in +user-visible files, but rather stores this information internally. +.SS quotaoff +.IX "quotaoff command" "" "\fLquotaoff\fP \(em turn filesystem quotas off" +.IX "user quotas" "quotaoff command" "" "\fLquotaoff\fP \(em turn filesystem quotas off" +.IX "disk quotas" "quotaoff command" "" "\fLquotaoff\fP \(em turn filesystem quotas off" +.IX "quotas" "quotaoff command" "" "\fLquotaoff\fP \(em turn filesystem quotas off" +.IX "filesystem" "quotaoff command" "" "\fLquotaoff\fP \(em turn filesystem quotas off" +.LP +.B quotaoff +announces to the system that the specified filesystems should +have any disk quotas turned off. +.SH OPTIONS +.SS quotaon +.TP +.B \-a +All filesystems in +.B /etc/fstab +marked read-write with quotas will have their quotas turned on. +This is normally used at boot time to enable quotas. +.TP +.B \-v +Display a message for each filesystem where quotas are turned on. +.TP +.B \-u +Manipulate user quotas. This is the default. +.TP +.B \-g +Manipulate group quotas. +.SS quotaoff +.TP +.B \-a +Force all filesystems in +.B /etc/fstab +to have their quotas disabled. +.TP +.B \-v +Display a message for each filesystem affected. +.TP +.B \-u +Manipulate user quotas. This is the default. +.TP +.B \-g +Manipulate group quotas. +.TP +.B \-x delete +Free up the space used to hold quota information (maintained +internally) within XFS. +This option is only applicable to XFS, and is silently +ignored for other filesystem types. +It can only be used on a filesystem with quota previously turned off. +.TP +.B \-x enforce +Switch off limit enforcement for XFS filesystems (perform +quota accounting only). +This option is only applicable to XFS, and is silently +ignored for other filesystem types. +.LP +.SH "XFS EXAMPLES" +.TP 0 +.B "Turning on quotas on a non-root XFS filesystem" +Use +.IR mount (8) +or +.B /etc/fstab +option quota to enable both accounting and limit enforcement. +.B quotaon +utility cannot be used for this purpose. +.TP +.B "Turning on quotas on an XFS root filesystem" +Use +.BR "quotaon -v /" , +and +.IR reboot (8). +This procedure will enable both accounting and limit enforcement. +.TP +.B "Turning off quota limit enforcement on any XFS filesystem" +Make sure that quota accounting and enforcement are both turned on using +.BR "repquota -s" . +Use +.B "quotaoff -vo" +to disable limit enforcement. +This may be done while the filesystem is mounted. +.TP +.BR "Turning on quota limit enforcement on any XFS filesystem" +Make sure that quota accounting is turned on using +.BR "repquota -s" . +Use +.BR "quotaon -v" . +This may be done while the filesystem is mounted. +.SH FILES +.PD 0 +.TP 20 +.B aquota.user or aquota.group +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP +.B quota.user or quota.group +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/fstab +default filesystems +.PD +.SH "SEE ALSO" +.BR quotactl (2), +.BR fstab (5), +.BR repquota (8). diff --git a/quotaon.c b/quotaon.c new file mode 100644 index 0000000..6e8d17b --- /dev/null +++ b/quotaon.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. All + * rights reserved. + * + * This code is derived from software contributed to Berkeley by Robert Elz at + * The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ident "$Copyright: (c) 1980, 1990 Regents of the University of California $" +#ident "$Copyright: All rights reserved. $" +#ident "$Id: quotaon.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $" + +/* + * Turn quota on/off for a filesystem. + */ +#include <stdio.h> +#include <getopt.h> +#include <string.h> +#include <stdlib.h> + +#include "quotaon.h" + +int aflag; /* all file systems */ +int gflag; /* operate on group quotas */ +int uflag; /* operate on user quotas */ +int vflag; /* verbose */ +int kqf; /* kernel quota format */ + +static void usage(char *whoami) +{ + fprintf(stderr, _("Usage:\n\t%s [-guv] [-x state] -a\n"), whoami); + fprintf(stderr, _("\t%s [-guv] [-x state] filesys ...\n"), whoami); + exit(1); +} + +/* + * Check to see if target appears in list of size cnt. + */ +static int oneof(char *target, char *list[], int cnt) +{ + int i; + + for (i = 0; i < cnt; i++) + if (strcmp(target, list[i]) == 0) + return (i); + return (-1); +} + +/* + * For both VFS quota formats, need to pass in the quota file; + * for XFS quota manager, pass on the -x command line option. + */ +static int newstate(struct mntent *mnt, int offmode, int type, char *extra) +{ + int flags, ret; + newstate_t *statefunc; + const char *mnt_fsname = get_device_name(mnt->mnt_fsname); + + if (!mnt_fsname) + return -1; + flags = offmode ? STATEFLAG_OFF : STATEFLAG_ON; + if (vflag > 1) + flags |= STATEFLAG_VERYVERBOSE; + else if (vflag) + flags |= STATEFLAG_VERBOSE; + if (aflag) + flags |= STATEFLAG_ALL; + + if (kqf & (1 << QF_XFS) && + ((offmode + && (kern_quota_on(mnt_fsname, USRQUOTA, 1 << QF_XFS) + || kern_quota_on(mnt_fsname, GRPQUOTA, 1 << QF_XFS))) + || (!offmode && kern_quota_on(mnt_fsname, type, 1 << QF_XFS)))) + ret = xfs_newstate(mnt, type, extra, flags); + else { + extra = get_qf_name(mnt, type, kqf); + statefunc = (kqf & (1 << QF_VFSV0)) ? v1_newstate : v2_newstate; + ret = statefunc(mnt, type, extra, flags); + free(extra); + } + return ret; +} + +int main(int argc, char **argv) +{ + FILE *fp; + struct mntent *mnt; + long argnum, done = 0; + char *whoami, *xarg = NULL; + int c, offmode = 0, errs = 0; + + gettexton(); + + whoami = basename(argv[0]); + if (strcmp(whoami, "quotaoff") == 0) + offmode++; + else if (strcmp(whoami, "quotaon") != 0) + die(1, _("Name must be quotaon or quotaoff not %s\n"), whoami); + + while ((c = getopt(argc, argv, "afvugx:V")) != EOF) { + switch (c) { + case 'a': + aflag++; + break; + case 'f': + offmode++; + break; + case 'g': + gflag++; + break; + case 'u': + uflag++; + break; + case 'v': + vflag++; + break; + case 'x': + xarg = optarg; + break; + case 'V': + version(); + exit(0); + default: + usage(whoami); + } + } + argc -= optind; + argv += optind; + + if (argc <= 0 && !aflag) + usage(whoami); + if (!gflag && !uflag) { + gflag++; + uflag++; + } + + kqf = kern_quota_format(); + + fp = setmntent(MNTTAB, "r"); + while ((mnt = getmntent(fp))) { + if (aflag) { + if (hasmntopt(mnt, MNTOPT_NOAUTO)) + continue; + } + else { + if ((argnum = oneof(mnt->mnt_dir, argv, argc)) >= 0 || + (argnum = oneof(mnt->mnt_fsname, argv, argc)) >= 0) + done |= 1 << argnum; + else + continue; + } + + if (gflag) + errs += newstate(mnt, offmode, GRPQUOTA, xarg); + if (uflag) + errs += newstate(mnt, offmode, USRQUOTA, xarg); + } + endmntent(fp); + + for (c = 0; c < argc; c++) + if ((done & (1 << c)) == 0) + fprintf(stderr, _("%s not found in fstab\n"), argv[c]); + return errs; +} + +/* + * Enable/disable VFS quota on given filesystem + */ +static int quotaonoff(char *quotadev, char *quotafile, int type, int flags) +{ + int qcmd; + + if (flags & STATEFLAG_OFF) { + qcmd = QCMD(Q_QUOTAOFF, type); + if (quotactl(qcmd, quotadev, 0, (void *)0) < 0) { + fprintf(stderr, "quotaoff: "); + perror(quotadev); + return 1; + } + if (flags & STATEFLAG_VERBOSE) + printf(_("%s: %s quotas turned off\n"), quotadev, type2name(type)); + return 0; + } + qcmd = QCMD(Q_QUOTAON, type); + if (quotactl(qcmd, quotadev, 0, (void *)quotafile) < 0) { + fprintf(stderr, _("quotaon: using %s on "), quotafile); + perror(quotadev); + return 1; + } + if (flags & STATEFLAG_VERBOSE) + printf(_("%s: %s quotas turned on\n"), quotadev, type2name(type)); + return 0; +} + +/* + * Enable/disable rsquash on given filesystem + */ +static int quotarsquashonoff(const char *quotadev, int type, int flags) +{ +#if defined(MNTOPT_RSQUASH) + int mode = (flags & STATEFLAG_OFF) ? 0 : 1; + int qcmd = QCMD(Q_V1_RSQUASH, type); + + if (quotactl(qcmd, quotadev, 0, (void *)&mode) < 0) { + fprintf(stderr, _("quotaon: set root_squash on")); + perror(quotadev); + return 1; + } + if ((flags & STATEFLAG_VERBOSE) && (flags & STATEFLAG_OFF)) + printf(_("%s: %s root_squash turned off\n"), quotadev, type2name(type)); + else if ((flags & STATEFLAG_VERBOSE) && (flags & STATEFLAG_ON)) + printf(_("%s: %s root_squash turned on\n"), quotadev, type2name(type)); +#endif + return 0; +} + +/* + * Enable/disable quota/rootsquash on given filesystem (version 1) + */ +int v1_newstate(struct mntent *mnt, int type, char *file, int flags) +{ + int errs = 0; + const char *dev = get_device_name(mnt->mnt_fsname); + + if (!dev) + return 1; + if ((flags & STATEFLAG_OFF) && hasmntopt(mnt, MNTOPT_RSQUASH)) + errs += quotarsquashonoff(dev, type, flags); + if (hasquota(mnt, type)) + errs += quotaonoff((char *)dev, file, type, flags); + if ((flags & STATEFLAG_ON) && hasmntopt(mnt, MNTOPT_RSQUASH)) + errs += quotarsquashonoff(dev, type, flags); + free((char *)dev); + return errs; +} + +/* + * Enable/disable quota on given filesystem (version 2 quota) + */ +int v2_newstate(struct mntent *mnt, int type, char *file, int flags) +{ + const char *dev = get_device_name(mnt->mnt_fsname); + int err = 1; + + if (!dev) + return err; + if (hasquota(mnt, type)) + err = quotaonoff((char *)dev, file, type, flags); + free((char *)dev); + return err; +} diff --git a/quotaon.h b/quotaon.h new file mode 100644 index 0000000..ced9b2a --- /dev/null +++ b/quotaon.h @@ -0,0 +1,22 @@ +/* + * Common types, macros, and routines for enabling/disabling + * quota for each of the various Linux quota formats. + */ + +#include "pot.h" +#include "quota.h" +#include "quotasys.h" +#include "bylabel.h" +#include "common.h" +#include "quotaio.h" + +#define STATEFLAG_ON 0x01 +#define STATEFLAG_OFF 0x02 +#define STATEFLAG_ALL 0x04 +#define STATEFLAG_VERBOSE 0x08 +#define STATEFLAG_VERYVERBOSE 0x10 + +typedef int (newstate_t) (struct mntent * mnt, int type, char *file, int flags); +extern int v1_newstate(struct mntent *mnt, int type, char *file, int flags); +extern int v2_newstate(struct mntent *mnt, int type, char *file, int flags); +extern int xfs_newstate(struct mntent *mnt, int type, char *file, int flags); diff --git a/quotaon_xfs.c b/quotaon_xfs.c new file mode 100644 index 0000000..a3c0480 --- /dev/null +++ b/quotaon_xfs.c @@ -0,0 +1,206 @@ +/* + * State changes for the XFS Quota Manager. + */ + +#ident "Copyright (c) 2001 Silicon Graphics, Inc." + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "quotaon.h" +#include "dqblk_xfs.h" + +#define QOFF 1 +#define ACCT 2 +#define ENFD 3 + +/* + * Ensure we don't attempt to go into a dodgey state. + */ + +static int xfs_state_check(int qcmd, int type, int flags, char *dev, int root, int *xopts) +{ + struct xfs_mem_dqinfo info; + int state; + + /* we never want to operate via -a in XFS quota */ + if (flags & STATEFLAG_ALL) + return 0; /* noop */ + + if (quotactl(QCMD(Q_XFS_GETQSTAT, 0), dev, 0, (void *)&info) < 0) { + fprintf(stderr, flags & STATEFLAG_ON ? "quotaon: " : "quotaoff: "); + perror(dev); + return -1; + } + + /* establish current state before any transition */ + state = QOFF; + if (type == USRQUOTA) { + if (info.qs_flags & XFS_QUOTA_UDQ_ACCT) + state = ACCT; + if (info.qs_flags & XFS_QUOTA_UDQ_ENFD) + state = ENFD; + } + else { /* GRPQUOTA */ + if (info.qs_flags & XFS_QUOTA_GDQ_ACCT) + state = ACCT; + if (info.qs_flags & XFS_QUOTA_GDQ_ENFD) + state = ENFD; + } + + switch (state) { + case QOFF: + switch (qcmd) { + case Q_XFS_QUOTARM: + return 1; + case Q_XFS_QUOTAON: + if (root) { + *xopts |= (type == USRQUOTA) ? + XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; + printf(_("Enabling %s quota on root filesystem" + " (reboot to take effect)\n"), type2name(type)); + return 1; + } + fprintf(stderr, _("Enable XFS %s quota during mount\n"), + type2name(type)); + return -1; + case Q_XFS_QUOTAOFF: + return 0; /* noop */ + } + break; + case ACCT: + switch (qcmd) { + case Q_XFS_QUOTARM: + fprintf(stderr, _("Cannot delete %s quota on %s - " + "switch quota accounting off first\n"), + type2name(type), dev); + return -1; + case Q_XFS_QUOTAON: + if (root) { + *xopts |= (type == USRQUOTA) ? + XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; + printf(_("Enabling %s quota on root filesystem" + " (reboot to take effect)\n"), type2name(type)); + return 1; + } + printf(_("Enabling %s quota accounting on %s\n"), type2name(type), dev); + *xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; + return 1; + case Q_XFS_QUOTAOFF: + printf(_("Disabling %s quota accounting on %s\n"), + type2name(type), dev); + *xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; + return 1; + } + break; + + case ENFD: + switch (qcmd) { + case Q_XFS_QUOTARM: + fprintf(stderr, _("Cannot delete %s quota on %s - " + "switch quota enforcement off first\n"), + type2name(type), dev); + return -1; + case Q_XFS_QUOTAON: + fprintf(stderr, _("Enforcing %s quota already on %s\n"), + type2name(type), dev); + return -1; + case Q_XFS_QUOTAOFF: + printf(_("Disabling %s quota enforcement on %s\n"), + type2name(type), dev); + *xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD : XFS_QUOTA_GDQ_ENFD; + return 1; + } + break; + } + fprintf(stderr, _("Unexpected XFS quota state sought on %s\n"), dev); + return -1; +} + +static int xfs_onoff(char *dev, int type, int flags, int rootfs, int *xopts) +{ + int qoff, qcmd; + + qoff = (flags & STATEFLAG_OFF); + qcmd = qoff ? Q_XFS_QUOTAOFF : Q_XFS_QUOTAON; + if (xfs_state_check(qcmd, type, flags, dev, rootfs, xopts) < 0) + return 1; + + if (quotactl(QCMD(qcmd, type), dev, 0, (void *)xopts) < 0) { + fprintf(stderr, qoff ? "quotaoff: " : "quotaon: "); + perror(dev); + return 1; + } + if ((flags & STATEFLAG_VERBOSE) && qoff) + printf(_("%s: %s quotas turned off\n"), dev, type2name(type)); + else if ((flags & STATEFLAG_VERBOSE) && !qoff) + printf(_("%s: %s quotas turned on\n"), dev, type2name(type)); + return 0; +} + +static int xfs_delete(char *dev, int type, int flags, int rootfs, int *xopts) +{ + int qcmd, check; + + qcmd = Q_XFS_QUOTARM; + check = xfs_state_check(qcmd, type, flags, dev, rootfs, xopts); + if (check != 1) + return (check < 0); + + if (quotactl(QCMD(qcmd, type), dev, 0, (void *)xopts) < 0) { + fprintf(stderr, _("Failed to delete quota: ")); + perror(dev); + return 1; + } + + if (flags & STATEFLAG_VERBOSE) + printf(_("%s: deleted %s quota blocks\n"), dev, type2name(type)); + return 0; +} + +/* + * Change state for given filesystem - on/off, acct/enfd, & delete. + * Must consider existing state and also whether or not this is the + * root filesystem. + * We are passed in the new requested state through "type" & "xarg". + */ +int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags) +{ + int err = 1; + int xopts = 0; + int rootfs = !strcmp(mnt->mnt_dir, "/"); + const char *dev = get_device_name(mnt->mnt_fsname); + + if (!dev) + return err; + + if (xarg == NULL) { /* both acct & enfd on/off */ + xopts |= (type == USRQUOTA) ? + (XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD) : + (XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD); + err = xfs_onoff((char *)dev, type, flags, rootfs, &xopts); + } + else if (strcmp(xarg, "account") == 0) { + /* only useful if we want root accounting only */ + if (!rootfs || !(flags & STATEFLAG_ON)) + goto done; + xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; + err = xfs_onoff((char *)dev, type, flags, rootfs, &xopts); + } + else if (strcmp(xarg, "enforce") == 0) { + xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD : XFS_QUOTA_GDQ_ENFD; + err = xfs_onoff((char *)dev, type, flags, rootfs, &xopts); + } + else if (strcmp(xarg, "delete") == 0) { + xopts |= (type == USRQUOTA) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA; + err = xfs_delete((char *)dev, type, flags, rootfs, &xopts); + } + else + die(1, _("Invalid argument \"%s\"\n"), xarg); + done: + free((char *)dev); + return err; +} diff --git a/quotaops.c b/quotaops.c new file mode 100644 index 0000000..82bfb43 --- /dev/null +++ b/quotaops.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. All + * rights reserved. + * + * This code is derived from software contributed to Berkeley by Robert Elz at + * The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. 3. All advertising + * materials mentioning features or use of this software must display the + * following acknowledgement: This product includes software developed by the + * University of California, Berkeley and its contributors. 4. Neither the + * name of the University nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $" +#ident "$Copyright: All rights reserved. $" +#ident "$Id: quotaops.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $" + +#include <rpc/rpc.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/wait.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <paths.h> +#include <unistd.h> + +#if defined(RPC) +#include "rquota.h" +#endif + +#include "mntopt.h" +#include "quotaops.h" +#include "pot.h" +#include "bylabel.h" +#include "common.h" +#include "quotasys.h" +#include "quotaio.h" + +/* + * Convert ASCII input times to seconds. + */ +static int cvtatos(time_t time, char *units, time_t * seconds) +{ + if (memcmp(units, "second", 6) == 0) + *seconds = time; + else if (memcmp(units, "minute", 6) == 0) + *seconds = time * 60; + else if (memcmp(units, "hour", 4) == 0) + *seconds = time * 60 * 60; + else if (memcmp(units, "day", 3) == 0) + *seconds = time * 24 * 60 * 60; + else { + fprintf(stderr, _("%s: bad units, specify:\n %s, %s, %s, or %s"), units, + "days", "hours", "minutes", "seconds"); + return -1; + } + return 0; +} + +/* + * Collect the requested quota information. + */ +struct dquot *getprivs(qid_t id, struct quota_handle **handles) +{ + struct dquot *q, *qtail = NULL, *qhead = NULL; + int i; + + for (i = 0; handles[i]; i++) { + if (!(q = handles[i]->qh_ops->read_dquot(handles[i], id))) { + fprintf(stderr, _("Error while getting quota from %s for %u: %s\n"), + handles[i]->qh_quotadev, id, strerror(errno)); + continue; + } + if (qhead == NULL) + qhead = q; + else + qtail->dq_next = q; + qtail = q; + q->dq_next = NULL; /* This should be already set, but just for sure... */ + } + return qhead; +} + +/* + * Store the requested quota information. + */ +int putprivs(struct dquot *qlist) +{ + struct dquot *q; + + for (q = qlist; q; q = q->dq_next) { + if (q->dq_h->qh_ops->commit_dquot(q) == -1) { + fprintf(stderr, _("Can't write quota for %u on %s: %s\n"), q->dq_id, + q->dq_h->qh_quotadev, strerror(errno)); + continue; + } + } + return 0; +} + +/* + * Take a list of priviledges and get it edited. + */ +int editprivs(char *tmpfile) +{ + long omask; + int pid, stat; + + omask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGHUP)); + if ((pid = fork()) < 0) { + perror("fork"); + return -1; + } + if (pid == 0) { + char *ed; + + sigsetmask(omask); + setgid(getgid()); + setuid(getuid()); + if ((ed = getenv("VISUAL")) == (char *)0) + if ((ed = getenv("EDITOR")) == (char *)0) + ed = _PATH_VI; + execlp(ed, ed, tmpfile, 0); + die(1, _("Can't exec %s\n"), ed); + } + waitpid(pid, &stat, 0); + sigsetmask(omask); + + return 0; +} + +/* + * Convert a dquot list to an ASCII file. + */ +int writeprivs(struct dquot *qlist, int outfd, char *name, int quotatype) +{ + struct dquot *q; + FILE *fd; + + ftruncate(outfd, 0); + lseek(outfd, 0, SEEK_SET); + if (!(fd = fdopen(dup(outfd), "w"))) + die(1, _("Can't duplicate descriptor of file to write to: %s\n"), strerror(errno)); + +#if defined(ALT_FORMAT) + fprintf(fd, _("Disk quotas for %s %s (%cid %d):\n"), + type2name(quotatype), name, *type2name(quotatype), name2id(name, quotatype)); + + fprintf(fd, + _ + (" Filesystem blocks soft hard inodes soft hard\n")); + + for (q = qlist; q; q = q->dq_next) { + fprintf(fd, " %-24s %10Lu %10Lu %10Lu %10Lu %8Lu %8Lu\n", + q->dq_h->qh_quotadev, + (long long)toqb(q->dq_dqb.dqb_curspace), + (long long)q->dq_dqb.dqb_bsoftlimit, + (long long)q->dq_dqb.dqb_bhardlimit, + (long long)q->dq_dqb.dqb_curinodes, + (long long)q->dq_dqb.dqb_isoftlimit, (long long)q->dq_dqb.dqb_ihardlimit); + } +#else + fprintf(fd, _("Quotas for %s %s:\n"), type2name(quotatype), name); + for (q = qlist; q; q = q->dq_next) { + fprintf(fd, _("%s: %s %d, limits (soft = %d, hard = %d)\n"), + q->dq_h->qh_quotadev, _("blocks in use:"), + (int)toqb(q->dq_dqb.dqb_curspace), + q->dq_dqb.dqb_bsoftlimit, q->dq_dqb.dqb_bhardlimit); + fprintf(fd, _("%s %d, limits (soft = %d, hard = %d)\n"), + _("\tinodes in use:"), q->dq_dqb.dqb_curinodes, + q->dq_dqb.dqb_isoftlimit, q->dq_dqb.dqb_ihardlimit); + } +#endif + fclose(fd); + return 0; +} + +/* Merge changes on one dev to proper structure in the list */ +static void merge_to_list(struct dquot *qlist, char *dev, u_int64_t blocks, u_int64_t bsoft, + u_int64_t bhard, u_int64_t inodes, u_int64_t isoft, u_int64_t ihard) +{ + struct dquot *q; + + for (q = qlist; q; q = q->dq_next) { + if (strcmp(dev, q->dq_h->qh_quotadev)) + continue; + + /* + * Cause time limit to be reset when the quota is + * next used if previously had no soft limit or were + * under it, but now have a soft limit and are over + * it. + */ + if (bsoft && (toqb(q->dq_dqb.dqb_curspace) >= bsoft) && + (q->dq_dqb.dqb_bsoftlimit == 0 || + toqb(q->dq_dqb.dqb_curspace) < q->dq_dqb.dqb_bsoftlimit)) + q->dq_dqb.dqb_btime = 0; + + if (isoft && (q->dq_dqb.dqb_curinodes >= isoft) && + (q->dq_dqb.dqb_isoftlimit == 0 || + q->dq_dqb.dqb_curinodes < q->dq_dqb.dqb_isoftlimit)) q->dq_dqb.dqb_itime = 0; + + q->dq_dqb.dqb_bsoftlimit = bsoft; + q->dq_dqb.dqb_bhardlimit = bhard; + q->dq_dqb.dqb_isoftlimit = isoft; + q->dq_dqb.dqb_ihardlimit = ihard; + q->dq_flags |= DQ_FOUND; + + if (blocks != toqb(q->dq_dqb.dqb_curspace)) + fprintf(stderr, _("WARNING: %s: cannot change current block allocation\n"), + q->dq_h->qh_quotadev); + if (inodes != q->dq_dqb.dqb_curinodes) + fprintf(stderr, _("WARNING: %s: cannot change current inode allocation\n"), + q->dq_h->qh_quotadev); + } +} + +/* + * Merge changes to an ASCII file into a dquot list. + */ +int readprivs(struct dquot *qlist, int infd) +{ + FILE *fd; + int cnt; + long long blocks, bsoft, bhard, inodes, isoft, ihard; + struct dquot *q; + +#if defined(ALT_FORMAT) + char fsp[BUFSIZ], line[BUFSIZ]; +#else + char *fsp, line1[BUFSIZ], line2[BUFSIZ]; +#endif + + lseek(infd, 0, SEEK_SET); + if (!(fd = fdopen(dup(infd), "r"))) + die(1, _("Can't duplicate descriptor of temp file: %s\n"), strerror(errno)); + +#if defined(ALT_FORMAT) + /* + * Discard title lines, then read lines to process. + */ + fgets(line, sizeof(line), fd); + fgets(line, sizeof(line), fd); + + while (fgets(line, sizeof(line), fd)) { + cnt = sscanf(line, "%s %Lu %Lu %Lu %Lu %Lu %Lu", + fsp, &blocks, &bsoft, &bhard, &inodes, &isoft, &ihard); + + if (cnt != 7) { + fprintf(stderr, _("Bad format:\n%s\n"), line); + return -1; + } + + merge_to_list(qlist, fsp, blocks, bsoft, bhard, inodes, isoft, ihard); + } +#else + /* + * Discard title line, then read pairs of lines to process. + */ + fgets(line1, sizeof(line1), fd); + while (fgets(line1, sizeof(line1), fd) && fgets(line2, sizeof(line2), fd)) { + if (!(fsp = strtok(line1, " \t:"))) { + fprintf(stderr, _("%s: bad format\n"), line1); + return -1; + } + if (!(cp = strtok(NULL, "\n"))) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, &fsp[strlen(fsp) + 1]); + return -1; + } + + cnt = sscanf(cp, _(" blocks in use: %Lu, limits (soft = %Lu, hard = %Lu)"), + &blocks, &bsoft, &bhard); + if (cnt != 3) { + fprintf(stderr, _("%s:%s: bad format\n"), fsp, cp); + return -1; + } + + if (!(cp = strtok(line2, "\n"))) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, line2); + return -1; + } + + cnt = sscanf(cp, _("\tinodes in use: %Lu, limits (soft = %Lu, hard = %Lu)"), + &inodes, &isoft, &ihard); + if (cnt != 3) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, line2); + return -1; + } + + merge_to_list(qlist, fsp, blocks, bsoft, bhard, inodes, isoft, ihard); + } +#endif + fclose(fd); + + /* + * Disable quotas for any filesystems that have not been found. + */ + for (q = qlist; q; q = q->dq_next) { + if (q->dq_flags & DQ_FOUND) { + q->dq_flags &= ~DQ_FOUND; + continue; + } + q->dq_dqb.dqb_bsoftlimit = 0; + q->dq_dqb.dqb_bhardlimit = 0; + q->dq_dqb.dqb_isoftlimit = 0; + q->dq_dqb.dqb_ihardlimit = 0; + } + return 0; +} + +/* + * Convert a dquot list to an ASCII file of grace times. + */ +int writetimes(struct quota_handle **handles, int outfd) +{ + FILE *fd; + char itimebuf[MAXTIMELEN], btimebuf[MAXTIMELEN]; + int i; + + if (!handles[0]) + return 0; + + ftruncate(outfd, 0); + lseek(outfd, 0, SEEK_SET); + if ((fd = fdopen(dup(outfd), "w")) == NULL) + die(1, _("Can't duplicate descriptor of file to edit: %s\n"), strerror(errno)); + +#if defined(ALT_FORMAT) + fprintf(fd, _("Grace period before enforcing soft limits for %ss:\n"), + type2name(handles[0]->qh_type)); + fprintf(fd, _("Time units may be: days, hours, minutes, or seconds\n")); + fprintf(fd, _(" Filesystem Block grace period Inode grace period\n")); + + for (i = 0; handles[i]; i++) { + time2str(handles[i]->qh_info.dqi_bgrace, btimebuf, 0); + time2str(handles[i]->qh_info.dqi_igrace, itimebuf, 0); + fprintf(fd, " %-12s %22s %22s\n", handles[i]->qh_quotadev, btimebuf, itimebuf); + } +#else + fprintf(fd, _("Time units may be: days, hours, minutes, or seconds\n")); + fprintf(fd, _("Grace period before enforcing soft limits for %ss:\n"), + type2name(handles[0]->qh_type)); + for (i = 0; handles[i]; i++) { + time2str(handles[i]->qh_info.dqi_bgrace, btimebuf, 0); + time2str(handles[i]->qh_info.dqi_igrace, itimebuf, 0); + fprintf(fd, _("%s: block grace period: %s, file grace period: %s\n"), + handles[i]->qh_quotadev, btimebuf, itimebuf); + } +#endif + + fclose(fd); + return 0; +} + +/* + * Merge changes of grace times in an ASCII file into a dquot list. + */ +int readtimes(struct quota_handle **handles, int infd) +{ + FILE *fd; + int itime, btime, i, cnt; + time_t iseconds, bseconds; + +#if defined(ALT_FORMAT) + char fsp[BUFSIZ], bunits[10], iunits[10], line[BUFSIZ]; +#else + char *fsp, bunits[10], iunits[10], line1[BUFSIZ]; +#endif + + if (!handles[0]) + return 0; + lseek(infd, 0, SEEK_SET); + if (!(fd = fdopen(dup(infd), "r"))) { + fprintf(stderr, _("Can't reopen temp file: %s\n"), strerror(errno)); + return -1; + } + + /* Set all grace times to default values */ + for (i = 0; handles[i]; i++) { + handles[i]->qh_info.dqi_bgrace = MAX_DQ_TIME; + handles[i]->qh_info.dqi_igrace = MAX_IQ_TIME; + mark_quotafile_info_dirty(handles[i]); + } +#if defined(ALT_FORMAT) + /* + * Discard three title lines, then read lines to process. + */ + fgets(line, sizeof(line), fd); + fgets(line, sizeof(line), fd); + fgets(line, sizeof(line), fd); + + while (fgets(line, sizeof(line), fd)) { + cnt = sscanf(line, "%s %d %s %d %s", fsp, &btime, bunits, &itime, iunits); + if (cnt != 5) { + fprintf(stderr, _("bad format:\n%s\n"), line); + return -1; + } +#else + /* + * Discard two title lines, then read lines to process. + */ + fgets(line1, sizeof(line1), fd); + fgets(line1, sizeof(line1), fd); + + while (fgets(line1, sizeof(line1), fd)) { + if (!(fsp = strtok(line1, " \t:"))) { + fprintf(stderr, _("%s: bad format\n"), line1); + return -1; + } + if (!(cp = strtok(NULL, "\n"))) { + fprintf(stderr, _("%s: %s: bad format\n"), fsp, &fsp[strlen(fsp) + 1]); + return -1; + } + cnt = sscanf(cp, _(" block grace period: %d %s file grace period: %d %s"), + &btime, bunits, &itime, iunits); + if (cnt != 4) { + fprintf(stderr, _("%s:%s: bad format\n"), fsp, cp); + return -1; + } +#endif + if (cvtatos(btime, bunits, &bseconds) < 0) + return -1; + if (cvtatos(itime, iunits, &iseconds) < 0) + return -1; + for (i = 0; handles[i]; i++) { + if (strcmp(fsp, handles[i]->qh_quotadev)) + continue; + handles[i]->qh_info.dqi_bgrace = bseconds; + handles[i]->qh_info.dqi_igrace = iseconds; + mark_quotafile_info_dirty(handles[i]); + break; + } + } + fclose(fd); + + return 0; +} + +/* + * Free a list of dquot structures. + */ +void freeprivs(struct dquot *qlist) +{ + struct dquot *q, *nextq; + + for (q = qlist; q; q = nextq) { + nextq = q->dq_next; + free(q); + } +} diff --git a/quotaops.h b/quotaops.h new file mode 100644 index 0000000..da28bde --- /dev/null +++ b/quotaops.h @@ -0,0 +1,16 @@ +#ifndef _QUOTAOPS_H +#define _QUOTAOPS_H + +#include "quotaio.h" + +__BEGIN_DECLS extern struct dquot *getprivs __P((qid_t id, struct quota_handle ** handles)); +extern int putprivs __P((struct dquot * qlist)); +extern int editprivs __P((char *tmpfile)); +extern int writeprivs __P((struct dquot * qlist, int outfd, char *name, int quotatype)); +extern int readprivs __P((struct dquot * qlist, int infd)); +extern int writetimes __P((struct quota_handle ** handles, int outfd)); +extern int readtimes __P((struct quota_handle ** handles, int infd)); +extern void freeprivs __P((struct dquot * qlist)); + +__END_DECLS +#endif /* _QUOTAOPS_H */ diff --git a/quotastats.c b/quotastats.c new file mode 100644 index 0000000..6b67222 --- /dev/null +++ b/quotastats.c @@ -0,0 +1,59 @@ +/* + * QUOTA An implementation of the diskquota system for the LINUX operating + * system. QUOTA is implemented using the BSD systemcall interface + * as the means of communication with the user level. Should work for + * all filesystems because of integration into the VFS layer of the + * operating system. This is based on the Melbourne quota system wich + * uses both user and group quota files. + * + * Program to query for the internal statistics. + * + * Author: Marco van Wieringen <mvw@planets.elm.net> + * + * Version: $Id: quotastats.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <unistd.h> + +#include "pot.h" +#include "quota.h" + +static inline int get_stats(struct dqstats *dqstats) +{ + return quotactl(QCMD(Q_GETSTATS, 0), (char *)NULL, 0, (caddr_t) dqstats); +} + +static inline int print_stats(struct dqstats *dqstats) +{ + fprintf(stdout, _("Number of dquot lookups: %ld\n"), (long)dqstats->lookups); + fprintf(stdout, _("Number of dquot drops: %ld\n"), (long)dqstats->drops); + fprintf(stdout, _("Number of still active inodes with quota : %ld\n"), + (long)(dqstats->lookups - dqstats->drops)); + fprintf(stdout, _("Number of dquot reads: %ld\n"), (long)dqstats->reads); + fprintf(stdout, _("Number of dquot writes: %ld\n"), (long)dqstats->writes); + fprintf(stdout, _("Number of quotafile syncs: %ld\n"), (long)dqstats->syncs); + fprintf(stdout, _("Number of dquot cache hits: %ld\n"), (long)dqstats->cache_hits); + fprintf(stdout, _("Number of allocated dquots: %ld\n"), (long)dqstats->allocated_dquots); + fprintf(stdout, _("Number of free dquots: %ld\n"), (long)dqstats->free_dquots); + fprintf(stdout, _("Number of in use dquot entries (user/group): %ld\n"), + (long)(dqstats->allocated_dquots - dqstats->free_dquots)); + return (0); +} + +int main(int argc, char **argv) +{ + struct dqstats dqstats; + + gettexton(); + + if (!get_stats(&dqstats)) + print_stats(&dqstats); + return 0; +} diff --git a/quotasys.c b/quotasys.c new file mode 100644 index 0000000..d4d5f80 --- /dev/null +++ b/quotasys.c @@ -0,0 +1,442 @@ +/* + * + * Interactions of quota with system - filenames, fstab and so on... + * + */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <pwd.h> +#include <grp.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "pot.h" +#include "bylabel.h" +#include "common.h" +#include "quotasys.h" +#include "quotaio.h" +#include "dqblk_v1.h" +#include "dqblk_v2.h" +#include "dqblk_xfs.h" + +#define min(x,y) (((x) < (y)) ? (x) : (y)) +#define CORRECT_FSTYPE(type) \ +((!strcmp(type, MNTTYPE_EXT2)) || \ +(!strcmp(type, MNTTYPE_EXT3)) || \ +(!strcmp(type, MNTTYPE_MINIX)) || \ +(!strcmp(type, MNTTYPE_UFS)) || \ +(!strcmp(type, MNTTYPE_UDF)) || \ +(!strcmp(type, MNTTYPE_REISER)) || \ +(!strcmp(type, MNTTYPE_XFS))) + +static char extensions[MAXQUOTAS + 2][20] = INITQFNAMES; +static char *basenames[] = INITQFBASENAMES; + +/* + * Convert type of quota to written representation + */ +char *type2name(int type) +{ + return extensions[type]; +} + +/* + * Convert name to uid + */ +uid_t user2uid(char *name) +{ + struct passwd *entry; + uid_t ret; + char *errch; + + ret = strtol(name, &errch, 0); + if (!*errch) /* Is name number - we got directly uid? */ + return ret; + if (!(entry = getpwnam(name))) { + fprintf(stderr, _("User %s doesn't exist.\n"), name); + exit(1); + } + return entry->pw_uid; +} + +/* + * Convert group name to gid + */ +gid_t group2gid(char *name) +{ + struct group *entry; + gid_t ret; + char *errch; + + ret = strtol(name, &errch, 0); + if (!*errch) /* Is name number - we got directly gid? */ + return ret; + if (!(entry = getgrnam(name))) { + fprintf(stderr, _("Group %s doesn't exist.\n"), name); + exit(1); + } + return entry->gr_gid; +} + +/* + * Convert name to id + */ +int name2id(char *name, int qtype) +{ + if (qtype == USRQUOTA) + return user2uid(name); + else + return group2gid(name); +} + +/* + * Convert uid to name + */ +void uid2user(uid_t id, char *buf) +{ + struct passwd *entry; + + if (!(entry = getpwuid(id))) + sprintf(buf, "#%u", (uint) id); + else + sstrncpy(buf, entry->pw_name, MAXNAMELEN); +} + +/* + * Convert gid to name + */ +void gid2group(gid_t id, char *buf) +{ + struct group *entry; + + if (!(entry = getgrgid(id))) + sprintf(buf, "#%u", (uint) id); + else + sstrncpy(buf, entry->gr_name, MAXNAMELEN); +} + +/* + * Convert id to user/groupname + */ +void id2name(int id, int qtype, char *buf) +{ + if (qtype == USRQUOTA) + uid2user(id, buf); + else + gid2group(id, buf); +} + +/* + * Convert quota format name to number + */ +int name2fmt(char *str) +{ + if (!strcmp(str, _("vfsold"))) /* Old quota format */ + return QF_VFSOLD; + if (!strcmp(str, _("vfsv0"))) /* New quota format */ + return QF_VFSV0; + if (!strcmp(str, _("rpc"))) /* RPC quota calls */ + return QF_RPC; + fprintf(stderr, _("Unknown quota format: %s\nSupported formats are:\n\ + vfsold - original quota format\n\ + vfsv0 - new quota format\n\ + rpc - use RPC calls\n"), str); + return QF_ERROR; +} + +/* + * Convert time difference of seconds and current time + */ +void difftime2str(time_t seconds, char *buf) +{ + time_t now; + + buf[0] = 0; + if (!seconds) + return; + time(&now); + if (seconds <= now) { + strcpy(buf, _("none")); + return; + } + time2str(seconds - now, buf, TF_ROUND); +} + +/* + * Convert time to printable form + */ +void time2str(time_t seconds, char *buf, int flags) +{ + uint minutes, hours, days; + + minutes = (seconds + 30) / 60; /* Rounding */ + hours = minutes / 60; + minutes %= 60; + days = hours / 24; + hours %= 24; + if (flags & TF_ROUND) { + if (days >= 2) + sprintf(buf, _("%ddays"), days); + else + sprintf(buf, _("%02d:%02d"), hours + days * 24, minutes); + } + else { + if (minutes || (!minutes && !hours && !days)) + sprintf(buf, _("%uminutes"), (uint) (seconds + 30) / 60); + else if (hours) + sprintf(buf, _("%uhours"), hours + days * 24); + else + sprintf(buf, _("%udays"), days); + } +} + +/* + * Check to see if a particular quota is to be enabled (filesystem mounted with proper option) + */ +int hasquota(struct mntent *mnt, int type) +{ + char *option; + + if (!CORRECT_FSTYPE(mnt->mnt_type)) + return 0; + + option = hasmntopt(mnt, MNTOPT_USRQUOTA); + if ((type == USRQUOTA) && (option || !strcmp(mnt->mnt_type, MNTTYPE_XFS))) + return 1; + option = hasmntopt(mnt, MNTOPT_GRPQUOTA); + if ((type == GRPQUOTA) && (option || !strcmp(mnt->mnt_type, MNTTYPE_XFS))) + return 1; + option = hasmntopt(mnt, MNTOPT_QUOTA); + if ((type == USRQUOTA) && (option || !strcmp(mnt->mnt_type, MNTTYPE_XFS))) + return 1; + return 0; +} + +/* Check whether quotafile for given format exists - return its name in namebuf */ +static int check_fmtfile_exists(struct mntent *mnt, int type, int fmt, char *namebuf) +{ + struct stat buf; + + sprintf(namebuf, "%s/%s.%s", mnt->mnt_dir, basenames[fmt], extensions[type]); + if (!stat(namebuf, &buf)) + return 1; + if (errno != ENOENT) { + fprintf(stderr, "Can't stat quotafile %s: %s\n", namebuf, strerror(errno)); + return -1; + } + return 0; +} + +/* + * Get quotafile name for given entry; "" means format has no quota + * Note that formats without quotafile *must* be detected prior to calling this function + */ +char *get_qf_name(struct mntent *mnt, int type, int fmt) +{ + char *option, *pathname, has_quota_file_definition = 0; + char qfullname[PATH_MAX] = ""; + + if ((type == USRQUOTA) && (option = hasmntopt(mnt, MNTOPT_USRQUOTA))) { + if (*(pathname = option + strlen(MNTOPT_USRQUOTA)) == '=') + has_quota_file_definition = 1; + } + else if ((type == GRPQUOTA) && (option = hasmntopt(mnt, MNTOPT_GRPQUOTA))) { + if (*(pathname = option + strlen(MNTOPT_GRPQUOTA)) == '=') + has_quota_file_definition = 1; + } + else if ((type == USRQUOTA) && (option = hasmntopt(mnt, MNTOPT_QUOTA))) { + if (*(pathname = option + strlen(MNTOPT_QUOTA)) == '=') + has_quota_file_definition = 1; + } + else + return NULL; + + if (has_quota_file_definition) { + if ((option = strchr(++pathname, ','))) + strncpy(qfullname, pathname, min((option - pathname), sizeof(qfullname))); + else + strncpy(qfullname, pathname, sizeof(qfullname)); + } + else if (fmt == -1) { /* Should guess quota format? */ + int ret; + + if ((ret = check_fmtfile_exists(mnt, type, QF_VFSV0, qfullname)) == -1) + return NULL; + if (ret) + fmt = QF_VFSV0; + else { + if ((ret = check_fmtfile_exists(mnt, type, QF_VFSOLD, qfullname)) == -1) + return NULL; + if (ret) + fmt = QF_VFSOLD; + } + if (fmt == -1) + return NULL; + } + else if (basenames[fmt][0]) /* Any name specified? */ + sprintf(qfullname, "%s/%s.%s", mnt->mnt_dir, basenames[fmt], extensions[type]); + + return sstrdup(qfullname); +} + +/* + * Create NULL terminated list of quotafile handles from given list of mountpoints + * List of zero length means scan all entries in /etc/mtab + */ +struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt, + char local_only) +{ + FILE *mntf; + struct mntent *mnt; + int i, gotmnt = 0; + static struct quota_handle *hlist[MAXMNTPOINTS]; + const char *dev; + + if (!(mntf = setmntent(MOUNTED, "r"))) + die(2, _("Can't open %s: %s\n"), MOUNTED, strerror(errno)); + while ((mnt = getmntent(mntf))) { + if (!(dev = get_device_name(mnt->mnt_fsname))) + continue; + for (i = 0; i < gotmnt && strcmp(dev, hlist[i]->qh_quotadev); i++); + /* We already have this device? (can happen when filesystem is mounted multiple times */ + if (i < gotmnt) + continue; + for (i = 0; i < count; i++) + /* Is this what we want? */ + if (!strcmp(dev, mntpoints[i]) || !strcmp(mnt->mnt_dir, mntpoints[i])) + break; + free((char *)dev); + if (!count || i < count) { + if (strcmp(mnt->mnt_type, MNTTYPE_NFS)) { /* No NFS? */ + if (gotmnt == MAXMNTPOINTS) + die(3, _("Too many mountpoints. Please report to: %s\n"), + MY_EMAIL); + if (!(hlist[gotmnt] = init_io(mnt, type, fmt))) + continue; + gotmnt++; + } + else if (!local_only) { /* Use NFS? */ +#ifdef RPC + if (gotmnt == MAXMNTPOINTS) + die(3, _("Too many mountpoints. Please report to: %s\n"), + MY_EMAIL); + if (!(hlist[gotmnt] = init_io(mnt, type, 0))) + continue; + gotmnt++; +#endif + } + } + } + endmntent(mntf); + hlist[gotmnt] = NULL; + if (count && gotmnt != count) + die(1, _("Not all specified mountpoints are using quota.\n")); + return hlist; +} + +/* + * Free given list of handles + */ +int dispose_handle_list(struct quota_handle **hlist) +{ + int i, ret; + + for (i = 0; hlist[i]; i++) + if ((ret = end_io(hlist[i]))) + fprintf(stderr, _("Error while releasing file on %s\n"), + hlist[i]->qh_quotadev); + return 0; +} + +/* + * Check kernel quota version + */ + +#define KERN_KNOWN_QUOTA_VERSION (6*10000 + 5*100 + 0) + +int kern_quota_format(void) +{ + struct dqstats stats; + int ret = 0; + struct stat st; + + if (!stat("/proc/fs/xfs/stat", &st)) + ret |= (1 << QF_XFS); + if (quotactl(QCMD(Q_GETSTATS, 0), NULL, 0, (void *)&stats) < 0) { + if (errno == ENOSYS || errno == ENOTSUP) /* Quota not compiled? */ + return QF_ERROR; + if (errno == EINVAL || errno == EFAULT || errno == EPERM) /* Old quota compiled? */ + return ret | (1 << QF_VFSOLD); + die(4, "Error while detecting kernel quota version: %s\n", strerror(errno)); + } + /* We might do some more generic checks in future but this should be enough for now */ + if (stats.version > KERN_KNOWN_QUOTA_VERSION) /* Newer kernel than we know? */ + return QF_TOONEW; + return ret | (1 << QF_VFSV0); /* New format supported */ +} + +/* + * Warn about too new kernel + */ +void warn_new_kernel(int fmt) +{ + if (fmt == -1 && kern_quota_format() == QF_TOONEW) + fprintf(stderr, + _ + ("Warning: Kernel quota is newer than supported. Quotafile used by utils need not be the one used by kernel.\n")); +} + +/* Check whether old quota is turned on on given device */ +static int v1_kern_quota_on(const char *dev, int type) +{ + char tmp[1024]; /* Just temporary buffer */ + + if (!quotactl(QCMD(Q_V1_GETQUOTA, type), dev, 0, tmp)) /* OK? */ + return 1; + return 0; +} + +/* Check whether new quota is turned on on given device */ +static int v2_kern_quota_on(const char *dev, int type) +{ + char tmp[1024]; /* Just temporary buffer */ + + if (!quotactl(QCMD(Q_V2_GETINFO, type), dev, 0, tmp)) /* OK? */ + return 1; + return 0; +} + +/* Check whether XFS quota is turned on on given device */ +static int xfs_kern_quota_on(const char *dev, int type) +{ + struct xfs_mem_dqinfo info; + + if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) { + if (type == USRQUOTA && info.qs_flags & XFS_QUOTA_UDQ_ACCT) + return 1; + else if (type == GRPQUOTA && info.qs_flags & XFS_QUOTA_GDQ_ACCT) + return 1; + } + return 0; +} + +/* + * Check whether is quota turned on on given device for given type + */ +int kern_quota_on(const char *dev, int type, int fmt) +{ + /* Check whether quota is turned on... */ + if ((fmt & (1 << QF_VFSV0)) && v2_kern_quota_on(dev, type)) /* New quota format */ + return QF_VFSV0; + if ((fmt & (1 << QF_XFS)) && xfs_kern_quota_on(dev, type)) /* XFS quota format */ + return QF_XFS; + if ((fmt & (1 << QF_VFSOLD)) && v1_kern_quota_on(dev, type)) /* Old quota format */ + return QF_VFSOLD; + return -1; +} diff --git a/quotasys.h b/quotasys.h new file mode 100644 index 0000000..e0380fb --- /dev/null +++ b/quotasys.h @@ -0,0 +1,75 @@ +/* + * + * Headerfile of quota interactions with system - filenames, fstab... + * + */ + +#ifndef _QUOTASYS_H +#define _QUOTASYS_H + +#include <sys/types.h> +#include "mntopt.h" + +#define MAXNAMELEN 64 /* Maximal length of user/group name */ +#define MAXTIMELEN 40 /* Maximal length of time string */ +#define MAXMNTPOINTS 128 /* Maximal number of processed mountpoints per one run */ + +/* Flags for formatting time */ +#define TF_ROUND 0x1 /* Should be printed time rounded? */ + +/* + * Exported functions + */ +/* Convert quota type to written form */ +char *type2name(int); + +/* Convert username to uid */ +uid_t user2uid(char *); + +/* Convert groupname to gid */ +gid_t group2gid(char *); + +/* Convert user/groupname to id */ +int name2id(char *name, int qtype); + +/* Convert uid to username */ +void uid2user(uid_t, char *); + +/* Convert gid to groupname */ +void gid2group(gid_t, char *); + +/* Convert id to user/group name */ +void id2name(int id, int qtype, char *buf); + +/* Convert quota format name to number */ +int name2fmt(char *str); + +/* Convert time difference between given time and current time to printable form */ +void difftime2str(time_t, char *); + +/* Convert time to printable form */ +void time2str(time_t, char *, int); + +/* Check to see if particular quota is to be enabled */ +int hasquota(struct mntent *mnt, int type); + +/* Get quotafile name for given entry */ +char *get_qf_name(struct mntent *mnt, int type, int fmt); + +/* Create NULL-terminated list of handles for quotafiles for given mountpoints */ +struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt, + + char local_only); +/* Dispose given list of handles */ +int dispose_handle_list(struct quota_handle **hlist); + +/* Warn about too new kernel */ +void warn_new_kernel(int fmt); + +/* Check kernel supported quotafile format */ +int kern_quota_format(void); + +/* Check whether is quota turned on on given device for given type */ +int kern_quota_on(const char *dev, int type, int fmt); + +#endif /* _QUOTASYS_H */ diff --git a/repquota.8 b/repquota.8 new file mode 100644 index 0000000..a4f5854 --- /dev/null +++ b/repquota.8 @@ -0,0 +1,71 @@ +.TH REPQUOTA 8 +.UC 4 +.SH NAME +repquota \- summarize quotas for a filesystem +.SH SYNOPSIS +.B /usr/etc/repquota +[ +.B \-vug +] +.IR filesystem .\|.\|. +.LP +.B /usr/etc/repquota +[ +.B \-avug +] +.SH DESCRIPTION +.IX "repquota command" "" "\fLrepquota\fP \(em summarize quotas" +.IX "user quotas" "repquota command" "" "\fLrepquota\fP \(em summarize quotas" +.IX "disk quotas" "repquota command" "" "\fLrepquota\fP \(em summarize quotas" +.IX "quotas" "repquota command" "" "\fLrepquota\fP \(em summarize quotas" +.IX "filesystem" "repquota command" "" "\fLrepquota\fP \(em summarize quotas" +.IX "summarize filesystem quotas repquota" "" "summarize filesystem quotas \(em \fLrepquota\fP" +.IX "report filesystem quotas repquota" "" "report filesystem quotas \(em \fLrepquota\fP" +.IX display "filesystem quotas \(em \fLrepquota\fP" +.LP +.B repquota +prints a summary of the disc usage and quotas for the specified file +systems. For each user the current number of files and amount of space +(in kilobytes) is printed, along with any quotas created with +.BR edquota (8). +.SH OPTIONS +.TP +.B \-a +Report on all filesystems indicated in +.B /etc/mtab +to be read-write with quotas. +.TP +.B \-v +Report all quotas, even if there is no usage. +.TP +.B \-g +Report quotas for groups. +.TP +.B \-u +Report quotas for users. This is the default. +.LP +Only the super-user may view quotas which are not their own. +.SH FILES +.PD 0 +.TP 20 +.B aquota.user or aquota.group +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP +.B quota.user or quota.group +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/mtab +default filesystems +.TP +.B /etc/passwd +default set of users +.TP +.B /etc/passwd +default set of groups +.PD +.SH SEE ALSO +.BR quota (1), +.BR quotactl (2), +.BR edquota (8), +.BR quotacheck (8), +.BR quotaon (8) diff --git a/repquota.c b/repquota.c new file mode 100644 index 0000000..b296149 --- /dev/null +++ b/repquota.c @@ -0,0 +1,160 @@ +/* + * + * Utility for reporting quotas + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <time.h> +#include <errno.h> + +#include "pot.h" +#include "common.h" +#include "quotasys.h" +#include "quotaio.h" + +#define FL_USER 1 +#define FL_GROUP 2 +#define FL_VERBOSE 4 +#define FL_ALL 8 + +int flags, fmt = -1; +char **mnt; +int mntcnt; + +static void parse_options(int argcnt, char **argstr) +{ + int ret; + char *slash = strrchr(argstr[0], '/'); + + if (!slash) + slash = argstr[0]; + else + slash++; + + while ((ret = getopt(argcnt, argstr, "VavughF:")) != EOF) { + switch (ret) { + case '?': + case 'h': + usage: + fprintf(stderr, + _ + ("Utility for reporting quotas.\nUsage:\n%s [-vug] [-F quotaformat] (-a | mntpoint)\n"), + slash); + fprintf(stderr, _("Bugs to %s\n"), MY_EMAIL); + exit(1); + case 'V': + version(); + exit(0); + case 'u': + flags |= FL_USER; + break; + case 'g': + flags |= FL_GROUP; + break; + case 'v': + flags |= FL_VERBOSE; + break; + case 'a': + flags |= FL_ALL; + break; + case 'F': + if ((fmt = name2fmt(optarg)) == QF_ERROR) + exit(1); + break; + + } + } + + if ((flags & FL_ALL && optind != argcnt) || (!(flags & FL_ALL) && optind == argcnt)) { + fputs(_("Bad number of arguments.\n"), stderr); + goto usage; + } + if (fmt == QF_RPC) { + fputs(_("Repquota can't report through RPC calls.\n"), stderr); + exit(1); + } + if (!(flags & (FL_USER | FL_GROUP))) + flags |= FL_USER; + if (!(flags & FL_ALL)) { + mnt = argstr + optind; + mntcnt = argcnt - optind; + } +} + +static char overlim(uint usage, uint softlim, uint hardlim) +{ + if ((usage > softlim && softlim) || (usage > hardlim && hardlim)) + return '+'; + return '-'; +} + +static int print(struct dquot *dquot) +{ + char name[MAXNAMELEN]; + char time[MAXTIMELEN]; + struct util_dqblk *entry = &dquot->dq_dqb; + + if (!entry->dqb_curspace && !entry->dqb_curinodes && !(flags & FL_VERBOSE)) + return 0; + id2name(dquot->dq_id, dquot->dq_h->qh_type, name); + difftime2str(entry->dqb_btime, time); + printf("%-10s%c%c%8Lu%8Lu%8Lu%7s", name, + overlim(qb2kb(toqb(entry->dqb_curspace)), qb2kb(entry->dqb_bsoftlimit), + qb2kb(entry->dqb_bhardlimit)), overlim(entry->dqb_curinodes, + entry->dqb_isoftlimit, + entry->dqb_ihardlimit), + (long long)qb2kb(toqb(entry->dqb_curspace)), (long long)qb2kb(entry->dqb_bsoftlimit), + (long long)qb2kb(entry->dqb_bhardlimit), time); + difftime2str(entry->dqb_itime, time); + printf("%8Lu%6Lu%6Lu%7s\n", (long long)entry->dqb_curinodes, + (long long)entry->dqb_isoftlimit, (long long)entry->dqb_ihardlimit, time); + return 0; +} + +static void report_it(struct quota_handle *h, int type) +{ + char bgbuf[MAXTIMELEN], igbuf[MAXTIMELEN]; + + printf(_("*** Report for %s quotas on device %s\n"), type2name(type), h->qh_quotadev); + time2str(h->qh_info.dqi_bgrace, bgbuf, TF_ROUND); + time2str(h->qh_info.dqi_igrace, igbuf, TF_ROUND); + printf("Block grace time: %s Inode grace time: %s\n", bgbuf, igbuf); + printf(" Block limits File limits\n"); + printf("User used soft hard grace used soft hard grace\n"); + + if (h->qh_ops->scan_dquots(h, print) < 0) + return; + if (h->qh_ops->report) + h->qh_ops->report(h, flags & FL_VERBOSE); +} + +static void report(int type) +{ + struct quota_handle **handles; + int i; + + if (flags & FL_ALL) + handles = create_handle_list(0, NULL, type, fmt, 1); + else + handles = create_handle_list(mntcnt, mnt, type, fmt, 1); + for (i = 0; handles[i]; i++) + report_it(handles[i], type); + dispose_handle_list(handles); +} + +int main(int argcnt, char **argstr) +{ + gettexton(); + parse_options(argcnt, argstr); + warn_new_kernel(fmt); + if (flags & FL_USER) + report(USRQUOTA); + if (flags & FL_GROUP) + report(GRPQUOTA); + return 0; +} diff --git a/rquota.3 b/rquota.3 new file mode 100644 index 0000000..8eee71e --- /dev/null +++ b/rquota.3 @@ -0,0 +1,34 @@ +.\"@(#)rquota.3; +.TH RQUOTA 3 +.SH NAME +rquota \- implement quotas on remote machines +.SH PROTOCOL +.B /usr/include/rpcsvc/rquota.x +.SH DESCRIPTION +.IX "rquota()" "" "\fLrquota()\fP \(em implement quotas on remote machines" +.LP +The +.B rquota(\|) +protocol inquires about quotas on remote machines. +It is used in conjunction with +.SM NFS\s0, +since +.SM NFS +itself does not implement quotas. +.SH PROGRAMMING +.LP +.B #include <rpcsvc/rquota.h> +.LP +The following +.SM XDR +routines are available in +.BR librpcsvc : +.nf +.B xdr_getquota_arg +.B xdr_getquota_rslt +.B xdr_rquota +.fi +.SH SEE ALSO +.BR quota (1), +.BR quotactl (2) + diff --git a/rquota.x b/rquota.x new file mode 100644 index 0000000..3cd5c10 --- /dev/null +++ b/rquota.x @@ -0,0 +1,139 @@ +/* @(#)rquota.x 2.1 88/08/01 4.0 RPCSRC */ +/* @(#)rquota.x 1.2 87/09/20 Copyr 1987 Sun Micro */ + +/* + * Remote quota protocol + * Requires unix authentication + */ + +const RQ_PATHLEN = 1024; + +struct sq_dqblk { + unsigned int rq_bhardlimit; /* absolute limit on disk blks alloc */ + unsigned int rq_bsoftlimit; /* preferred limit on disk blks */ + unsigned int rq_curblocks; /* current block count */ + unsigned int rq_fhardlimit; /* absolute limit on allocated files */ + unsigned int rq_fsoftlimit; /* preferred file limit */ + unsigned int rq_curfiles; /* current # allocated files */ + unsigned int rq_btimeleft; /* time left for excessive disk use */ + unsigned int rq_ftimeleft; /* time left for excessive files */ +}; + +struct getquota_args { + string gqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */ + int gqa_uid; /* Inquire about quota for uid */ +}; + +struct setquota_args { + int sqa_qcmd; + string sqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */ + int sqa_id; /* Set quota for uid */ + sq_dqblk sqa_dqblk; +}; + +struct ext_getquota_args { + string gqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */ + int gqa_type; /* Type of quota info is needed about */ + int gqa_id; /* Inquire about quota for id */ +}; + +struct ext_setquota_args { + int sqa_qcmd; + string sqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */ + int sqa_id; /* Set quota for id */ + int sqa_type; /* Type of quota to set */ + sq_dqblk sqa_dqblk; +}; + +/* + * remote quota structure + */ +struct rquota { + int rq_bsize; /* block size for block counts */ + bool rq_active; /* indicates whether quota is active */ + unsigned int rq_bhardlimit; /* absolute limit on disk blks alloc */ + unsigned int rq_bsoftlimit; /* preferred limit on disk blks */ + unsigned int rq_curblocks; /* current block count */ + unsigned int rq_fhardlimit; /* absolute limit on allocated files */ + unsigned int rq_fsoftlimit; /* preferred file limit */ + unsigned int rq_curfiles; /* current # allocated files */ + unsigned int rq_btimeleft; /* time left for excessive disk use */ + unsigned int rq_ftimeleft; /* time left for excessive files */ +}; + +enum qr_status { + Q_OK = 1, /* quota returned */ + Q_NOQUOTA = 2, /* noquota for uid */ + Q_EPERM = 3 /* no permission to access quota */ +}; + +union getquota_rslt switch (qr_status status) { +case Q_OK: + rquota gqr_rquota; /* valid if status == Q_OK */ +case Q_NOQUOTA: + void; +case Q_EPERM: + void; +}; + +union setquota_rslt switch (qr_status status) { +case Q_OK: + rquota sqr_rquota; /* valid if status == Q_OK */ +case Q_NOQUOTA: + void; +case Q_EPERM: + void; +}; + +program RQUOTAPROG { + version RQUOTAVERS { + /* + * Get all quotas + */ + getquota_rslt + RQUOTAPROC_GETQUOTA(getquota_args) = 1; + + /* + * Get active quotas only + */ + getquota_rslt + RQUOTAPROC_GETACTIVEQUOTA(getquota_args) = 2; + + /* + * Set all quotas + */ + setquota_rslt + RQUOTAPROC_SETQUOTA(setquota_args) = 3; + + /* + * Get active quotas only + */ + setquota_rslt + RQUOTAPROC_SETACTIVEQUOTA(setquota_args) = 4; + } = 1; + version EXT_RQUOTAVERS { + /* + * Get all quotas + */ + getquota_rslt + RQUOTAPROC_GETQUOTA(ext_getquota_args) = 1; + + /* + * Get active quotas only + */ + getquota_rslt + RQUOTAPROC_GETACTIVEQUOTA(ext_getquota_args) = 2; + + /* + * Set all quotas + */ + setquota_rslt + RQUOTAPROC_SETQUOTA(ext_setquota_args) = 3; + + /* + * Set active quotas only + */ + setquota_rslt + RQUOTAPROC_SETACTIVEQUOTA(ext_setquota_args) = 4; + } = 2; +} = 100011; diff --git a/rquota_client.c b/rquota_client.c new file mode 100644 index 0000000..017dd2c --- /dev/null +++ b/rquota_client.c @@ -0,0 +1,309 @@ +/* + * QUOTA An implementation of the diskquota system for the LINUX + * operating system. QUOTA is implemented using the BSD systemcall + * interface as the means of communication with the user level. + * Should work for all filesystems because of integration into the + * VFS layer of the operating system. + * This is based on the Melbourne quota system wich uses both user and + * group quota files. + * + * This part does the rpc-communication with the rquotad. + * + * Version: $Id: rquota_client.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $ + * + * Author: Marco van Wieringen <mvw@planets.elm.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <rpc/rpc.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> + +#include "mntopt.h" +#include "rquota.h" +#include "common.h" +#include "quotaio.h" + +#if defined(RPC) + +/* Convert network format of quotas to utils one */ +static inline void clinet2utildqblk(struct util_dqblk *u, struct rquota *n) +{ + /* Copy the quota */ + u->dqb_bhardlimit = n->rq_bhardlimit; + u->dqb_bsoftlimit = n->rq_bsoftlimit; + u->dqb_ihardlimit = n->rq_fhardlimit; + u->dqb_isoftlimit = n->rq_fsoftlimit; + u->dqb_curinodes = n->rq_curfiles; + u->dqb_curspace = n->rq_curblocks * n->rq_bsize; + u->dqb_btime = n->rq_btimeleft; + u->dqb_itime = n->rq_ftimeleft; + /* Convert from remote block size */ + if (n->rq_bsize != RPC_DQBLK_SIZE) { + int conversion_unit; + + conversion_unit = n->rq_bsize >> RPC_DQBLK_SIZE_BITS; + if (conversion_unit == 0) { + conversion_unit = RPC_DQBLK_SIZE / n->rq_bsize; + + u->dqb_bhardlimit /= conversion_unit; + u->dqb_bsoftlimit /= conversion_unit; + } + else { + u->dqb_bhardlimit *= conversion_unit; + u->dqb_bsoftlimit *= conversion_unit; + } + } +} + +/* Convert utils format of quotas to network one */ +static inline void cliutil2netdqblk(struct sq_dqblk *n, struct util_dqblk *u) +{ + n->rq_bhardlimit = u->dqb_bhardlimit; + n->rq_bsoftlimit = u->dqb_bsoftlimit; + n->rq_fhardlimit = u->dqb_ihardlimit; + n->rq_fsoftlimit = u->dqb_isoftlimit; + n->rq_curblocks = toqb(u->dqb_curspace); + n->rq_curfiles = u->dqb_curinodes; + n->rq_btimeleft = u->dqb_btime; + n->rq_ftimeleft = u->dqb_itime; +} + +/* + * Collect the requested quota information from a remote host. + */ +void rpc_rquota_get(struct dquot *dquot) +{ + CLIENT *clnt; + getquota_rslt *result; + union { + getquota_args arg; + ext_getquota_args ext_arg; + } args; + char *fsname_tmp, *host, *pathname; + struct timeval timeout = { 2, 0 }; + + /* + * Initialize with NULL. + */ + memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb)); + + /* + * Convert host:pathname to seperate host and pathname. + */ + fsname_tmp = (char *)smalloc(strlen(dquot->dq_h->qh_quotadev) + 1); + strcpy(fsname_tmp, dquot->dq_h->qh_quotadev); + host = fsname_tmp; + + /* + * Strip off pathname on nfs mounted dir. Ignore entries of any + * automounter. + */ + if ((pathname = strchr(fsname_tmp, ':')) == (char *)0 || *(pathname + 1) == '(') + return; + + *pathname++ = '\0'; + + /* + * First try EXT_RQUOTAPROG (Extended (LINUX) RPC quota program) + */ + args.ext_arg.gqa_pathp = pathname; + args.ext_arg.gqa_id = dquot->dq_id; + args.ext_arg.gqa_type = dquot->dq_h->qh_type; + + /* + * Create a RPC client. + */ + if ((clnt = clnt_create(host, RQUOTAPROG, EXT_RQUOTAVERS, "udp")) != NULL) { + /* + * Initialize unix authentication + */ + clnt->cl_auth = authunix_create_default(); + + /* + * Setup protocol timeout. + */ + clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout); + + /* + * Do RPC call and check result. + */ + result = rquotaproc_getquota_2(&args.ext_arg, clnt); + if (result != NULL && result->status == Q_OK) + clinet2utildqblk(&dquot->dq_dqb, &result->getquota_rslt_u.gqr_rquota); + + /* + * Destroy unix authentication and RPC client structure. + */ + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + } + else { + result = NULL; + } + + if (result == NULL || !result->status) { + if (dquot->dq_h->qh_type == USRQUOTA) { + /* + * Try RQUOTAPROG because server doesn't seem to understand EXT_RQUOTAPROG. (NON-LINUX servers.) + */ + args.arg.gqa_pathp = pathname; + args.arg.gqa_uid = dquot->dq_id; + + /* + * Create a RPC client. + */ + if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) != NULL) { + /* + * Initialize unix authentication + */ + clnt->cl_auth = authunix_create_default(); + + /* + * Setup protocol timeout. + */ + clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout); + + /* + * Do RPC call and check result. + */ + result = rquotaproc_getquota_1(&args.arg, clnt); + if (result != NULL && result->status == Q_OK) + clinet2utildqblk(&dquot->dq_dqb, + &result->getquota_rslt_u.gqr_rquota); + + /* + * Destroy unix authentication and RPC client structure. + */ + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + } + } + } + + free(fsname_tmp); +} + +/* + * Set the requested quota information on a remote host. + */ +void rpc_rquota_set(int qcmd, struct dquot *dquot) +{ +#if defined(RPC_SETQUOTA) + CLIENT *clnt; + setquota_rslt *result; + union { + setquota_args arg; + ext_setquota_args ext_arg; + } args; + char *fsname_tmp, *host, *pathname; + struct timeval timeout = { 2, 0 }; + + /* + * Convert host:pathname to seperate host and pathname. + */ + fsname_tmp = (char *)smalloc(strlen(dquot->dq_h->qh_quotadev) + 1); + strcpy(fsname_tmp, dquot->dq_h->qh_quotadev); + host = fsname_tmp; + + /* + * Strip off pathname on nfs mounted dir. Ignore entries of any + * automounter. + */ + if ((pathname = strchr(fsname_tmp, ':')) == (char *)0 || *(pathname + 1) == '(') + return; + + *pathname++ = '\0'; + + /* + * First try EXT_RQUOTAPROG (Extended (LINUX) RPC quota program) + */ + args.ext_arg.sqa_qcmd = qcmd; + args.ext_arg.sqa_pathp = pathname; + args.ext_arg.sqa_id = dquot->dq_id; + args.ext_arg.sqa_type = dquot->dq_h->qh_type; + cliutil2netdqblk(&args.ext_arg.sqa_dqblk, &dquot->dq_dqb); + + if ((clnt = clnt_create(host, RQUOTAPROG, EXT_RQUOTAVERS, "udp")) != NULL) { + /* + * Initialize unix authentication + */ + clnt->cl_auth = authunix_create_default(); + + /* + * Setup protocol timeout. + */ + clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout); + + /* + * Do RPC call and check result. + */ + result = rquotaproc_setquota_2(&args.ext_arg, clnt); + if (result != NULL && result->status == Q_OK) + clinet2utildqblk(&dquot->dq_dqb, &result->setquota_rslt_u.sqr_rquota); + + /* + * Destroy unix authentication and RPC client structure. + */ + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + } + else + result = NULL; + + if (result == NULL || !result->status) { + if (dquot->dq_h->qh_type == USRQUOTA) { + /* + * Try RQUOTAPROG because server doesn't seem to understand EXT_RQUOTAPROG. (NON-LINUX servers.) + */ + args.arg.sqa_qcmd = qcmd; + args.arg.sqa_pathp = pathname; + args.arg.sqa_id = dquot->dq_id; + cliutil2netdqblk(&args.arg.sqa_dqblk, &dquot->dq_dqb); + + /* + * Create a RPC client. + */ + if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) != NULL) { + /* + * Initialize unix authentication + */ + clnt->cl_auth = authunix_create_default(); + + /* + * Setup protocol timeout. + */ + clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout); + + /* + * Do RPC call and check result. + */ + result = rquotaproc_setquota_1(&args.arg, clnt); + if (result != NULL && result->status == Q_OK) + clinet2utildqblk(&dquot->dq_dqb, + &result->setquota_rslt_u.sqr_rquota); + + /* + * Destroy unix authentication and RPC client structure. + */ + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + } + } + } + free(fsname_tmp); +#endif +} +#endif diff --git a/rquota_client.h b/rquota_client.h new file mode 100644 index 0000000..7bf92b5 --- /dev/null +++ b/rquota_client.h @@ -0,0 +1,18 @@ +/* + * + * Header file for rquota functions + * + */ + +#ifndef _RQUOTA_CLIENT_H +#define _RQUOTA_CLIENT_H + +#include "quotaio.h" + +/* Collect the requested quota information from a remote host. */ +void rpc_rquota_get(struct dquot *dquot); + +/* Set the requested quota information on a remote host. */ +void rpc_rquota_set(int qcmd, struct dquot *dquot); + +#endif diff --git a/rquota_server.c b/rquota_server.c new file mode 100644 index 0000000..7468661 --- /dev/null +++ b/rquota_server.c @@ -0,0 +1,342 @@ +/* + * QUOTA An implementation of the diskquota system for the LINUX + * operating system. QUOTA is implemented using the BSD systemcall + * interface as the means of communication with the user level. + * Should work for all filesystems because of integration into the + * VFS layer of the operating system. + * This is based on the Melbourne quota system wich uses both user and + * group quota files. + * + * This part does the lookup of the info. + * + * Version: $Id: rquota_server.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $ + * + * Author: Marco van Wieringen <mvw@planets.elm.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <rpc/rpc.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/mount.h> +#include <arpa/inet.h> +#include <paths.h> +#include <stdio.h> +#include <syslog.h> +#include <netdb.h> +#ifdef HOST_ACCESS +#include <tcpd.h> +#endif + +#include "mntopt.h" +#include "quotaops.h" +#include "bylabel.h" +#include "rquota.h" +#include "quotaio.h" +#include "quotasys.h" +#include "dqblk_rpc.h" + +#define STDIN_FILENO 0 + +#define TYPE_EXTENDED 0x01 +#define ACTIVE 0x02 + +#define FACILITY LOG_LOCAL7 + +#ifndef MAXPATHNAMELEN +#define MAXPATHNAMELEN BUFSIZ +#endif + +#define NETTYPE AF_INET + +#ifdef HOSTS_ACCESS +#define good_client(a,b) hosts_ctl("rpc.rquotad", b, inet_ntoa(a->sin_addr), "") +#endif + +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; + +/* + * Global unix authentication credentials. + */ +extern struct authunix_parms *unix_cred; + +int in_group(gid_t * gids, u_int len, gid_t gid) +{ + gid_t *gidsp = gids + len; + + while (gidsp > gids) + if (*(--gids) == gid) + return 1; + + return 0; +} + +static inline void servnet2utildqblk(struct util_dqblk *u, sq_dqblk * n) +{ + u->dqb_bhardlimit = n->rq_bhardlimit; + u->dqb_bsoftlimit = n->rq_bsoftlimit; + u->dqb_ihardlimit = n->rq_fhardlimit; + u->dqb_isoftlimit = n->rq_fsoftlimit; + u->dqb_curspace = n->rq_curblocks << RPC_DQBLK_SIZE_BITS; + u->dqb_curinodes = n->rq_curfiles; + u->dqb_btime = n->rq_btimeleft; + u->dqb_itime = n->rq_ftimeleft; +} + +static inline void servutil2netdqblk(struct rquota *n, struct util_dqblk *u) +{ + n->rq_bhardlimit = u->dqb_bhardlimit; + n->rq_bsoftlimit = u->dqb_bsoftlimit; + n->rq_fhardlimit = u->dqb_ihardlimit; + n->rq_fsoftlimit = u->dqb_isoftlimit; + n->rq_curblocks = (u->dqb_curspace + RPC_DQBLK_SIZE - 1) >> RPC_DQBLK_SIZE_BITS; + n->rq_curfiles = u->dqb_curinodes; + n->rq_btimeleft = u->dqb_btime; + n->rq_ftimeleft = u->dqb_itime; +} + +setquota_rslt *setquotainfo(int flags, caddr_t * argp, struct svc_req *rqstp) +{ + static setquota_rslt result; + +#if defined(RPC_SETQUOTA) + union { + setquota_args *args; + ext_setquota_args *ext_args; + } arguments; + struct stat st; + dev_t device; + FILE *mntf; + struct util_dqblk dqblk; + struct dquot *dquot; + struct mntent *mnt; + char *pathname; + int id, qcmd, type; + struct quota_handle *handles[2] = { NULL, NULL }; + +#ifdef HOSTS_ACCESS + struct hostent *hp; + struct sockaddr_in *addr; + + addr = (svc_getcaller(rqstp->rq_xprt)); + hp = gethostbyaddr((char *)&(addr->sin_addr), sizeof(addr->sin_addr), AF_INET); + + if (!good_client(svc_getcaller(rqstp->rq_xprt), hp->h_name)) { + result.status = Q_EPERM; + return (&result); + } + +#endif + + /* + * First check authentication. + */ + if (flags & TYPE_EXTENDED) { + arguments.ext_args = (ext_setquota_args *) argp; + + id = arguments.ext_args->sqa_id; + if (unix_cred->aup_uid != 0) { + result.status = Q_EPERM; + return (&result); + } + + qcmd = arguments.ext_args->sqa_qcmd; + type = arguments.ext_args->sqa_type; + pathname = arguments.ext_args->sqa_pathp; + servnet2utildqblk(&dqblk, &arguments.ext_args->sqa_dqblk); + } + else { + arguments.args = (setquota_args *) argp; + + id = arguments.args->sqa_id; + if (unix_cred->aup_uid != 0) { + result.status = Q_EPERM; + return (&result); + } + + qcmd = arguments.args->sqa_qcmd; + type = USRQUOTA; + pathname = arguments.args->sqa_pathp; + servnet2utildqblk(&dqblk, &arguments.args->sqa_dqblk); + } + + result.status = Q_NOQUOTA; + if (stat(pathname, &st) == -1) + return (&result); + + device = st.st_dev; + result.setquota_rslt_u.sqr_rquota.rq_bsize = RPC_DQBLK_SIZE; + + mntf = setmntent(_PATH_MOUNTED, "r"); + while ((mnt = getmntent(mntf))) { + if (stat(mnt->mnt_dir, &st) == -1) + continue; + if (st.st_dev != device) + continue; + if (!(handles[0] = init_io(mnt, type, -1))) + continue; + break; + } + endmntent(mntf); + if (!(dquot = handles[0]->qh_ops->read_dquot(handles[0], id))) + goto out; + if (qcmd == QCMD(Q_RPC_SETQLIM, type) || qcmd == QCMD(Q_RPC_SETQUOTA, type)) { + dquot->dq_dqb.dqb_bsoftlimit = dqblk.dqb_bsoftlimit; + dquot->dq_dqb.dqb_bhardlimit = dqblk.dqb_bhardlimit; + dquot->dq_dqb.dqb_isoftlimit = dqblk.dqb_isoftlimit; + dquot->dq_dqb.dqb_ihardlimit = dqblk.dqb_ihardlimit; + dquot->dq_dqb.dqb_btime = dqblk.dqb_btime; + dquot->dq_dqb.dqb_itime = dqblk.dqb_itime; + } + if (qcmd == QCMD(Q_RPC_SETUSE, type) || qcmd == QCMD(Q_RPC_SETQUOTA, type)) { + dquot->dq_dqb.dqb_curspace = dqblk.dqb_curspace; + dquot->dq_dqb.dqb_curinodes = dqblk.dqb_curinodes; + } + if (handles[0]->qh_ops->commit_dquot(dquot) == -1) + goto out; + result.status = Q_OK; + out: + dispose_handle_list(handles); +#else + result.status = Q_EPERM; +#endif + return (&result); +} + +getquota_rslt *getquotainfo(int flags, caddr_t * argp, struct svc_req * rqstp) +{ + static getquota_rslt result; + union { + getquota_args *args; + ext_getquota_args *ext_args; + } arguments; + struct stat st; + dev_t device; + FILE *mntf; + struct dquot *dquot = NULL; + struct mntent *mnt; + char *pathname; + int id, type; + struct quota_handle *handles[2] = { NULL, NULL }; + +#ifdef HOSTS_ACCESS + struct hostent *hp; + struct sockaddr_in *addr; + + addr = (svc_getcaller(rqstp->rq_xprt)); + hp = gethostbyaddr((char *)&(addr->sin_addr), sizeof(addr->sin_addr), AF_INET); + + if (!good_client(svc_getcaller(rqstp->rq_xprt), hp->h_name)) { + return (FALSE); + } +#endif + + /* + * First check authentication. + */ + if (flags & TYPE_EXTENDED) { + arguments.ext_args = (ext_getquota_args *) argp; + id = arguments.ext_args->gqa_id; + type = arguments.ext_args->gqa_type; + pathname = arguments.ext_args->gqa_pathp; + + if (type == USRQUOTA && unix_cred->aup_uid && unix_cred->aup_uid != id) { + result.status = Q_EPERM; + return (&result); + } + + if (type == GRPQUOTA && unix_cred->aup_uid && unix_cred->aup_gid != id && + !in_group((gid_t *) unix_cred->aup_gids, unix_cred->aup_len, id)) { + result.status = Q_EPERM; + return (&result); + } + } + else { + arguments.args = (getquota_args *) argp; + id = arguments.args->gqa_uid; + type = USRQUOTA; + pathname = arguments.args->gqa_pathp; + + if (unix_cred->aup_uid && unix_cred->aup_uid != id) { + result.status = Q_EPERM; + return (&result); + } + } + + result.status = Q_NOQUOTA; + + if (stat(pathname, &st) == -1) + return (&result); + + device = st.st_dev; + result.getquota_rslt_u.gqr_rquota.rq_bsize = RPC_DQBLK_SIZE; + + mntf = setmntent(_PATH_MOUNTED, "r"); + while ((mnt = getmntent(mntf))) { + if (stat(mnt->mnt_dir, &st) == -1) + continue; + if (st.st_dev != device) + continue; + if (!(handles[0] = init_io(mnt, type, -1))) + continue; + break; + } + endmntent(mntf); + if (!(flags & ACTIVE) || QIO_ENABLED(handles[0])) + dquot = handles[0]->qh_ops->read_dquot(handles[0], id); + if (dquot) { + result.status = Q_OK; + result.getquota_rslt_u.gqr_rquota.rq_active = + QIO_ENABLED(handles[0]) ? TRUE : FALSE; + servutil2netdqblk(&result.getquota_rslt_u.gqr_rquota, &dquot->dq_dqb); + } + dispose_handle_list(handles); + return (&result); +} + +/* + * Map RPC-entrypoints to local function names. + */ +getquota_rslt *rquotaproc_getquota_1_svc(getquota_args * argp, struct svc_req * rqstp) +{ + return (getquotainfo(0, (caddr_t *) argp, rqstp)); +} + +getquota_rslt *rquotaproc_getactivequota_1_svc(getquota_args * argp, struct svc_req * rqstp) +{ + return (getquotainfo(ACTIVE, (caddr_t *) argp, rqstp)); +} + +getquota_rslt *rquotaproc_getquota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp) +{ + return (getquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp)); +} + +getquota_rslt *rquotaproc_getactivequota_2_svc(ext_getquota_args * argp, struct svc_req * rqstp) +{ + return (getquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp)); +} + +setquota_rslt *rquotaproc_setquota_1_svc(setquota_args * argp, struct svc_req * rqstp) +{ + return (setquotainfo(0, (caddr_t *) argp, rqstp)); +} + +setquota_rslt *rquotaproc_setactivequota_1_svc(setquota_args * argp, struct svc_req * rqstp) +{ + return (setquotainfo(ACTIVE, (caddr_t *) argp, rqstp)); +} + +setquota_rslt *rquotaproc_setquota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp) +{ + return (setquotainfo(TYPE_EXTENDED, (caddr_t *) argp, rqstp)); +} + +setquota_rslt *rquotaproc_setactivequota_2_svc(ext_setquota_args * argp, struct svc_req * rqstp) +{ + return (setquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *) argp, rqstp)); +} diff --git a/rquota_svc.c b/rquota_svc.c new file mode 100644 index 0000000..368d212 --- /dev/null +++ b/rquota_svc.c @@ -0,0 +1,233 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <rpc/pmap_clnt.h> /* for pmap_unset */ +#include <stdio.h> +#include <stdlib.h> /* getenv, exit */ +#include <string.h> /* strcmp */ +#include <memory.h> +#include <unistd.h> + +#ifdef __STDC__ +#define SIG_PF void(*)(int) +#endif + +#include "pot.h" +#include "rquota.h" +#include "quotasys.h" + +/* + * Global authentication credentials. + */ +struct authunix_parms *unix_cred; + +char **argvargs; +int argcargs; +static void rquotaprog_1(struct svc_req *rqstp, register SVCXPRT * transp) +{ + union { + getquota_args rquotaproc_getquota_1_arg; + setquota_args rquotaproc_setquota_1_arg; + getquota_args rquotaproc_getactivequota_1_arg; + setquota_args rquotaproc_setactivequota_1_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + char *(*local) (char *, struct svc_req *); + + /* + * Don't bother authentication for NULLPROC. + */ + if (rqstp->rq_proc == NULLPROC) { + (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL); + return; + } + + /* + * First get authentication. + */ + switch (rqstp->rq_cred.oa_flavor) { + case AUTH_UNIX: + unix_cred = (struct authunix_parms *)rqstp->rq_clntcred; + break; + case AUTH_NULL: + default: + svcerr_weakauth(transp); + return; + } + + switch (rqstp->rq_proc) { + case RQUOTAPROC_GETQUOTA: + xdr_argument = (xdrproc_t) xdr_getquota_args; + xdr_result = (xdrproc_t) xdr_getquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_getquota_1_svc; + break; + + case RQUOTAPROC_SETQUOTA: + xdr_argument = (xdrproc_t) xdr_setquota_args; + xdr_result = (xdrproc_t) xdr_setquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_setquota_1_svc; + break; + + case RQUOTAPROC_GETACTIVEQUOTA: + xdr_argument = (xdrproc_t) xdr_getquota_args; + xdr_result = (xdrproc_t) xdr_getquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_getactivequota_1_svc; + break; + + case RQUOTAPROC_SETACTIVEQUOTA: + xdr_argument = (xdrproc_t) xdr_setquota_args; + xdr_result = (xdrproc_t) xdr_setquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_setactivequota_1_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + (void)memset((char *)&argument, 0, sizeof(argument)); + if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) { + svcerr_decode(transp); + return; + } + result = (*local) ((char *)&argument, rqstp); + if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) { + fprintf(stderr, _("unable to free arguments")); + exit(1); + } + return; +} + +static void rquotaprog_2(struct svc_req *rqstp, register SVCXPRT * transp) +{ + union { + ext_getquota_args rquotaproc_getquota_2_arg; + ext_setquota_args rquotaproc_setquota_2_arg; + ext_getquota_args rquotaproc_getactivequota_2_arg; + ext_setquota_args rquotaproc_setactivequota_2_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + char *(*local) (char *, struct svc_req *); + + /* + * Don't bother authentication for NULLPROC. + */ + if (rqstp->rq_proc == NULLPROC) { + (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL); + return; + } + + /* + * First get authentication. + */ + switch (rqstp->rq_cred.oa_flavor) { + case AUTH_UNIX: + unix_cred = (struct authunix_parms *)rqstp->rq_clntcred; + break; + case AUTH_NULL: + default: + svcerr_weakauth(transp); + return; + } + + switch (rqstp->rq_proc) { + case RQUOTAPROC_GETQUOTA: + xdr_argument = (xdrproc_t) xdr_ext_getquota_args; + xdr_result = (xdrproc_t) xdr_getquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_getquota_2_svc; + break; + + case RQUOTAPROC_SETQUOTA: + xdr_argument = (xdrproc_t) xdr_ext_setquota_args; + xdr_result = (xdrproc_t) xdr_setquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_setquota_2_svc; + break; + + case RQUOTAPROC_GETACTIVEQUOTA: + xdr_argument = (xdrproc_t) xdr_ext_getquota_args; + xdr_result = (xdrproc_t) xdr_getquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_getactivequota_2_svc; + break; + + case RQUOTAPROC_SETACTIVEQUOTA: + xdr_argument = (xdrproc_t) xdr_ext_setquota_args; + xdr_result = (xdrproc_t) xdr_setquota_rslt; + local = (char *(*)(char *, struct svc_req *))rquotaproc_setactivequota_2_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + (void)memset((char *)&argument, 0, sizeof(argument)); + if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) { + svcerr_decode(transp); + return; + } + result = (*local) ((char *)&argument, rqstp); + if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) { + fprintf(stderr, _("unable to free arguments")); + exit(1); + } + return; +} + +int main(int argc, char **argv) +{ + register SVCXPRT *transp; + + argcargs = argc; + argvargs = argv; + + gettexton(); + warn_new_kernel(-1); + + (void)pmap_unset(RQUOTAPROG, RQUOTAVERS); + (void)pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS); + + transp = svcudp_create(RPC_ANYSOCK); + if (transp == NULL) { + fprintf(stderr, _("cannot create udp service.")); + exit(1); + } + if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_UDP)) { + fprintf(stderr, _("unable to register (RQUOTAPROG, RQUOTAVERS, udp).")); + exit(1); + } + if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_UDP)) { + fprintf(stderr, _("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, udp).")); + exit(1); + } + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + fprintf(stderr, _("cannot create tcp service.")); + exit(1); + } + if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_TCP)) { + fprintf(stderr, _("unable to register (RQUOTAPROG, RQUOTAVERS, tcp).")); + exit(1); + } + if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_TCP)) { + fprintf(stderr, _("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, tcp).")); + exit(1); + } + + daemon(1, 1); + svc_run(); + fprintf(stderr, _("svc_run returned")); + exit(1); + /* NOTREACHED */ +} diff --git a/rquotad.8 b/rquotad.8 new file mode 100644 index 0000000..e6bbb1e --- /dev/null +++ b/rquotad.8 @@ -0,0 +1,45 @@ +.TH RQUOTAD 8 +.SH NAME +rquotad, rpc.rquotad \- remote quota server +.SH SYNOPSIS +.B rpc.rquotad +.SH DESCRIPTION +.LP +.IX "rquotad daemon" "" "\fLrquotad\fP \(em remote quota server" +.IX daemons "rquotad daemon" "" "\fLrquotad\fP \(em remote quota server" +.IX "user quotas" "rquotad daemon" "" "\fLrquotad\fP \(em remote quota server" +.IX "disk quotas" "rquotad daemon" "" "\fLrquotad\fP \(em remote quota server" +.IX "quotas" "rquotad daemon" "" "\fLrquotad\fP \(em remote quota server" +.IX "filesystem" "rquotad daemon" "" "\fLrquotad\fP \(em remote quota server" +.IX "remote procedure call services" "rquotad" "" "\fLrquotad\fP \(em remote quota server" +.B rquotad +is an +.BR rpc (3N) +server which returns quotas for a user of a local filesystem +which is mounted by a remote machine over the +.SM NFS\s0. +The results are used by +.BR quota (1) +to display user quotas for remote filesystems. +The +.B rquotad +daemon is normally started at boot time from the +system startup scripts. +.SH FILES +.PD 0 +.TP 20 +.B aquota.user or aquota.group +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP +.B quota.user or quota.group +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/mtab +default filesystems +.PD +.SH "SEE ALSO" +.BR quota (1), +.BR rpc (3N), +.BR nfs (5), +.BR services (5), +.BR inetd (8) diff --git a/set_limits_example.c b/set_limits_example.c new file mode 100644 index 0000000..52af20c --- /dev/null +++ b/set_limits_example.c @@ -0,0 +1,60 @@ +#include <sys/types.h> +#include <sys/quota.h> +#include <errno.h> +#include <stdio.h> + +#include "pot.h" + +int copy_user_quota_limits(const char *block_device, uid_t from, uid_t to) +{ + struct dqblk dq; + + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), block_device, from, (caddr_t) & dq) == 0) { + if (quotactl(QCMD(Q_SETQLIM, USRQUOTA), block_device, to, (caddr_t) & dq) == 0) { + return (0); + } + else { + fprintf(stderr, + _ + ("copy_user_quota_limits: Failed to set userquota for uid %ld : %s\n"), + to, strerror(errno)); + return (1); + } + } + else { + fprintf(stderr, + _("copy_user_quota_limits: Failed to get userquota for uid %ld : %s\n"), + from, strerror(errno)); + return (1); + } +} + +int copy_group_quota_limits(const char *block_device, gid_t from, gid_t to) +{ + struct dqblk dq; + + if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), block_device, from, (caddr_t) & dq) == 0) { + if (quotactl(QCMD(Q_SETQLIM, GRPQUOTA), block_device, to, (caddr_t) & dq) == 0) { + return (0); + } + else { + fprintf(stderr, + _ + ("copy_group_quota_limits: Failed to set groupquota for uid %ld : %s\n"), + to, strerror(errno)); + return (1); + } + } + else { + fprintf(stderr, + _("copy_group_quota_limits: Failed to get groupquota for uid %ld : %s\n"), + from, strerror(errno)); + return (1); + } +} + +main(int argc, char **argv) +{ + gettexton(); + copy_user_quota_limits("/dev/hda8", 152, 151); +} diff --git a/setquota.8 b/setquota.8 new file mode 100644 index 0000000..4e4323d --- /dev/null +++ b/setquota.8 @@ -0,0 +1,88 @@ +.TH SETQUOTA 8 +.SH NAME +setquota \- set disk quotas +.SH SYNOPSIS +.B /usr/sbin/setquota +[ +.B \-nr +] +[ +.B \-u +| +.B \-g +] +.I name +.I filesystem +.I block-softlimit +.I block-hardlimit +.I inode-softlimit +.I inode-hardlimit +.LP +.B /usr/sbin/setquota +[ +.B \-nr +] +[ +.B \-u +| +.B \-g +] +[ +.B \-p protoname +] +.I name +.I filesystem +.SH DESCRIPTION +.IX "setquota command" "" "\fLsetquota\fP \(em set disk quotas" +.IX set "disk quotas \(em \fLsetquota\fP" +.IX "disk quotas" "setquota command" "" "\fLsetquota\fP \(em set disk quotas" +.IX "disk quotas" "setquota command" "" "\fLsetquota\fP \(em set disk quotas" +.IX "quotas" "setquota command" "" "\fLsetquota\fP \(em set disk quotas" +.IX "filesystem" "setquota command" "" "\fLsetquota\fP \(em set disk quotas" +.B setquota +is a command line quota editor. +The filesystem, user/group name and new quotas for this +filesystem can be specified on the command line. +.TP +.B -n +Consider +.I name +to be a numeric ID (don't lookup user/group names). +.TP +.B -r +Edit also remote quota use rpc.rquotad on remote server to set quota. +.TP +.B -u +Set user quotas for named user. This is the default. +.TP +.B -g +Set group quotas for named group. +.TP +.B -p \f2protoname\f1 +Use quota settings of user or group +.I protoname +to set the quota for the named user or group. +.PP +To disable a quota, set the coresponding parameter to 0. To change quotas +for several filesystems, invoke once for each filesystem. +.PP +Only the super-user may edit quotas. +.SH FILES +.PD 0 +.TP 20 +.B aquota.user or aquota.group +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP +.B quota.user or quota.group +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/mtab +mounted filesystems +.PD +.SH SEE ALSO +.BR edquota (8), +.BR quota (1), +.BR quotactl (2), +.BR quotacheck (8), +.BR quotaon (8), +.BR repquota (8) diff --git a/setquota.c b/setquota.c new file mode 100644 index 0000000..63f80c4 --- /dev/null +++ b/setquota.c @@ -0,0 +1,232 @@ +/* + * + * Set disk quota from command line + * + */ +#include <rpc/rpc.h> +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> + +#if defined(RPC) +#include "rquota.h" +#include "rquota_client.h" +#endif +#include "pot.h" +#include "quotaops.h" +#include "common.h" +#include "quotasys.h" + +#define FL_USER 1 +#define FL_GROUP 2 +#define FL_RPC 4 +#define FL_ALL 8 +#define FL_PROTO 16 +#define FL_GRACE 32 + +int flags, fmt = -1; +char **mnt; +int mntcnt; +qid_t protoid, id; +struct util_dqblk toset; + +/* Print usage information */ +static void usage(void) +{ +#if defined(RPC_SETQUOTA) + fprintf(stderr, _("Usage:\n" + " setquota [-u|-g] [-r] [-F quotaformat] <user|group>\n" + "\t<block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> -a|<filesystem>...\n" + " setquota [-u|-g] [-r] [-F quotaformat] <-p protouser|protogroup> <user|group> -a|<filesystem>...\n" + " setquota [-u|-g] [-F quotaformat] -t <blockgrace> <inodegrace> -a|<filesystem>...\n")); +#else + fprintf(stderr, _("Usage:\n" + " setquota [-u|-g] [-F quotaformat] <user|group>\n" + "\t<block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> -a|<filesystem>...\n" + " setquota [-u|-g] [-F quotaformat] <-p protouser|protogroup> <user|group> -a|<filesystem>...\n" + " setquota [-u|-g] [-F quotaformat] -t <blockgrace> <inodegrace> -a|<filesystem>...\n")); +#endif + fprintf(stderr, _("Bugs to: %s\n"), MY_EMAIL); + exit(1); +} + +/* Convert string to number - print error message in case of failure */ +static long parse_num(char *str, char *msg) +{ + char *errch; + long ret = strtol(str, &errch, 0); + + if (*errch) { + fprintf(stderr, _("Bad %s: %s\n"), msg, str); + usage(); + } + return ret; +} + +/* Convert our flags to quota type */ +static inline int flag2type(int flags) +{ + if (flags & FL_USER) + return USRQUOTA; + if (flags & FL_GROUP) + return GRPQUOTA; + return -1; +} + +/* Parse options of setquota */ +static void parse_options(int argcnt, char **argstr) +{ + int ret, otherargs; + char *protoname = NULL; + +#ifdef RPC_SETQUOTA + char *opts = "igp:urVF:ta"; +#else + char *opts = "igp:uVF:ta"; +#endif + +#ifdef RPC_SETQUOTA + flags |= FL_RPC; +#endif + + while ((ret = getopt(argcnt, argstr, opts)) != EOF) { + switch (ret) { + case '?': + case 'h': + usage(); + case 'g': + flags |= FL_GROUP; + break; + case 'u': + flags |= FL_USER; + break; + case 'p': + flags |= FL_PROTO; + protoname = optarg; + break; + case 'r': + flags &= ~FL_RPC; + break; + case 'a': + flags |= FL_ALL; + break; + case 't': + flags |= FL_GRACE; + break; + case 'F': + if ((fmt = name2fmt(optarg)) == QF_ERROR) + exit(1); + break; + case 'V': + version(); + break; + } + } + if (flags & FL_USER && flags & FL_GROUP) { + fputs(_("Group and user quotas can't be used together.\n"), stderr); + usage(); + } + if (flags & FL_PROTO && flags & FL_GRACE) { + fputs(_("Prototype user has no sense when editting grace times.\n"), stderr); + usage(); + } + if (flags & FL_GRACE) + otherargs = 2; + else { + otherargs = 1; + if (!(flags & FL_PROTO)) + otherargs += 4; + } + if (optind + otherargs > argcnt) { + fputs(_("Bad number of arguments.\n"), stderr); + usage(); + } + if (!(flags & (FL_USER | FL_GROUP))) + flags |= FL_USER; + if (!(flags & FL_GRACE)) { + id = name2id(argstr[optind++], flag2type(flags)); + if (!(flags & FL_PROTO)) { + toset.dqb_bsoftlimit = parse_num(argstr[optind++], _("block softlimit")); + toset.dqb_bhardlimit = parse_num(argstr[optind++], _("block hardlimit")); + toset.dqb_isoftlimit = parse_num(argstr[optind++], _("inode softlimit")); + toset.dqb_ihardlimit = parse_num(argstr[optind++], _("inode hardlimit")); + } + else + protoid = name2id(protoname, flag2type(flags)); + } + else { + toset.dqb_btime = parse_num(argstr[optind++], _("block grace time")); + toset.dqb_itime = parse_num(argstr[optind++], _("inode grace time")); + } + if (!(flags & FL_ALL)) { + mntcnt = argcnt - optind; + mnt = argstr + optind; + if (!mntcnt) { + fputs(_("Mountpoint not specified.\n"), stderr); + usage(); + } + } +} + +/* Set user limits */ +static void setlimits(struct quota_handle **handles) +{ + struct dquot *q, *protoq, *protoprivs = NULL, *curprivs; + + curprivs = getprivs(id, handles); + if (flags & FL_PROTO) { + protoprivs = getprivs(protoid, handles); + for (q = curprivs, protoq = protoprivs; q; q = q->dq_next, protoq = protoq->dq_next) { + q->dq_dqb.dqb_bsoftlimit = protoq->dq_dqb.dqb_bsoftlimit; + q->dq_dqb.dqb_bhardlimit = protoq->dq_dqb.dqb_bhardlimit; + q->dq_dqb.dqb_isoftlimit = protoq->dq_dqb.dqb_isoftlimit; + q->dq_dqb.dqb_ihardlimit = protoq->dq_dqb.dqb_ihardlimit; + } + freeprivs(protoprivs); + } + else { + for (q = curprivs; q; q = q->dq_next) { + q->dq_dqb.dqb_bsoftlimit = toset.dqb_bsoftlimit; + q->dq_dqb.dqb_bhardlimit = toset.dqb_bhardlimit; + q->dq_dqb.dqb_isoftlimit = toset.dqb_isoftlimit; + q->dq_dqb.dqb_ihardlimit = toset.dqb_ihardlimit; + } + } + putprivs(curprivs); + freeprivs(curprivs); +} + +/* Set grace times */ +static void setgraces(struct quota_handle **handles) +{ + int i; + + for (i = 0; handles[i]; i++) { + handles[i]->qh_info.dqi_bgrace = toset.dqb_btime; + handles[i]->qh_info.dqi_igrace = toset.dqb_itime; + mark_quotafile_info_dirty(handles[i]); + } +} + +int main(int argc, char **argv) +{ + struct quota_handle **handles; + + gettexton(); + parse_options(argc, argv); + warn_new_kernel(fmt); + + if (flags & FL_ALL) + handles = create_handle_list(0, NULL, flag2type(flags), fmt, !(flags & FL_RPC)); + else + handles = create_handle_list(mntcnt, mnt, flag2type(flags), fmt, !(flags & FL_RPC)); + + if (flags & FL_GRACE) + setgraces(handles); + else + setlimits(handles); + dispose_handle_list(handles); + return 0; +} diff --git a/setup_quota_group b/setup_quota_group new file mode 100755 index 0000000..7343fea --- /dev/null +++ b/setup_quota_group @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ $# -lt 2 ]; then + echo "Usage: $0 proto_type_user group" + exit 1 +fi + +gid=`cat /etc/group | grep "^$2" | cut -d: -f3` +for user in `cat /etc/passwd | grep ".*:.*:$gid:" | cut -d: -f1` +do + edquota -p $1 $user +done diff --git a/warnquota.8 b/warnquota.8 new file mode 100644 index 0000000..9acd434 --- /dev/null +++ b/warnquota.8 @@ -0,0 +1,37 @@ +.TH WARNQUOTA 8 +.SH NAME +warnquota \- send mail to users over quota +.SH SYNOPSIS +.B warnquota +.SH DESCRIPTION +.B warnquota +checks the disk quota for each filesystem and mails a warning +message to those users who have reached their limit. +It is typically run via +.BR cron (8). +.SH FILES +.PD 0 +.TP 20 +.B aquota.user +quota file at the filesystem root (version 2 quota, non-XFS filesystems) +.TP +.B quota.user +quota file at the filesystem root (version 1 quota, non-XFS filesystems) +.TP +.B /etc/warnquota.conf +configuration file +.TP +.B /etc/mtab +default filesystems +.TP +.B /etc/passwd +default set of users +.PD +.SH "SEE ALSO" +.BR quota (1), +.BR cron (8), +.BR edquota (8). +.SH AUTHORS +.BR warnquota (8) +was written by Marco van Wieringen <mvw@planets.elm.net>. +This reference page written by Heiko Schlittermann <heiko@lotte.sax.de>. diff --git a/warnquota.c b/warnquota.c new file mode 100644 index 0000000..a4516d5 --- /dev/null +++ b/warnquota.c @@ -0,0 +1,374 @@ +/* + * QUOTA An implementation of the diskquota system for the LINUX operating + * system. QUOTA is implemented using the BSD systemcall interface + * as the means of communication with the user level. Should work for + * all filesystems because of integration into the VFS layer of the + * operating system. This is based on the Melbourne quota system wich + * uses both user and group quota files. + * + * Program to mail to users that they are over there quota. + * + * Author: Marco van Wieringen <mvw@planets.elm.net> + * + * Version: $Id: warnquota.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> + +#include "mntopt.h" +#include "pot.h" +#include "bylabel.h" +#include "common.h" +#include "quotasys.h" +#include "quotaio.h" + +/* these are just defaults, overridden in the WARNQUOTA_CONF file */ +#define MAIL_CMD "/usr/lib/sendmail -t" +#define FROM "support@localhost" +#define SUBJECT "Disk Quota usage on system" +#define CC_TO "root" +#define SUPPORT "support@localhost" +#define PHONE "(xxx) xxx-xxxx or (yyy) yyy-yyyy" + +#define DEF_MESSAGE _("Hi,\n\nWe noticed that you are in violation with the quotasystem\n" \ + "used on this system. We have found the following violations:\n\n") +#define DEF_SIGNATURE _("\nWe hope that you will cleanup before your grace period expires.\n" \ + "\nBasically, this means that the system thinks you are using more disk space\n" \ + "on the above partition(s) than you are allowed. If you do not delete files\n" \ + "and get below your quota before the grace period expires, the system will\n" \ + "prevent you from creating new files.\n\n" \ + "For additional assistance, please contact us at %s\nor via " \ + "phone at %s.\n") + +#define QUOTATAB "/etc/quotatab" +#define CNF_BUFFER 2048 +#define WARNQUOTA_CONF "/etc/warnquota.conf" + +struct usage { + char *devicename; + struct util_dqblk dq_dqb; + struct usage *next; +}; + +struct configparams { + char mail_cmd[CNF_BUFFER]; + char from[CNF_BUFFER]; + char subject[CNF_BUFFER]; + char cc_to[CNF_BUFFER]; + char support[CNF_BUFFER]; + char phone[CNF_BUFFER]; +}; + +struct offenderlist { + int offender_id; + char *offender_name; + struct usage *usage; + struct offenderlist *next; +}; + +typedef struct quotatable { + char *devname; + char *devdesc; +} quotatable_t; + +int qtab_i = 0; +quotatable_t *quotatable = (quotatable_t *) NULL; + +/* + * Global pointers to list. + */ +static struct offenderlist *offenders = (struct offenderlist *)0; + +struct offenderlist *add_offender(int id) +{ + struct passwd *pwd; + struct offenderlist *offender; + + if ((pwd = getpwuid(id)) == (struct passwd *)0) + return ((struct offenderlist *)0); + + offender = (struct offenderlist *)smalloc(sizeof(struct offenderlist)); + + offender->offender_id = id; + offender->offender_name = (char *)smalloc(strlen(pwd->pw_name) + 1); + offender->usage = (struct usage *)NULL; + strcpy(offender->offender_name, pwd->pw_name); + offender->next = offenders; + offenders = offender; + return offender; +} + +void add_offence(struct dquot *dquot) +{ + struct offenderlist *lptr; + struct usage *usage; + + for (lptr = offenders; lptr; lptr = lptr->next) + if (lptr->offender_id == dquot->dq_id) + break; + + if (!lptr) + if (!(lptr = add_offender(dquot->dq_id))) + return; + + usage = (struct usage *)smalloc(sizeof(struct usage)); + memcpy(&usage->dq_dqb, &dquot->dq_dqb, sizeof(struct util_dqblk)); + + usage->devicename = sstrdup(dquot->dq_h->qh_quotadev); + /* + * Stuff it in front + */ + usage->next = lptr->usage; + lptr->usage = usage; +} + +int check_offence(struct dquot *dquot) +{ + if ( + (dquot->dq_dqb.dqb_bsoftlimit + && toqb(dquot->dq_dqb.dqb_curspace) >= dquot->dq_dqb.dqb_bsoftlimit) + || (dquot->dq_dqb.dqb_isoftlimit + && dquot->dq_dqb.dqb_curinodes >= dquot->dq_dqb.dqb_isoftlimit)) add_offence(dquot); + return 0; +} + +void mail_user(struct offenderlist *offender, struct configparams *config) +{ + struct usage *lptr; + FILE *fp; + int cnt; + char timebuf[MAXTIMELEN]; + struct util_dqblk *dqb; + + if ((fp = popen(config->mail_cmd, "w")) != (FILE *) 0) { + fprintf(fp, "From: %s\n", config->from); + fprintf(fp, "Reply-To: %s\n", config->support); + fprintf(fp, "Subject: %s\n", config->subject); + fprintf(fp, "To: %s\n", offender->offender_name); + fprintf(fp, "Cc: %s\n", config->cc_to); + fprintf(fp, "\n"); + fprintf(fp, DEF_MESSAGE); + for (lptr = offender->usage; lptr != (struct usage *)0; lptr = lptr->next) { + dqb = &lptr->dq_dqb; + for (cnt = 0; cnt < qtab_i; cnt++) { + if (!strncmp + (quotatable[cnt].devname, lptr->devicename, + strlen(quotatable[cnt].devname))) + fprintf(fp, "\n%s\n", quotatable[cnt].devdesc); + } + fprintf(fp, + _ + ("\n Block limits File limits\n")); + fprintf(fp, + _ + ("Filesystem used soft hard grace used soft hard grace\n")); + if (strlen(lptr->devicename) > 15) + fprintf(fp, "%s\n%15s", lptr->devicename, ""); + else + fprintf(fp, "%-15s", lptr->devicename); + if (dqb->dqb_bsoftlimit && dqb->dqb_bsoftlimit <= toqb(dqb->dqb_curspace)) + difftime2str(dqb->dqb_btime, timebuf); + else + timebuf[0] = '\0'; + fprintf(fp, "%c%c%8Lu%8Lu%8Lu%7s", + dqb->dqb_bsoftlimit + && toqb(dqb->dqb_curspace) >= dqb->dqb_bsoftlimit ? '+' : '-', + dqb->dqb_isoftlimit + && dqb->dqb_curinodes >= dqb->dqb_isoftlimit ? '+' : '-', + (long long)toqb(dqb->dqb_curspace), (long long)dqb->dqb_bsoftlimit, + (long long)dqb->dqb_bhardlimit, timebuf); + if (dqb->dqb_isoftlimit && dqb->dqb_isoftlimit <= dqb->dqb_curinodes) + difftime2str(dqb->dqb_itime, timebuf); + else + timebuf[0] = '\0'; + fprintf(fp, " %6Lu%6Lu%6Lu%7s\n\n", + (long long)dqb->dqb_curinodes, + (long long)dqb->dqb_isoftlimit, + (long long)dqb->dqb_ihardlimit, timebuf); + } + fprintf(fp, DEF_SIGNATURE, config->support, config->phone); + fclose(fp); + } +} + +void mail_to_offenders(struct configparams *config) +{ + struct offenderlist *lptr; + + /* + * Dump offenderlist. + */ + for (lptr = offenders; lptr != (struct offenderlist *)0; lptr = lptr->next) + mail_user(lptr, config); +} + +void get_quotatable(void) +{ + FILE *fp; + char buffer[2048], *filename, *colpos; + + filename = (char *)smalloc(strlen(QUOTATAB) + 1); + sprintf(filename, "%s", QUOTATAB); + + if ((fp = fopen(filename, "r")) == (FILE *) NULL) + return; + + for (qtab_i = 0; + quotatable = + (quotatable_t *) realloc(quotatable, sizeof(quotatable_t) * (qtab_i + 1)), + fgets(buffer, sizeof(buffer), fp) != (char *)NULL; qtab_i++) { + if ((colpos = strchr(buffer, ':'))) { + *colpos = 0; + quotatable[qtab_i].devname = (char *)smalloc(strlen(buffer) + 1); + strcpy(quotatable[qtab_i].devname, buffer); + quotatable[qtab_i].devdesc = (char *)smalloc(strlen(++colpos) + 1); + strcpy(quotatable[qtab_i].devdesc, colpos); + if ((colpos = strchr(quotatable[qtab_i].devdesc, '\n'))) + *colpos = 0; + while ((colpos = strchr(quotatable[qtab_i].devdesc, '|'))) + *colpos = '\n'; + } + + if (buffer[0] == '#' || /* comment */ + !quotatable[qtab_i].devname || !quotatable[qtab_i].devdesc || + strlen(quotatable[qtab_i].devname) < 2 || + strlen(quotatable[qtab_i].devdesc) < 2 /* stupid root */ )qtab_i--; + } + fclose(fp); + free(filename); +} + +/* + * Wipe spaces, tabs, quotes and newlines from beginning and end of string + */ +void stripstring(char **buff) +{ + char *p; + + /* first put a \0 at the tight place to end the string */ + p = *buff + strlen(*buff) - 1; + while (*p == ' ' || *p == '\n' || *p == '\t' || *p == '"' || *p == '\'') + p--; + p[1] = 0; + + /* then determine the position to start */ + p = *buff; + while (*p == ' ' || *p == '\n' || *p == '\t' || *p == '"' || *p == '\'') + p++; + + *buff = p; +} + +/* + * Reads config parameters from configfile + * uses default values if error occurs + */ +void readconfigfile(const char *filename, struct configparams *config) +{ + FILE *fp; + char *buff; + char *var; + char *value; + char *pos; + int line; + + /* set default values */ + strncpy(config->mail_cmd, MAIL_CMD, CNF_BUFFER); + strncpy(config->from, FROM, CNF_BUFFER); + strncpy(config->subject, SUBJECT, CNF_BUFFER); + strncpy(config->cc_to, CC_TO, CNF_BUFFER); + strncpy(config->support, SUPPORT, CNF_BUFFER); + strncpy(config->phone, PHONE, CNF_BUFFER); + + fp = fopen(filename, "r"); + if (fp == (FILE *) NULL) { /* if config file doesn't exist or is not readable */ + return; + } + + buff = (char *)smalloc(CNF_BUFFER); + line = 0; + while (fgets(buff, CNF_BUFFER, fp)) { /* start reading lines */ + line++; + + /* check for comments or empty lines */ + if (buff[0] == '#' || buff[0] == ';' || buff[0] == '\n') + continue; + + /* check for a '=' char */ + if ((pos = strchr(buff, '='))) { + pos[0] = '\0'; /* split buff in two parts: var and value */ + var = buff; + value = pos + 1; + + stripstring(&var); /* clean up var and value */ + stripstring(&value); + + /* check if var matches anything */ + if (!strncmp(var, "MAIL_CMD", CNF_BUFFER)) { + strncpy(config->mail_cmd, value, CNF_BUFFER); + } + else if (!strncmp(var, "FROM", CNF_BUFFER)) { + strncpy(config->from, value, CNF_BUFFER); + } + else if (!strncmp(var, "SUBJECT", CNF_BUFFER)) { + strncpy(config->subject, value, CNF_BUFFER); + } + else if (!strncmp(var, "CC_TO", CNF_BUFFER)) { + strncpy(config->cc_to, value, CNF_BUFFER); + } + else if (!strncmp(var, "SUPPORT", CNF_BUFFER)) { + strncpy(config->support, value, CNF_BUFFER); + } + else if (!strncmp(var, "PHONE", CNF_BUFFER)) { + strncpy(config->phone, value, CNF_BUFFER); + } + else { /* not matched at all */ + fprintf(stderr, "Error in config file (line %d), ignoring\n", line); + } + } + else { /* no '=' char in this line */ + fprintf(stderr, "Possible error in config file (line %d), ignoring\n", + line); + } + } + fclose(fp); + + free(buff); + + return; +} + +void warn_quota(void) +{ + struct quota_handle **handles; + struct configparams config; + int i; + + readconfigfile(WARNQUOTA_CONF, &config); + + handles = create_handle_list(0, NULL, USRQUOTA, -1, 1); + for (i = 0; handles[i]; i++) + handles[i]->qh_ops->scan_dquots(handles[i], check_offence); + get_quotatable(); + mail_to_offenders(&config); +} + +int main(int argc, char **argv) +{ + gettexton(); + warn_new_kernel(-1); + warn_quota(); + return 0; +} diff --git a/warnquota.conf b/warnquota.conf new file mode 100644 index 0000000..c957c0e --- /dev/null +++ b/warnquota.conf @@ -0,0 +1,16 @@ +# this is an example warnquota.conf +# +; ; and # type comments are allowed +# and even blank lines + +# values can be quoted: +MAIL_CMD = "/usr/my/sendmail/instead/sendmail -t" +FROM = "bas@localhost" +# but they don't have to be: +SUBJECT = Hey, user, clean up your account! +CC_TO = "sysadm@localhost" +SUPPORT = "support@myhost.com" +PHONE = "(123) 456-1111 or (222) 333-4444" +# +# end of example warnquota.conf file +# diff --git a/xqmstats.c b/xqmstats.c new file mode 100644 index 0000000..ed66e46 --- /dev/null +++ b/xqmstats.c @@ -0,0 +1,53 @@ +/* + * Display XFS quota manager statistics from /proc. + */ + +#ident "Copyright (c) 2001 Silicon Graphics, Inc." + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include "pot.h" + +#define XQMFILE "/proc/fs/xfs/xqm" +#define STATFILE "/proc/fs/xfs/stat" + +int main(int argc, char **argv) +{ + FILE *stats, *xqm; + char buffer[256]; + unsigned values[8]; + + gettexton(); + + memset(values, 0, sizeof(unsigned) * 8); + + if ((stats = fopen(STATFILE, "r")) == NULL || (xqm = fopen(XQMFILE, "r")) == NULL) { + fprintf(stderr, "The running kernel does not support XFS\n"); + return 1; + } + while (!feof(stats)) { + fgets(buffer, 256, stats); + if (sscanf(buffer, "qm %u %u %u %u %u %u %u %u\n", + &values[0], &values[1], &values[2], &values[3], + &values[4], &values[5], &values[6], &values[7]) == 8) + break; + } + if (!feof(stats)) { + printf(_("XFS Quota Manager dquot statistics\n")); + printf(_(" reclaims: %u\n"), values[0]); + printf(_(" missed reclaims: %u\n"), values[1]); + printf(_(" dquot dups: %u\n"), values[2]); + printf(_(" cache misses: %u\n"), values[3]); + printf(_(" cache hits: %u\n"), values[4]); + printf(_(" dquot wants: %u\n"), values[5]); + printf(_(" shake reclaims: %u\n"), values[6]); + printf(_(" inact reclaims: %u\n"), values[7]); + } + if (fscanf(xqm, "%u %u %u %u\n", &values[0], &values[1], &values[2], &values[3]) == 4) + printf(_("Maximum %u dquots (currently %u incore, %u on freelist)\n"), values[0], + values[1], values[3]); + fclose(stats); + fclose(xqm); + return 0; +} |