From 869fe242340fefe0540fdcf51698ba4c3c8c07bb Mon Sep 17 00:00:00 2001 From: jkar8572 Date: Fri, 23 Mar 2001 12:03:26 +0000 Subject: Initial revision --- Changelog | 497 +++++++ Makefile.in | 140 ++ README.gettext | 21 + bylabel.c | 256 ++++ bylabel.h | 4 + common.c | 74 + common.h | 30 + configure | 1721 ++++++++++++++++++++++ configure.in | 73 + convertquota.8 | 51 + convertquota.c | 136 ++ doc/edquota(8).html | 96 ++ doc/fstab(5).html | 127 ++ doc/quota(1).html | 92 ++ doc/quota.html | 288 ++++ doc/quota4th.fig | 62 + doc/quotacheck(8).html | 94 ++ doc/quotactl(2).html | 197 +++ doc/quotaon(8).html | 80 ++ doc/quotas-1.eps | 3716 ++++++++++++++++++++++++++++++++++++++++++++++++ doc/quotas.ms | 318 +++++ doc/quotas.preformated | 330 +++++ doc/repquota(8).html | 68 + doc/rquotad(8).html | 38 + dqblk_rpc.h | 20 + dqblk_v1.h | 18 + dqblk_v2.h | 36 + dqblk_xfs.h | 25 + edquota.8 | 95 ++ edquota.c | 200 +++ install-sh | 251 ++++ mntopt.h | 22 + po/pl.po | 857 +++++++++++ pot.c | 15 + pot.h | 24 + quot.8 | 45 + quot.c | 352 +++++ quot.h | 113 ++ quota.1 | 100 ++ quota.c | 226 +++ quota.h | 83 ++ quotacheck.8 | 94 ++ quotacheck.c | 849 +++++++++++ quotacheck.h | 44 + quotacheck_v1.c | 83 ++ quotacheck_v2.c | 344 +++++ quotactl.2 | 231 +++ quotaio.c | 238 ++++ quotaio.h | 141 ++ quotaio_rpc.c | 55 + quotaio_v1.c | 302 ++++ quotaio_v1.h | 39 + quotaio_v2.c | 734 ++++++++++ quotaio_v2.h | 88 ++ quotaio_xfs.c | 277 ++++ quotaio_xfs.h | 159 +++ quotaon.8 | 168 +++ quotaon.c | 277 ++++ quotaon.h | 22 + quotaon_xfs.c | 206 +++ quotaops.c | 476 +++++++ quotaops.h | 16 + quotastats.c | 59 + quotasys.c | 442 ++++++ quotasys.h | 75 + repquota.8 | 71 + repquota.c | 160 +++ rquota.3 | 34 + rquota.x | 139 ++ rquota_client.c | 309 ++++ rquota_client.h | 18 + rquota_server.c | 342 +++++ rquota_svc.c | 233 +++ rquotad.8 | 45 + set_limits_example.c | 60 + setquota.8 | 88 ++ setquota.c | 232 +++ setup_quota_group | 12 + warnquota.8 | 37 + warnquota.c | 374 +++++ warnquota.conf | 16 + xqmstats.c | 53 + 82 files changed, 18633 insertions(+) create mode 100644 Changelog create mode 100644 Makefile.in create mode 100644 README.gettext create mode 100644 bylabel.c create mode 100644 bylabel.h create mode 100644 common.c create mode 100644 common.h create mode 100755 configure create mode 100644 configure.in create mode 100644 convertquota.8 create mode 100644 convertquota.c create mode 100644 doc/edquota(8).html create mode 100644 doc/fstab(5).html create mode 100644 doc/quota(1).html create mode 100644 doc/quota.html create mode 100644 doc/quota4th.fig create mode 100644 doc/quotacheck(8).html create mode 100644 doc/quotactl(2).html create mode 100644 doc/quotaon(8).html create mode 100644 doc/quotas-1.eps create mode 100644 doc/quotas.ms create mode 100644 doc/quotas.preformated create mode 100644 doc/repquota(8).html create mode 100644 doc/rquotad(8).html create mode 100644 dqblk_rpc.h create mode 100644 dqblk_v1.h create mode 100644 dqblk_v2.h create mode 100644 dqblk_xfs.h create mode 100644 edquota.8 create mode 100644 edquota.c create mode 100755 install-sh create mode 100644 mntopt.h create mode 100644 po/pl.po create mode 100644 pot.c create mode 100644 pot.h create mode 100644 quot.8 create mode 100644 quot.c create mode 100644 quot.h create mode 100644 quota.1 create mode 100644 quota.c create mode 100644 quota.h create mode 100644 quotacheck.8 create mode 100644 quotacheck.c create mode 100644 quotacheck.h create mode 100644 quotacheck_v1.c create mode 100644 quotacheck_v2.c create mode 100644 quotactl.2 create mode 100644 quotaio.c create mode 100644 quotaio.h create mode 100644 quotaio_rpc.c create mode 100644 quotaio_v1.c create mode 100644 quotaio_v1.h create mode 100644 quotaio_v2.c create mode 100644 quotaio_v2.h create mode 100644 quotaio_xfs.c create mode 100644 quotaio_xfs.h create mode 100644 quotaon.8 create mode 100644 quotaon.c create mode 100644 quotaon.h create mode 100644 quotaon_xfs.c create mode 100644 quotaops.c create mode 100644 quotaops.h create mode 100644 quotastats.c create mode 100644 quotasys.c create mode 100644 quotasys.h create mode 100644 repquota.8 create mode 100644 repquota.c create mode 100644 rquota.3 create mode 100644 rquota.x create mode 100644 rquota_client.c create mode 100644 rquota_client.h create mode 100644 rquota_server.c create mode 100644 rquota_svc.c create mode 100644 rquotad.8 create mode 100644 set_limits_example.c create mode 100644 setquota.8 create mode 100644 setquota.c create mode 100755 setup_quota_group create mode 100644 warnquota.8 create mode 100644 warnquota.c create mode 100644 warnquota.conf create mode 100644 xqmstats.c 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 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 . + +* 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 + +* 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 + +* 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 ) + +* Removed searching of /dev dir from rquota_server. Only lookup mounted filesystems. + (Patch by Roman Kagan ) + +* 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 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 ) + +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 + +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 + + +* 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 , 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 . + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * 2000-01-20 James Antill + * - Added error message if /proc/partitions cannot be opened + * 2000-05-09 Erik Troan + * - Added cache for UUID and disk labels + * 2000-11-07 Nathan Scott + * - Added XFS support + */ + +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +#include + +#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 <&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 < +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 < +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 < +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 < +#include +#include +#include +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 +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 +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 < +#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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 +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 +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 <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 <&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 < 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 </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 < 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 <> $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 <> $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 \ + 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 +#include +#include +#include +#include +#include + +#include + +#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 @@ + + +edquota(8) manualpage + + + + + +

NAME

+edquota - edit user quotas +

SYNOPSIS

+edquota +[ +-p +proto-user +] [ +-ug +] +name +
+edquota +[ +-ug +] +-t +

DESCRIPTION

+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 +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, +edquota +reads the temporary file and modifies the binary quota files to reflect +the changes made. +

+The editor invoked is +vi (1) +unless the +EDITOR +environment variable specifies otherwise. +

+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 +quota.user +or +quota.group +. See +quotaon (8) +for details.) +

OPTIONS

+
    +
  • +-u +
    +Edit the userquota. This is the default. +
  • +-g +
    +Edit the groupquota. +
  • +-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. +
  • +-t +
    +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. +
+

FILES

+quota.user + : located at the filesystem root with user quotas +
+quota.group + : located at the filesystem root with group quotas +
+/etc/fstab + : to find filesystem names and locations +

SEE ALSO

+quota (1), +quotactl (2), +fstab (5), +quotacheck (8), +quotaon (8), +repquota (8) +

BUGS

+The format of the temporary file is inscrutable. + + 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 @@ + + +fstab(5) manualpage + + + + + +

NAME

+fstab - static information about the filesystems +

SYNOPSIS

+#include +

DESCRIPTION

+The file +fstab +contains descriptive information about the various file systems. +fstab +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 +fstab +is important because fsck (8), mount (8), and umount (8) sequentially iterate through +fstab +doing their thing. +

+The first field, +fs_spec +describes the block special device or remote filesystem to be mounted. +

+The second field, +fs_file +describes the mount point for the filesystem. For swap partitions, this +field should be specified as ``none''. +

+The third field, +fs_vfstype +describes the type of the filesystem. The system currently supports three +types of filesystems: +

    +
  • +minix +
    +a local filesystem, supporting filenames of length 14 or 30 characters. +
  • +ext +
    +a local filesystem with longer filenames and larger inodes. This +filesystem has been replaced by the +ext2 +file system, and should no longer be used. +
  • +ext2 +
    +a local filesystem with longer filenames, larger inodes, and lots of other +features. +
  • +xiafs +
    +a local filesystem with longer filenames, larger inodes, and lots of other +features. +
  • +msdos +
    +a local filesystem for MS-DOS partitions. +
  • +hpfs +
    +a local filesystem for HPFS partitions. +
  • +iso9660 +
    +a local filesystem used for CD-ROM drives. +
  • +nfs +
    +a filesystem for mounting partitions from remote systems. +
  • +swap +
    +a disk partition to be used for swapping. +
+

+If +vfs_fstype +is specified as ``ignore'' the entry is ignored. This is useful to show +disk partitions which are currently unused. +

+The fourth field, +fs_mntops +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). +

+The fifth field, +fs_freq +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. +

+The sixth field, +fs_passno +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 +fs_passno +of 1, and other filesystems should have a +fs_passno +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. +

+The proper way to read records from +fstab +is to use the routines getmntent (3). +

FILES

+/etc/fstab +resides in +/etc +

SEE ALSO

+getmntent (3), mount (8), swapon (8) + + 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 @@ + + +quota(1) manualpage + + + + + +

NAME

+quota - display disk usage and limits +

SYNOPSIS

+quota [ +-guv | q +] +
+quota [ +-uv | q +] user +
+quota [ +-gv | q +] group +

DESCRIPTION

+Quota +displays users' disk usage and limits. +By default only the user quotas are printed. +
    +
  • +-g +
    +Print group quotas for the group of which the user is a member. The optional +
  • +-u +
    +flag is equivalent to the default. +
  • +-v +
    +will display quotas on filesystems where no storage is allocated. +
  • +-q +
    +Print a more terse message, containing only information +on filesystems where usage is over quota. +
+Specifying both +-g +and +-u +displays both the user quotas and the group quotas (for the user). +

+Only the super-user may use the +-u +flag and the optional +user +argument to view the limits of other users. Non-super-users can use the the +-g +flag and optional +group +argument to view only the limits of groups of which they are members. +

+The +-q +flag takes precedence over the +-v +flag. +

+Quota +reports the quotas of all the filesystems listed in +/etc/fstab. +For filesystems that are NFS-mounted a call to the rpc.rquotad on +the server machine is performed to get the information. If +quota +exits with a non-zero status, one or more filesystems are over quota. +

FILES

+quota.user + : located at the filesystem root with user quotas +
+quota.group + : located at the filesystem root with group quotas +
+/etc/fstab + : to find filesystem names and locations +

SEE ALSO

+quotactl (2), +fstab (5), +edquota (8), +quotacheck (8), +quotaon (8), +repquota (8) + + 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 @@ + + +Linux DiskQuota system + + + + + +

General

+

+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 +Users +will see the quota-system and the way the quota-system can be configured +by the +System Administator +. +

+

Users' view of diskquotas

+

General

+To most users, diskquotas will either be of no concern, or a fact of life +that cannot be avoided. The +quota(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. +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. +

+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. +

+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. +

+

Surviving when quota limit is reached

+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 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. +

+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. +

Administering the quota system

+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: + +

Kernel configuration

+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 . Then +run and install the new kernel images as the one that is booted +at boottime. +

Electing filesystems

+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. +

+To enable quotas on a certain filesystem one should edit the /etc/fstab +file and add entries for usrquota and grpquota. Mine looks like : +

+# 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
+
+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. +

+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 +mntent.h +for a definition. +

+

Enabling quotas

+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 +quotacheck(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 quotacheck when the +filesystem is idle will certainly correct any inaccuracy. +

+To check the filesystem for the actual number of blocks used by a user run +quotacheck -avug +to install or update all the quotafiles. +

+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. +

+Ok now one should have all the quotafiles one needs. +Now you can add a line like: +/usr/etc/quotaon -avug +

+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. +

Checking a filesystem for quotas

+The super-user may use the +quota (1) +command to examine the usage and quotas +of any user, and the +repquota (8) +command may be used to check the usages and +limits for all users on a filesystem. Just run +quotacheck -avug +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 +quotacheck (8) +program this says if it updates the in core quotas in the kernel. +

+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. +

Specifing a quota for a user or group

+To edit the quotas for various users we use the +edquota (8) program. Now use +edquota -u +to edit user quotas and +edquota -g +to edit group quotas. +

+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. +

+The graceperiod can be changed with +edquota -t +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. +

+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. +

+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 +edquota -p prototypeusername * +this should do the trick, all users now have the quota they need, now +you could edit the ones that still need other values. +

Checking quotas for a user or group

+Run the quota program. The syntax for this program is : +
+quota [-guqv]
+quota [-qv] -u username ...
+quota [-qv] -g groupname ...
+
+Use -v to see the quotas on +
    +
  • +filesystems you don't have quotas on +
  • +filesystems on which you do have quota but haven't allocated any blocks yet +
+Use -q to only see filesystems on which you are over your softlimit or +have reached your hardlimit. +

+The -g flags give you all quotas for the groups you are in (also +additional groups). +

Disabling quota for a user or group

+When you want to disable quotas for a certain user use the quota editor +edquota. Type +edquota username | uid +or +edquota -g groupname | gid +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. +

Quotas on NFS-mounted disks

+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 +rquotad (8) +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. +

Some implementation details

+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. +

+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. +

+The system is informed of the existence of the quota file by the +quotactl (2) +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. +

+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. + + 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 @@ + + +quotacheck(8) manualpage + + + + + +

NAME

+quotacheck - scan a file system for disk usages +

SYNOPSIS

+quotacheck +[-g] [-u] [-v] -a +
+quotacheck +[-g] [-u] [-v] filesys ... +

DESCRIPTION

+Quotacheck +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: +
    +
  • +A user scan: +quota.user +
  • +A group scan: +quota.group +
+

+The resulting file consist of a +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 +struct dqblk +see +<linux/quota.h> +) +

+Quotacheck +should be run each time the system boots and mounts non-valid file systems. +This is most likely to happen after a system crash. +

+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. +

OPTIONS

+
    +
  • +-v +
    +This way the program will give some usefull information about what it is +doing, plus some fancy stuff. +
  • +-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. +
  • +-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. +
  • +-g +
    +This flag forces the program to count the the files and directories +used by a certain gid. +
+

NOTE

+Quotacheck +should only be run as Super User. Non-privilidged users are presumably not allowed +to read all the directories on the given file system. +

FILES

+quota.user +located at the filesystem root with user quotas +
+quota.group +located at the filesystem root with group quotas +
+/etc/fstab +to find filesystem names and locations +

SEE ALSO

+quota (1), +quotactl (2), +fstab (5), +edquota (8), +quotaon (8), +repquota (8) + + 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 @@ + + +quotactl(2) manualpage + + + + + +

NAME

+quotactl - manipulate disk quotas +

SYNOPSIS

+#include <linux/quota.h> +

+int quotactl(cmd, special, uid, addr) +
+int cmd; +
+char **special; +
+int id; +
+caddr_t addr;
+

DESCRIPTION

+The +quotactl +call manipulates disk quotas. +cmd +indicates a command to be applied to +UID id +or +GID id +. To set the type of quota use the +QCMD(cmd, type) +macro. +

+Special +is a pointer to a null-terminated string containing the path +name of the block special device for the file system being manipulated. +

+Addr +is the address of an optional, command specific, data structure +which is copied in or out of the system. The interpretation of +addr +is given with each command below. +

    +
  • +Q_QUOTAON +
    +Turn on quotas for a file system. +addr +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 +quotacheck (8) +program. This call is restricted to the super-user. +
  • +Q_QUOTAOFF +
    +Turn off quotas for a file system. +addr +and +id +are ignored. +This call is restricted to the super-user. +
  • +Q_GETQUOTA +
    +Get disk quota limits and current usage for user or group +id +. +Addr +is a pointer to a +dqblk +structure (defined in +<linux/quota.h> +). +Only the super-user may get the quotas of a user other than himself. +
  • +Q_SETQUOTA +
    +Set disk quota limits and current usage for user or group +id +. +Addr +is a pointer to a +dqblk +structure (defined in +<linux/quota.h> +). +This call is restricted to the super-user. +
  • +Q_SETQLIM +
    +Set disk quota limits for user or group +id +. +Addr +is a pointer to a +dqblk +structure (defined in +<linux/quota.h> +). +This call is restricted to the super-user. +
  • +Q_SYNC +
    +Update the on-disk copy of quota usages for a file system. +If +special +is null then all file systems with active quotas are sync'ed. +Addr +and +id +are ignored. +
+

RETURN VALUES

+quotactl +returns: +
    +
  • +0 on success. +
  • +-1 on failure and sets +errno +to indicate the error. +
+

ERRORS

+
    +
  • +EFAULT +
    +addr +or +special +are invalid. +
  • +EINVAL +
    +The kernel has not been compiled with the +QUOTA +option or +cmd +is invalid. +
  • +ENOENT +
    +The file specified by +special +or +addr +does not exist. +
  • +ENOTBLK +
    +special +is not a block device. +
  • +EPERM +
    +The call is privileged and the caller was not the super-user. +
  • +ESRCH +
    +No disc quota is found for the indicated user. +
    +Quotas have not been turned on for this file system. +
  • +EUSERS +
    +The quota table is full. +
+

+If +cmd +is +Q_QUOTAON quotactl +may set errno to: +

    +
  • +EACCES +
    +The quota file pointed to by +addr +exists but is not a regular file. +
  • +EBUSY +
    +Q_QUOTAON +attempted while another +Q_QUOTAON +has already taken place. +
+

SEE ALSO

+quota (1), +quotacheck (8), +quotaon (8), + + 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 @@ + + +quotaon(8) manualpage + + + + + +

NAME

+quotaon, quotaoff - turn file system quotas on and off +

SYNOPSIS

+quotaon +[ +-vug +] +filesystem +
+quotaon +[ +-avug +] +

+quotaoff +[ +-vug +] +filesystem +
+quotaoff +[ +-avug +] +

DESCRIPTION

+quotaon +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 +quota.user +for userquota or +quota.group +for groupquota. +

+quotaoff +announces to the system that file systems specified should have any disk quotas turned off. +

OPTIONS

+
    +
  • +-a +
    +All file systems in +/etc/fstab +marked read-write with quotas will have their quotas turned on. This is normally used at +boot time to enable quotas. +
  • +-v +
    +Display a message for each file system where quotas are turned on. +
  • +-u +
    +Manupulate user quotas. This is the default. +
  • +-g +
    +Manupulate group quotas. +
+

FILES

+quota.user + : located at the filesystem root with user quotas +
+quota.group + : located at the filesystem root with group quotas +
+/etc/fstab + : to find filesystem names and locations +

SEE ALSO

+quotactl (2), +fstab (5) + + 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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] {} 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 @@ + + +repquota(8) manualpage + + + + + +

NAME

+repquota - summarize quotas for a file system +

SYNOPSIS

+repquota +[ +-vug +] +filesystem +
+repquota +[ +-avug +] +

DESCRIPTION

+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 +edquota (8) +. +

OPTIONS

+
    +
  • +-a +
    +Report on all file systems indicated in +/etc/fstab +to be read-write with quotas. +
  • +-v +
    +Report all quotas, even if there is no usage. +
  • +-g +
    +Report quotas for groups. +
  • +-u +
    +Report quotas for users. This is the default. +
+

+Only the super-user may view quotas which are not their own. +

FILES

+quota.user + : located at the filesystem root with user quotas +
+quota.group + : located at the filesystem root with group quotas +
+/etc/fstab + : to find filesystem names and locations +

SEE ALSO

+quotactl (2), +fstab (5), +edquota (8), +quotacheck (8), +quotaon (8) + + 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 @@ + + +rquotad(8) manualpage + + + + + +

NAME

+rquotad, rpc.rquotad - remote quota server +

SYNOPSIS

+rpc.rquotad +

DESCRIPTION

+rquotad +is an +rpc (3N) +server which returns quotas for a user of a local file system +which is mounted by a remote machine over the +NFS +The results are used by +quota (1) +to display user quotas for remote file systems. +The +rquotad +daemon is normally started at boottime from the +rc.net +script +

FILES

+quota.user + : located at the filesystem root with user quotas +
+quota.group + : located at the filesystem root with group quotas +

SEE ALSO

+quota (1), +rpc (3N), nfs (4P), services (5) inetd (8C), + + 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 + +#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 +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +/* 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 , 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 \n" +"Language-Team: PL \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] \n" +"\t\t \n" +"\tsetquota [-u|-g] [-n] <-p protousername|protogroupname> " +" \n" +msgstr "" +"U¿ycie:\n" +"\tsetquota [-u|-g] [-n] \n" +"\t\t \n" +"\tsetquota [-u|-g] [-n] <-p u_prototyp|g_prototyp> " +"\n" + +#: setquota.c:79 +msgid "" +"Usage:\n" +"\tsetquota [-u|-g] \n" +"\t\t \n" +"\tsetquota [-u|-g] <-p protousername|protogroupname> " +"\n" +msgstr "" +"U¿ycie:\n" +"\tsetquota [-u|-g] \n" +"\t\t \n" +"\tsetquota [-u|-g] <-p u_prototyp|g_prototyp> " +"\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" diff --git a/pot.c b/pot.c new file mode 100644 index 0000000..bfacfe2 --- /dev/null +++ b/pot.c @@ -0,0 +1,15 @@ +#include "pot.h" +#include + +/************************************************************************* + * 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 +} diff --git a/pot.h b/pot.h new file mode 100644 index 0000000..b50dc27 --- /dev/null +++ b/pot.h @@ -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 + +#define _(x) gettext((x)) + +void gettexton(void); + +#else + +#define _(x) (x) + +#endif + +#endif diff --git a/quot.8 b/quot.8 new file mode 100644 index 0000000..f72973d --- /dev/null +++ b/quot.8 @@ -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. diff --git a/quot.c b/quot.c new file mode 100644 index 0000000..162511d --- /dev/null +++ b/quot.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/quot.h b/quot.h new file mode 100644 index 0000000..2ba44fc --- /dev/null +++ b/quot.h @@ -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 + +/* 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 === + */ diff --git a/quota.1 b/quota.1 new file mode 100644 index 0000000..fec0b29 --- /dev/null +++ b/quota.1 @@ -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) diff --git a/quota.c b/quota.c new file mode 100644 index 0000000..0bb7def --- /dev/null +++ b/quota.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef RPC +#include +#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")); + } +} diff --git a/quota.h b/quota.h new file mode 100644 index 0000000..8e56826 --- /dev/null +++ b/quota.h @@ -0,0 +1,83 @@ +#ifndef _QUOTA_H +#define _QUOTA_H + +#include + +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 +#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 \ +) +.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 \ +.br +Marco van Wieringen \ + 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 and Edvard Tuinder + * + */ + +#ident "$Id: quotacheck.c,v 1.1 2001/03/23 12:03:27 jkar8572 Exp $" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined(EXT2_DIRECT) +#include +#include +#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 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 + +#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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +#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 +.B #include +.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 ). +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 ). +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 ). +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 . +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 ). +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 ). +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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +#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 +#include + +#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 +#include +#include +#include + +#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 + +#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 +#include +#include +#include +#include +#include +#include + +#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 +#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 +#include +#include +#include +#include +#include +#include + +#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 + +#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 +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#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 +#include +#include +#include +#include +#include +#include + +#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 +.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; /* path to filesystem of interest */ + int gqa_uid; /* Inquire about quota for uid */ +}; + +struct setquota_args { + int sqa_qcmd; + string sqa_pathp; /* path to filesystem of interest */ + int sqa_id; /* Set quota for uid */ + sq_dqblk sqa_dqblk; +}; + +struct ext_getquota_args { + string gqa_pathp; /* 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; /* 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HOST_ACCESS +#include +#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 +#include +#include +#include /* for pmap_unset */ +#include +#include /* getenv, exit */ +#include /* strcmp */ +#include +#include + +#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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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] \n" + "\t -a|...\n" + " setquota [-u|-g] [-r] [-F quotaformat] <-p protouser|protogroup> -a|...\n" + " setquota [-u|-g] [-F quotaformat] -t -a|...\n")); +#else + fprintf(stderr, _("Usage:\n" + " setquota [-u|-g] [-F quotaformat] \n" + "\t -a|...\n" + " setquota [-u|-g] [-F quotaformat] <-p protouser|protogroup> -a|...\n" + " setquota [-u|-g] [-F quotaformat] -t -a|...\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 . +This reference page written by Heiko Schlittermann . 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#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; +} -- cgit v1.2.3