vzquota-3.1.orig/0000755000000000000000000000000012023504012010700 5ustar vzquota-3.1.orig/COPYING0000644000000000000000000004311012023504012011732 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. vzquota-3.1.orig/NEWS0000644000000000000000000000005312023504012011375 0ustar See http://git.openvz.org/?p=vzquota;a=log vzquota-3.1.orig/.gitignore0000644000000000000000000000002012023504012012660 0ustar cscope.out tags vzquota-3.1.orig/man/0000755000000000000000000000000012023504012011453 5ustar vzquota-3.1.orig/man/vzquota.8.in0000644000000000000000000002613412023504012013670 0ustar .TH vzquota 8 "27 Jun 2011" "Virtuozzo/OpenVZ" "Containers" .SH NAME vzquota \- manipulate containers disk quotas .SH SYNOPSIS .\" .TP \fBvzquota\fP [\fIquota_options\fP] \fIcommand quota_id\fR [\fIcommand_options\fP] .\" Commented out: either we'll provide syntax for all commands, or no .\" commands at all. --kir. .\" .TP .\" \fBvzquota setlimit2\fP \fIquota_id\fP \fB-t\fR [\fB-u\fR|\fB-g\fR] \fIblock-exptime\fR \fIinode-exptime\fP .\" .TP .\" \fBvzquota setlimit2\fP \fIquota_id\fP [\fB-u\fR|\fB-g\fR] \fIugid\fP \fIblock-softlimit block-hardlimit inode-softlimit inode-hardlimit\fP .SH DESCRIPTION \fBvzquota\fP controls disk quotas for Virtuozzo/OpenVZ container. These are per-container disk quotas set from Virtuozzo/OpenVZ host system. The \fIcommand\fR can be one of the following: \fBinit\fP, \fBdrop\fP, \fBon\fP, \fBoff\fP, \fBsetlimit\fP, \fBsetlimit2\fP, \fBreload2\fR, \fBstat\fP, \fBshow\fP. The \fIquota_id\fP must be numeric-only identifier. Note, that quota ID is not the same as container ID (CTID). One container can mount several filesystems and each of them can have its own quotas. .SH OPTIONS .SS General .TP .B -h Print usage information. .TP .B -V Print utility version. .TP .B -q Quiet mode. Causes all warning and diagnostic messages to be suppressed. Only fatal errors are displayed. .TP .B -v Verbose mode. Causes \fBvzquota\fR to print debugging messages about its progress. Multiple \fB-v\fP options increase verbosity. Maximum is 2. .TP .B -b Batch mode. in this mode outputs (usually on \fBstat\fP and \fBshow\fP commands) will be in format better suitable for parsing by a script. .SS Quota Commands The following commands are available: .TP .B init A necessary preliminary for any other quota command work: create a new quota file, calculating current disk usage from given path. This command requires full set of quota soft- and hardlimits given as command-line options. Limits are also stored in quota file, so subsequent \fBvzquota on\fP doesn't requires any quota limit as command-line parameter, although accepts them as well. New specified limits and flags will also be stored in the quota file. You can also create your own quota files for arbitrary quota accounting points. Quota file location and path to quota accounting point can be specified via \fB-c\fP and \fB-p\fP options (see below). You can use also \fB-R\fP option instead of \fB-c\fP option, to set relative quota file location. In this case quota file resides one dirrectory upper than quota accounting point and has special name (see below). .TP .B drop Remove quota file. Command checks if quota is running and refuses to remove file in this case, option \fB-f\fP allows to override that rule. .TP .B on Turn quota on. If previous quota session wasn't switched off properly (quota is not running, but quota file indicates it is), initialization procedure will be performed. \fB-f\fP option allow to force initialization procedure regardless of the shutdown status. Command \fBon\fP doesn't work in case specified quota id is running. .TP .B off Turn quota off, write usage statistic back to the quota file. Doesn't work if quota file cannot be accessed, also accepts \fB-f\fP option (force switching off, even if usage statistic will be lost). This is possible that quota will still be in a stopped state, even if \fB-f\fP flag is used. .TP .B setlimit Set new quota parameters. Requires at least one quota parameter or flag specified. Applies new parameters immediately if quota with given quota_id is running. Stores new limits and flags in the quota file. Option \fB-f\fP specifies to mark quota as dirty, so at the next quota start, disk will be rescanned and usage updated. .TP .B setlimit2 Set second-level quota parameters. Applies new parameters immediately if quota with given quota_id is running and second-level quota is on. Stores new limits in the quota file. .TP .B reload2 Reload second-level quota limits from quota file for given quota_id. .TP .B stat Show usage statistics and update it in quota file. Option \fB-f\fP causes to do not read and update quota file, just print statistics from kernel. Option \fB-t\fP specifies to show and update user/group based quota statistics for a container. Works on running containers only. The command with \fB-t\fP option flushes all quota statistics from kernel to file and thus may be used for backup purposes. .TP .B show Show usage and limits info from quota file. Option \fB-t\fP specifies to show user/group quota information as well. .SS Setting quota limits All these options are required in \fBinit\fP command, and optionally accepted in \fBon\fP and \fBsetlimit\fP commands. .TP .BR \-s ,\ --sub\-quotas\ 1 | 0 Enables or disables user/group based quota inside the container. Here \fB1\fP means to enable, and \fB0\fP - to disable. By default user/group quota is disabled. This option is accepted by \fBinit\fP, \fBon\fP and \fBsetlimit\fR commands. .TP .BI \-u\ user_id For \fBsetlimit2\fP command only. Limits will be applied to the specified \fIuser_id\fP. .TP .BI \-g\ group_id For \fBsetlimit2\fP command only. Limits will be applied to the specified \fIgroup_id\fP. .TP \fB\-u\fR, \fB--ugid\-limit\fP \fIlimit\fP For \fBon\fP and \fBsetlimit\fP commands only. Specifies maximum number of user and group IDs allowed in the container. If the value is \fB0\fP, user/group quota will not be accounted. Default value is \fI0\fP. There is one note concerning \fBsetlimit\fP command. If first-level quota is running, second-level quota is active and not all ugid objects were loaded into kernel by \fBon\fP command due to insufficient \fIugid_limit\fP value (this can be checked by issuing \fBstat -t\fP command and observing whether ugid limit was exceeded), then \fBsetlimit\fP with new \fIlimit\fP value updates it in kernel and file but this change does not take immediate effect. Modification will be applied after quota restart. .TP \fB\-b\fR, \fB--block\-softlimit\fP \fIbsl\fP Disk quota block soft limit. Soft limit is amount of blocks which excess is allowed in time equal \fIexptime\fP. On the expiration of this time soft limit becomes hard limit. Block limits are set in 1k sized blocks. .TP \fB\-B\fR, \fB--block\-hardlimit\fP \fIbhl\fP Disk quota block hard limit. Hard limit is amount of blocks which excess is not allowed. .TP \fB\-e\fR, \fB--block\-exptime\fP \fIbet\fP Disk quota expiration time for excess of a block soft limit. Time can be given in two different formats: .br 1. \fIdd:hh:mm:ss\fP .br For instance: \fI30\fP - 30 seconds; \fI12:00\fP - 12 minutes; \fI20:15:11:00\fP - 20 days, 15 hours, 11 minutes .br 2. \fIxxA\fP, where \fIA\fR - h/H(hour); d/D(day); w/W(week); m/M(month); y/Y(year). .br For instance: \fI7D\fP - 7 days; \fI01w\fP - 1 week; \fI3m\fP - 3 months .TP \fB\-i\fR, \fB--inode\-softlimit\fP \fIisl\fP Disk quota inode soft limit. Similarly to block soft limit. .TP \fB\-I\fR, \fB--inode\-hardlimit\fP \fIihl\fP Disk quota inode hard limit. .TP \fB\-n\fR, \fB--inode\-exptime\fP \fIiet\fP Disk quota expiration time for excess of a inode soft limit. .SS Other options .TP .BI \-p\ path Point of quota accounting for given \fIquota_id\fP. This option required for \fBinit\fP command and can be used also with any another command to override quota path obtained from quota file. For \fBon\fP and \fBsetlimit\fP commands, this option can be used to set and save new quota accounting path for given \fIquota_id\fP .TP .B \-R Set special relative path to \fIquota_file\fR. If this option is specified, quota file location will depends on path to quota accounting dir: if your quota accounting path is /path/to/\fIsomewhere\fR/ than quota file will be /path/to/quota.\fIsomewhere\fR. If this option is not specified, quota file location is /var/vzquota/quota.\fIquota_id\fP. All commands accept this option. .TP .BI \-c\ quota_file This option allows to specify a \fIquota_file\fR to work with. All commands accept this option. If this option is not specified, default file location depends on whether \fB-R\fP option is specified or not (see above). .TP .B \-f Force option. Accepted by \fBdrop\fP, \fBon\fP, \fBoff\fP, \fBstat\fP, \fBsetlimit\fP and \fBsetlimit2\fR commands. Action of this option differs for different commands and is described above for each command separately. .TP .B \-t For \fBstat\fP and \fBshow\fP commands only. Processes user/group quota statistics. Specifies whether to show (update in file) user/group quota information. .TP .B \-t For \fBsetlimit2\fP command. Set second-level quota time grace parameters. .SH LIMITATIONS It is impossible to start or stop quota accounting if the directory given by \fB-p\fP option is busy. This is rather limitation of kernel part of disk quota implementation. .SH DISPLAY \fBvzquota stat\fP and \fBvzquota show\fP display the following information: .TP .B resource Either 1k-blocks or inodes. .TP .B usage Current usage of resource. .TP .B softlimit Resource limit. Current usage can exceed this limit up to hard limit during grace time. .TP .B hardlimit Resource limit. Current usage can't exceed this limit. .TP .B grace During this amount of time usage can exceed softlimit. If a soft limit has not been exceeded the grace column is blank. If the grace period has expired, the grace column contain special \fBnone\fP value. .PP In case option \fB\-t\fP is specified, the following information is also displayed: .TP .B User/group quota: Status of the 2nd level quota. This can be \fBon\fR or \fBoff\fR, \fBactive\fR or \fBinactive\fR. Values \fBon\fR/\fBoff\fR define the state of the 2nd level quota at the next start of container quota. Values \fBactive\fR/\fBinactive\fR indicate the current state of the 2nd level quota in the kernel. .TP .B Ugids: Three values are shown: \fIloaded\fP, \fItotal\fP and \fIlimit\fP. \fIloaded\fP is the number of records (uids or gids) in the kernel. \fItotal\fP is the number of unique records located in the kernel and quota file. \fIlimit\fP is the current kernel limit of records amount. Note that \fIloaded\fP and \fItotal\fP may be greater then \fIlimit\fP. .TP .B Ugid limit was exceeded: Can be \fByes\fR or \fBno\fR. \fByes\fP indicates that vzquota did not loaded all records into the kernel. In this case you should reduce the number of unique records (remove files which belong to unnecessary users) or increase the ugid limit. After that you should restart quota. .TP .B User/group grace times and quotafile flags: Grace times and quota file flags (internal parameters of standard linux kernel quota v.3). .SH EXIT STATUS .TP .B 0 Command executed successfully .TP .B 1 System error .TP .B 2 Usage error .TP .B 3 Virtuozzo syscall error .TP .B 4 Quota file error .TP .B 5 Quota is already running .TP .B 6 Quota is not running .TP .B 7 Can not get lock on this quota id .TP .B 8 Directory tree crosses mount points .TP .B 9 Quota is running but user/group quota is inactive; this status is returned by \fBstat -t\fP command for information purposes and does not indicate a error .TP .B 10 Quota is marked as dirty in file; this status is returned by \fBshow\fP command for information purposes and does not indicate a error .TP .B 11 Quota file does not exist .TP .B 12 Internal error .TP .B 13 Can't obtain mount point .SH COPYRIGHT Copyright (C) 2000-2011, Parallels, Inc. Licensed under GNU GPL. vzquota-3.1.orig/man/Makefile0000644000000000000000000000073512023504012013120 0ustar MAN8 = vzdqdump.8 vzdqcheck.8 vzquota.8 MANS = $(MAN8) MANDIR=/usr/share/man MAN8DIR=$(MANDIR)/man8 all depend: .PHONY: all depend %.8: %.8.in macros.tmac cat macros.tmac $< > $@ install: $(MANS) $(INSTALL) -d $(DESTDIR)$(MAN8DIR) install -m 644 $(MAN8) $(DESTDIR)$(MAN8DIR)/ cd $(DESTDIR)$(MANDIR)/man8; ext=`ls vzdqdump.8*`; ext=$${ext#*.}; \ ln -fs vzdqdump.$$ext vzdqload.$$ext; chmod 644 vzdqload.$$ext; cd - .PHONY: install clean: rm -f $(MANS) .PHONY: clean vzquota-3.1.orig/man/macros.tmac0000644000000000000000000000127212023504012013607 0ustar .\" Stolen from groff's an-ext.tmac as of 2012-Mar-05 .nr mS 0 . . .\" Declare start of command synopsis. Sets up hanging indentation. .de SY . ie !\\n(mS \{\ . nh . nr mS 1 . nr mA \\n(.j . ad l . nr mI \\n(.i . \} . el \{\ . br . ns . \} . . nr mT \w'\fB\\$1\fP\ ' . HP \\n(mTu . B "\\$1" .. . . .\" End of command synopsis. Restores adjustment. .de YS . in \\n(mIu . ad \\n(mA . hy \\n(HY . nr mS 0 .. . . .\" Declare optional option. .de OP . ie \\n(.$-1 \ . RI "[\fB\\$1\fP" "\ \\$2" "]" . el \ . RB "[" "\\$1" "]" .. . . .\" Start example. .de EX . nr mE \\n(.f . nf . nh . ft CW .. . . .\" End example. .de EE . ft \\n(mE . fi . hy \\n(HY .. vzquota-3.1.orig/man/vzdqdump.8.in0000644000000000000000000000327112023504012014026 0ustar .TH vzdqdump 8 "11 Sep 2012" "Virtuozzo/OpenVZ" "Containers" .SH NAME vzdqdump, vzdqload \- dump, load user/group quotas .SH SYNOPSIS .SY vzdqdump [\fIgeneral_options\fP] \fIquota_id\fP .OP -f .OP -c quota_file .OP -G .OP -U .OP -T .OP -F .SY vzdqload [\fIgeneral_options\fP] \fIquota_id\fP .OP -c quota_file .OP -G .OP -U .OP -T .OP -F .YS .SH DESCRIPTION \fBvzdqdump\fP dumps user/group quota information obtained either from a quota file or the kernel to stdout. .PP \fBvzdqload\fP loads user/group quota information provided by \fBvzdqdump\fP from stdin into quota file. Quota must be stopped at load. The \fIquota_id\fP must be numeric-only identifier. Note that quota ID is not the same as container ID (CTID). One container can mount several filesystems and each of them can have its own quotas. .SH OPTIONS .SS General .TP .B -h Print usage information. .TP .B -V Print utility version. .TP .B -q Quiet mode. Causes all warning and diagnostic messages to be suppressed. Only fatal errors are displayed. .TP .B -v Verbose mode. Causes the utilities to print debugging messages about their progress. Multiple \fB-v\fP options increase verbosity. Maximum is 2. .SS Parameters .TP .B -f Dump user/group quota information from kernel rather than quota file. .TP .BI -c \ quota_file Specifies quota file to process. .TP .BR -G ,\ --grace Dump (load) user/group grace times. .TP .BR -U ,\ --limits Dump (load) disk limits of users/groups. .TP .BR -T ,\ --exptimes Dump (load) expiration times of users/groups. .TP .BR -F ,\ --first Dump (load) first level quota. .SH EXIT STATUS See \fBvzquota\fP(8). .SH SEE ALSO .BR vzquota (8). .SH COPYRIGHT Copyright (C) 2000-2012, Parallels, Inc. Licensed under GNU GPL. vzquota-3.1.orig/man/vzdqcheck.8.in0000644000000000000000000000142412023504012014134 0ustar .TH vzdqcheck 8 "6 Jun 2011" "Virtuozzo/OpenVZ" "Containers" .SH NAME vzdqcheck \- count disk usage .SH SYNOPSIS .SY vzdqcheck [\fIoption\fP ...] \fIpath\fP .YS .SH DESCRIPTION \fBvzdqcheck\fP scans all the files under the \fIpath\fP, using the same code as \fBvzquota init\fR, and reports disk usage (in 1 KB blocks and inodes). .SH OPTIONS .TP .B -h Print usage information. .TP .B -V Print utility version. .TP .B -q Quiet mode. Causes all warning and diagnostic messages to be suppressed. Only fatal errors are displayed. .TP .B -v Verbose mode. Causes the utility to print debugging messages about its progress. Multiple \fB-v\fP options increase verbosity. Maximum is 2. .SH SEE ALSO .BR vzquota (8). .SH COPYRIGHT Copyright (C) 2000-2011, Parallels, Inc. Licensed under GNU GPL. vzquota-3.1.orig/Makefile0000644000000000000000000000272512023504012012346 0ustar # Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. # # 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. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # SUBDIRS=src man NAME=vzquota SPEC=$(NAME).spec VERSION=$(shell awk '/^Version:/{print $$2}' $(SPEC)) NAMEVER=$(NAME)-$(VERSION) TARBALL=$(NAMEVER).tar.bz2 all install depend clean: @set -e; \ for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done .PHONY: all install depend clean clean-all: clean rm -f $(TARBALL) dist: tar tar: $(TARBALL) .PHONY: dist tar $(TARBALL): clean-all rm -f ../$(NAMEVER) ln -s `pwd | awk -F / '{print $$NF}'` ../$(NAMEVER) tar --directory .. --exclude .git --exclude .depend \ --exclude-from .gitignore \ -cvhjf ../$(TARBALL) $(NAMEVER) rm -f $(TARBALL) mv ../$(TARBALL) . rm -f ../$(NAMEVER) rpms: tar rpmbuild -ta $(TARBALL) ${RPMB_ARGS} .PHONY: rpms -include .depend vzquota-3.1.orig/vzquota.spec0000644000000000000000000000604312023504012013270 0ustar Summary: Virtuozzo/OpenVZ disk quota control utility Name: vzquota Version: 3.1 Release: 1%{?dist} License: GPL Group: System Environment/Kernel Source: http://download.openvz.org/utils/%{name}/%{version}/src/%{name}-%{version}.tar.bz2 ExclusiveOS: Linux BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: vzquotamod URL: http://openvz.org/ %description This utility allows system administator to control disk quotas for Virtuozzo/OpenVZ containers. %prep %setup %build CFLAGS="$RPM_OPT_FLAGS" make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT MANDIR=%{_mandir} %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %attr(755,root,root) %{_sbindir}/vzquota %attr(755,root,root) %{_sbindir}/vzdqcheck %attr(755,root,root) %{_sbindir}/vzdqdump %attr(755,root,root) %{_sbindir}/vzdqload %attr(755,root,root) %{_var}/vzquota %attr(644,root,root) %{_mandir}/man8/vzquota.8* %attr(644,root,root) %{_mandir}/man8/vzdqcheck.8* %attr(644,root,root) %{_mandir}/man8/vzdqdump.8* %attr(644,root,root) %{_mandir}/man8/vzdqload.8* %changelog * Tue Sep 11 2012 Kir Kolyshkin - 3.1-1 - New functionality: - * vzdqdump, vzdqload: add -F to dump/load first level quotas - Fixes: - * Make ext4 delalloc work with vzquota (#2035) - * fix quota init fail then run from deleted directory - * fix building with fresh toolchain (#1357 etc.) - * skip quota file locking on 'vzquota show' action - * fix to work with more than 1 TB quotas - * correct exit code in case quota file does not exist - * minor code style fixes - * whitespace cleanups - Improvements: - * quota on: more info on failed quota on with EEXIST - * quota off: enable detailed info on fail by default - * quota off: add processing EIO - * man/*: assorted fixes and formatting improvements - * man/vzquota: minor improvements (#2310) - * vzdqdump, vzdqload: fix typo in usage - * Makefile: Don't strip executable, respect LDFLAGS (#1191) * Thu Mar 06 2008 Kir Kolyshkin - 3.0.12-1 - updated description, VE->container terminology change * Wed Jun 13 2007 Andy Shevchenko - 3.0.9-1 - fixed according to Fedora Packaging Guidelines: - use dist tag - removed Vendor tag - added URL tag - use full url for source - changed BuildRoot tag * Mon Oct 09 2006 Dmitry Mishin 3.0.9-1 - added README and NEWS files - deleted debian directory (requested by debian package maintainers) - fixed compilation on ppc64 platform. * Tue Apr 18 2006 Kir Kolyshkin 3.0.0-5 - fixed license in man pages * Wed Mar 15 2006 Andrey Mirkin 3.0.0-3 - added new function to reload 2nd level quota * Mon Feb 6 2006 Kir Kolyshkin 3.0.0-2 - fixed gcc4 compilation issue * Fri Sep 09 2005 Dmitry Mishin 2.7.0-7 - fixes to use new vzkernel headers provisioning scheme * Thu Aug 11 2005 Dmitry Mishin 2.7.0-5 - reworked hard links check - mans fixes * Sat Aug 06 2005 Dmitry Mishin 2.7.0-4 - adopted for new vzctl_quota ioctls vzquota-3.1.orig/doc/0000755000000000000000000000000012023504012011445 5ustar vzquota-3.1.orig/doc/alg.txt0000644000000000000000000000510512023504012012752 0ustar quotainit - обязательные параметры: -i veid -p path --block-softlimit bsl --block-hardlimit bhl --inode-softlimit isl --inode-hardlimit ihl --block-exptime bet --inode-exptime iet опционально: [-c quota_file] - файл квоты, если не задано то берется по умолчанию (/var/vzquota.{veid}) [-s ugid_limit|0] - включает/выключает квоту 2 уровня внутри ВЕ. 0 - выключить, не 0 - включить с лимитом на количество user и group ID в ugid_limit. создает файл квоты (если он уже существует то выдает ворнинг, а если он не нашего формата то выход из программы) делает quotacheck если usage превышает лимиты то выдается warning если softlimit больше hardlimit то также warning quotaon - обязательные параметры: -i veid опционально: [-c quota_file] [-f] [-s ugid_limit|0] [--block-softlimit bsl] [--block-hardlimit bhl] [--inode-softlimit isl] [--inode-hardlimit ihl] [--block-exptime bet] [--inode-exptime iet] если файла нет или не тот формат выходит читается файл квоты если -f проводит quotacheck если в файле флаг QUOTA_ON установлен то вызывается сисколл с GET_STAT, если квота оказывается не запущена то пишет ворнинг и делает скан иначе вываливается с ворнингом лимиты переданные в командной строке (если есть) перекрывают считанные из файла проверяет лимиты и текущий usage (выдает соответствующие ворнинги) вызываем syscall quotaon. проставляем флаг QUOTA_ON и записываем новые данные (лимиты если они были перекрыты) в файл quotaoff - обязательные параметры: -i veid опционально: [-c quota_file] [-f] если файл не находится или не тот формат то выходим если не стоит флага QUOTA_ON то выходим с ворнингом вызываем syscall с quota_off записываем данные в файл.. очищаем флажок QUOTA_ON если при вызове установить -f то syscall С quota_off будет вызван в любом случае не смотря на ошибки при работе с файлом setlimit - обязательные параметры: -i veid опционально: [-c quota_file] [-s ugid_limit|0] [--block-softlimit bsl] [--block-hardlimit bhl] [--inode-softlimit isl] [--inode-hardlimit ihl] [--block-exptime bet] [--inode-exptime iet] если файл квоты не находится или не тот формат то выходим выполняем syscall getstat, если квота включена то берем параметры возвращаемые getstat иначе иначе берем лимиты из файла перекрываем лимиты заданные в коммандной строке (делаем соответствующие ворнинги) вызываем syscall set_limit записываем новые лимиты в файл vzquota-3.1.orig/README0000644000000000000000000000100412023504012011553 0ustar vzquota - OpenVZ quota management tool ============================================ This tool allows to manage OpenVZ quotas - both guest environments diskspace and inodes quotas and user/group quotas inside them. Requirements ------------ kernel should provide vzdquota module. Installation ------------ make install Usage ----- See man pages and info at http://openvz.org/ Copyright --------- Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. For the licensing terms, see COPYING file. vzquota-3.1.orig/src/0000755000000000000000000000000012023504012011467 5ustar vzquota-3.1.orig/src/quotacheck.c0000644000000000000000000001661612023504012013774 0ustar /* * Copyright (C) 2000-2012, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include "vzquota.h" #include "common.h" #include "quota_io.h" #include "quotacheck.h" #ifndef EXT4_SUPER_MAGIC #define EXT4_SUPER_MAGIC 0xEF53 #endif /* From ext4.h */ #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) static int ext4_sync_fd(int fd) { /* Force block allocation */ return ioctl(fd, EXT4_IOC_ALLOC_DA_BLKS); } static inline struct dir * new_dir_entry(const char * item_name) { struct dir * new_dir = xmalloc(sizeof(struct dir)); new_dir->name = xstrdup(item_name); return new_dir; } static inline void insert_dir_entry(struct dir * ind, struct dir * entry) { entry->next = ind->next; ind->next = entry; } void scan_dir(struct scan_info *info, dev_t root_dev); /* in bytes! */ static loff_t get_inode_size(struct scan_info *info, const char* fname, struct stat *st) { static int ioctl_fail_warn; static int sync_fd_warn; int fd; loff_t size; /* There's no way to do ioctl() on links... */ if (S_ISLNK(st->st_mode) || !(S_ISDIR(st->st_mode) || S_ISREG(st->st_mode))) return ((loff_t) st->st_blocks) << STAT_BLOCK_BITS; fd = open(fname, O_RDONLY); if (fd < 0) error(EC_SYSTEM, errno, "Quota check : open '%s'", fname); if (info->sync_fd && info->sync_fd(fd) != 0) if (!sync_fd_warn) { sync_fd_warn = 1; debug(LOG_WARNING, "Cannot sync file." " Results might be inaccurate.\n"); } if (ioctl(fd, FIOQSIZE, &size) < 0) { size = ((loff_t) st->st_blocks) << STAT_BLOCK_BITS; if (!ioctl_fail_warn) { ioctl_fail_warn = 1; debug(LOG_WARNING, "Cannot get exact used space." " Results might be inaccurate.\n"); } } close(fd); return size; } static inline int hash_index(int inode_num) { return (inode_num & (HASHSIZE - 1)); } static int check_hard_link(struct scan_info *info, ino_t inode_num) { struct hardlink *hl; int hash_id = hash_index(inode_num); info->hard_links++; for (hl = info->links_hash[hash_id]; hl; hl = hl->next) if (hl->inode_num == inode_num) return 1; hl = (struct hardlink *) xmalloc(sizeof(struct hardlink)); hl->inode_num = inode_num; hl->next = info->links_hash[hash_id]; info->links_hash[hash_id] = hl; return 0; } static void add_quota_item(struct scan_info *info, const char * item_name, int resolve_sym, dev_t root_dev) { struct stat st; qint qspace; loff_t space; ASSERT(info && item_name); if ((resolve_sym ? stat(item_name, &st) : lstat(item_name, &st)) < 0) error(EC_SYSTEM, errno, "quota check : lstat `%s'", item_name); /* debug(LOG_DEBUG, "stat %s :st_blocks %d:ino %d:links %d:type %#o\n", item_name, st.st_blocks, st.st_ino, st.st_nlink, st.st_mode & S_IFMT); */ if (st.st_dev != root_dev) error(EC_EXDEV, 0, "quota check : crossing mount point"); if (st.st_nlink > 1 && !S_ISDIR(st.st_mode)) if (check_hard_link(info, st.st_ino)) return; space = get_inode_size(info, item_name, &st); /* debug(LOG_DEBUG, "get size for %s: %llu\n", item_name, space);*/ qspace = space; info->size += qspace; info->inodes++; if (info->ugid_stat) { add_ugid_usage(info->ugid_stat, USRQUOTA, st.st_uid, qspace); add_ugid_usage(info->ugid_stat, GRPQUOTA, st.st_gid, qspace); } if (S_ISDIR(st.st_mode)) { // Add new directory entry struct dir * new_dir = new_dir_entry(item_name); if (info->dir_stack != NULL) insert_dir_entry(info->dir_stack, new_dir); else { new_dir->next = NULL; info->dir_stack = new_dir; } /* debug(LOG_DEBUG, "push dir %s\n", new_dir->name); */ info->dirs++; } else { info->files++; } return; } void free_lists(struct scan_info *info) { int i; struct hardlink *hl, *tmp; for (i = 0; i < HASHSIZE; i++) { hl = info->links_hash[i]; while (hl) { tmp = hl; hl = tmp->next; xfree(tmp); } info->links_hash[i] = NULL; } } void scan(struct scan_info *info, const char *mnt) { struct stat root_st; struct statfs root_stfs; struct ugid_quota *ugid_stat = info->ugid_stat; int cwd; ASSERT(info && mnt); debug(LOG_INFO, "scan mount point begin '%s'\n", mnt); if ((cwd = open(".", O_RDONLY)) == -1) error(0, errno, "failed to open cwd"); memset(info, 0, sizeof(struct scan_info)); if (ugid_stat) { info->ugid_stat = ugid_stat; reset_ugid_usage(info->ugid_stat); } if (stat(mnt, &root_st) == -1) error(EC_SYSTEM, errno, "quota check : stat %s", mnt); if (!S_ISDIR(root_st.st_mode)) error(EC_SYSTEM, errno, "quota check : path %s is not dir", mnt); if (statfs(mnt, &root_stfs) == -1) error(EC_SYSTEM, errno, "quota check : statfs %s", mnt); if (root_stfs.f_type == EXT4_SUPER_MAGIC) { DIR *dp = opendir(mnt); int dfd; if (dp == (DIR *) NULL) error(EC_SYSTEM, errno, "quota check : opendir '%s'", mnt); dfd = dirfd(dp); if (dfd < 0) error(EC_SYSTEM, errno, "quota check : dirfd '%s'", mnt); if (ext4_sync_fd(dfd) != -1) info->sync_fd = ext4_sync_fd; closedir(dp); } add_quota_item(info, mnt, 1, root_st.st_dev); while (info->dir_stack != (struct dir *) NULL) { struct dir *next_dir; // scan dir on top of info->dir_stack scan_dir(info, root_st.st_dev); next_dir = info->dir_stack->next; xfree(info->dir_stack->name); xfree(info->dir_stack); info->dir_stack = next_dir; } if (info->ugid_stat) { /* drop dummy ugid entries */ drop_dummy_ugid(info->ugid_stat); /* update size of buffer */ info->ugid_stat->info.buf_size = info->ugid_stat->dquot_size; } if (cwd != -1) { if (fchdir(cwd)) error(0, errno, "failed to fchdir cwd"); close(cwd); } free_lists(info); debug(LOG_INFO, "scan mount point end :%s:inodes %d:size %lld:files %d:dirs %d:hard_links %d\n", mnt, info->inodes, info->size, info->files, info->dirs, info->hard_links); return; } void scan_dir(struct scan_info *info, dev_t root_dev) { DIR *dp; struct dirent *de; const char *pathname = info->dir_stack->name; if (chdir(pathname) != 0) error(EC_SYSTEM, errno, "quota check : chdir '%s'", pathname); // check on special case if (!strcmp(pathname, "..")) return ; /* debug(LOG_DEBUG, "scan dir begin :%s:\n", pathname); */ // add return path insert_dir_entry(info->dir_stack, new_dir_entry("..")); dp = opendir("."); if (dp == (DIR *) NULL) error(EC_SYSTEM, errno, "quota check : opendir '%s'", pathname); while ((de = readdir(dp)) != (struct dirent *) NULL) { const char * p = de->d_name; // skip '.', '..' if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0'))) continue; add_quota_item(info, de->d_name, 0, root_dev); } closedir(dp); /* debug(LOG_DEBUG, "scan dir end :%s:\n", pathname); */ } vzquota-3.1.orig/src/vzdqload.c0000644000000000000000000001713312023504012013464 0ustar /* * Copyright (C) 2000-2012, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "common.h" #include "vzquota.h" #include "quota_io.h" #include "quotadump.h" const char *program_name = "vzdqload"; char *command_name = NULL; /* for usage() */ static char dump_usage[] = "Usage: %s quotaid [-c file] commands\n" "Loads user/group quota information from stdin into quota file.\n" "\t-c file\tuse given quota file\n" "Commands specify what user/group information to load:\n" "\t-F\tfirst level quota\n" "\t-G\tgrace time\n" "\t-U\tdisk limits\n" "\t-T\texpiration times\n" ; static char dump_short_options[] = "c:FGUT"; static struct option dump_long_options[] = { {"first", no_argument, NULL, 'F'}, {"quota-file", required_argument, NULL, 'c'}, {"gracetime", no_argument, NULL, 'G'}, {"limits", no_argument, NULL, 'U'}, {"exptimes", no_argument, NULL, 'T'}, {0, 0, 0, 0} }; void err(char *line, struct qf_data *q, int fd) { if (q) free_quota_data(q); if (fd > 0) close_quota_file(fd); error(EC_USAGE, 0, "Invalid input data: %s", line); } /* reads _argnum_ arguments from _f_ excluding comments # and empty lines; * returns: 0 - end of file, -1 - invalid syntax */ int read_line(FILE *f, char *line, size_t bufsize, int argnum, const char *fmt, ...) { int i; va_list pvar; memset(line, 0, bufsize); do if (! fgets(line, bufsize-1, f)) { /* end of file */ error(0, 0, "End of input file"); return 0; } while (line[0] == 0 || line[0] == '#'); va_start(pvar, fmt); i = vsscanf(line, fmt, pvar); va_end(pvar); if (argnum != i) /* invalid syntax */ return -1; return i; } int main(int argc, char **argv) { int fd = 0; FILE *file = stdin; int rc; struct qf_data qd; struct ugid_quota *q = NULL; unsigned int ugid_quota_status = 0; unsigned int ugidnum = 0; size_t bufsize = 4*1024; char line[bufsize]; char label[bufsize]; unsigned int i; parse_global_options(&argc, &argv, dump_usage); argc += 1; argv -= 1; parse_options(argc, argv, dump_short_options, dump_long_options, dump_usage, 0); if (!(option & FL_VEID)) usage(dump_usage); if (!(option & FL_DUMP)) usage(dump_usage); init_quota_data(&qd); /* open quota file */ fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0) { if (errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } /* we must read and write whole files cause of checksum */ if (check_quota_file(fd) < 0 || read_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); /* status of user/group quota */ rc = read_line(file, line, bufsize, 2, "%s%u", &label, &ugid_quota_status); if (rc == 0 || rc < 0 || strcmp(label, STATUS_LABEL) || ugid_quota_status > 1) err(line, &qd, fd); if (!ugid_quota_status) { /* ugid quota is off */ // qd.head.flags &= ~QUOTA_UGID_ON; /* we must read and write whole files cause of checksum */ // rc = write_quota_file(fd, &qd, IOF_ALL); // if (rc < 0) // exit(EC_QUOTAFILE); goto get_first_level; } /* ugid quota is on */ q = &qd.ugid_stat; // qd.head.flags |= QUOTA_UGID_ON; /* grace times */ if (option & FL_DUMP_GRACE) { for (i = 0; i < MAXQUOTAS; i++) { unsigned int type; unsigned long bexp, iexp; rc = read_line(file, line, bufsize, 4, "%s%u%lu%lu", &label, &type, &bexp, &iexp); if( rc == 0 || rc < 0 || strcmp(label, GRACE_LABEL) || type != i) err(line, &qd, fd); q->info.ugid_info[i].bexpire = (time_t) bexp; q->info.ugid_info[i].iexpire = (time_t) iexp; } } /* number of ugids */ if (option & (FL_DUMP_LIMITS | FL_DUMP_EXPTIME)) { rc = read_line(file, line, bufsize, 2, "%s%u", &label, &ugidnum); if (rc == 0 || rc < 0 || strcmp(label, NUMBER_LABEL)) err(line, &qd, fd); } /* ugid objs */ if ((option & (FL_DUMP_LIMITS | FL_DUMP_EXPTIME)) && ugidnum) { for (i = 0; i < ugidnum; i++) { unsigned int id, type; unsigned int bsoft, bhard, isoft, ihard; unsigned long btime, itime; struct dquot *dq = NODQUOT; struct vz_quota_iface *s; if (! (option & FL_DUMP_EXPTIME)) /* limits only */ rc = read_line(file, line, bufsize, 7, "%s%u%u%u%u%u%u", &label, &id, &type, &bsoft, &bhard, &isoft, &ihard); else if (! (option & FL_DUMP_LIMITS)) /* grace times only */ rc = read_line(file, line, bufsize, 5, "%s%u%u%lu%lu", &label, &id, &type, &btime, &itime); else /* both */ rc = read_line(file, line, bufsize, 9, "%s%u%u%u%u%u%u%lu%lu", &label, &id, &type, &bsoft, &bhard, &isoft, &ihard, &btime, &itime); if( rc == 0 || rc < 0 || strcmp(label, UGID_LABEL) || type > MAXQUOTAS) err(line, &qd, fd); /* find or create obj */ dq = lookup_dquot_(q, id, type); if (dq == NODQUOT) dq = add_dquot_(q, id, type); s = &dq->obj.istat; /* limits */ if (option & FL_DUMP_LIMITS) { s->qi_stat.bsoftlimit = block2ker(bsoft); s->qi_stat.bhardlimit = block2ker(bhard); s->qi_stat.isoftlimit = isoft; s->qi_stat.ihardlimit = ihard; } /* exp times */ if (option & FL_DUMP_EXPTIME) { s->qi_stat.btime = (time_t) btime; s->qi_stat.itime = (time_t) itime; } } /* set number of ugid objects in buffer */ q->info.buf_size = q->dquot_size; } get_first_level: if (option & FL_DUMP_LIMITS_FIRST) { unsigned long long bcurrent, bsoftlimit, bhardlimit; unsigned long btime, bexpire; unsigned icurrent, isoftlimit, ihardlimit; unsigned long itime, iexpire; struct vz_quota_stat *stat = &qd.stat; rc = read_line(file, line, bufsize, 1, "%s", &label); if (rc < 0 || rc == 0 || strncmp(label, FIRST_LEVEL_LABEL, strlen(FIRST_LEVEL_LABEL)) != 0) { fprintf(stderr, "Invalid input data: %s\n", line); exit(EC_USAGE); } /* OK, read 1k-blocks */ rc = read_line(file, line, bufsize, 5, "%llu%llu%llu%lu%lu", &bcurrent, &bsoftlimit, &bhardlimit, &btime, &bexpire); if (rc < 0 || rc == 0) { fprintf(stderr, "Invalid input data: %s\n", line); exit(EC_USAGE); } /* read inodes */ rc = read_line(file, line, bufsize, 5, "%u%u%u%lu%lu", &icurrent, &isoftlimit, &ihardlimit, &itime, &iexpire); if (rc < 0 || rc == 0) { fprintf(stderr, "Invalid input data: %s\n", line); exit(EC_USAGE); } stat->dq_stat.bhardlimit = bhardlimit; stat->dq_stat.bsoftlimit = bsoftlimit; stat->dq_stat.bcurrent = bcurrent; stat->dq_stat.btime = btime; stat->dq_info.bexpire = bexpire; stat->dq_stat.ihardlimit = ihardlimit; stat->dq_stat.isoftlimit = isoftlimit; stat->dq_stat.icurrent = icurrent; stat->dq_stat.itime = itime; stat->dq_info.iexpire = iexpire; } if (ugid_quota_status == 1 || option & FL_DUMP_LIMITS_FIRST) { /* we must read and write whole files cause of checksum */ rc = write_quota_file(fd, &qd, IOF_ALL); if (rc < 0) exit(EC_QUOTAFILE); } close_quota_file(fd); free_quota_data(&qd); return EC_SUCCESS; } vzquota-3.1.orig/src/quota_io.c0000644000000000000000000013413612023504012013463 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "common.h" #include "vzquota.h" #include "quota_io.h" #define QF_OFF_HEADER 0 #define QF_OFF_STAT (QF_OFF_HEADER + sizeof(struct vz_quota_header)) #define QF_OFF_PATH_LEN(size) (QF_OFF_STAT + (size)) #define QF_OFF_PATH(size) (QF_OFF_PATH_LEN(size) + sizeof(size_t)) #define QF_OFF_UGID_INFO(path_len) (QF_OFF_PATH(sizeof(struct vz_quota_stat)) + (path_len)) #define QF_OFF_UGID_BUF(path_len) (QF_OFF_UGID_INFO(path_len) + sizeof(struct ugid_info)) #define min(a,b) (((a) > (b)) ? (b) : (a)) static inline int is_dummy_stat(struct dq_stat *stat) { return !(stat->bhardlimit || stat->bsoftlimit || stat->bcurrent || stat->ihardlimit || stat->isoftlimit || stat->icurrent); } static char quotanames[MAXQUOTAS + 1][20] = QUOTANAMES; /* Convert type of quota to written representation */ char *type2name(int type) { return quotanames[type]; } /* Hash given id */ static inline unsigned int hash_dquot(unsigned int 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_(struct ugid_quota *q, unsigned int id, unsigned int type) { struct dquot *lptr; unsigned int hash = hash_dquot(id); for (lptr = q->dquot_hash[type][hash]; lptr != NODQUOT; lptr = lptr->dq_next) if (lptr->obj.istat.qi_id == id) return lptr; return NODQUOT; } struct dquot *lookup_dquot(struct ugid_quota *q, struct ugid_obj *obj) { return lookup_dquot_(q, obj->istat.qi_id, obj->istat.qi_type); } /* Add a new dquot for a new id to the list. */ struct dquot *add_dquot_(struct ugid_quota *q, unsigned int id, unsigned int type) { struct dquot *lptr; unsigned int hash = hash_dquot(id); lptr = (struct dquot *)xmalloc(sizeof(struct dquot)); lptr->obj.istat.qi_id = id; lptr->obj.istat.qi_type = type; lptr->dq_next = q->dquot_hash[type][hash]; q->dquot_hash[type][hash] = lptr; q->dquot_size++; /* debug(LOG_DEBUG, "add dquot for ugid(id=%u,type=%u)\n", lptr->obj.istat.qi_id, lptr->obj.istat.qi_type); */ return lptr; } struct dquot *add_dquot(struct ugid_quota *q, struct ugid_obj *obj) { struct dquot *lptr; lptr = add_dquot_(q, obj->istat.qi_id, obj->istat.qi_type); memcpy(&(lptr->obj), obj, sizeof(struct ugid_obj)); return lptr; } /* Drop dquot from the list. */ void drop_dquot_(struct ugid_quota *q, unsigned int id, int type) { struct dquot *lptr, *prev; unsigned int hash = hash_dquot(id); prev = NODQUOT; for (lptr = q->dquot_hash[type][hash]; lptr != NODQUOT; prev = lptr, lptr = lptr->dq_next) { if (lptr == NODQUOT) return; if (lptr->obj.istat.qi_id == id) { if (prev == NODQUOT) { q->dquot_hash[type][hash] = lptr->dq_next; } else { prev->dq_next = lptr->dq_next; } debug(LOG_DEBUG, "drop ugid (%s %u)\n", type2name(lptr->obj.istat.qi_type), lptr->obj.istat.qi_id); free(lptr); if (q->dquot_size > 0) q->dquot_size--; return; } } } void drop_dquot(struct ugid_quota *q, struct ugid_obj *obj) { drop_dquot_(q, obj->istat.qi_id, obj->istat.qi_type); return; } /* compare dquot */ int comp_dquot(const void *pa, const void *pb) { struct dquot *a = *(struct dquot **)pa; struct dquot *b = *(struct dquot **)pb; return (a->obj.istat.qi_id > b->obj.istat.qi_id) ? 1 : ((a->obj.istat.qi_id < b->obj.istat.qi_id) ? -1 : 0); } /* search facility */ unsigned int cur_index; unsigned int cur_id; unsigned int cur_type; struct dquot *cur_dquot; void reset_dquot_search() { cur_index = 0; cur_id = 0; cur_type = 0; cur_dquot = NODQUOT; } struct dquot *get_next_dquot(struct ugid_quota *q) { if (cur_index < q->dquot_size) for (; cur_type < MAXQUOTAS; cur_type++) { for (; cur_id < DQUOTHASHSIZE; cur_id++) { if (cur_dquot != NODQUOT) cur_dquot = cur_dquot->dq_next; else cur_dquot = q->dquot_hash[cur_type][cur_id]; if (cur_dquot != NODQUOT) { cur_index++; return cur_dquot; } } if (cur_id >= DQUOTHASHSIZE) cur_id = 0; } reset_dquot_search(); return NODQUOT; } /* sort ugids objects by ID; * obj should be an allocated array of (struct dquot *) of dquot_size */ void sort_dquot(struct ugid_quota *q, struct dquot **obj) { unsigned int i; struct dquot *dq; reset_dquot_search(); for (i = 0; (dq = get_next_dquot(q)) != NODQUOT; i++) obj[i] = dq; qsort(obj, q->dquot_size, sizeof(struct dquot *), &comp_dquot); } /* drop dummy entries */ void drop_dummy_ugid(struct ugid_quota *q) { struct dquot *dquot; void **buf = NULL; size_t i, n = 0, size = 0; /* select ugids */ reset_dquot_search(); while( (dquot = get_next_dquot(q)) != NODQUOT) { if (!is_dummy_stat(&(dquot->obj.istat.qi_stat))) continue; if (n >= size) { size += 100; buf = xrealloc(buf, size * sizeof(void *)); } buf[n] = (void *) dquot; n++; } /* drop ugids */ for (i = 0; i < n; i++) { dquot = (struct dquot *) buf[i]; drop_dquot(q, &(dquot->obj)); } free(buf); } /* drop ugid entries by flags */ void drop_ugid_by_flags(struct ugid_quota *q, unsigned int mask) { struct dquot *dquot; void **buf = NULL; size_t i, n = 0, size = 0; /* select ugids */ reset_dquot_search(); while( (dquot = get_next_dquot(q)) != NODQUOT) { if (!(dquot->obj.flags & mask)) continue; if (n >= size) { size += 100; buf = xrealloc(buf, size * sizeof(void *)); } buf[n] = (void *) dquot; n++; } /* drop ugids */ for (i = 0; i < n; i++) { dquot = (struct dquot *) buf[i]; drop_dquot(q, &(dquot->obj)); } } /* clean dquots memory */ void free_ugid_quota(struct ugid_quota *q) { unsigned int i, cnt; struct dquot *dquot, *dquot_free; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { for (i = 0; i < DQUOTHASHSIZE; i++) { dquot = q->dquot_hash[cnt][i]; while (dquot != NODQUOT) { dquot_free = dquot; dquot = dquot->dq_next; free(dquot_free); } q->dquot_hash[cnt][i] = NODQUOT; } } q->dquot_size = 0; } /* clean ugid info */ void clean_ugid_info( struct ugid_quota *q) { memset( &(q->info), 0, sizeof(struct ugid_info)); } /* Add a number of blocks and inodes to a quota */ void add_ugid_usage(struct ugid_quota *q, unsigned int type, unsigned int id, qint space) { struct dquot *lptr; /* __u32 i; qint b; */ if ((lptr = lookup_dquot_(q, id, type)) == NODQUOT) lptr = add_dquot_(q, id, type); /* i = lptr->obj.istat.qi_stat.icurrent; b = lptr->obj.istat.qi_stat.bcurrent; */ lptr->obj.istat.qi_stat.icurrent++; lptr->obj.istat.qi_stat.bcurrent += space; /* debug(LOG_DEBUG, "add %llu bytes to ugid(%u,%s): " "(i=%u,b:%llu) -> (i=%u,b=%llu)\n", space, lptr->obj.istat.qi_id, type2name(lptr->obj.istat.qi_type), i, b, lptr->obj.istat.qi_stat.icurrent, lptr->obj.istat.qi_stat.bcurrent); */ } /* reset usage stat of ugid objects */ void reset_ugid_usage( struct ugid_quota *q) { struct dquot *dq; reset_dquot_search(); while ((dq = get_next_dquot(q)) != NODQUOT) { dq->obj.istat.qi_stat.bcurrent = 0; dq->obj.istat.qi_stat.icurrent = 0; } } /* reset flags of ugid objects */ void reset_ugid_flags( struct ugid_quota *q, unsigned int mask) { struct dquot *dquot; reset_dquot_search(); while ((dquot = get_next_dquot(q)) != NODQUOT) { dquot->obj.flags &= ~mask; } } /* are there dirty ugid objects */ int is_ugid_dirty( struct ugid_quota *q) { struct dquot *dquot; reset_dquot_search(); while ((dquot = get_next_dquot(q)) != NODQUOT) { if (dquot->obj.flags & UGID_DIRTY) return 1; } return 0; } /* quota file data init; it should be called as A MUST */ void init_quota_data(struct qf_data *qd) { qd->version = 0; memset(&(qd->head), 0, sizeof(struct vz_quota_header)); memset(&(qd->stat), 0, sizeof(struct vz_quota_stat)); qd->path_len = 0; qd->path = NULL; memset(&qd->chksum, 0, sizeof(qd->chksum)); clean_ugid_info(&(qd->ugid_stat)); qd->ugid_stat.dquot_size = 0; memset(qd->ugid_stat.dquot_hash, 0, MAXQUOTAS * DQUOTHASHSIZE * sizeof(struct dquot *)); } /* quota file data cleaning */ void free_quota_data(struct qf_data *qd) { free_ugid_quota(&(qd->ugid_stat)); if (qd->path) free(qd->path); qd->path = NULL; init_quota_data(qd); } /* Get quota accounting point path */ char *get_quota_path(struct qf_data *qd) { char *path; path = NULL; if (mount_point) path = mount_point; else if (qd->path) path = qd->path; if (path) debug(LOG_DEBUG, "Actual quota path: %s\n", path); else error(EC_NOMOUNTPOINT, 0, "path to mount point can't be read " "from config file,\nuse -p option\n"); return path; } /* converts quota between different versions */ void convert_quota_stat( void *dest, int dest_ver, void *src, int src_ver) { struct vz_quota_stat *q; struct vz_quota_stat_old1 *q1; struct vz_quota_stat_old2 *q2; if ( (!dest) || (!src) || (!((dest_ver == QUOTA_V3) || (dest_ver == QUOTA_V2) || (dest_ver == QUOTA_V1))) || (!((src_ver == QUOTA_V3) || (src_ver == QUOTA_V2) || (src_ver == QUOTA_V1))) ) return; if (dest_ver == QUOTA_V1) { if (src_ver == QUOTA_V1) { /* v1 -> v1 */ memcpy( dest, src, sizeof(struct vz_quota_stat_old1)); } else if (src_ver == QUOTA_V2) { /* v2 -> v1 */ q1 = (struct vz_quota_stat_old1 *) dest; q2 = (struct vz_quota_stat_old2 *) src; q1->bhardlimit = size2block(q2->bhardlimit); q1->bsoftlimit = size2block(q2->bsoftlimit); q1->bexpire = q2->bexpire; q1->btime = q2->btime; q1->bcurrent = size2block(q2->bcurrent); q1->ihardlimit = q2->ihardlimit; q1->isoftlimit = q2->isoftlimit; q1->iexpire = q2->iexpire; q1->itime = q2->itime; q1->icurrent = q2->icurrent; q1->options = q2->options; } else if (src_ver == QUOTA_V3) { /* v3 -> v1 */ struct vz_quota_stat_old2 t; /* v3 -> v2 -> v1 */ convert_quota_stat( &t, QUOTA_V2, src, QUOTA_V3); convert_quota_stat( dest, QUOTA_V1, &t, QUOTA_V2); } } else if (dest_ver == QUOTA_V2) { if (src_ver == QUOTA_V1) { /* v1 -> v2 */ q1 = (struct vz_quota_stat_old1 *) src; q2 = (struct vz_quota_stat_old2 *) dest; q2->bhardlimit = block2size(q1->bhardlimit); q2->bsoftlimit = block2size(q1->bsoftlimit); q2->bexpire = q1->bexpire; q2->btime = q1->btime; q2->bcurrent = block2size(q1->bcurrent); q2->ihardlimit = q1->ihardlimit; q2->isoftlimit = q1->isoftlimit; q2->iexpire = q1->iexpire; q2->itime = q1->itime; q2->icurrent = q1->icurrent; q2->options = q1->options; } else if (src_ver == QUOTA_V2) { /* v2 -> v2 */ memcpy( dest, src, sizeof(struct vz_quota_stat_old2)); } else if (src_ver == QUOTA_V3) { /* v3 -> v2 */ q2 = (struct vz_quota_stat_old2 *) dest; q = (struct vz_quota_stat *) src; q2->bhardlimit = ker2size(q->dq_stat.bhardlimit); q2->bsoftlimit = ker2size(q->dq_stat.bsoftlimit); q2->bexpire = q->dq_info.bexpire; q2->btime = q->dq_stat.btime; q2->bcurrent = ker2size(q->dq_stat.bcurrent); q2->ihardlimit = q->dq_stat.ihardlimit; q2->isoftlimit = q->dq_stat.isoftlimit; q2->iexpire = q->dq_info.iexpire; q2->itime = q->dq_stat.itime; q2->icurrent = q->dq_stat.icurrent; q2->options = 0; } } else if (dest_ver == QUOTA_V3) { if (src_ver == QUOTA_V1) { /* v1 -> v3 */ struct vz_quota_stat_old2 t; /* v1 -> v2 -> v3 */ convert_quota_stat( &t, QUOTA_V2, src, QUOTA_V1); convert_quota_stat( dest, QUOTA_V3, &t, QUOTA_V2); } else if (src_ver == QUOTA_V2) { /* v2 -> v3 */ q2 = (struct vz_quota_stat_old2 *) src; q = (struct vz_quota_stat *) dest; q->dq_stat.bhardlimit = size2ker(q2->bhardlimit); q->dq_stat.bsoftlimit = size2ker(q2->bsoftlimit); q->dq_info.bexpire = q2->bexpire; q->dq_stat.btime = q2->btime; q->dq_stat.bcurrent = size2ker(q2->bcurrent); q->dq_stat.ihardlimit = q2->ihardlimit; q->dq_stat.isoftlimit = q2->isoftlimit; q->dq_info.iexpire = q2->iexpire; q->dq_stat.itime = q2->itime; q->dq_stat.icurrent = q2->icurrent; q->dq_info.flags = 0; } else if (src_ver == QUOTA_V3) { /* v3 -> v3 */ memcpy( dest, src, sizeof(struct vz_quota_stat)); } } } /* * Show hints and error message in case of quota on failed. */ static void error_quotaon(struct qf_data *qd, int err, char *buf) { /* show error message */ error(0, err, "Quota on syscall for id %d", quota_id); /* try to find the reason */ if (err == EBUSY) { error(0, 0, "\tPossible reasons:"); error(0, 0, "\t- Container's root is already mounted"); error(0, 0, "\t- there are opened files inside Container's private" " area"); error(0, 0, "\t- your current working directory is inside Container's"); error(0, 0, "\t private area"); if (buf) { error(0, 0, "\tCurrently used file(s):\n%s", buf); if (strlen(buf) > getpagesize() - 2) error(0, 0, "\t... more files found"); } } else if (err == EEXIST) { error(0, 0, "\tNative quota is already running " "for this partition."); } /* exit with error status */ error(EC_VZCALL, 0, NULL); } /* turn quota on * return 0 if success, * <0 if quota is on */ int quota_syscall_on(struct qf_data *qd) { int rc; int retry = 0; int sleeptime = 1; struct vz_quota_stat *stat; struct ugid_quota *ugid_stat; char *path; char *buf; ASSERT(qd); stat = &qd->stat; ugid_stat = &qd->ugid_stat; path = get_quota_path(qd); /* create new quota */ rc = vzquotactl_syscall(VZ_DQ_CREATE, quota_id, stat, NULL); if (rc < 0) { if (errno == EEXIST) return rc; else error(EC_VZCALL, errno, "Quota create for id %d", quota_id); } /* null ugid config */ ugid_stat->info.config.flags = 0; ugid_stat->info.config.count = 0; /* set kernel flag of user/group quota status */ if (qd->head.flags & QUOTA_UGID_ON) ugid_stat->info.config.flags |= VZDQUG_ON; /* set ugid config */ if ((ugid_stat->info.config.flags & VZDQUG_ON) && !ugid_stat->info.config.limit) /* set indicator of ugids are broken if quota is on and limit=0 */ ugid_stat->info.config.flags |= VZDQUG_FIXED_SET; rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_SETCONFIG, quota_id, 0, 0, &(ugid_stat->info.config)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_setconfig syscall for id %d", quota_id); /* set ugid graces and flags */ if (ugid_stat->info.config.flags & VZDQUG_ON) { rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_SETGRACE, quota_id, 0, 0, &(ugid_stat->info.ugid_info)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_setgrace syscall for id %d", quota_id); } /* add ugid objects */ if ((ugid_stat->info.config.flags & VZDQUG_ON) && ugid_stat->dquot_size && ugid_stat->info.config.limit) { struct dquot *obj[ugid_stat->dquot_size]; struct dquot *dq; unsigned int b_size, loaded, i, lim; struct vz_quota_iface *buf; /* drop dummy entries */ drop_dummy_ugid(ugid_stat); /* create temp buf */ reset_dquot_search(); for (i = 0; (dq = get_next_dquot(ugid_stat)) != NODQUOT; i++) obj[i] = dq; /* sort if number of ugid objects is over the limit */ if (ugid_stat->dquot_size > ugid_stat->info.config.limit) qsort(obj, ugid_stat->dquot_size, sizeof(struct dquot *), &comp_dquot); /* load by portions */ lim = min(ugid_stat->dquot_size, ugid_stat->info.config.limit); b_size = IO_BUF_SIZE / sizeof(struct vz_quota_iface); b_size = min(b_size, lim); buf = xmalloc(b_size * sizeof(struct vz_quota_iface)); loaded = 0; for (i = 0; i < lim; i += b_size) { unsigned int j; /* fill buf */ for (j = i; j < min(lim, i + b_size); j++) { dq = obj[j]; memcpy( &buf[j-i], &(dq->obj.istat), sizeof(struct vz_quota_iface)); } /* push buf to kernel */ debug(LOG_DEBUG, "push ugids from %u to %u...\n", i, j - 1); rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_ADDSTAT, quota_id, 0, j - i, buf); if (rc < 0) { free(buf); error(EC_VZCALL, errno, "Quota ugid_addstat syscall for id %d", quota_id); } debug(LOG_DEBUG, "%u ugids were successfully pushed\n", rc); for (j = 0; j < (unsigned)rc; j++) debug(LOG_DEBUG,"%5d: ugid (%s %u) was pushed\n", i + j, type2name(buf[j].qi_type), buf[j].qi_id); loaded += rc; } free(buf); /* indicate to kernel that ugid limit is exceeded */ if (loaded < ugid_stat->dquot_size) { debug(LOG_WARNING, "Quotas were not loaded for some users/groups for id " "%d due to ugid limit\n", quota_id); ugid_stat->info.config.flags |= VZDQUG_FIXED_SET; rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_SETCONFIG, quota_id, 0, 0, &(ugid_stat->info.config)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_setconfig syscall for id %d", quota_id); } /* mark loaded entries */ for (i = 0; i < loaded; i++) { dq = obj[i]; dq->obj.flags |= UGID_LOADED; } ugid_stat->info.config.count = loaded; /* mark unloaded entries as dirty */ for (i = loaded; i < ugid_stat->dquot_size; i++) { dq = obj[i]; dq->obj.flags |= UGID_DIRTY; } /* set number of ugid objects in buffer */ ugid_stat->info.buf_size = ugid_stat->dquot_size; } buf = NULL; /* turn quota on */ for (retry = 0; ; retry++) { /* * If this is the last chance to enable quota, allocate memory buffer * and ask kernel to find currently used files. */ if (retry == MAX_RETRY) { buf = (char *)malloc(getpagesize()); *buf = '\0'; } rc = vzquotactl_syscall(VZ_DQ_ON, quota_id, (struct vz_quota_stat *)buf, path); if (rc >= 0) break; if (errno != EBUSY || retry >= MAX_RETRY) { int save_errno; save_errno = errno; vzquotactl_syscall(VZ_DQ_DESTROY, quota_id, NULL, NULL); error_quotaon(qd, save_errno, buf); } usleep(sleeptime * 1000); sleeptime = sleeptime * 2; } if (ugid_stat->info.config.flags & VZDQUG_ON) debug(LOG_INFO, "User/group quota was activated with ugid limit of %u\n", ugid_stat->info.config.limit); else debug(LOG_INFO, "User/group quota is off\n"); return 0; } /* * Show hints and error message in case of quota off failed. */ static void error_quotaoff(struct qf_data *qd, int err, char *buf) { /* show error message */ error(0, err, "Quota off syscall for id %d", quota_id); /* try to find the reason */ if (err == EBUSY && (option & FL_FORCE)) /* Hmm, shouldn't be */ error(0, 0, "Forced quota off failed. Device is busy\n"); else if (err == EBUSY) { error(0, 0, "\tPossible reasons:"); error(0, 0, "\t- Container's root is not unmounted"); error(0, 0, "\t- there are opened files inside container's root/private" " area"); error(0, 0, "\t- your current working directory is inside a container directory"); error(0, 0, "\t root/private area"); if (buf) { error(0, 0, "\tCurrently used file(s):\n%s", buf); if (strlen(buf) > getpagesize() - 2) error(0, 0, "\t... more files found"); } } else if (err == EINVAL && (option & FL_FORCE)) { error(0, 0, "\tPossible reasons:"); error(0, 0, "\t- Kernel doesn't support forced quota off"); } /* exit with error status */ error(EC_VZCALL, 0, NULL); } /* turn quota off * return 0 if success, * OENT if quota is off */ int quota_syscall_off(struct qf_data *qd) { int rc; int retry = 0; int sleeptime = 1; int broken = 0; struct vz_quota_stat *stat; struct ugid_quota *ugid_stat; int cmd; char *buf; ASSERT(qd); stat = &qd->stat; ugid_stat = &qd->ugid_stat; cmd = VZ_DQ_OFF; buf = NULL; /* turn quota off */ for (retry = 0; ; retry++) { /* * If this is the last chance to disable quota, allocate memory buffer * and ask kernel to find currently used files. */ if (retry == MAX_RETRY && debug_level >= LOG_WARNING) { buf = (char *)malloc(getpagesize()); *buf = '\0'; } rc = vzquotactl_syscall(cmd, quota_id, NULL, buf); if (rc >= 0) break; if (errno == EALREADY || errno == EIO) {/* quota is created and off */ broken = errno; goto destroy; } if (errno == ENOENT) return rc; /* quota is not created */ if (errno != EBUSY || retry >= MAX_RETRY) error_quotaoff(qd, errno, buf); usleep(sleeptime * 1000); sleeptime = sleeptime * 2; /* * When 'force' option is set, try to use VZ_DQ_OFF first, * and in case of failure use VZ_DQ_OFF_FORCED. */ if (errno == EBUSY && (option & FL_FORCE) && (retry >= (MAX_RETRY - 1))) { cmd = VZ_DQ_OFF_FORCED; /* Mark as dirty now */ qd->head.flags |= QUOTA_DIRTY; } } /* get VE stat */ rc = vzquotactl_syscall(VZ_DQ_GETSTAT, quota_id, stat, NULL); if (rc < 0) error(EC_VZCALL, errno, "Quota getstat syscall for id %d", quota_id); /* get ugid config */ rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_GETCONFIG, quota_id, 0, 0, &(ugid_stat->info.config)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_getconfig syscall for id %d", quota_id); /* get ugid graces */ if (ugid_stat->info.config.flags & VZDQUG_ON) { rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_GETGRACE, quota_id, 0, 0, &(ugid_stat->info.ugid_info)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_getgrace syscall for id %d", quota_id); } /* get ugid objects */ if ((ugid_stat->info.config.flags & VZDQUG_ON) /* TODO save loaded objs if limit was set to 0 ? * && ugid_stat->info.config.limit */ && ugid_stat->info.config.count) { struct dquot *dq; unsigned int b_size, i; struct vz_quota_iface *buf; /* get by portions */ b_size = IO_BUF_SIZE / sizeof(struct vz_quota_iface); b_size = min(b_size, ugid_stat->info.config.count); buf = xmalloc(b_size * sizeof(struct vz_quota_iface)); for (i = 0; i < ugid_stat->info.config.count; i += b_size) { int j; j = min(b_size, ugid_stat->info.config.count - i); debug(LOG_DEBUG, "get ugids from %u to %u...\n", i, i + j - 1); rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_GETSTAT, quota_id, i, j, buf); if (rc < 0) { free(buf); error(EC_VZCALL, errno, "Quota ugid_getstat syscall for id %d", quota_id); } debug(LOG_DEBUG, "%u ugids were received\n", rc); for (j = 0; j < rc; j++) { if (buf[j].qi_type >= MAXQUOTAS) error(EC_VZCALL, 0, "Quota ugid_getstat syscall for id %d returned " "ugid object with invalid type (id=%u, type=%u)", quota_id, buf[j].qi_id, buf[j].qi_type); dq = lookup_dquot_(ugid_stat, buf[j].qi_id, buf[j].qi_type); if (dq == NODQUOT) { debug(LOG_DEBUG,"%5d: add ugid (%s %u)\n", i + j, type2name(buf[j].qi_type), buf[j].qi_id); dq = add_dquot_(ugid_stat, buf[j].qi_id, buf[j].qi_type); } else { debug(LOG_DEBUG, "%5d: update ugid (%s %u)\n", i + j, type2name(buf[j].qi_type), buf[j].qi_id); } memcpy( &(dq->obj.istat), &buf[j], sizeof(struct vz_quota_iface)); dq->obj.flags &= ~UGID_LOADED; } } free(buf); /* delete entries destroyed by kernel */ drop_ugid_by_flags(ugid_stat, UGID_LOADED); /* set number of ugid objects in buffer */ ugid_stat->info.buf_size = ugid_stat->dquot_size; /* reset number of loaded ugid items */ ugid_stat->info.config.count = 0; } /*TODO see upper... * else if ((ugid_stat->info.config.flags & VZDQUG_ON) && ugid_stat->info.config.count) reset_ugid_flags(ugid_stat, UGID_LOADED); */ /* drop user/group quota kernel status */ ugid_stat->info.config.flags &= ~VZDQUG_ON; destroy: /* destroy quota */ rc = vzquotactl_syscall(VZ_DQ_DESTROY, quota_id, NULL, NULL); if (rc < 0) error(EC_VZCALL, errno, "Quota destroy syscall for id %d", quota_id); if (broken) { errno = broken; return -1; } return 0; } /* get quota stat * return 0 if success, * <0 if quota is off */ int quota_syscall_stat(struct qf_data *qd, int no_ugid_stat) { int rc; int loop_counter; struct vz_quota_stat *stat; struct ugid_quota *ugid_stat; ASSERT(qd); stat = &qd->stat; ugid_stat = &qd->ugid_stat; /* get VE stat */ rc = vzquotactl_syscall(VZ_DQ_GETSTAT, quota_id, stat, NULL); if (rc < 0) { if (errno == ENOENT) return rc; else error(EC_VZCALL, errno, "Quota getstat syscall for id %d", quota_id); } /* return if no ugid stat is required */ if (no_ugid_stat) return 0; loop_counter = 0; ugid_loop: if (loop_counter++ > 25) error(EC_VZCALL, 0, "Can't get all ugid records at once"); /* get ugid config */ rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_GETCONFIG, quota_id, 0, 0, &(ugid_stat->info.config)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_getconfig syscall for id %d", quota_id); /* get ugid graces */ if (ugid_stat->info.config.flags & VZDQUG_ON) { rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_GETGRACE, quota_id, 0, 0, &(ugid_stat->info.ugid_info)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_getgrace for id %d", quota_id); } /* get ugid objects */ if ((ugid_stat->info.config.flags & VZDQUG_ON) && ugid_stat->info.config.count && ugid_stat->info.config.limit) { struct dquot *dq; unsigned int b_size, j; struct vz_quota_iface *buf; struct dquot **dq_buf = NULL; /* get the whole stat to minimize quota inconsistency */ b_size = ugid_stat->info.config.count + 100; buf = xmalloc(b_size * sizeof(struct vz_quota_iface)); debug(LOG_DEBUG, "get ugids from %u to %u...", 0, b_size); rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_GETSTAT, quota_id, 0, b_size, buf); if (rc < 0) { free(buf); error(EC_VZCALL, errno, "Quota ugid_getstat syscall for id %d", quota_id); } debug(LOG_DEBUG, " %u received\n", rc); /* loop while we have all kernel ugid at once */ if ((unsigned)rc == b_size) { free(buf); goto ugid_loop; } if (rc > 0) dq_buf = xmalloc(b_size * sizeof(struct dquot *)); for (j = 0; j < (unsigned)rc; j++) { if (buf[j].qi_type >= MAXQUOTAS) error(EC_VZCALL, 0, "Quota ugid_getstat syscall for id %d returned " "ugid object with invalid type (id=%u, type=%u)", quota_id, buf[j].qi_id, buf[j].qi_type); dq = lookup_dquot_(ugid_stat, buf[j].qi_id, buf[j].qi_type); if (dq == NODQUOT) { debug(LOG_DEBUG,"%5d: add ugid (%s %u)\n", j, type2name(buf[j].qi_type), buf[j].qi_id); dq = add_dquot_(ugid_stat, buf[j].qi_id, buf[j].qi_type); } else { debug(LOG_DEBUG, "%5d: update ugid (%s %u)\n", j, type2name(buf[j].qi_type), buf[j].qi_id); } memcpy( &(dq->obj.istat), &buf[j], sizeof(struct vz_quota_iface)); /* handle deleted entries */ dq->obj.flags &= ~UGID_LOADED; dq_buf[j] = dq; } free(buf); debug(LOG_DEBUG, "received %d ugids were processed\n", rc); /* delete entries destroyed by kernel */ drop_ugid_by_flags(ugid_stat, UGID_LOADED); /* handle deleted entries */ for (j = 0; j < (unsigned)rc; j++) { debug(LOG_DEBUG,"%5d: mark ugid (%s %u) as loaded\n", j, type2name(dq_buf[j]->obj.istat.qi_type), dq_buf[j]->obj.istat.qi_id); dq_buf[j]->obj.flags |= UGID_LOADED; } if (dq_buf) free(dq_buf); /* set number of ugid objects in buffer */ ugid_stat->info.buf_size = ugid_stat->dquot_size; } return 0; } /* set quota limits * return 0 if success, * <0 if quota is off */ int quota_syscall_setlimit(struct qf_data *qd, int no_stat, int no_ugid_stat) { int rc; struct vz_quota_ugid_stat config; struct vz_quota_stat *stat; struct ugid_quota *ugid_stat; ASSERT(qd); stat = &qd->stat; ugid_stat = &qd->ugid_stat; /* set VE limits */ if (!no_stat) { rc = vzquotactl_syscall(VZ_DQ_SETLIMIT, quota_id, stat, NULL); if (rc < 0) { if (errno == ENOENT) return rc; else error(EC_VZCALL, errno, "Quota setlimit syscall for id %d", quota_id); } } if (no_ugid_stat) return 0; /* get ugid config */ rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_GETCONFIG, quota_id, 0, 0, &config); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_getconfig syscall for id %d", quota_id); /* nothing to change */ if (ugid_stat->info.config.limit == config.limit) return 0; /* user/group quota is inactive in kernel */ if (!(ugid_stat->info.config.flags & VZDQUG_ON)) { /* debug(LOG_WARNING, "User/group quota is inactive for id %d, " "ugid limit change will take effect after " "user/group quota activation\n", quota_id); */ return 0; } /* limit was exceeded or no ugids were loaded */ if (ugid_stat->info.config.flags & VZDQUG_FIXED_SET || !config.limit) { debug(LOG_WARNING, "Number of ugid objects exceeded the ugid limit; " "ugid limit change for id %d will take " "effect after quota restart only\n", quota_id); } /* set ugid limit */ rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_SETCONFIG, quota_id, 0, 0, &(ugid_stat->info.config)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_setmax syscall for id %d", quota_id); /* set indicator of limit was changed: 0 -> x */ if (!config.limit) { errno = EBUSY; return -1; } return 0; } static void dqstat2dqblk(struct dq_stat * ulimit, struct _if_dqblk * dqb) { dqb->dqb_bsoftlimit = ulimit->bsoftlimit; dqb->dqb_bhardlimit = ulimit->bhardlimit; dqb->dqb_isoftlimit = ulimit->isoftlimit; dqb->dqb_ihardlimit = ulimit->ihardlimit; } static void vzdqinfo2dqinfo(struct dq_info * info, struct _if_dqinfo * dqi) { dqi->dqi_bgrace = info->bexpire; dqi->dqi_igrace = info->iexpire; } #define VZFS_DEV "/dev/vzfs" static int quotactl_syscall(int cmd, int type, const char * root_path, int id, void * data) { char path[PATH_MAX]; int err, qerr = 0; int fd; /* we should chroot to VE priv dir */ sprintf(path, "%s/root", root_path); fd = open("/", O_RDONLY); if (fd < 0) return -1; if ((err = chroot(path)) != 0) goto out; qerr = quotactl(QCMD(cmd, type), VZFS_DEV, id, data); if ((err = fchdir(fd)) != 0) goto out; err = chroot("."); out: close(fd); if (qerr != 0) return qerr; return err; } int vzquotactl_ugid_setgrace(struct qf_data *data, int type, struct dq_info *vzdqinfo) { struct vz_quota_ugid_setinfo inf; long err; char *path; path = get_quota_path(data); memset(&inf, 0, sizeof(inf)); vzdqinfo2dqinfo(vzdqinfo, &inf.dqi); inf.dqi.dqi_valid = IIF_BGRACE | IIF_IGRACE; inf.type = type; err = vzquotactl_ugid_syscall(VZ_DQ_UGID_SETINFO, quota_id, 0, 0, &inf); if (err == -EINVAL || err == -EPERM) { struct mem_dqinfo _info; memset(&_info, 0, sizeof(_info)); _info.dqi_bgrace = vzdqinfo->bexpire; _info.dqi_igrace = vzdqinfo->iexpire; err = quotactl_syscall(Q_SETGRACE, type, path, 0, (void *) &_info); } return err; } int vzquotactl_ugid_setlimit(struct qf_data *data, int id, int type, struct dq_stat *vzdqlim) { struct vz_quota_ugid_setlimit lim; long err; char *path; path = get_quota_path(data); memset(&lim, 0, sizeof(lim)); dqstat2dqblk(vzdqlim, &lim.dqb); lim.dqb.dqb_valid = QIF_LIMITS; lim.type = type; lim.id = id; err = vzquotactl_ugid_syscall(VZ_DQ_UGID_SETLIMIT, quota_id, 0, 0, &lim); if (err == -EINVAL || err == -EPERM) { struct mem_dqblk dqb; memset(&dqb, 0, sizeof(dqb)); dqb.dqb_bsoftlimit = vzdqlim->bsoftlimit; dqb.dqb_bhardlimit = vzdqlim->bhardlimit; dqb.dqb_isoftlimit = vzdqlim->isoftlimit; dqb.dqb_ihardlimit = vzdqlim->ihardlimit; err = quotactl_syscall(Q_SETQLIM, type, path, id, (void *) &dqb); } return err; } /* * Return path to quota config according to VZ3 scheme */ static char* get_quota_file_name_vz3(unsigned int quota_id, char *buf, int bufsize) { memset(buf, 0, bufsize); bufsize--; if (snprintf(buf, bufsize, "%s/%s.%u", VZQUOTA_FILES_PATH_VZ3, VZQUOTA_FILE_NAME, quota_id) >= bufsize) error(EC_NOQUOTAFILE, 0, "quota.%d file name is too long\n", quota_id); return buf; } /* * Return path to quota config according to VZ4 scheme (or) * exit on critical errors (or) * return NULL if quota file name can't be obtained */ static char *get_quota_file_name_vz4(unsigned int quota_id, char *buf, int bufsize) { char *ve_priv; memset(buf, 0, bufsize); bufsize--; if (option & FL_PATH) { char *fs; int ret; char *p1, *p2; ASSERT(mount_point); p1 = xstrdup(mount_point); p2 = xstrdup(mount_point); ve_priv = dirname(p1); fs = basename(p2); /* ve_priv and fs can't be NULL even in case of error */ ret = snprintf(buf, bufsize, "%s/quota.%s", ve_priv, fs); free(p1); free(p2); if (ret >= bufsize) { error(EC_NOQUOTAFILE, 0, "path to quota file is " "too long\n"); return NULL; } } else { /* * mount point is not set. * * TODO: * We have to parse VE config file to obtain path to VE * private and use default relative path to 'fs'. */ return NULL; } return buf; } /* * Return path to quota config file for given quota_id, or exit with error */ char *get_quota_file_name(unsigned int quota_id, char *buf, int bufsize, int flags) { char *name; struct stat s; int ret; if (flags & O_CREAT) { /* * vzquota init QID -p path [-R] * * We just want to create a quota file. The -p /PATH/TO/FS * option (path to quota accounting point) must be used with * vzquota init. * * New files can be created in two places, it depends on * -R option, that specifies do we want to use relative path * or absolute path to accounting point: * * (1) The -R option is set: * quota config file is /PATH/TO/quota.FS, i.e. * in most cases /vz/private/ID/quota.fs * * (2) The -R option is omitted: * quota config file will be created in old (VZ3) place: * /var/vzquota/quota.QID */ if (option & FL_RELATIVE) name = get_quota_file_name_vz4(quota_id, buf, bufsize); else name = get_quota_file_name_vz3(quota_id, buf, bufsize); debug(LOG_DEBUG, "Create config file %s\n", name); return name; } /* * vzquota on/off/drop/... QID * * Try to find quota file according to VZ4 format first. */ name = get_quota_file_name_vz4(quota_id, buf, bufsize); /* * Now we want just to ensure, that VZ4 quota config file exists, and * if not - fall back to VZ3 path. Actual open() will be done later in * open_quota_file(). */ if (name) { ret = stat(name, &s); if (ret < 0) ret = errno; } else ret = ENOENT; switch (ret) { case 0: /* Ok, VZ4 file looks alive */ debug(LOG_DEBUG, "Open: looking for %s ... ok\n", name); break; case ENOENT: if (name) debug(LOG_DEBUG, "Open: looking for %s ... failed\n", name); /* * Backward compatibility, try to find it in old (VZ3) place * This behaviour is disabled when the -R option is used. */ if (!(option & FL_RELATIVE)) { name = get_quota_file_name_vz3(quota_id, buf, bufsize); debug(LOG_DEBUG, "set quota config name to %s\n", name); break; } /* Fall through ... */ default: error(EC_NOQUOTAFILE, errno, "can't open quota config file %s\n", name); } return name; } int get_quota_version(struct vz_quota_header *head) { switch(head->magic) { case MAGIC_V3: return QUOTA_V3; case MAGIC_V2: return QUOTA_V2; case MAGIC_V1: return QUOTA_V1; } error(0, 0, "Can't detect quota file version; file is not a VZ quota file"); return -1; } int unlink_quota_file(unsigned int quota_id, const char *name) { char buf[MAXFILENAMELEN]; int status; if (!name) name = get_quota_file_name(quota_id, buf, MAXFILENAMELEN, 0); if ((status = unlink(name)) < 0) { error(0, errno, "unlink quota file '%s'", name); return status; } return 0; } static int reformat_quota (int fd) { int rc; struct qf_data qd; init_quota_data(&qd); rc = read_quota_file(fd, &qd, IOF_ALL); if (rc < 0) return rc; /* v2 -> v3 requires quota recalculation */ if (qd.version == QUOTA_V2) qd.head.flags |= QUOTA_DIRTY; /* v1 -> v3 */ //TODO saw@ thinks about recalculation rc = write_quota_file(fd, &qd, IOF_ALL); if (rc < 0) return rc; return 0; } /* computes checksum of quota file, checksum being in the end of file */ int chksum_quota_file(int fd, chksum_t *chksum) { off_t fsize; size_t b_size, size, i, j; chksum_t *buf; int err; fsize = lseek(fd, 0, SEEK_END); if (fsize <= 0) return EC_QUOTAFILE; fsize -= sizeof(chksum_t); debug(LOG_DEBUG, "Computing hash of quota file (first %u bytes)\n", fsize); memset(chksum, 0, sizeof(chksum_t)); b_size = (IO_BUF_SIZE / sizeof(chksum_t)) * sizeof(chksum_t); buf = xmalloc(b_size); for (i = 0; i < fsize; i += b_size) { size = (i + b_size < fsize) ? b_size : fsize - i; memset(buf, 0, b_size); err = read_field(fd, buf, size, i); if (err < 0) { free(buf); return err; } for (j = 0; j < b_size / sizeof(chksum_t); j++) *chksum ^= buf[j]; } debug(LOG_DEBUG, "Hash is 64bit number %llu\n", *chksum); free(buf); return 0; } int do_check_quota_file(int fd, int reformat) { int rc; struct qf_data qd; init_quota_data(&qd); rc = read_quota_file(fd, &qd, IOF_HEAD); if (rc < 0) return rc; if (qd.version != QUOTA_CURRENT) { if (!reformat) { debug(LOG_WARNING, "Quota file for id %d is in old quota format"); return -1; } /* convert quota */ if (reformat_quota(fd) < 0) { free_quota_data(&qd); return -1; } } else { /* verify checksum*/ chksum_t chksum; rc = read_quota_file(fd, &qd, IOF_CHKSUM); if (rc < 0) return rc; chksum_quota_file(fd, &chksum); if (memcmp(&chksum, &qd.chksum, sizeof(chksum_t))) { debug(LOG_ERROR, "Quota file check sum is invalid for id %d; " "file is broken\n", quota_id); return -1; } } free_quota_data(&qd); return 0; } int check_quota_file(int fd) { return do_check_quota_file(fd, 1); } int open_quota_file(unsigned int quota_id, const char *name, int flags) { int fd; char buf[MAXFILENAMELEN]; if (!name) name = get_quota_file_name(quota_id, buf, MAXFILENAMELEN, flags); actual_config_file = xstrdup(name); if ((fd = open(name, flags, 00600)) < 0) { if (!(flags & O_CREAT)) { error(0, errno, "Can't open quota file for id %d, " "maybe you need to reinitialize quota", quota_id); } else if (errno != EEXIST) error(0, errno, "create quota file '%s'", name); return fd; } if (flags & O_RDWR) { if (flock(fd, LOCK_EX | LOCK_NB) < 0) error(EC_LOCK, 0, "can't lock quota file, some quota operations " "are performing for id %d", quota_id); } debug(LOG_DEBUG, "file %s %d was opened\n", name, fd); return fd; } int close_quota_file(int fd) { fsync(fd); flock(fd, LOCK_UN); debug(LOG_DEBUG, "file %d was closed\n", fd); return close(fd); } int read_field(int fd, void *field, size_t size, off_t offset) { int err = pread(fd, field, size, offset); if (err < 0) { error(0, errno, "read quota file"); return err; } else if ((unsigned)err != size) { error(0, 0, "quota file is corrupted"); return -E_FILECORRUPT; } return 0; } int read_quota_file(int fd, struct qf_data *q, int io_flags) { off_t err; int struct_size = sizeof(struct vz_quota_stat); debug(LOG_DEBUG, "Start reading quota file\n"); /* read header */ if (io_flags & IOF_HEAD) { debug(LOG_DEBUG, "Reading header from file\n"); err = read_field(fd, &(q->head), sizeof(struct vz_quota_header), QF_OFF_HEADER); if (err < 0) return err; /* get version */ q->version = get_quota_version( &(q->head)); if (q->version < 0) return -1; } /* read 1-level quota stat */ if (io_flags & IOF_STAT) { void *st; debug(LOG_DEBUG, "Reading 1-level quota stat from file\n"); switch(q->version) { case QUOTA_V1: struct_size = sizeof(struct vz_quota_stat_old1); break; case QUOTA_V2: struct_size = sizeof(struct vz_quota_stat_old2); break; case QUOTA_V3: struct_size = sizeof(struct vz_quota_stat); break; default : error(0, 0, "File is not a VZ quota file"); return -1; } st = xmalloc(struct_size); if ((err = read_field(fd, st, struct_size, QF_OFF_STAT)) < 0) return err; convert_quota_stat( &(q->stat), QUOTA_CURRENT, st, q->version); free(st); } /* read path */ if (io_flags & IOF_PATH) { debug(LOG_DEBUG, "Reading mount point path from file\n"); err = read_field(fd, &(q->path_len), sizeof(size_t), QF_OFF_PATH_LEN(struct_size)); if (err < 0) return err; if (q->path) free(q->path); q->path = NULL; if (q->path_len) { q->path = xmalloc( q->path_len + 1); err = read_field(fd, q->path, q->path_len, QF_OFF_PATH(struct_size)); if (err < 0) return err; } debug(LOG_DEBUG, "Read quota path: %s\n", q->path ? q->path : "[relative]"); } /* read 2-level quota info */ if (io_flags & IOF_UGID_INFO) { clean_ugid_info(&(q->ugid_stat)); if (q->version == QUOTA_CURRENT) { debug(LOG_DEBUG, "Reading 2-level quota info from file\n"); err = read_field(fd, &(q->ugid_stat.info), sizeof(struct ugid_info), QF_OFF_UGID_INFO(q->path_len)); if (err < 0) return err; } } /* read ugid objects */ if (io_flags & IOF_UGID_BUF) { free_ugid_quota(&(q->ugid_stat)); if (q->version == QUOTA_CURRENT) { debug(LOG_DEBUG, "Reading ugid objects from file: %u entries total\n", q->ugid_stat.info.buf_size); if (q->ugid_stat.info.buf_size > 0) { size_t b_size, size, i, j; struct ugid_obj *buf; struct dquot *dq; b_size = IO_BUF_SIZE / sizeof(struct ugid_obj); buf = xmalloc(b_size * sizeof(struct ugid_obj)); for (i = 0; i < q->ugid_stat.info.buf_size; i += b_size) { size = (i + b_size < q->ugid_stat.info.buf_size) ? b_size : q->ugid_stat.info.buf_size - i; err = read_field(fd, buf, size * sizeof(struct ugid_obj), QF_OFF_UGID_BUF(q->path_len) + i * sizeof(struct ugid_obj)); if (err < 0) { free(buf); return err; } for (j = 0; j < size; j++) { if (buf[j].istat.qi_type >= MAXQUOTAS) error(EC_QUOTAFILE, 0, "%u ugid object has incorrect type: id=%u, type=%u; " "quota file is corrupted", i*b_size + j, buf[j].istat.qi_id, buf[j].istat.qi_type); dq = lookup_dquot(&(q->ugid_stat), &buf[j]); if (dq == NODQUOT) dq = add_dquot(&(q->ugid_stat), &buf[j]); else memcpy( &(dq->obj), &buf[j], sizeof(struct ugid_obj)); } } free(buf); } } if (q->ugid_stat.dquot_size != q->ugid_stat.info.buf_size) error(EC_QUOTAFILE, 0, "Number of ugid objects read from quota file is not " "equal to one in 2-level quota statistics; " "quota file is corrupted for id %d\n", quota_id); } /* read checksum */ if ((io_flags & IOF_CHKSUM) && (q->version >= QUOTA_V3)) { off_t fsize; debug(LOG_DEBUG, "Reading quota file checksum\n"); fsize = lseek(fd, 0, SEEK_END); if (fsize <= 0) return EC_QUOTAFILE; err = read_field(fd, &q->chksum, sizeof(q->chksum), fsize - sizeof(q->chksum)); if (err < 0) return err; debug(LOG_DEBUG, "Checksum is 64bit number %llu\n", q->chksum); } debug(LOG_DEBUG, "Quota file was read\n"); return 0; } int write_field(int fd, const void *field, size_t size, off_t offset) { int err = pwrite(fd, field, size, offset); if (err < 0 || (unsigned)err != size) { error(0, errno, "write quota file"); return err; } return 0; } /* this function should be called with io_flags=IOF_ALL cause of checksum */ int write_quota_file(int fd, struct qf_data *q, int io_flags) { off_t err; q->version = QUOTA_CURRENT; q->head.magic = MAGIC_CURRENT; debug(LOG_DEBUG, "Start writing quota file\n"); /* write header */ if (io_flags & IOF_HEAD) { debug(LOG_DEBUG, "Writing header to file\n"); err = write_field(fd, &(q->head), sizeof(struct vz_quota_header), QF_OFF_HEADER); if (err < 0) return err; } /* write 1-level quota stat */ if (io_flags & IOF_STAT) { debug(LOG_DEBUG, "Writing 1-level quota stat to file\n"); err = write_field(fd, &(q->stat), sizeof(struct vz_quota_stat), QF_OFF_STAT); if (err < 0) return err; } /* write path */ if (io_flags & IOF_PATH) { debug(LOG_DEBUG, "Writing mount point path to file\n"); q->path_len = q->path ? strlen(q->path) : 0; err = write_field(fd, &(q->path_len), sizeof(size_t), QF_OFF_PATH_LEN(sizeof(struct vz_quota_stat))); if (err < 0) return err; err = write_field(fd, q->path, q->path_len, QF_OFF_PATH(sizeof(struct vz_quota_stat))); if (err < 0) return err; } /* write 2-level quota info */ if (io_flags & IOF_UGID_INFO) { debug(LOG_DEBUG, "Writing 2-level quota info to file\n"); /* at this point info.buf_size MUST be equal to dquot_size */ err = write_field(fd, &(q->ugid_stat.info), sizeof(struct ugid_info), QF_OFF_UGID_INFO(q->path_len)); if (err < 0) return err; } /* write ugid objects */ if (io_flags & IOF_UGID_BUF) { debug(LOG_DEBUG, "Writing ugid objects to file: %u entries total\n", q->ugid_stat.dquot_size); if (q->ugid_stat.info.buf_size != q->ugid_stat.dquot_size) error(EC_QUOTAFILE, 0, "Number of stored ugids objects is not equal to " "one in 2-level quota statistics; " "quota file is corrupted for id %d\n", quota_id); if (q->ugid_stat.dquot_size > 0) { size_t b_size, size, i, j; struct ugid_obj *buf; struct dquot *dq; b_size = IO_BUF_SIZE / sizeof(struct ugid_obj); buf = xmalloc(b_size * sizeof(struct ugid_obj)); reset_dquot_search(); size = 0; for (i = 0; ; i++) { dq = get_next_dquot(&(q->ugid_stat)); if ((dq == NODQUOT) || (i >= b_size)) { j = (i >= b_size) ? b_size : i; err = write_field(fd, buf, j * sizeof(struct ugid_obj), QF_OFF_UGID_BUF(q->path_len) + size * sizeof(struct ugid_obj)); if (err < 0) { free(buf); return err; } size += j; i = 0; } if (dq == NODQUOT) break; memcpy( &buf[i], &(dq->obj), sizeof(struct ugid_obj)); } free(buf); q->ugid_stat.info.buf_size = size; if (q->ugid_stat.info.buf_size != q->ugid_stat.dquot_size) error(EC_QUOTAFILE, 0, "Number of saved ugids objects is not equal to " "one in 2-level quota statistics; " "quota file is corrupted for id %d\n", quota_id); } /* truncate file */ err = ftruncate(fd, QF_OFF_UGID_BUF(q->path_len) + q->ugid_stat.dquot_size * sizeof(struct ugid_obj)); if (err < 0) return err; } /* compute and write checksum */ if (io_flags & IOF_CHKSUM) { off_t fsize; debug(LOG_DEBUG, "Writing quota file checksum\n"); /* complete file with null checksum */ fsize = lseek(fd, 0, SEEK_END); if (fsize <= 0) return EC_QUOTAFILE; memset(&q->chksum, 0, sizeof(q->chksum)); err = write_field(fd, &q->chksum, sizeof(q->chksum), fsize); if (err < 0) return err; /* compute checksum */ err = chksum_quota_file(fd, &q->chksum); if (err < 0) return err; /* write checksum */ err = write_field(fd, &q->chksum, sizeof(q->chksum), fsize); if (err < 0) return err; } debug(LOG_DEBUG, "Quota file was written\n"); return 0; } vzquota-3.1.orig/src/.gitignore0000644000000000000000000000000412023504012013451 0ustar *.o vzquota-3.1.orig/src/stat.c0000644000000000000000000002233412023504012012612 0ustar /* * Copyright (C) 2000-2012, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "vzquota.h" #include "common.h" #include "quota_io.h" /* quota stat, quota show */ static char vestat_usage[] = "Usage: %s %s quotaid [-p ] [-c ]\n" "\t[-R,--relative]\n" "\t[-f,--force]\n" "\t[-t,--user-group]\n" "\t(Specify the --help global option for a list of other help options)\n"; static char quotashow_usage[] = "Usage: %s %s quotaid [-p ] [-c ]\n" "\t[-R,--relative]\n" "\t[-t,--user-group]\n" "\t(Specify the --help global option for a list of other help options)\n"; static char vestat_short_options[] = "p:c:tfR"; static struct option vestat_long_options[] = { {"quota-file", required_argument, NULL, 'c'}, {"user-group", no_argument, NULL, 't'}, {"relative", no_argument, NULL, 'R'}, {"force", no_argument, NULL, 'f'}, {0, 0, 0, 0} }; static char quotashow_short_options[] = "p:c:tR"; static struct option quotashow_long_options[] = { {"quota-file", required_argument, NULL, 'c'}, {"user-group", no_argument, NULL, 't'}, {"relative", no_argument, NULL, 'R'}, {0, 0, 0, 0} }; /* For printing '*' char when overlimit */ char b_overlim(qint usage, qint softlim, qint hardlim) { if ((softlim && usage > softlim) || (hardlim && usage > hardlim)) return '*'; return ' '; } char i_overlim(__u32 usage, __u32 softlim, __u32 hardlim) { if ((softlim && usage > softlim) || (hardlim && usage > hardlim)) return '*'; return ' '; } void print_status(struct qf_data *qd) { char buf[QMAXTIMELEN]; struct vz_quota_stat *stat = &qd->stat; struct dq_stat *s = &(stat->dq_stat); struct dq_info *i = &(stat->dq_info); if (s->bcurrent <= s->bsoftlimit) s->btime = 0; if (s->icurrent <= s->isoftlimit) s->itime = 0; if (batch_mode) { /* usage soft hard grace expire */ printf("%14llu %14llu %14llu %14lu %14lu\n", ker2block(s->bcurrent), ker2block(s->bsoftlimit), ker2block(s->bhardlimit), s->btime, i->bexpire); /* usage soft hard grace expire */ printf("%14u %14u %14u %14lu %14lu\n", s->icurrent, s->isoftlimit, s->ihardlimit, s->itime, i->iexpire); } else { printf("%11s %14s %14s %14s %8s\n", "resource", "usage", "softlimit", "hardlimit", "grace"); difftime2str(s->btime, buf); printf("%11s %14llu%c %14llu %14llu %8s\n", "1k-blocks", ker2block(s->bcurrent), b_overlim(s->bcurrent, s->bsoftlimit, s->bhardlimit), ker2block(s->bsoftlimit), ker2block(s->bhardlimit), buf); difftime2str(s->itime, buf); printf("%11s %14u%c %14u %14u %8s\n", "inodes", s->icurrent, i_overlim(s->icurrent, s->isoftlimit, s->ihardlimit), s->isoftlimit, s->ihardlimit, buf); } } void print_ugid_status(struct qf_data *qd) { char buf1[QMAXTIMELEN], buf2[QMAXTIMELEN]; struct ugid_quota *q = &qd->ugid_stat; struct dquot *dq; struct dquot *obj[q->dquot_size]; unsigned int i; /* ugid quota status */ /* if force option was supplied, we do not read quota file and thus * do not know 2-level quota status at the next run */ if (batch_mode) { printf("%d %d\n", (option & FL_FORCE) ? -1 : (qd->head.flags & QUOTA_UGID_ON) ? 1 : 0, (q->info.config.flags & VZDQUG_ON) ? 1 : 0); /* ugid usage */ printf("%d %d %d\n", q->info.config.count, q->info.buf_size, q->info.config.limit); printf("%d\n", (q->info.config.flags & VZDQUG_FIXED_SET) ? 1 : 0); } else { printf("%s %s,%s\n", "User/group quota:", (option & FL_FORCE) ? "-" : (qd->head.flags & QUOTA_UGID_ON) ? "on" : "off", (q->info.config.flags & VZDQUG_ON) ? "active" : "inactive"); /* ugid usage */ printf("%s%s loaded %u, total %u, limit %u\n", (q->info.buf_size > q->info.config.limit) ? "*" : "", "Ugids:", q->info.config.count, q->info.buf_size, q->info.config.limit); printf("%s %s\n", "Ugid limit was exceeded:", (q->info.config.limit && q->info.config.count >= q->info.config.limit) ? "yes" : "no"); } /* grace times */ if (!batch_mode) { printf("\n"); printf("User/group grace times and quotafile flags:\n"); printf("%5s %14s %14s %10s\n", "type", "block_exp_time", "inode_exp_time", "dqi_flags"); } for (i = 0; i < MAXQUOTAS; i++) { if (batch_mode) { printf("%5s %ld %ld %9Xh\n", type2name(i), q->info.ugid_info[i].bexpire, q->info.ugid_info[i].iexpire, q->info.ugid_info[i].flags); continue; } buf1[0] = buf2[0] = 0; if (q->info.ugid_info[i].bexpire) time2str(q->info.ugid_info[i].bexpire, buf1, TF_ROUND); if (q->info.ugid_info[i].iexpire) time2str(q->info.ugid_info[i].iexpire, buf2, TF_ROUND); printf("%5s %14s %14s %9Xh\n", type2name(i), buf1, buf2, q->info.ugid_info[i].flags); } if (!q->dquot_size) return; sort_dquot(q, obj); /* output ugid objects */ if (!batch_mode) { printf("\n"); printf("User/group objects:\n"); printf("%-11s %5s %9s %11s %11s %11s %8s %6s\n", "ID", "type", "resource", "usage", "softlimit", "hardlimit", "grace", "status"); } for (i = 0; i < q->dquot_size; i++) { struct vz_quota_iface *s; time_t t; char status[256] = ""; dq = obj[i]; s = &(dq->obj.istat); /* status */ if (batch_mode) { sprintf(status, "%d %d", (dq->obj.flags & UGID_LOADED) ? 1 : 0, (dq->obj.flags & UGID_DIRTY) ? 1 : 0); } else { if (dq->obj.flags & UGID_LOADED) sprintf(status, "loaded"); if (dq->obj.flags & UGID_DIRTY) sprintf(status, "%s%sdirty", status, (strlen(status)) ? "," : ""); } /* blocks */ t = (s->qi_stat.bcurrent < s->qi_stat.bsoftlimit) ? 0 : s->qi_stat.btime; if (batch_mode) { sprintf(buf1, "%ld", t); } else { difftime2str(t, buf1); } printf("%-11u %5s %9s %11llu %11llu %11llu %8s %6s\n", s->qi_id, type2name(s->qi_type), "1k-blocks", ker2block(s->qi_stat.bcurrent), ker2block(s->qi_stat.bsoftlimit), ker2block(s->qi_stat.bhardlimit), buf1, status); /* inodes */ t = (s->qi_stat.icurrent < s->qi_stat.isoftlimit) ? 0 : s->qi_stat.itime; if (batch_mode) { sprintf(buf1, "%ld", t); } else { difftime2str(t, buf1); } printf("%-11u %5s %9s %11u %11u %11u %8s %6s\n", s->qi_id, type2name(s->qi_type), "inodes", s->qi_stat.icurrent, s->qi_stat.isoftlimit, s->qi_stat.ihardlimit, buf1, status); } } int vestat_proc(int argc, char **argv) { int fd = 0; int rc = 0; struct qf_data qd; init_quota_data(&qd); parse_options(argc, argv, vestat_short_options, vestat_long_options, vestat_usage, 0); if (!(option & FL_VEID)) usage(vestat_usage); /* if force option was supplied, we do not read and update quota file */ if (!(option & FL_FORCE)) { fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0) { if (errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } /* we must read and write whole files cause of checksum */ if (check_quota_file(fd) < 0 || read_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); } if (quota_syscall_stat(&qd, !(option & FL_SQT)) < 0) { /* indicate that quota is off */ error(EC_NOTRUN, 0, "Quota accounting is off, " "try vzquota show id\n"); } else if (!(option & FL_FORCE)) { if (write_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); close_quota_file(fd); } print_status(&qd); if (option & FL_SQT) { print_ugid_status(&qd); /* indicate that VE quota is on but user/group quota is inactive in KERNEL */ if (!(qd.ugid_stat.info.config.flags & VZDQUG_ON)) rc = EC_UG_NOTRUN; } free_quota_data(&qd); /* indicate that VE and user/group quotas are on */ return rc; } int quotashow_proc(int argc, char **argv) { int fd; int rc = 0; struct qf_data qd; init_quota_data(&qd); parse_options(argc, argv, quotashow_short_options, quotashow_long_options, quotashow_usage, 0); if (!((option & FL_VEID) || (option & FL_CONF_FILE))) usage(quotashow_usage); fd = open_quota_file(quota_id, config_file, O_RDONLY); if (fd < 0) { if (errno == ENOENT) error(EC_NOQUOTAFILE, 0, "Quota file must exist for show command"); else exit(EC_QUOTAFILE); } /* we must read and write whole files cause of checksum */ if (do_check_quota_file(fd, 0) < 0 || read_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); if (qd.head.flags & QUOTA_ON) debug(LOG_WARNING, "Quota is running, so data reported from " "quota file may not reflect current values\n"); if (qd.head.flags & QUOTA_DIRTY) rc = EC_QUOTADIRTY; print_status(&qd); if (option & FL_SQT) print_ugid_status(&qd); free_quota_data(&qd); close_quota_file(fd); return rc; } vzquota-3.1.orig/src/syscall.c0000644000000000000000000000601212023504012013304 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "vzquota.h" #include "common.h" #ifdef VZCTL_QUOTA_CTL #define VZCTL_DEVICE "/dev/vzctl" #include long vzquotactl_syscall( int _cmd, unsigned int _quota_id, struct vz_quota_stat *_qstat, const char *_ve_root) { int rc; int fd; struct vzctl_quotactl qu = { .cmd = _cmd, .quota_id = _quota_id, .qstat = _qstat, .ve_root = (char *) _ve_root }; // ASSERT(_qstat); debug(LOG_DEBUG, "vzquotactl ioctl start:cmd %d: id %d\n", _cmd, _quota_id); fd = open(VZCTL_DEVICE, O_RDWR); if (fd < 0) error(EC_VZCALL, errno, "can't open vzctl device '%s'", VZCTL_DEVICE); debug(LOG_DEBUG, "attempt new ioctl[%d]\n", VZCTL_QUOTA_CTL); rc = ioctl(fd, VZCTL_QUOTA_NEW_CTL, &qu); debug(LOG_DEBUG, "vzquotactl ioctl end:cmd %d: id %d: status %d\n", _cmd, _quota_id, rc); close(fd); return rc; } long vzquotactl_ugid_syscall( int _cmd, /* subcommand */ unsigned int _quota_id, /* quota id where it applies to */ unsigned int _ugid_index,/* for reading statistic. index of first uid/gid record to read */ unsigned int _ugid_size, /* size of ugid_buf array */ void *_addr /* user-level buffer */ ) { int rc; int fd; struct vzctl_quotaugidctl qu = { .cmd = _cmd, .quota_id = _quota_id, .ugid_index = _ugid_index, .ugid_size = _ugid_size, .addr = _addr }; debug(LOG_DEBUG, "vzquotaugidctl ioctl start:cmd %d: id %d\n", _cmd, _quota_id); fd = open(VZCTL_DEVICE, O_RDWR); if (fd < 0) error(EC_VZCALL, errno, "can't open vzctl device '%s'", VZCTL_DEVICE); rc = ioctl(fd, VZCTL_QUOTA_UGID_CTL, &qu); debug(LOG_DEBUG, "vzquotaugidctl ioctl end:cmd %d: id %d: status %d\n", _cmd, _quota_id, rc); close(fd); return rc; } #else vza _syscall4(long, vzquotactl, int, cmd, unsigned int, quota_id, struct vz_quota_stat *, qstat, const char *, ve_root); long vzquotactl_syscall(int cmd, unsigned int quota_id, struct vz_quota_stat *qstat, const char *ve_root) { long status; debug(LOG_DEBUG, "vzquotactl call start:cmd %d: id %d\n", cmd, quota_id); status = vzquotactl(cmd, quota_id, qstat, ve_root); debug(LOG_DEBUG, "vzquotactl call end:cmd %d: id %d: status %d\n", cmd, quota_id, status); return status; } #endif vzquota-3.1.orig/src/Makefile0000644000000000000000000000436212023504012013134 0ustar # Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. # # 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. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # INSTALL = install PREFIX = /usr SBINDIR = ${PREFIX}/sbin VARDIR = /var #DEBUG = -D_DEBUG -g3 -ggdb3 -p -pg CFLAGS += -pipe -I../include -std=gnu99 \ -g -Wall -Werror -Wformat -D_FILE_OFFSET_BITS=64 \ -D_LINUX_QUOTA_VERSION=6 -D_LARGEFILE64_SOURCE \ -DVARDIR=\"$(VARDIR)\" $(DEBUG) # We need -m64 for ppc64 in order to get proper ioctls ifeq ($(shell uname -m),ppc64) CFLAGS += -m64 endif OBJS_main = common.o quota_io.o syscall.o \ main.o stat.o quotaon.o \ quotacheck.o OBJS_check = common.o quota_io.o syscall.o \ quotacheck.o vzdqcheck.o OBJS_dump = common.o quota_io.o syscall.o \ vzdqdump.o OBJS_load = common.o quota_io.o syscall.o \ vzdqload.o OBJS=$(OBJS_main) $(OBJS_check) $(OBJS_dump) $(OBJS_load) PROGS=vzquota vzdqcheck vzdqdump vzdqload all: $(PROGS) depend: $(OBJS:.o=.c) $(CC) $(CFLAGS) -MM $(OBJS:.o=.c) > .depend %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ install: $(PROGS) $(INSTALL) -d $(DESTDIR)$(SBINDIR) $(INSTALL) -d $(DESTDIR)$(MANDIR)/man8 $(INSTALL) -d $(DESTDIR)$(VARDIR)/vzquota for file in $(PROGS); do \ $(INSTALL) -m 755 $$file $(DESTDIR)$(SBINDIR)/$$file; \ done clean: rm -f $(OBJS) $(PROGS) .depend core *.log find . -regex '.*[~#].*' | xargs rm -f vzquota: $(OBJS_main) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_main) vzdqcheck: $(OBJS_check) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_check) vzdqdump: $(OBJS_dump) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_dump) vzdqload: $(OBJS_load) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_load) -include .depend vzquota-3.1.orig/src/common.c0000644000000000000000000002647012023504012013134 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "vzquota.h" #include "common.h" __u32 option; unsigned int quota_id; char *mount_point = NULL; char *config_file = NULL; char *actual_config_file = NULL; /* path to actually used config file */ struct vz_quota_stat limits; //struct vz_quota_stat ugid_limits; struct vz_quota_ugid_stat ug_config; //int ugid; int debug_level = 0; int batch_mode = 0; typedef struct clean_item_t { func_cleaner_t func; void * data; struct clean_item_t * next; } clean_item_t; static struct clean_item_t * cleaners = NULL; void register_cleaner(func_cleaner_t func, void * data) { struct clean_item_t * p = xmalloc(sizeof(struct clean_item_t)); p->func = func; p->data = data; p->next = cleaners; cleaners = p; } static void error_cleaning() { struct clean_item_t * p = cleaners; while (p) { p->func(p->data); p = p->next; } } void vdebug_print(int level, char *oformat, va_list pvar) { FILE* output; if (!oformat) return; if (level <= LOG_WARNING) output = stderr; else output = stdout; fprintf(output, VZQUOTA_LOG_PREFIX); switch (level) { case LOG_ERROR: fprintf(output, "(error) "); break; case LOG_WARNING: fprintf(output, "(warning) "); break; case LOG_INFO: fprintf(output, "(info) "); break; case LOG_DEBUG: default: fprintf(output, "(debug) "); break; } vfprintf(output, oformat, pvar); return; } void debug_print(int level, char *oformat, ...) { va_list pvar; va_start(pvar, oformat); vdebug_print(level, oformat, pvar); va_end(pvar); } void exit_cleanup(int status) { error(status, 0, NULL); } void error(int status, int errnum, char *oformat, ...) { if (oformat) { va_list pvar; va_start(pvar, oformat); vdebug_print(LOG_ERROR, oformat, pvar); va_end(pvar); if (errnum) fprintf(stderr, ": %s", strerror(errnum)); fprintf(stderr, "\n"); } if (status) { /* do cleaning */ error_cleaning(); exit(status); } } void *xmalloc(size_t size) { void *ptr; ptr = malloc(size); if (!ptr) error(EC_SYSTEM, errno, "not enough memory for %d bytes", size); memset(ptr, 0, size); return (ptr); } void *xrealloc(void *p, size_t size) { void *ptr; ptr = realloc(p, size); if (!ptr) error(EC_SYSTEM, errno, "not enough memory for %d bytes", size); return (ptr); } char *xstrdup(const char* s) { char *n; n = strdup(s); if (!n) error(EC_SYSTEM, errno,"can't strdup '%s'", s); return (n); } int str2uint(char *str, unsigned int *number) { char *p; ASSERT(str && number); *number = strtol(str, &p, 10); if (*str == '\0' || *p != '\0') return -1; return 0; } int str2u32(char *str, __u32 * number) { char *p; ASSERT(str && number); *number = strtol(str, &p, 10); if (*str == '\0' || *p != '\0') return -1; return 0; } int str2u64(char *str, __u64 * number) { char *p; ASSERT(str && number); *number = strtoll(str, &p, 10); if (*str == '\0' || *p != '\0') return -1; return 0; } /* * run on string - ignore leading spaces and tabs */ static char *gostr(char *s) { /* check input params */ ASSERT(s); while (*s && ((' ' == *s) || ('\t' == *s))) s++; return s; } int str_isdigit(char *s) { /* check input params */ ASSERT(s); /* empty string */ if (0 == strlen(s)) return -1; while (*s) { if (!isdigit(*s)) return -1; s++; } return 0; } static int str_istime(char *s, int n) { int i = 0; /* check input params */ ASSERT(s); while (*s) { if (isdigit(*s) || (':' == *s)) { if (':' == *s) { i++; if (i > n) return -1; } s++; } else return -1; } return 0; } typedef struct dq_time { char c; long int t; } dq_time; static int dq_thr[4] = { 1, VE_DQ_MIN, VE_DQ_HOUR, VE_DQ_DAY }; static dq_time dq_t[] = { {'H', VE_DQ_HOUR}, {'D', VE_DQ_DAY}, {'W', VE_DQ_WEEK}, {'M', VE_DQ_MONTH}, {'Y', VE_DQ_YEAR}, {0, 0} }; #define ASP_STR_LEN 256 int str2time(char *s, long int *n) { int len, i, tmp; long int val = 0; char c, buf[ASP_STR_LEN], *p, *q; /* check input params */ ASSERT((s) && (n)); if (0 == (len = strlen(s))) return -1; if (len >= ASP_STR_LEN) return -1; c = s[len - 1]; // last char (Q: trail spaces?) strncpy(buf, s, ASP_STR_LEN); if (isdigit(c)) { /* format 1 */ /* ignore leading spaces & tabs */ p = gostr(buf); /* only seconds? */ if (0 == str_isdigit(p)) { if (0 == strlen(p)) return -1; sscanf(p, "%ld", n); return 0; } if (str_istime(p, 3)) return -1; /* bad format */ for (i = 0; i < 4; i++) { q = (char *) rindex(p, (int) ':'); if (q) { *q++ = 0; /* check - may be empty field */ if (0 == strlen(q)) return -1; sscanf(q, "%u", &tmp); } else { /* check - may be empty field */ if (0 == strlen(p)) return -1; sscanf(p, "%u", &tmp); } /* convert to seconds */ tmp *= dq_thr[i]; if (i < 3) { /* check overflow */ if (tmp >= dq_thr[i + 1]) return -1; } val += tmp; if (0 == q) { *n = val; return 0; } } /* for */ *n = val; } /* if (isdigit(c)) */ else { /* format 2 */ /* convert to uppercase */ c = toupper(c); /* reject last char */ buf[len - 1] = 0; /* look up */ for (i = 0; dq_t[i].c; i++) { if (c == dq_t[i].c) { /* ignore leading spaces & tabs */ p = gostr(buf); if (str_isdigit(p)) return -1; sscanf(p, "%ld", &val); *n = dq_t[i].t * val; return 0; } }; return -1; /* bad format */ } return 0; } /* 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) sprintf(buf, "%ddays", days); else sprintf(buf, "%02d:%02d", hours, 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); } } /* For printing grace 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); } static char time_usage[] = "Available time formats:\n" "1. dd:hh:mm:ss\n" "2. xxA, where A - h/H(hour);d/D(day);w/W(week);m/M(month);y/Y(year)\n" "For instance: 7D - 7 days; 01w - 1 week; 3m - 3 months\n"; //TODO realpath ? char* globolize_path(char *path) { char *cwd = NULL; char *newpath = NULL; ASSERT(path); if (path[0] == '/') return xstrdup(path); if (!(cwd = getcwd(NULL, 0))) error(EC_SYSTEM, errno, "getcwd"); newpath = xmalloc(strlen(cwd) + strlen(path) + 2); sprintf(newpath, "%s/%s", cwd, path); xfree(cwd); return newpath; } int parse_options(int argc, char **argv, char *short_options, struct option *long_options, char *opt_usage, int cmd_type) { int c; option = 0; memset(&limits, 0, sizeof(limits)); memset(&ug_config, 0, sizeof(ug_config)); if (argc < 2) /* cmd */ usage(opt_usage); /* skip 'cmd' */ argc --; argv ++; /* get VEID */ if (str2uint(argv[0], "a_id) < 0) usage(opt_usage); option |= FL_VEID; optind = 0; while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { switch (c) { case 13: option |= FL_NOCHECK; break; case 'r': break; case 's': if (!strcmp(optarg, "1")) { ug_config.flags |= VZDQUG_ON; } else if (!strcmp(optarg, "0")) { ug_config.flags &= ~VZDQUG_ON; } else { usage(opt_usage); } option |= FL_SQT; break; case 'u' : if (cmd_type & PARSE_SETUGID) { option |= FL_L2_USER; break; } if (str2uint(optarg, &ug_config.limit) < 0) usage(opt_usage); option |= FL_UGL; break; case 'g': option |= FL_L2_GROUP; break; case 't': if (cmd_type & PARSE_SETUGID) option |= FL_L2_GRACE; else option |= FL_SQT; break; case 'G': option |= FL_DUMP_GRACE; break; case 'U': option |= FL_DUMP_LIMITS; break; case 'T': option |= FL_DUMP_EXPTIME; break; case 'c': option |= FL_CONF_FILE; config_file = optarg; break; case 'F': option |= FL_DUMP_LIMITS_FIRST; break; case 'f': option |= FL_FORCE; break; case 'p': mount_point = globolize_path(optarg); option |= FL_PATH; break; case 'b': if (str2u64(optarg, &limits.dq_stat.bsoftlimit) < 0) usage(opt_usage); option |= FL_BSL; break; case 'B': if (str2u64(optarg, &limits.dq_stat.bhardlimit) < 0) usage(opt_usage); option |= FL_BHL; break; case 'e': if (str2time(optarg, &limits.dq_info.bexpire) < 0) usage(time_usage); option |= FL_BET; break; case 'i': if (str2u32(optarg, &(limits.dq_stat.isoftlimit)) < 0) usage(opt_usage); option |= FL_ISL; break; case 'I': if (str2u32(optarg, &(limits.dq_stat.ihardlimit)) < 0) usage(opt_usage); option |= FL_IHL; break; case 'n': if (str2time(optarg, &limits.dq_info.iexpire) < 0) usage(time_usage); option |= FL_IET; break; case 'R': option |= FL_RELATIVE; break; case '?': default: usage(opt_usage); } } if ((option & FL_RELATIVE) && (option & FL_CONF_FILE)) error(EC_USAGE, 0, "-c and -R options can't be set together\n"); return optind; } static void print_version() { printf("Vzquota version %s\n", VZQUOTA_VERSION); exit(EC_SUCCESS); } /*pointers to argc and argv of main()*/ void parse_global_options(int *argc, char ***argv, const char *usg) { int c; static char short_options[] = "+hvqVb"; static struct option long_options[] = { {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, {0, 0, 0, 0} }; int option_index = 0; int help = 0; /* Has the user asked for help? This lets us support the `vzquota -H cmd' convention to give help for cmd. */ #ifndef _DEBUG debug_level = LOG_WARNING; #else debug_level = LOG_DEBUG; #endif while ((c = getopt_long(*argc, *argv, short_options, long_options, &option_index)) != -1) { switch (c) { case 'h': help = 1; break; case 'V': print_version(); break; case 'v': debug_level++; break; case 'b': batch_mode++; break; case 'q': debug_level = LOG_ERROR; break; case '?': default: usage(usg); } } *argc -= optind; *argv += optind; if (*argc < 1) usage(usg); if (help) *argc = -1; } void usage(const char *usg) { if (!command_name) fprintf(stderr, usg, program_name); else fprintf(stderr, usg, program_name, command_name); exit(EC_USAGE); } vzquota-3.1.orig/src/vzdqdump.c0000644000000000000000000001176712023504012013521 0ustar /* * Copyright (C) 2000-2012, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "common.h" #include "vzquota.h" #include "quota_io.h" #include "quotadump.h" const char *program_name = "vzdqdump"; char *command_name = NULL; /* for usage() */ static char dump_usage[] = "Usage: %s quotaid [-c file] [-f] commands\n" "Dumps user/group quota information from quota file.\n" "\t-c file\tuse given quota file\n" "\t-f\tdump data from kernel rather than quota file\n" "Commands specify what user/group information to dump:\n" "\t-F\tfirst level quota\n" "\t-G\tgrace time\n" "\t-U\tdisk limits\n" "\t-T\texpiration times\n" ; static char dump_short_options[] = "c:fFGUT"; static struct option dump_long_options[] = { {"quota-file", required_argument, NULL, 'c'}, {"first", no_argument, NULL, 'F'}, {"kernel", no_argument, NULL, 'f'}, {"gracetime", no_argument, NULL, 'G'}, {"limits", no_argument, NULL, 'U'}, {"exptimes", no_argument, NULL, 'T'}, {0, 0, 0, 0} }; int main(int argc, char **argv) { int fd = 0; unsigned int i; struct qf_data qd; struct ugid_quota *q = NULL; unsigned int ugid_quota_status = 0; parse_global_options(&argc, &argv, dump_usage); argc += 1; argv -= 1; parse_options(argc, argv, dump_short_options, dump_long_options, dump_usage, 0); if (!(option & FL_VEID)) usage(dump_usage); if (!(option & FL_DUMP)) usage(dump_usage); init_quota_data(&qd); if (!(option & FL_FORCE)) { /* dump from quota file */ fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0) { if (errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } /* we must read and write whole files cause of checksum */ if (check_quota_file(fd) < 0 || read_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); close_quota_file(fd); ugid_quota_status = (qd.head.flags & QUOTA_UGID_ON) ? 1 : 0; } else { /* dump from kernel */ if (quota_syscall_stat(&qd, 0) < 0) error(EC_NOTRUN, 0, "Quota accounting is off"); ugid_quota_status = (qd.ugid_stat.info.config.flags & VZDQUG_ON) ? 1 : 0; } /* status of user/group quota */ printf("%s\t%u\n", STATUS_LABEL, ugid_quota_status); if (!ugid_quota_status) goto print_first_level; q = &qd.ugid_stat; /* grace times */ if (option & FL_DUMP_GRACE) { printf("#%s\ttype\tblock\tinode\n", GRACE_LABEL); for (i = 0; i < MAXQUOTAS; i++) { printf("%s\t%u\t%lu\t%lu\n", GRACE_LABEL, i, q->info.ugid_info[i].bexpire, q->info.ugid_info[i].iexpire ); } } if (option & (FL_DUMP_LIMITS | FL_DUMP_EXPTIME)) { /* number of ugids */ printf("%s\t%u\n", NUMBER_LABEL, q->dquot_size); if (q->dquot_size) { struct dquot *dq; struct dquot *obj[q->dquot_size]; struct vz_quota_iface *s; printf("#%s\tID\ttype", UGID_LABEL); if (option & FL_DUMP_LIMITS) printf("\tbsoft\tbhard\tisoft\tihard"); if (option & FL_DUMP_EXPTIME) printf("\tbtime\titime"); printf("\n"); sort_dquot(q, obj); for (i = 0; i < q->dquot_size; i++) { dq = obj[i]; s = &(dq->obj.istat); /* id, type */ printf("%s\t%u\t%u", UGID_LABEL, s->qi_id, s->qi_type); /* limits */ if (option & FL_DUMP_LIMITS) printf("\t%llu\t%llu\t%u\t%u", ker2block(s->qi_stat.bsoftlimit), ker2block(s->qi_stat.bhardlimit), s->qi_stat.isoftlimit, s->qi_stat.ihardlimit); /* exp times */ if (option & FL_DUMP_EXPTIME) printf("\t%lu\t%lu", (s->qi_stat.bcurrent < s->qi_stat.bsoftlimit) ? 0 : s->qi_stat.btime, (s->qi_stat.icurrent < s->qi_stat.isoftlimit) ? 0 : s->qi_stat.itime ); printf("\n"); } } } print_first_level: if (option & FL_DUMP_LIMITS_FIRST) { struct vz_quota_stat *stat = &qd.stat; printf(FIRST_LEVEL_LABEL "\n"); /* usage soft hard grace expire */ printf("%llu %llu %llu %lu %lu\n", stat->dq_stat.bcurrent, stat->dq_stat.bsoftlimit, stat->dq_stat.bhardlimit, stat->dq_stat.btime, stat->dq_info.bexpire); /* usage soft hard grace expire */ printf("%u %u %u %lu %lu\n", stat->dq_stat.icurrent, stat->dq_stat.isoftlimit, stat->dq_stat.ihardlimit, stat->dq_stat.itime, stat->dq_info.iexpire); } free_quota_data(&qd); return EC_SUCCESS; } vzquota-3.1.orig/src/vzdqcheck.c0000644000000000000000000000302412023504012013614 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "common.h" #include "vzquota.h" #include "quotacheck.h" const char *program_name = "vzdqcheck"; char *command_name = NULL; /* for usage() */ char* globolize_path(char *path); static char usg[] = "Usage: %s [options] path\n" "\t-h\thelp\n" "\t-V\tversion info\n" "\tpath\tscan path\n"; int main(int argc, char **argv) { struct scan_info info; parse_global_options(&argc, &argv, usg); mount_point = globolize_path(argv[0]); info.ugid_stat = NULL; scan(&info, mount_point); printf("quota usage for %s\n", mount_point); printf("%11s%11s\n","blocks", "inodes"); printf("%11llu%11u\n", ker2block(info.size), info.inodes); exit(0); } vzquota-3.1.orig/src/quotaon.c0000644000000000000000000006644612023504012013341 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "vzquota.h" #include "common.h" #include "quota_io.h" #include "quotacheck.h" /* quota init */ static char quotainit_usage[] = "Usage: %s %s -p [-c ]\n" "\t[-R,--relative]\n" "\t[-s,--sub-quotas 1|0]\n" "\t[-u,--ugid-limit ]\n" "\t-b,--block-softlimit \n" "\t-B,--block-hardlimit \n" "\t-i,--inode-softlimit \n" "\t-I,--inode-hardlimit \n" "\t-e,--block-exptime \n" "\t-n,--inode-exptime \n"; static char quotainit_short_options[] = "p:c:r:s:u:" "b:B:i:I:e:n:R"; static struct option quotainit_long_options[] = { {"rsquash", required_argument, NULL, 'r'}, /* depricated */ {"sub-quotas", required_argument, NULL, 's'}, {"ugid-limit", required_argument, NULL, 'u'}, {"quota-file", required_argument, NULL, 'c'}, {"block-softlimit", required_argument, NULL, 'b'}, {"block-hardlimit", required_argument, NULL, 'B'}, {"block-exptime", required_argument, NULL, 'e'}, {"inode-softlimit", required_argument, NULL, 'i'}, {"inode-hardlimit", required_argument, NULL, 'I'}, {"inode-exptime", required_argument, NULL, 'n'}, {"relative", no_argument, NULL, 'R'}, {0, 0, 0, 0} }; /* quota on */ static char quotaon_usage[] = "Usage: %s %s [-p ] [-c ]\n" "\t[-R,--relative]\n" "\t[-f,--force]\n" "\t[-s,--sub-quotas 1|0]\n" "\t[-u,--ugid-limit ]\n" "\t[-b ] [-B ]\n" "\t[-i ] [-I ]\n" "\t[-e ] [-n ]\n"; static char quotaon_short_options[] = "p:c:r:s:u:f" "b:B:i:I:e:n:R"; static struct option quotaon_long_options[] = { {"rsquash", required_argument, NULL, 'r'}, /* depricated */ {"sub-quotas", required_argument, NULL, 's'}, {"ugid-limit", required_argument, NULL, 'u'}, {"quota-file", required_argument, NULL, 'c'}, {"nocheck", no_argument, NULL, 13}, {"block-softlimit", required_argument, NULL, 'b'}, {"block-hardlimit", required_argument, NULL, 'B'}, {"block-exptime", required_argument, NULL, 'e'}, {"inode-softlimit", required_argument, NULL, 'i'}, {"inode-hardlimit", required_argument, NULL, 'I'}, {"inode-exptime", required_argument, NULL, 'n'}, {"relative", no_argument, NULL, 'R'}, {"force", no_argument, NULL, 'f'}, {0, 0, 0, 0} }; /* quota setlimit */ static char quotaset_usage[] = "Usage: %s %s [-p ] [-c ]\n" "\t[-R,--relative]\n" "\t[-f,--force]\n" "\t[-s,--sub-quotas 1|0]\n" "\t[-u,--ugid-limit ]\n" "\t[-b ] [-B ]\n" "\t[-i ] [-I ]\n" "\t[-e ] [-n ]\n"; static char quotaset_short_options[] = "p:c:r:s:u:f" "b:B:i:I:e:n:R"; static struct option quotaset_long_options[] = { {"rsquash", required_argument, NULL, 'r'}, /* depricated */ {"sub-quotas", required_argument, NULL, 's'}, {"ugid-limit", required_argument, NULL, 'u'}, {"quota-file", required_argument, NULL, 'c'}, {"block-softlimit", required_argument, NULL, 'b'}, {"block-hardlimit", required_argument, NULL, 'B'}, {"block-exptime", required_argument, NULL, 'e'}, {"inode-softlimit", required_argument, NULL, 'i'}, {"inode-hardlimit", required_argument, NULL, 'I'}, {"inode-exptime", required_argument, NULL, 'n'}, {"relative", no_argument, NULL, 'R'}, {"force", no_argument, NULL, 'f'}, {0, 0, 0, 0} }; /* quota ugidset */ static char quotaugidset_usage[] = "Usage: \n" "\t%s %s [-p ] [-c ]\n" "\t\t[-R,--relative]\n" "\t\t[-u|-g] \n" "\t\t \n" "\t\t \n" "\t%1$s %2$s [-p ] [-c ] -t\n" "\t\t[-R,--relative]\n" "\t\t \n"; static char quotaugidset_short_options[] = "p:c:ugtR"; static struct option quotaugidset_long_options[] = { {"quota-file", required_argument, NULL, 'c'}, {"uid", required_argument, NULL, 'u'}, {"gid", required_argument, NULL, 'g'}, {"relative", no_argument, NULL, 'R'}, {0, 0, 0, 0} }; /* quota off */ static char quotaoff_usage[] = "Usage: %s %s [-p ] [-c ]\n" "\t[-R,--relative]\n" "\t[-f,--force]\n"; static char quotaoff_short_options[] = "p:fc:R"; static struct option quotaoff_long_options[] = { {"quota-file", required_argument, NULL, 'c'}, {"relative", no_argument, NULL, 'R'}, {"force", no_argument, NULL, 'f'}, {0, 0, 0, 0} }; /* quota drop */ static char quotadrop_usage[] = "Usage: %s %s [-p ] [-c ]\n" "\t[-R,--relative]\n" "\t[-f,--force]\n"; static char quotadrop_short_options[] = "p:fc:R"; static struct option quotadrop_long_options[] = { {"quota-file", required_argument, NULL, 'c'}, {"relative", no_argument, NULL, 'R'}, {"force", no_argument, NULL, 'f'}, {0, 0, 0, 0} }; /* quota reload */ static char quotareloadugid_usage[] = "Usage: %s %s [-p ] [-c ]\n" "\t[-R,--relative]\n"; static char quotareloadugid_short_options[] = "p:c:R"; static struct option quotareloadugid_long_options[] = { {"quota-file", required_argument, NULL, 'c'}, {"relative", no_argument, NULL, 'R'}, {0, 0, 0, 0} }; static void set_quotas_from_line(struct qf_data *qd) { struct vz_quota_stat *stat; struct ugid_quota *ugid_stat; ASSERT(qd); stat = &qd->stat; ugid_stat = &qd->ugid_stat; /* user enters 1k blocks */ if (option & FL_BHL) stat->dq_stat.bhardlimit = block2ker(limits.dq_stat.bhardlimit); if (option & FL_BSL) stat->dq_stat.bsoftlimit = block2ker(limits.dq_stat.bsoftlimit); if (option & FL_BET) stat->dq_info.bexpire = limits.dq_info.bexpire; if (option & FL_IHL) stat->dq_stat.ihardlimit = limits.dq_stat.ihardlimit; if (option & FL_ISL) stat->dq_stat.isoftlimit = limits.dq_stat.isoftlimit; if (option & FL_IET) stat->dq_info.iexpire = limits.dq_info.iexpire; if (option & FL_SQT) { /* mark quota dirty if ugid quota is changing OFF -> ON */ if (!(qd->head.flags & QUOTA_UGID_ON) && //if (!(ugid_stat->info.config.flags & VZDQUG_ON) && (ug_config.flags & VZDQUG_ON)) qd->head.flags |= QUOTA_DIRTY; qd->head.flags &= ~QUOTA_UGID_ON; if (ug_config.flags & VZDQUG_ON) qd->head.flags |= QUOTA_UGID_ON; } if (option & FL_UGL) { /* mark quota dirty if ugid quota is ON and limit is changing as 0 -> X */ if ( (!ugid_stat->info.config.limit) && ug_config.limit && //(ug_config.flags & VZDQUG_ON)) (qd->head.flags & QUOTA_UGID_ON)) qd->head.flags |= QUOTA_DIRTY; ugid_stat->info.config.limit = ug_config.limit; } } static void check_limits(struct qf_data *qd, int what_given) { struct vz_quota_stat *qstat; struct ugid_quota *ugid_stat; struct dq_stat *stat; ASSERT(qd); qstat = &(qd->stat); ugid_stat = &(qd->ugid_stat); stat = &(qstat->dq_stat); if ((stat->bhardlimit < stat->bsoftlimit) && (what_given ? (option & (FL_BHL | FL_BSL)) : 1)) error(EC_USAGE, 0, "block_hard_limit [%u] < block_soft_limit [%u]\n", ker2block(stat->bhardlimit), ker2block(stat->bsoftlimit)); if ((stat->ihardlimit < stat->isoftlimit) && (what_given ? (option & (FL_IHL | FL_ISL)) : 1)) error(EC_USAGE, 0, "inode_hard_limit [%u] < inode_soft_limit [%u]\n", stat->ihardlimit, stat->isoftlimit); if ((stat->bhardlimit < stat->bcurrent) && (what_given ? (option & FL_BHL) : 1)) debug(LOG_WARNING, "block_hard_limit [%u] < block_current_usage [%u]\n", ker2block(stat->bhardlimit), ker2block(stat->bcurrent)); else if ((stat->bsoftlimit < stat->bcurrent) && (what_given ? (option & FL_BSL) : 1)) debug(LOG_WARNING, "block_soft_limit [%u] < block_current_usage [%u]\n", ker2block(stat->bsoftlimit), ker2block(stat->bcurrent)); if ((stat->ihardlimit < stat->icurrent) && (what_given ? (option & FL_IHL) : 1)) debug(LOG_WARNING, "inode_hard_limit [%u] < inode_current_usage [%u]\n", stat->ihardlimit, stat->icurrent); else if ((stat->isoftlimit < stat->icurrent) && (what_given ? (option & FL_ISL) : 1)) debug(LOG_WARNING, "inode_soft_limit [%u] < inode_current_usage [%u]\n", stat->isoftlimit, stat->icurrent); if (!(qd->head.flags & QUOTA_UGID_ON)) return; if ((ugid_stat->info.config.limit < ugid_stat->info.buf_size) && (what_given ? (option & FL_UGL) : 1)) debug(LOG_WARNING, "ugid_limit [%u] < ugid_current_usage [%u]\n", ugid_stat->info.config.limit, ugid_stat->info.buf_size); //TODO check limits for ugids -> warnings } static void correct_grace(struct vz_quota_stat *stat, struct ugid_quota *ugid_stat) { struct dquot *dq; struct dq_stat *s; struct dq_info *i; int type; time_t nowt; ASSERT(stat); nowt = time(NULL); /* VE quota */ if (stat) { s = &(stat->dq_stat); i = &(stat->dq_info); if (s->bcurrent <= s->bsoftlimit) s->btime = 0; else if (s->btime == 0) s->btime = nowt + i->bexpire; if (s->icurrent <= s->isoftlimit) s->itime = 0; else if (s->itime == 0) s->itime = nowt + i->iexpire; } /* ugid quota */ if (ugid_stat) { reset_dquot_search(); while ((dq = get_next_dquot(ugid_stat)) != NODQUOT) { s = &(dq->obj.istat.qi_stat); type = dq->obj.istat.qi_type; i = &(ugid_stat->info.ugid_info[type]); if ((s->bcurrent <= s->bsoftlimit) || !s->bsoftlimit) s->btime = 0; else if (s->btime == 0) s->btime = nowt + i->bexpire; if ((s->icurrent <= s->isoftlimit) || !s->isoftlimit) s->itime = 0; else if (s->itime == 0) s->itime = nowt + i->iexpire; } } } static void calc_current_usage(struct qf_data *qd) { struct scan_info info; char *path; path = get_quota_path(qd); /* whether to scan user/group info */ if (qd->head.flags & QUOTA_UGID_ON) info.ugid_stat = &(qd->ugid_stat); else info.ugid_stat = NULL; scan(&info, path); qd->stat.dq_stat.bcurrent = info.size; qd->stat.dq_stat.icurrent = info.inodes; qd->head.flags &= ~QUOTA_DIRTY; } struct quota_file_t { unsigned int id; const char * path; }; void quota_file_cleaner(void * data) { struct quota_file_t * qf = (struct quota_file_t *) data; unlink_quota_file(qf->id, qf->path); } static void quota_init() { int fd; int rc; struct qf_data qd; init_quota_data(&qd); ASSERT(mount_point); rc = quota_syscall_stat(&qd, 1); if (rc == 0) error(EC_RUN, 0, "Quota is running, stop it first"); fd = open_quota_file(quota_id, config_file, O_RDWR|O_CREAT|O_EXCL); if (fd < 0) { if (errno == EEXIST) { debug(LOG_WARNING, "Quota file exists, it will be overwritten\n"); /* * Don't remove file here, just try to reopen it without * O_EXCL. If we remove it now, then in case of error * later we'll: * - lost all data for this quota.id; * - get empty (== corrupted) quota file. */ fd = open_quota_file(quota_id, config_file, O_RDWR|O_CREAT); } if (fd < 0) exit(EC_QUOTAFILE); } else { /* add remove created quota file in case of error */ struct quota_file_t * qf = xmalloc(sizeof(struct quota_file_t)); qf->id = quota_id; /* * Use actual_config_file, because config_file can be NULL, * but we've just created a file in the default place. * * NB! Internal redesign is required - the config_file * pointer is global, but it's also used as an argument to some * functions. The same for some other variables. VZ3 vzquota * internal interface was simple, but now there are some * additional issues: compatibility, new options for example. */ qf->path = actual_config_file; register_cleaner(quota_file_cleaner, qf); } memset(&qd.stat, 0, sizeof(struct vz_quota_stat)); free_ugid_quota(&qd.ugid_stat); clean_ugid_info(&qd.ugid_stat); if (!(option & FL_RELATIVE)) qd.path = xstrdup(mount_point); qd.head.flags = 0; set_quotas_from_line(&qd); calc_current_usage(&qd); check_limits(&qd, 0); /* we must read and write whole files cause of checksum */ if (write_quota_file(fd, &qd, IOF_ALL) < 0) exit_cleanup(EC_QUOTAFILE); #ifdef _DEBUG print_status(&qd); print_ugid_status(&qd); #endif free_quota_data(&qd); close_quota_file(fd); debug(LOG_INFO, "quota initialization for id %d complete\n", quota_id); } static void quota_on() { int fd; struct qf_data qd; struct vz_quota_ugid_stat old_conf; int rescan = 0; int rc; struct qf_data *qd_temp; init_quota_data(&qd); fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0 && errno == ENOENT) exit(EC_NOQUOTAFILE); /* we must read and write whole files cause of checksum */ if (fd < 0 || check_quota_file(fd) < 0 || read_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); if ((option & FL_PATH) && qd.path && strcmp(qd.path, mount_point)) { if (qd.path_len) { /* * Change mount point only if it's not relative */ if (qd.path) free(qd.path); qd.path = xstrdup(mount_point); } option |= FL_FORCE; } /* set ugid config before scan */ memcpy(&old_conf, &(qd.ugid_stat.info.config), sizeof(struct vz_quota_ugid_stat)); set_quotas_from_line(&qd); /* clean ugids if user/group quota is off or ugid limit = 0, * saving ugid limit */ if ( !(qd.head.flags & QUOTA_UGID_ON) || //if ( !(qd.ugid_stat.info.config.flags & VZDQUG_ON) || !qd.ugid_stat.info.config.limit) { //unsigned int fl = qd.ugid_stat.info.config.flags; unsigned int ul = qd.ugid_stat.info.config.limit; clean_ugid_info(&qd.ugid_stat); free_ugid_quota(&qd.ugid_stat); //qd.ugid_stat.info.config.flags = fl & ~VZDQUG_ON; qd.ugid_stat.info.config.limit = ul; } qd_temp = (struct qf_data*) xmalloc(sizeof(struct qf_data)); rc = quota_syscall_stat(qd_temp, 1); free(qd_temp); if (rc >= 0) /* quota is on*/ goto out_run; if ((qd.head.flags & QUOTA_ON) && !(option & FL_NOCHECK)) { debug(LOG_WARNING, "Incorrect quota shutdown for id %d, " "recalculating disk usage\n", quota_id); rescan = 1; } if ((qd.head.flags & QUOTA_DIRTY) && !rescan && !(option & FL_NOCHECK)) { debug(LOG_WARNING, "quota usage is invalid for id %d, " "recalculating disk usage...\n", quota_id); rescan = 1; } if (option & FL_FORCE && !rescan) { debug(LOG_INFO, "Force quota checking for id %d...\n", quota_id); rescan = 1; } /* scan quota after applying cmd-line parameters; they would switch * ugid quota on/off, that acts on calc_current_usage() */ if (rescan) calc_current_usage(&qd); check_limits(&qd, 0); correct_grace(&qd.stat, &qd.ugid_stat); reset_ugid_flags(&qd.ugid_stat, UGID_ALL); /* clear all ugid flags*/ if (quota_syscall_on(&qd) < 0) /* quota is on */ goto out_run; qd.head.flags |= QUOTA_ON; if (is_ugid_dirty(&qd.ugid_stat)) qd.head.flags |= QUOTA_DIRTY; else qd.head.flags &= ~QUOTA_DIRTY; /* we must read and write whole files cause of checksum */ if (write_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); #ifdef _DEBUG print_status(&qd); print_ugid_status(&qd); #endif free_quota_data(&qd); close_quota_file(fd); debug(LOG_INFO, "Quota was switched on for id %d\n", quota_id); return; out_run: debug(LOG_WARNING, "Quota is running for id %d already\n", quota_id); exit(EC_RUN); } static void quota_off() { int fd; int rc; struct qf_data qd; int force = 0; init_quota_data(&qd); fd = open_quota_file(quota_id, config_file, O_RDWR); /* we must read and write whole files cause of checksum */ if (fd < 0 || check_quota_file(fd) < 0 || read_quota_file(fd, &qd, IOF_ALL) < 0) { /* file read error */ if (option & FL_FORCE) { debug(LOG_WARNING, "Force switching quota off for id %d " "(quota file may be inconsistent)\n", quota_id); force = 1; } else { if (fd < 0 && errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } } rc = quota_syscall_off(&qd); if (rc < 0) { /* quota is off or (broken or exceeded) */ if (errno == EALREADY || errno == EIO) { /* quota is broken */ if (errno == EALREADY) debug(LOG_WARNING, "Quota is broken for id %d\n", quota_id); else /* quota exceeded */ debug(LOG_WARNING, "Quota off syscall for id %d: Input/output error.\nQuota exceeded?\n", quota_id); if (force) { free_quota_data(&qd); debug(LOG_INFO, "Quota was switched off for id %d\n", quota_id); return; } qd.head.flags |= QUOTA_DIRTY; } else { /* quota is off */ error(0, 0, "Quota is not running for id %d", quota_id); if (force) exit(EC_NOTRUN); if (!(qd.head.flags & QUOTA_ON)) exit(EC_NOTRUN); else debug(LOG_WARNING, "Repairing quota: it was incorrectly" " marked as running for id %d\n", quota_id); } } else { /* ok, quota was on */ if (force) { free_quota_data(&qd); debug(LOG_INFO, "Quota was switched off for id %d\n", quota_id); return; } if (!(qd.head.flags & QUOTA_ON)) debug(LOG_WARNING, "Repairing quota: it was incorrectly" " marked as stopped for id %d\n", quota_id); } qd.head.flags &= ~QUOTA_ON; /* we must read and write whole files cause of checksum */ rc = write_quota_file(fd, &qd, IOF_ALL); // /* write quota stats only if quota was running */ // (rc < 0) ? IOF_HEAD : IOF_ALL); if (rc < 0) exit(EC_QUOTAFILE); close_quota_file(fd); #ifdef _DEBUG print_status(&qd); print_ugid_status(&qd); #endif free_quota_data(&qd); debug(LOG_INFO, "Quota was switched off for id %d\n", quota_id); return; } static void quota_drop() { struct qf_data qd_temp; int fd; fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0) { if (errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } if (quota_syscall_stat(&qd_temp, 1) >= 0) { /* quota is on */ debug(LOG_WARNING, "Quota is running for id %d\n", quota_id); if (option & FL_FORCE) debug(LOG_WARNING, "Force quota file delete\n", quota_id); else exit(EC_RUN); } if (unlink_quota_file(quota_id, config_file) < 0) exit(EC_QUOTAFILE); close_quota_file(fd); debug(LOG_INFO, "Quota file was deleted for id %d\n", quota_id); return; } static void quota_reload_ugid() { struct qf_data qd; struct qf_data *temp_qd; struct ugid_quota *ugid_stat; struct dquot *dquot; int fd; int rc; unsigned int i; init_quota_data(&qd); fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0) { if (errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } /* we must read and write whole files cause of checksum */ if (check_quota_file(fd) < 0 || read_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); temp_qd = (struct qf_data *) xmalloc(sizeof(struct qf_data)); rc = quota_syscall_stat(temp_qd, 0); if (rc < 0 || !(temp_qd->ugid_stat.info.config.flags & VZDQUG_ON)) { free(temp_qd); close_quota_file(fd); free_quota_data(&qd); return; } free(temp_qd); ugid_stat = &qd.ugid_stat; /* set ugid config */ rc = vzquotactl_ugid_syscall(VZ_DQ_UGID_SETCONFIG, quota_id, 0, 0, &(ugid_stat->info.config)); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_setconfig syscall for id %d", quota_id); /* set ugid graces and flags */ for (i = 0; i < MAXQUOTAS; i++) { rc = vzquotactl_ugid_setgrace(&qd, i, &(ugid_stat->info.ugid_info[i])); if (rc < 0) error(EC_VZCALL, errno, "Quota ugid_setgrace syscall for id %d", quota_id); } /* set ugid limits */ reset_dquot_search(); while( (dquot = get_next_dquot(ugid_stat)) != NODQUOT) { struct vz_quota_iface *s; struct dq_stat dqstat; s = &dquot->obj.istat; /* limits */ memset(&dqstat, 0, sizeof(dqstat)); dqstat.bsoftlimit = ker2block(s->qi_stat.bsoftlimit); dqstat.bhardlimit = ker2block(s->qi_stat.bhardlimit); dqstat.isoftlimit = s->qi_stat.isoftlimit; dqstat.ihardlimit = s->qi_stat.ihardlimit; dqstat.btime = s->qi_stat.btime; dqstat.itime = s->qi_stat.itime; if (vzquotactl_ugid_setlimit(&qd, s->qi_id, s->qi_type, &dqstat) < 0) error(EC_VZCALL, errno, "quotactl failed"); } /* we must read and write whole files cause of checksum */ rc = write_quota_file(fd, &qd, IOF_ALL); if (rc < 0) exit(EC_QUOTAFILE); close_quota_file(fd); free_quota_data(&qd); return; } static void quota_set() { int fd; struct qf_data qd; struct qf_data *qd_temp; int rc; init_quota_data(&qd); fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0) { if (errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } if (check_quota_file(fd) < 0) exit(EC_QUOTAFILE); /* we must read and write whole files cause of checksum */ if (read_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); /* update VE stat from the kernel only, cause we can only change ugid_limit * in ugid_stat; it will be read in quota_syscall_setlimit() from the kernel */ qd_temp = (struct qf_data *) xmalloc(sizeof(struct qf_data)); rc = quota_syscall_stat(qd_temp, 1); free(qd_temp); if (rc < 0) { /* debug(LOG_WARNING, "Quota is not running for id %d, " "saving new limits to file only\n", quota_id); */ } set_quotas_from_line(&qd); check_limits(&qd, 1); correct_grace(&qd.stat, NULL); if (rc >= 0) if (quota_syscall_setlimit(&qd, !(option & FL_LIMITS), !(option & FL_UGIDS)) < 0) { if (errno == EBUSY) /* EBUSY is returned in case ugid quota is on and limit * was changed: 0 -> x */ qd.head.flags |= QUOTA_DIRTY; else { /* debug(LOG_WARNING, "Quota is not running for id %d, " "saving new limits to file only\n", quota_id); */ } } // Write modified path also // this hack was added 'cause migrate need functionality when // it changes VE private for given VE (in one partition), so // we don't want to recalculate quota and do simple quota file renaming if (option & FL_PATH) { if (qd.path_len && qd.path) { qd.path = xstrdup(mount_point); debug(LOG_INFO, "Set mount point path to %s\n", mount_point); } else debug(LOG_INFO, "Mount point path will not be changed, " "it's relative\n"); } /* mark quota dirty */ if (option & FL_FORCE) qd.head.flags |= QUOTA_DIRTY; /* we must read and write whole files cause of checksum */ if (write_quota_file(fd, &qd, IOF_ALL) < 0) exit(EC_QUOTAFILE); #ifdef _DEBUG print_status(&qd); print_ugid_status(&qd); #endif free_quota_data(&qd); close_quota_file(fd); debug(LOG_INFO, "Quota limits were set for id %d\n", quota_id); } static void quota_setugid(int ugid, struct dq_stat * lim, struct dq_info * info) { int fd; struct qf_data data; int type; init_quota_data(&data); fd = open_quota_file(quota_id, config_file, O_RDWR); if (fd < 0) { if (errno == ENOENT) exit(EC_NOQUOTAFILE); else exit(EC_QUOTAFILE); } if (check_quota_file(fd) < 0) exit(EC_QUOTAFILE); if (read_quota_file(fd, &data, IOF_ALL) < 0) exit(EC_QUOTAFILE); /* Check that 2-level quota is off */ if (quota_syscall_stat(&data, 0) < 0) { /* indicate that quota is off */ error(EC_NOTRUN, 0, "Quota accounting is off"); } if (!(data.ugid_stat.info.config.flags & VZDQUG_ON)) { /* 2-level is off */ error(EC_NOTRUN, 0, "Second level quota accounting is off"); } type = (option & FL_L2_GROUP) ? GRPQUOTA : USRQUOTA; if (info != NULL) { data.ugid_stat.info.ugid_info[type] = *info; if (vzquotactl_ugid_setgrace(&data, type, info) < 0) error(EC_VZCALL, errno, "quotactl failed"); } if (lim != NULL) { // Set ugid limits struct dquot * dq; int dirty; dirty = 0; /* user enter 1 k block, setugid call get 1 k blocks, another calls get bytes */ if (vzquotactl_ugid_setlimit(&data, ugid, type, lim) < 0) { if (errno == ESRCH) { /* ugid entry not found in kernel*/ dirty = 1; } else error(EC_VZCALL, errno, "quotactl failed"); } /* add to file */ dq = lookup_dquot_(&data.ugid_stat, ugid, type); if (dq == NODQUOT) { dq = add_dquot_(&data.ugid_stat, ugid, type); dirty = 1; data.ugid_stat.info.buf_size ++; } /* user enter 1 k block, kernel get bytes */ lim->bhardlimit = block2ker(lim->bhardlimit); lim->bsoftlimit = block2ker(lim->bsoftlimit); dq->obj.istat.qi_stat = *lim; if (dirty) { dq->obj.flags = UGID_DIRTY; data.head.flags |= QUOTA_DIRTY; } } /* we must read and write whole files cause of checksum */ if (write_quota_file(fd, &data, IOF_ALL) < 0) exit(EC_QUOTAFILE); close_quota_file(fd); free_quota_data(&data); } int quotainit_proc(int argc, char **argv) { parse_options(argc, argv, quotainit_short_options, quotainit_long_options, quotainit_usage, 0); if (!(option & FL_VEID) || !(option & FL_PATH) || ((option & FL_LIMITS) != FL_LIMITS)) /* if take limits from command string and */ /* there isn't all limit parameters */ usage(quotainit_usage); quota_init(); return 0; } int quotaon_proc(int argc, char **argv) { parse_options(argc, argv, quotaon_short_options, quotaon_long_options, quotaon_usage, 0); if (!(option & FL_VEID)) usage(quotaon_usage); quota_on(); return 0; } int quotaoff_proc(int argc, char **argv) { parse_options(argc, argv, quotaoff_short_options, quotaoff_long_options, quotaoff_usage, 0); if (!(option & FL_VEID)) usage(quotaoff_usage); quota_off(); return 0; } int quotaset_proc(int argc, char **argv) { parse_options(argc, argv, quotaset_short_options, quotaset_long_options, quotaset_usage, 0); if (!(option & FL_VEID) || (!(option & FL_PATH) && !(option & FL_LIMITS) && !(option & FL_UGIDS) && !(option & FL_FORCE)) ) usage(quotaset_usage); quota_set(); return 0; } int quotaugidset_proc(int argc, char **argv) { int rc; rc = parse_options(argc, argv, quotaugidset_short_options, quotaugidset_long_options, quotaugidset_usage, PARSE_SETUGID); argc -= (rc+1); argv += (rc+1); if (!(option & FL_VEID)) usage(quotaugidset_usage); if (option & FL_L2_GRACE) { struct dq_info info; memset(&info, 0, sizeof(info)); if (argc != 2 || str2time(*argv++, &info.bexpire) < 0 || str2time(*argv++, &info.iexpire) < 0) usage(quotaugidset_usage); quota_setugid(0, NULL, &info); } else { struct dq_stat stat; unsigned int ugid; /* get ugid */ if (argc != 5 || str2uint(*argv++, &ugid) < 0) usage(quotaugidset_usage); /* get limits */ memset(&stat, 0, sizeof(stat)); if (str2u64(*argv++, &stat.bsoftlimit) < 0 || str2u64(*argv++, &stat.bhardlimit) < 0 || str2u32(*argv++, &stat.isoftlimit) < 0 || str2u32(*argv++, &stat.ihardlimit) < 0) usage(quotaugidset_usage); quota_setugid(ugid, &stat, NULL); } return 0; } int quotadrop_proc(int argc, char **argv) { parse_options(argc, argv, quotadrop_short_options, quotadrop_long_options, quotadrop_usage, 0); if (!(option & FL_VEID)) usage(quotadrop_usage); quota_drop(); return 0; } int quotareloadugid_proc(int argc, char **argv) { parse_options(argc, argv, quotareloadugid_short_options, quotareloadugid_long_options, quotareloadugid_usage, 0); if (!(option & FL_VEID)) usage(quotareloadugid_usage); quota_reload_ugid(); return 0; } vzquota-3.1.orig/src/main.c0000644000000000000000000000466512023504012012572 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "vzquota.h" #include "common.h" char *command_name; const char *program_name = "vzquota"; static char cmd_usage[] = "Usage: %s [options] command quotaid [command-options-and-arguments]\n\n" "vzquota commands are:\n" "\tinit Initialize quota data for given quotaid\n" "\ton Turn on quota accounting for given quotaid\n" "\toff Turn off quota accounting for given quotaid\n" "\tdrop Delete quota limits from file\n" "\tsetlimit Set quota limits for given quotaid\n" "\tsetlimit2 Set L2 quota limits for given quotaid and QUGID\n" "\treload2 Reload L2 quota limits from quota file for given quotaid\n" "\tstat Show usage and quota limits for given quotaid\n" "\tshow Show usage and quota limits from quota file\n"; static const struct cmd { char *fullname; /* Full name of the function (e.g. "commit") */ int (*func) (); /* Function takes (argc, argv) arguments. */ } cmds[] = { { "on", quotaon_proc}, { "off", quotaoff_proc}, { "init", quotainit_proc}, { "drop", quotadrop_proc}, { "setlimit", quotaset_proc}, { "setlimit2", quotaugidset_proc}, { "reload2", quotareloadugid_proc}, { "stat", vestat_proc}, { "show", quotashow_proc}, { NULL, NULL} }; int main(int argc, char **argv) { int err; const struct cmd *cm; parse_global_options(&argc, &argv, cmd_usage); /* Look up the command name. */ command_name = argv[0]; for (cm = cmds; cm->fullname; cm++) { if (!strcmp(command_name, cm->fullname)) break; } if (!cm->fullname) { fprintf(stderr, "Unknown command: '%s'\n\n", command_name); usage(cmd_usage); } else command_name = cm->fullname; err = (*(cm->func)) (argc, argv); exit(err); } vzquota-3.1.orig/include/0000755000000000000000000000000012023504012012323 5ustar vzquota-3.1.orig/include/linux/0000755000000000000000000000000012023504012013462 5ustar vzquota-3.1.orig/include/linux/vzctl_quota.h0000644000000000000000000000316412023504012016212 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_VZCTL_QUOTA_H__ #define __LINUX_VZCTL_QUOTA_H__ /* * Quota management ioctl */ struct vz_quota_stat; struct vzctl_quotactl { int cmd; unsigned int quota_id; struct vz_quota_stat *qstat; char *ve_root; }; struct vzctl_quotaugidctl { int cmd; /* subcommand */ unsigned int quota_id; /* quota id where it applies to */ unsigned int ugid_index;/* for reading statistic. index of first uid/gid record to read */ unsigned int ugid_size; /* size of ugid_buf array */ void *addr; /* user-level buffer */ }; #define VZDQCTLTYPE '+' #define VZCTL_QUOTA_CTL _IOWR(VZDQCTLTYPE, 1, \ struct vzctl_quotactl) #define VZCTL_QUOTA_NEW_CTL _IOWR(VZDQCTLTYPE, 2, \ struct vzctl_quotactl) #define VZCTL_QUOTA_UGID_CTL _IOWR(VZDQCTLTYPE, 3, \ struct vzctl_quotaugidctl) #endif /* __LINUX_VZCTL_QUOTA_H__ */ vzquota-3.1.orig/include/linux/quota.h0000644000000000000000000002764212023504012014777 0ustar /* * Copyright (c) 1982, 1986 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. 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. * * Version: $Id: quota.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $ */ #ifndef _LINUX_QUOTA_ #define _LINUX_QUOTA_ #include #include #define __DQUOT_VERSION__ "dquot_6.5.1" #define __DQUOT_NUM_VERSION__ 6*10000+5*100+1 typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */ typedef __u64 qsize_t; /* Type in which we store sizes */ /* Size of blocks in which are counted size limits */ #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) #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", \ }; /* * 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_SYNC 0x800001 /* sync disk copy of a filesystems quotas */ #define Q_QUOTAON 0x800002 /* turn quotas on */ #define Q_QUOTAOFF 0x800003 /* turn quotas off */ #define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ #define Q_GETINFO 0x800005 /* get information about quota files */ #define Q_SETINFO 0x800006 /* set information about quota files */ #define Q_GETQUOTA 0x800007 /* get user quota structure */ #define Q_SETQUOTA 0x800008 /* set user quota structure */ /* * Quota structure used for communication with userspace via quotactl * Following flags are used to specify which fields are valid */ #define QIF_BLIMITS 1 #define QIF_SPACE 2 #define QIF_ILIMITS 4 #define QIF_INODES 8 #define QIF_BTIME 16 #define QIF_ITIME 32 #define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) #define QIF_USAGE (QIF_SPACE | QIF_INODES) #define QIF_TIMES (QIF_BTIME | QIF_ITIME) #define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) struct if_dqblk { __u64 dqb_bhardlimit; __u64 dqb_bsoftlimit; __u64 dqb_curspace; __u64 dqb_ihardlimit; __u64 dqb_isoftlimit; __u64 dqb_curinodes; __u64 dqb_btime; __u64 dqb_itime; __u32 dqb_valid; }; /* * Structure used for setting quota information about file via quotactl * Following flags are used to specify which fields are valid */ #define IIF_BGRACE 1 #define IIF_IGRACE 2 #define IIF_FLAGS 4 #define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) struct if_dqinfo { __u64 dqi_bgrace; __u64 dqi_igrace; __u32 dqi_flags; __u32 dqi_valid; }; #ifdef __KERNEL__ #include extern spinlock_t dq_list_lock; extern spinlock_t dq_data_lock; #include #include #include /* Maximal numbers of writes for quota operation (insert/delete/update) * (over all formats) - info block, 4 pointer blocks, data block */ #define DQUOT_MAX_WRITES 6 /* * Data for one user/group kept in memory */ struct mem_dqblk { __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ qsize_t dqb_curspace; /* current used space */ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ __u32 dqb_isoftlimit; /* preferred inode limit */ __u32 dqb_curinodes; /* current # allocated inodes */ time_t dqb_btime; /* time limit for excessive disk use */ time_t dqb_itime; /* time limit for excessive inode use */ }; /* * Data for one quotafile kept in memory */ struct quota_format_type; struct mem_dqinfo { struct quota_format_type *dqi_format; struct list_head dqi_dirty_list; /* List of dirty dquots */ unsigned long dqi_flags; unsigned int dqi_bgrace; unsigned int dqi_igrace; union { struct v1_mem_dqinfo v1_i; struct v2_mem_dqinfo v2_i; } u; }; struct super_block; #define DQF_MASK 0xffff /* Mask for format specific flags */ #define DQF_INFO_DIRTY_B 16 #define DQF_INFO_DIRTY (1 << DQF_INFO_DIRTY_B) /* Is info dirty? */ extern void mark_info_dirty(struct super_block *sb, int type); #define info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags) #define info_any_dquot_dirty(info) (!list_empty(&(info)->dqi_dirty_list)) #define info_any_dirty(info) (info_dirty(info) || info_any_dquot_dirty(info)) #define sb_dqopt(sb) (&(sb)->s_dquot) #define sb_dqinfo(sb, type) (sb_dqopt(sb)->info+(type)) struct dqstats { int lookups; int drops; int reads; int writes; int cache_hits; int allocated_dquots; int free_dquots; int syncs; }; extern struct dqstats dqstats; #define DQ_MOD_B 0 /* dquot modified since read */ #define DQ_BLKS_B 1 /* uid/gid has been warned about blk limit */ #define DQ_INODES_B 2 /* uid/gid has been warned about inode limit */ #define DQ_FAKE_B 3 /* no limits only usage */ #define DQ_READ_B 4 /* dquot was read into memory */ #define DQ_ACTIVE_B 5 /* dquot is active (dquot_release not called) */ #define DQ_WAITFREE_B 6 /* dquot being waited (by invalidate_dquots) */ struct dquot { struct hlist_node dq_hash; /* Hash list in memory */ struct list_head dq_inuse; /* List of all quotas */ struct list_head dq_free; /* Free list element */ struct list_head dq_dirty; /* List of dirty dquots */ struct semaphore dq_lock; /* dquot IO lock */ atomic_t dq_count; /* Use count */ wait_queue_head_t dq_wait_unused; /* Wait queue for dquot to become unused */ struct super_block *dq_sb; /* superblock this applies to */ unsigned int dq_id; /* ID this applies to (uid, gid) */ loff_t dq_off; /* Offset of dquot on disk */ unsigned long dq_flags; /* See DQ_* */ short dq_type; /* Type of quota */ struct mem_dqblk dq_dqb; /* Diskquota usage */ }; #define NODQUOT (struct dquot *)NULL #define QUOTA_OK 0 #define NO_QUOTA 1 /* Operations which must be implemented by each quota format */ struct quota_format_ops { int (*check_quota_file)(struct super_block *sb, int type); /* Detect whether file is in our format */ int (*read_file_info)(struct super_block *sb, int type); /* Read main info about file - called on quotaon() */ int (*write_file_info)(struct super_block *sb, int type); /* Write main info about file */ int (*free_file_info)(struct super_block *sb, int type); /* Called on quotaoff() */ int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ int (*commit_dqblk)(struct dquot *dquot); /* Write structure for one user */ int (*release_dqblk)(struct dquot *dquot); /* Called when last reference to dquot is being dropped */ }; struct inode; struct iattr; /* Operations working with dquots */ struct dquot_operations { int (*initialize) (struct inode *, int); int (*drop) (struct inode *); int (*alloc_space) (struct inode *, qsize_t, int); int (*alloc_inode) (const struct inode *, unsigned long); int (*free_space) (struct inode *, qsize_t); int (*free_inode) (const struct inode *, unsigned long); int (*transfer) (struct inode *, struct iattr *); int (*write_dquot) (struct dquot *); /* Ordinary dquot write */ int (*acquire_dquot) (struct dquot *); /* Quota is going to be created on disk */ int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */ int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */ int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */ int (*rename) (struct inode *, struct inode *, struct inode *); }; /* Operations handling requests from userspace */ struct v2_disk_dqblk; struct quotactl_ops { int (*quota_on)(struct super_block *, int, int, char *); int (*quota_off)(struct super_block *, int); int (*quota_sync)(struct super_block *, int); int (*get_info)(struct super_block *, int, struct if_dqinfo *); int (*set_info)(struct super_block *, int, struct if_dqinfo *); int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); int (*get_xstate)(struct super_block *, struct fs_quota_stat *); int (*set_xstate)(struct super_block *, unsigned int, int); int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); #ifdef CONFIG_QUOTA_COMPAT int (*get_quoti)(struct super_block *, int, unsigned int, struct v2_disk_dqblk *); #endif }; struct quota_format_type { int qf_fmt_id; /* Quota format id */ struct quota_format_ops *qf_ops; /* Operations of format */ struct module *qf_owner; /* Module implementing quota format */ struct quota_format_type *qf_next; }; #define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ #define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ struct quota_info { unsigned int flags; /* Flags for diskquotas on this device */ struct semaphore dqio_sem; /* lock device while I/O in progress */ struct semaphore dqonoff_sem; /* Serialize quotaon & quotaoff */ struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */ struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ }; /* Inline would be better but we need to dereference super_block which is not defined yet */ int mark_dquot_dirty(struct dquot *dquot); #define dquot_dirty(dquot) test_bit(DQ_MOD_B, &(dquot)->dq_flags) #define sb_has_quota_enabled(sb, type) ((type)==USRQUOTA ? \ (sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) : (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED)) #define sb_any_quota_enabled(sb) (sb_has_quota_enabled(sb, USRQUOTA) | \ sb_has_quota_enabled(sb, GRPQUOTA)) int register_quota_format(struct quota_format_type *fmt); void unregister_quota_format(struct quota_format_type *fmt); struct quota_module_name { int qm_fmt_id; char *qm_mod_name; }; #define INIT_QUOTA_MODULE_NAMES {\ {QFMT_VFS_OLD, "quota_v1"},\ {QFMT_VFS_V0, "quota_v2"},\ {0, NULL}} #else # /* nodep */ include __BEGIN_DECLS long quotactl __P ((unsigned int, const char *, int, caddr_t)); __END_DECLS #endif /* __KERNEL__ */ #endif /* _QUOTA_ */ vzquota-3.1.orig/include/linux/vzquota.h0000644000000000000000000001066712023504012015356 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _VZDQUOTA_H #define _VZDQUOTA_H #include #include /* vzquotactl syscall commands */ #define VZ_DQ_CREATE 5 /* create quota master block */ #define VZ_DQ_DESTROY 6 /* destroy qmblk */ #define VZ_DQ_ON 7 /* mark dentry with already created qmblk */ #define VZ_DQ_OFF 8 /* remove mark, don't destroy qmblk */ #define VZ_DQ_SETLIMIT 9 /* set new limits */ #define VZ_DQ_GETSTAT 10 /* get usage statistic */ #define VZ_DQ_OFF_FORCED 11 /* forced off */ /* set of syscalls to maintain UGID quotas */ #define VZ_DQ_UGID_GETSTAT 1 /* get usage/limits for ugid(s) */ #define VZ_DQ_UGID_ADDSTAT 2 /* set usage/limits statistic for ugid(s) */ #define VZ_DQ_UGID_GETGRACE 3 /* get expire times */ #define VZ_DQ_UGID_SETGRACE 4 /* set expire times */ #define VZ_DQ_UGID_GETCONFIG 5 /* get ugid_max limit, cnt, flags of qmblk */ #define VZ_DQ_UGID_SETCONFIG 6 /* set ugid_max limit, flags of qmblk */ #define VZ_DQ_UGID_SETLIMIT 7 /* set ugid B/I limits */ #define VZ_DQ_UGID_SETINFO 8 /* set ugid info */ /* common structure for vz and ugid quota */ struct dq_stat { /* blocks limits */ __u64 bhardlimit; /* absolute limit in bytes */ __u64 bsoftlimit; /* preferred limit in bytes */ time_t btime; /* time limit for excessive disk use */ __u64 bcurrent; /* current bytes count */ /* inodes limits */ __u32 ihardlimit; /* absolute limit on allocated inodes */ __u32 isoftlimit; /* preferred inode limit */ time_t itime; /* time limit for excessive inode use */ __u32 icurrent; /* current # allocated inodes */ }; /* One second resolution for grace times */ #define CURRENT_TIME_SECONDS (get_seconds()) /* Values for dq_info->flags */ #define VZ_QUOTA_INODES 0x01 /* inodes limit warning printed */ #define VZ_QUOTA_SPACE 0x02 /* space limit warning printed */ struct dq_info { time_t bexpire; /* expire timeout for excessive disk use */ time_t iexpire; /* expire timeout for excessive inode use */ unsigned flags; /* see previos defines */ }; struct vz_quota_stat { struct dq_stat dq_stat; struct dq_info dq_info; }; /* UID/GID interface record - for user-kernel level exchange */ struct vz_quota_iface { unsigned int qi_id; /* UID/GID this applies to */ unsigned int qi_type; /* USRQUOTA|GRPQUOTA */ struct dq_stat qi_stat; /* limits, options, usage stats */ }; /* values for flags and dq_flags */ /* this flag is set if the userspace has been unable to provide usage * information about all ugids * if the flag is set, we don't allocate new UG quota blocks (their * current usage is unknown) or free existing UG quota blocks (not to * lose information that this block is ok) */ #define VZDQUG_FIXED_SET 0x01 /* permit to use ugid quota */ #define VZDQUG_ON 0x02 #define VZDQ_USRQUOTA 0x10 #define VZDQ_GRPQUOTA 0x20 #define VZDQ_NOACT 0x1000 /* not actual */ #define VZDQ_NOQUOT 0x2000 /* not under quota tree */ struct vz_quota_ugid_stat { unsigned int limit; /* max amount of ugid records */ unsigned int count; /* amount of ugid records */ unsigned int flags; }; struct _if_dqblk { u_int64_t dqb_bhardlimit; u_int64_t dqb_bsoftlimit; u_int64_t dqb_curspace; u_int64_t dqb_ihardlimit; u_int64_t dqb_isoftlimit; u_int64_t dqb_curinodes; u_int64_t dqb_btime; u_int64_t dqb_itime; u_int32_t dqb_valid; }; struct vz_quota_ugid_setlimit { unsigned int type; /* quota type (USR/GRP) */ unsigned int id; /* ugid */ struct _if_dqblk dqb; /* limits info */ }; struct _if_dqinfo { u_int64_t dqi_bgrace; u_int64_t dqi_igrace; u_int32_t dqi_flags; u_int32_t dqi_valid; }; struct vz_quota_ugid_setinfo { unsigned int type; /* quota type (USR/GRP) */ struct _if_dqinfo dqi; /* grace info */ }; #endif /* _VZDQUOTA_H */ vzquota-3.1.orig/include/quota_io.h0000644000000000000000000001354512023504012014324 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __VZQUOTA_H__ #define __VZQUOTA_H__ #include "vzquota.h" #ifndef VARDIR #define VARDIR "/var" #endif #define VZQUOTA_FILES_PATH_VZ3 VARDIR "/vzquota" #define VZQUOTA_FILE_NAME "quota" #define DEFAULT_PRIVATE_FS "fs" #define MAGIC_V3 0xFEDCBC27 /* current quota v3 with ugid */ #define MAGIC_V2 0xFEDCBB00 /* quota v2 */ #define MAGIC_V1 0xFEDCBA98 /* quota v1 */ #define MAGIC_CURRENT MAGIC_V3 #define MAXFILENAMELEN 128 /* Maximal length of filename */ #define E_FILECORRUPT 0x2000 /* Quota file corrupted */ #define QUOTA_ON 0x0001 #define QUOTA_DIRTY 0x0002 #define QUOTA_UGID_ON 0x0004 #define UGID_LOADED 0x0001 #define UGID_DIRTY 0x0002 #define UGID_ALL 0xFFFFFFFF struct vz_quota_header { int magic; int flags; }; #define MAXQUOTAS 2 #define USRQUOTA 0 /* element used for user quotas */ #define GRPQUOTA 1 /* element used for group quotas */ #define DQUOTHASHSIZE 1023 /* Size of hashtable for dquots from file */ #define QUOTANAMES { \ "user", /* USRQUOTA */ \ "group" /* GRPQUOTA */ \ } #define NODQUOT ((struct dquot *)NULL) /* Structure for one loaded quota */ struct ugid_info { struct vz_quota_ugid_stat config; /* flags(on/off, limit_exceeded), ugid_limit, current ugids */ unsigned int buf_size; /* number of used entries in ugid_quota.buf */ struct dq_info ugid_info[MAXQUOTAS]; /* array of timeouts */ }; struct ugid_obj { struct vz_quota_iface istat; unsigned int flags; /* set of UGID_OBJ_xxx */ }; struct dquot { struct dquot *dq_next; /* Pointer to next dquot in the list */ struct ugid_obj obj; /* Pointer to an element in ugid_quota.buf */ }; /* ugid quota data */ struct ugid_quota { struct ugid_info info; /* general quota info */ unsigned int dquot_size; /* number of allocated entries in dquot_hash */ struct dquot *dquot_hash[MAXQUOTAS][DQUOTHASHSIZE]; }; /* check sum */ typedef __u64 chksum_t; /* data extracted from quota file */ struct qf_data { int version; /* field calculated from head.magic */ struct vz_quota_header head; /* quota flags and version */ struct vz_quota_stat stat; /* 1-level quota stat */ size_t path_len; /* mount pount path length */ char *path; /* mount point path */ struct ugid_quota ugid_stat; /* 2-level quota stat and ugid objects */ chksum_t chksum; /* quota file checksum*/ }; #define IOF_ALL 0xFFFFFFFF #define IOF_HEAD 0x01 #define IOF_STAT 0x02 #define IOF_PATH 0x04 #define IOF_UGID_INFO 0x08 #define IOF_UGID_BUF 0x10 #define IOF_CHKSUM 0x20 #define IOF_UGID_FLAGS 0x40 /* buffer size in bytes for ugid objects read/write operaitons and syscalls */ #ifndef _DEBUG #define IO_BUF_SIZE (64*1024) #else #define IO_BUF_SIZE (300) #endif int open_quota_file(unsigned int quota_id, const char *name, int flags); int unlink_quota_file(unsigned int quota_id, const char *name); int close_quota_file(int fd); int read_field(int fd, void *field, size_t size, off_t offset); int write_field(int fd, const void *field, size_t size, off_t offset); int read_quota_file(int fd, struct qf_data *q, int io_flags); int write_quota_file(int fd, struct qf_data *q, int io_flags); int check_quota_file(int fd); int do_check_quota_file(int fd, int reformat); int get_quota_version(struct vz_quota_header *head); char *type2name(int type); /* ugid */ //inline unsigned int hash_dquot(unsigned int id); struct dquot *lookup_dquot_(struct ugid_quota *q, unsigned int id, unsigned int type); struct dquot *lookup_dquot(struct ugid_quota *q, struct ugid_obj *obj); struct dquot *add_dquot_(struct ugid_quota *q, unsigned int id, unsigned int type); struct dquot *add_dquot(struct ugid_quota *q, struct ugid_obj *obj); void drop_dquot_(struct ugid_quota *q, unsigned int id, int type); void drop_dquot(struct ugid_quota *q, struct ugid_obj *obj); void reset_dquot_search(); struct dquot *get_next_dquot(struct ugid_quota *q); void sort_dquot(struct ugid_quota *q, struct dquot **obj); void drop_dummy_ugid(struct ugid_quota *q); void drop_ugid_by_flags(struct ugid_quota *q, unsigned int mask); void free_ugid_quota( struct ugid_quota *q); void clean_ugid_info( struct ugid_quota *q); void add_ugid_usage(struct ugid_quota *q, unsigned int type, unsigned int id, qint space); void reset_ugid_usage( struct ugid_quota *q); void reset_ugid_flags( struct ugid_quota *q, unsigned int mask); int is_ugid_dirty( struct ugid_quota *q); int comp_dquot(const void *pa, const void *pb); /* these func are defined in src/stat.c */ void print_status(struct qf_data *qd); void print_ugid_status(struct qf_data *qd); /* quota file */ void init_quota_data(struct qf_data *qd); void free_quota_data(struct qf_data *qd); char *get_quota_path(struct qf_data *qd); //int is_dummy_stat(struct *dq_stat stat); /* syscalls */ int quota_syscall_on(struct qf_data *qd); int quota_syscall_off(struct qf_data *qd); int quota_syscall_stat(struct qf_data *qd, int no_ugid_stat); int quota_syscall_setlimit(struct qf_data *qd, int no_stat, int no_ugid_stat); int vzquotactl_ugid_setlimit(struct qf_data * data, int id, int type, struct dq_stat * lim); int vzquotactl_ugid_setgrace(struct qf_data * data, int type, struct dq_info * lim); #endif /* __VZQUOTA_H__ */ vzquota-3.1.orig/include/quotadump.h0000644000000000000000000000205212023504012014512 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __QUOTADUMP_H__ #define __QUOTADUMP_H__ #define FIRST_LEVEL_LABEL "first_level_quota:" #define STATUS_LABEL "ugid_quota_status:" #define GRACE_LABEL "grace_time:" #define NUMBER_LABEL "ugid_number:" #define UGID_LABEL "ugid:" #endif /* __QUOTADUMP_H__ */ vzquota-3.1.orig/include/vzquota.h0000644000000000000000000001163312023504012014211 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __VZQUOTA_UTIL_H__ #define __VZQUOTA_UTIL_H__ #define __USE_UNIX98 #include #include #include #include #include #include #include #include "linux/vzquota.h" #include "linux/vzctl_quota.h" #include "kcompat.h" #define QMAXDEVLEN 128 #define QMAXPATHLEN 128 #define QMAXTYPELEN 32 #define QMAXOPTLEN 128 #define QMAXGARBLEN 512 #define QMAXTIMELEN 64 /* kernel space data type */ typedef __u64 qint; /* 1k block size */ #define BLOCK_BITS 10 #define BLOCK_SIZE (1 << BLOCK_BITS) /* block size used in stat syscall */ #define STAT_BLOCK_BITS 9 #define STAT_BLOCK_SIZE (1 << STAT_BLOCK_BITS) /* conversion between 1K block and bytes */ #define block2size(x) (((__u64) (x)) << BLOCK_BITS) #define size2block(x) ((__u32) (((x) + BLOCK_SIZE - 1) >> BLOCK_BITS)) /* conversion between (1K block, bytes) and kernel representation of quota */ /* these macros defines 32-bit or 64-bit quota */ #define size2ker(x) ((qint) (x)) #define block2ker(x) (((qint) (x)) << BLOCK_BITS) #define ker2size(x) ((__u64) (x)) #define ker2block(x) ((__u64) (((x) + BLOCK_SIZE - 1) >> BLOCK_BITS)) /* defines ration between quota and stat block size */ #define STAT_PER_QUOTA (BLOCK_SIZE / STAT_BLOCK_SIZE) /* Flags for formatting time */ #define TF_ROUND 0x1 /* Should be printed time rounded? */ /* Maximum retry number */ #define MAX_RETRY 9 extern FILE *mount_fd; extern char dev[QMAXDEVLEN]; //void usage(char *line); int vestat_proc(int argc, char **argv); int quotashow_proc(int argc, char **argv); int quotaon_proc(int argc, char **argv); int quotaoff_proc(int argc, char **argv); int quotaset_proc(int argc, char **argv); int quotaugidset_proc(int argc, char **argv); int quotareloadugid_proc(int argc, char **argv); int quotainit_proc(int argc, char **argv); int quotadrop_proc(int argc, char **argv); long vzquotactl_syscall( int cmd, unsigned int quota_id, struct vz_quota_stat *qstat, const char *ve_root); long vzquotactl_ugid_syscall( int _cmd, /* subcommand */ unsigned int _quota_id, /* quota id where it applies to */ unsigned int _ugid_index,/* for reading statistic. index of first uid/gid record to read */ unsigned int _ugid_size, /* size of ugid_buf array */ void *addr /* user-level buffer */ ); #define VZCTL_QUOTA_CTL_OLD _IOWR(VZDQCTLTYPE, 0, struct vzctl_quotactl) #define QUOTA_V3 3 /* current 2-level 32-bit 1K quota */ #define QUOTA_V2 2 /* previous 1-level 64-bit byte quota */ #define QUOTA_V1 1 /* first 1-level 32-bit 1K quota */ #define QUOTA_CURRENT QUOTA_V3 /* converts quota stat between different versions */ void convert_quota_stat( void *dest, int dest_ver, void *src, int src_ver); /* quota version 2 */ struct vz_quota_stat_old2 { /* bytes limits */ __u64 bhardlimit; /* absolute limit on disk bytes alloc */ __u64 bsoftlimit; /* preferred limit on disk bytes */ time_t bexpire; /* expire timeout for excessive disk use */ time_t btime; /* time limit for excessive disk use */ __u64 bcurrent; /* current bytes count */ /* inodes limits */ __u32 ihardlimit; /* absolute limit on allocated inodes */ __u32 isoftlimit; /* preferred inode limit */ __u32 icurrent; /* current # allocated inodes */ time_t iexpire; /* expire timeout for excessive inode use */ time_t itime; /* time limit for excessive inode use */ /* behaviour options */ int options; /* see VZ_QUOTA_OPT_* defines */ }; /* quota version 1 */ struct vz_quota_stat_old1 { /* bytes limits */ __u32 bhardlimit; /* absolute limit on disk 1K blocks alloc */ __u32 bsoftlimit; /* preferred limit on disk 1K blocks */ time_t bexpire; /* expire timeout for excessive disk use */ time_t btime; /* time limit for excessive disk use */ __u32 bcurrent; /* current 1K blocks count */ /* inodes limits */ __u32 ihardlimit; /* absolute limit on allocated inodes */ __u32 isoftlimit; /* preferred inode limit */ __u32 icurrent; /* current # allocated inodes */ time_t iexpire; /* expire timeout for excessive inode use */ time_t itime; /* time limit for excessive inode use */ /* behaviour options */ int options; /* see VZ_QUOTA_OPT_* defines */ }; #endif /* __VZQUOTA_UTIL_H__ */ vzquota-3.1.orig/include/quotacheck.h0000644000000000000000000000260212023504012014623 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __QUOTACHECK_H__ #define __QUOTACHECK_H__ #include #include "quota_io.h" #define HASHSIZE 65536 struct hardlink { ino_t inode_num; struct hardlink *next; }; struct dir { char *name; struct dir *next; }; struct scan_info { /* external fields */ qint size; int inodes; /* information (debug) fields */ int dirs; int files; int hard_links; /* internal fields */ struct dir *dir_stack; struct hardlink *links_hash[HASHSIZE]; struct ugid_quota *ugid_stat; int (*sync_fd)(int fd); }; void scan(struct scan_info *info, const char *mnt); #endif /* __QUOTACHECK_H__ */ vzquota-3.1.orig/include/kcompat.h0000644000000000000000000000315112023504012014132 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __KCOMPAT_H__ #define __KCOMPAT_H__ /* * This header file defines kernel structures for old quota interfaces */ #ifndef Q_SETGRACE #define Q_SETGRACE 0x0B00 /* set inode and block grace */ #define Q_SETQLIM 0x0700 /* set limits */ /* This is in-memory copy of quota block. See meaning of entries above */ struct mem_dqblk { unsigned int dqb_ihardlimit; unsigned int dqb_isoftlimit; unsigned int dqb_curinodes; unsigned int dqb_bhardlimit; unsigned int dqb_bsoftlimit; __u64 dqb_curspace; __kernel_time_t dqb_btime; __kernel_time_t dqb_itime; }; /* Inmemory copy of version specific information */ struct mem_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 #endif /* __KCOMPAT_H__ */ vzquota-3.1.orig/include/common.h0000644000000000000000000001262112023504012013766 0ustar /* * Copyright (C) 2000-2008, Parallels, Inc. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __COMMON_H__ #define __COMMON_H__ #include #include #include #include #include "vzquota.h" /* current utilities version */ #define VZQUOTA_VERSION "2.5.0" #define FL_VEID 0x0000001 #define FL_PATH 0x0000002 #define FL_FORCE 0x0000004 /*#define FL_FROM_LINE 0x0000008*/ #define FL_CONF_FILE 0x0000010 #define FL_BSL 0x0000100 #define FL_BHL 0x0000200 #define FL_BET 0x0000400 #define FL_ISL 0x0001000 #define FL_IHL 0x0002000 #define FL_IET 0x0004000 #define FL_RSQ 0x0010000 /* FL_RSQ is depricated */ #define FL_SQT 0x0020000 #define FL_UGL 0x0040000 /* this is for dump utility*/ #define FL_DUMP_GRACE 0x0100000 #define FL_DUMP_LIMITS 0x0200000 #define FL_DUMP_EXPTIME 0x0400000 #define FL_DUMP_LIMITS_FIRST 0x0800000 /* this is for setlimit */ #define FL_L2_USER 0x0100000 /* set limits for user */ #define FL_L2_GROUP 0x0200000 /* set limits for group */ #define FL_L2_GRACE 0x0400000 /* set graces limits */ #define FL_NOCHECK 0x1000000 /* VZ4 scheme: quota config file path is relative to quota accounting point */ #define FL_RELATIVE 0x2000000 #define FL_L2_UGID (FL_L2_USER | FL_L2_GROUP) #define FL_LIMITS (FL_BSL | FL_BHL | FL_BET | FL_ISL | FL_IHL | FL_IET) #define FL_UGIDS (FL_SQT | FL_UGL) #define FL_DUMP (FL_DUMP_GRACE | FL_DUMP_LIMITS | FL_DUMP_EXPTIME | FL_DUMP_LIMITS_FIRST) extern __u32 option; extern unsigned int quota_id; extern char *mount_point; extern char *config_file; extern char *actual_config_file; extern struct vz_quota_stat limits; extern struct vz_quota_ugid_stat ug_config; extern char *command_name; extern const char* program_name; /* exit codes */ #define EC_SUCCESS 0 #define EC_SYSTEM 1 #define EC_USAGE 2 #define EC_VZCALL 3 #define EC_QUOTAFILE 4 #define EC_RUN 5 #define EC_NOTRUN 6 #define EC_LOCK 7 #define EC_EXDEV 8 #define EC_UG_NOTRUN 9 /* quota is running but user/group quota is inactive */ /* this code is returned by "stat -t" command for information purposes * and does not indicate a error; DO NOT USE IT! */ #define EC_QUOTADIRTY 10 /* quota is marked dirty in file */ /* this code is returned by "show" command for information purposes * and does not indicate a error; DO NOT USE IT! */ #define EC_NOQUOTAFILE 11 /* quota file does not exist */ #if 0 /* * Reserverd error for the future purposes */ #define EC_CONFIGFILE 12 /* can't open/parse VE config file */ #endif #define EC_NOMOUNTPOINT 13 /* can't get quota mount point */ #define EC_ASSERT 255 /* log levels */ #define LOG_ERROR 0x01 #define LOG_WARNING 0x02 #define LOG_INFO 0x03 #define LOG_DEBUG 0x04 #define VE_DQ_MIN 60 /* seconds */ #define VE_DQ_HOUR 60*VE_DQ_MIN #define VE_DQ_DAY 24*VE_DQ_HOUR #define VE_DQ_WEEK 7*VE_DQ_DAY #define VE_DQ_MONTH 30*VE_DQ_DAY #define VE_DQ_YEAR 365*VE_DQ_DAY #define FMT_BUFLEN 4*1024 /** max log output len */ #define VZQUOTA_LOG_PREFIX "vzquota : " extern int debug_level; extern int batch_mode; #define debug(level, fmt, args...) \ (debug_level < level ? (void)0 : debug_print(level, fmt, ##args)) void error(int status, int errnum, char *oformat, ...); #ifdef ASSERT #undef ASSERT #endif #ifdef NDEBUG #define ASSERT(condition) #else #define ASSERT(condition) \ do { \ if(!(condition)) \ error(EC_ASSERT,0,"ASSERTION FAILED: %s(%d), function '%s()', condition: %s", \ __FILE__, __LINE__, __FUNCTION__, #condition); \ } while(0) #endif void debug_print(int level, char *oformat, ...); void vdebug_print(int level, char *oformat, va_list pvar); void *xmalloc(size_t size); char *xstrdup(const char* s); void *xrealloc(void *p, size_t size); #define xfree(x) \ do { \ free(x); \ x = NULL; \ } while(0) /* int str2uint(char *str, unsigned int *number); */ /* int str2u32(char *str, __u32 * number); */ /* int str2u64(char *str, __u64 * number); */ int str2time(char *str, time_t * number); void difftime2str(time_t seconds, char *buf); void time2str(time_t seconds, char *buf, int flags); int str2uint(char *str, unsigned int *number); int str2u64(char *str, __u64 * number); int str2u32(char *str, __u32 * number); /* Parse options type. Some commands can use the same option letters in various context */ #define PARSE_SETUGID 1 int parse_options(int argc, char **argv, char *short_options, struct option *long_options, char *opt_usage, int cmd_type); /*pointers to argc and argv of main()*/ void parse_global_options(int *argc, char ***argv, const char *usg); void usage(const char *usg); typedef void (*func_cleaner_t) (void * data); void register_cleaner(func_cleaner_t func, void * data); void exit_cleanup(int status); #endif /* __COMMON_H__ */