1- use { Errno , Result , NixPath } ;
1+ //! Set and configure disk quotas for users, groups, or projects.
2+ //!
3+ //! # Examples
4+ //!
5+ //! Enabling and setting a quota:
6+ //!
7+ //! ```rust,no_run
8+ //! # use nix::sys::quota::*;
9+ //! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user");
10+ //! let mut dqblk: Dqblk = Default::default();
11+ //! dqblk.set_blocks_hard_limit(10000);
12+ //! dqblk.set_blocks_soft_limit(8000);
13+ //! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QIF_BLIMITS);
14+ //! ```
15+ use std:: default:: Default ;
16+ use std:: { mem, ptr} ;
217use libc:: { self , c_int, c_char} ;
18+ use { Errno , Result , NixPath } ;
319
4- #[ cfg( all( target_os = "linux" ,
5- any( target_arch = "x86" ,
6- target_arch = "x86_64" ,
7- target_arch = "arm" ) ) ,
8- ) ]
9- pub mod quota {
10- use libc:: { self , c_int} ;
20+ struct QuotaCmd ( QuotaSubCmd , QuotaType ) ;
1121
12- pub struct QuotaCmd ( pub QuotaSubCmd , pub QuotaType ) ;
13- pub type QuotaSubCmd = c_int ;
22+ impl QuotaCmd {
23+ fn as_int ( & self ) -> c_int {
24+ unsafe { libc:: QCMD ( self . 0 as i32 , self . 1 as i32 ) }
25+ }
26+ }
27+
28+ // linux quota version >= 2
29+ libc_enum ! {
30+ #[ repr( i32 ) ]
31+ enum QuotaSubCmd {
32+ Q_SYNC ,
33+ Q_QUOTAON ,
34+ Q_QUOTAOFF ,
35+ Q_GETFMT ,
36+ Q_GETINFO ,
37+ Q_SETINFO ,
38+ Q_GETQUOTA ,
39+ Q_SETQUOTA ,
40+ }
41+ }
42+
43+ libc_enum ! {
44+ /// The scope of the quota.
45+ #[ repr( i32 ) ]
46+ pub enum QuotaType {
47+ /// Specify a user quota
48+ USRQUOTA ,
49+ /// Specify a group quota
50+ GRPQUOTA ,
51+ }
52+ }
53+
54+ libc_enum ! {
55+ /// The type of quota format to use.
56+ #[ repr( i32 ) ]
57+ pub enum QuotaFmt {
58+ /// Use the original quota format.
59+ QFMT_VFS_OLD ,
60+ /// Use the standard VFS v0 quota format.
61+ ///
62+ /// Handles 32-bit UIDs/GIDs and quota limits up to 2^42 bytes/2^32 inodes.
63+ QFMT_VFS_V0 ,
64+ /// Use the VFS v1 quota format.
65+ ///
66+ /// Handles 32-bit UIDs/GIDs and quota limits of 2^64 bytes/2^64 inodes.
67+ QFMT_VFS_V1 ,
68+ }
69+ }
1470
15- impl QuotaCmd {
16- pub fn as_int ( & self ) -> c_int {
17- ( ( self . 0 << 8 ) | ( self . 1 & 0x00ff ) ) as c_int
71+ libc_bitflags ! (
72+ /// Indicates the quota fields that are valid to read from.
73+ #[ derive( Default ) ]
74+ pub struct QuotaValidFlags : u32 {
75+ /// The block hard & soft limit fields.
76+ QIF_BLIMITS ;
77+ /// The current space field.
78+ QIF_SPACE ;
79+ /// The inode hard & soft limit fields.
80+ QIF_ILIMITS ;
81+ /// The current inodes field.
82+ QIF_INODES ;
83+ /// The disk use time limit field.
84+ QIF_BTIME ;
85+ /// The file quote time limit field.
86+ QIF_ITIME ;
87+ /// All block & inode limits.
88+ QIF_LIMITS ;
89+ /// The space & inodes usage fields.
90+ QIF_USAGE ;
91+ /// The time limit fields.
92+ QIF_TIMES ;
93+ /// All fields.
94+ QIF_ALL ;
95+ }
96+ ) ;
97+
98+ /// Wrapper type for `if_dqblk`
99+ // FIXME: Change to repr(transparent)
100+ #[ repr( C ) ]
101+ #[ derive( Clone , Copy ) ]
102+ pub struct Dqblk ( libc:: dqblk ) ;
103+
104+ impl Default for Dqblk {
105+ fn default ( ) -> Dqblk {
106+ Dqblk ( libc:: dqblk {
107+ dqb_bhardlimit : 0 ,
108+ dqb_bsoftlimit : 0 ,
109+ dqb_curspace : 0 ,
110+ dqb_ihardlimit : 0 ,
111+ dqb_isoftlimit : 0 ,
112+ dqb_curinodes : 0 ,
113+ dqb_btime : 0 ,
114+ dqb_itime : 0 ,
115+ dqb_valid : 0 ,
116+ } )
117+ }
118+ }
119+
120+ impl Dqblk {
121+ /// The absolute limit on disk quota blocks allocated.
122+ pub fn blocks_hard_limit ( & self ) -> Option < u64 > {
123+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
124+ if valid_fields. contains ( QIF_BLIMITS ) {
125+ Some ( self . 0 . dqb_bhardlimit )
126+ } else {
127+ None
18128 }
19129 }
20130
21- // linux quota version >= 2
22- pub const Q_SYNC : QuotaSubCmd = 0x800001 ;
23- pub const Q_QUOTAON : QuotaSubCmd = 0x800002 ;
24- pub const Q_QUOTAOFF : QuotaSubCmd = 0x800003 ;
25- pub const Q_GETFMT : QuotaSubCmd = 0x800004 ;
26- pub const Q_GETINFO : QuotaSubCmd = 0x800005 ;
27- pub const Q_SETINFO : QuotaSubCmd = 0x800006 ;
28- pub const Q_GETQUOTA : QuotaSubCmd = 0x800007 ;
29- pub const Q_SETQUOTA : QuotaSubCmd = 0x800008 ;
30-
31- pub type QuotaType = c_int ;
32-
33- pub const USRQUOTA : QuotaType = 0 ;
34- pub const GRPQUOTA : QuotaType = 1 ;
35-
36- pub type QuotaFmt = c_int ;
37-
38- pub const QFMT_VFS_OLD : QuotaFmt = 1 ;
39- pub const QFMT_VFS_V0 : QuotaFmt = 2 ;
40- pub const QFMT_VFS_V1 : QuotaFmt = 4 ;
41-
42- libc_bitflags ! (
43- #[ derive( Default ) ]
44- pub struct QuotaValidFlags : u32 {
45- QIF_BLIMITS ;
46- QIF_SPACE ;
47- QIF_ILIMITS ;
48- QIF_INODES ;
49- QIF_BTIME ;
50- QIF_ITIME ;
51- QIF_LIMITS ;
52- QIF_USAGE ;
53- QIF_TIMES ;
54- QIF_ALL ;
131+ /// Set the absolute limit on disk quota blocks allocated.
132+ pub fn set_blocks_hard_limit ( & mut self , limit : u64 ) {
133+ self . 0 . dqb_bhardlimit = limit;
134+ }
135+
136+ /// Preferred limit on disk quota blocks
137+ pub fn blocks_soft_limit ( & self ) -> Option < u64 > {
138+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
139+ if valid_fields. contains ( QIF_BLIMITS ) {
140+ Some ( self . 0 . dqb_bsoftlimit )
141+ } else {
142+ None
55143 }
56- ) ;
57-
58- #[ repr( C ) ]
59- #[ derive( Default , Debug , Copy , Clone ) ]
60- pub struct Dqblk {
61- pub bhardlimit : u64 ,
62- pub bsoftlimit : u64 ,
63- pub curspace : u64 ,
64- pub ihardlimit : u64 ,
65- pub isoftlimit : u64 ,
66- pub curinodes : u64 ,
67- pub btime : u64 ,
68- pub itime : u64 ,
69- pub valid : QuotaValidFlags ,
70144 }
71- }
72145
73- use std:: ptr;
146+ /// Set the preferred limit on disk quota blocks allocated.
147+ pub fn set_blocks_soft_limit ( & mut self , limit : u64 ) {
148+ self . 0 . dqb_bsoftlimit = limit;
149+ }
150+
151+ /// Current occupied space (bytes).
152+ pub fn occupied_space ( & self ) -> Option < u64 > {
153+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
154+ if valid_fields. contains ( QIF_SPACE ) {
155+ Some ( self . 0 . dqb_curspace )
156+ } else {
157+ None
158+ }
159+ }
160+
161+ /// Maximum number of allocated inodes.
162+ pub fn inodes_hard_limit ( & self ) -> Option < u64 > {
163+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
164+ if valid_fields. contains ( QIF_ILIMITS ) {
165+ Some ( self . 0 . dqb_ihardlimit )
166+ } else {
167+ None
168+ }
169+ }
170+
171+ /// Set the maximum number of allocated inodes.
172+ pub fn set_inodes_hard_limit ( & mut self , limit : u64 ) {
173+ self . 0 . dqb_ihardlimit = limit;
174+ }
175+
176+ /// Preferred inode limit
177+ pub fn inodes_soft_limit ( & self ) -> Option < u64 > {
178+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
179+ if valid_fields. contains ( QIF_ILIMITS ) {
180+ Some ( self . 0 . dqb_isoftlimit )
181+ } else {
182+ None
183+ }
184+ }
185+
186+ /// Set the preferred limit of allocated inodes.
187+ pub fn set_inodes_soft_limit ( & mut self , limit : u64 ) {
188+ self . 0 . dqb_isoftlimit = limit;
189+ }
190+
191+ /// Current number of allocated inodes.
192+ pub fn allocated_inodes ( & self ) -> Option < u64 > {
193+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
194+ if valid_fields. contains ( QIF_INODES ) {
195+ Some ( self . 0 . dqb_curinodes )
196+ } else {
197+ None
198+ }
199+ }
200+
201+ /// Time limit for excessive disk use.
202+ pub fn block_time_limit ( & self ) -> Option < u64 > {
203+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
204+ if valid_fields. contains ( QIF_BTIME ) {
205+ Some ( self . 0 . dqb_btime )
206+ } else {
207+ None
208+ }
209+ }
210+
211+ /// Set the time limit for excessive disk use.
212+ pub fn set_block_time_limit ( & mut self , limit : u64 ) {
213+ self . 0 . dqb_btime = limit;
214+ }
215+
216+ /// Time limit for excessive files.
217+ pub fn inode_time_limit ( & self ) -> Option < u64 > {
218+ let valid_fields = QuotaValidFlags :: from_bits_truncate ( self . 0 . dqb_valid ) ;
219+ if valid_fields. contains ( QIF_ITIME ) {
220+ Some ( self . 0 . dqb_itime )
221+ } else {
222+ None
223+ }
224+ }
225+
226+ /// Set the time limit for excessive files.
227+ pub fn set_inode_time_limit ( & mut self , limit : u64 ) {
228+ self . 0 . dqb_itime = limit;
229+ }
230+ }
74231
75- fn quotactl < P : ?Sized + NixPath > ( cmd : quota :: QuotaCmd , special : Option < & P > , id : c_int , addr : * mut c_char ) -> Result < ( ) > {
232+ fn quotactl < P : ?Sized + NixPath > ( cmd : QuotaCmd , special : Option < & P > , id : c_int , addr : * mut c_char ) -> Result < ( ) > {
76233 unsafe {
77234 Errno :: clear ( ) ;
78235 let res = try!(
@@ -86,27 +243,35 @@ fn quotactl<P: ?Sized + NixPath>(cmd: quota::QuotaCmd, special: Option<&P>, id:
86243 }
87244}
88245
89- pub fn quotactl_on < P : ?Sized + NixPath > ( which : quota:: QuotaType , special : & P , format : quota:: QuotaFmt , quota_file : & P ) -> Result < ( ) > {
246+ /// Turn on disk quotas for a block device.
247+ pub fn quotactl_on < P : ?Sized + NixPath > ( which : QuotaType , special : & P , format : QuotaFmt , quota_file : & P ) -> Result < ( ) > {
90248 try!( quota_file. with_nix_path ( |path| {
91249 let mut path_copy = path. to_bytes_with_nul ( ) . to_owned ( ) ;
92250 let p: * mut c_char = path_copy. as_mut_ptr ( ) as * mut c_char ;
93- quotactl ( quota :: QuotaCmd ( quota :: Q_QUOTAON , which) , Some ( special) , format as c_int , p)
251+ quotactl ( QuotaCmd ( QuotaSubCmd :: Q_QUOTAON , which) , Some ( special) , format as c_int , p)
94252 } ) )
95253}
96254
97- pub fn quotactl_off < P : ?Sized + NixPath > ( which : quota:: QuotaType , special : & P ) -> Result < ( ) > {
98- quotactl ( quota:: QuotaCmd ( quota:: Q_QUOTAOFF , which) , Some ( special) , 0 , ptr:: null_mut ( ) )
255+ /// Disable disk quotas for a block device.
256+ pub fn quotactl_off < P : ?Sized + NixPath > ( which : QuotaType , special : & P ) -> Result < ( ) > {
257+ quotactl ( QuotaCmd ( QuotaSubCmd :: Q_QUOTAOFF , which) , Some ( special) , 0 , ptr:: null_mut ( ) )
99258}
100259
101- pub fn quotactl_sync < P : ?Sized + NixPath > ( which : quota:: QuotaType , special : Option < & P > ) -> Result < ( ) > {
102- quotactl ( quota:: QuotaCmd ( quota:: Q_SYNC , which) , special, 0 , ptr:: null_mut ( ) )
260+ /// Update the on-disk copy of quota usages for a filesystem.
261+ pub fn quotactl_sync < P : ?Sized + NixPath > ( which : QuotaType , special : Option < & P > ) -> Result < ( ) > {
262+ quotactl ( QuotaCmd ( QuotaSubCmd :: Q_SYNC , which) , special, 0 , ptr:: null_mut ( ) )
103263}
104264
105- pub fn quotactl_get < P : ?Sized + NixPath > ( which : quota:: QuotaType , special : & P , id : c_int , dqblk : & mut quota:: Dqblk ) -> Result < ( ) > {
106- quotactl ( quota:: QuotaCmd ( quota:: Q_GETQUOTA , which) , Some ( special) , id, dqblk as * mut _ as * mut c_char )
265+ /// Get disk quota limits and current usage for the given user/group id.
266+ pub fn quotactl_get < P : ?Sized + NixPath > ( which : QuotaType , special : & P , id : c_int ) -> Result < Dqblk > {
267+ let mut dqblk = unsafe { mem:: uninitialized ( ) } ;
268+ quotactl ( QuotaCmd ( QuotaSubCmd :: Q_GETQUOTA , which) , Some ( special) , id, & mut dqblk as * mut _ as * mut c_char ) ?;
269+ dqblk
107270}
108271
109- pub fn quotactl_set < P : ?Sized + NixPath > ( which : quota:: QuotaType , special : & P , id : c_int , dqblk : & quota:: Dqblk ) -> Result < ( ) > {
272+ /// Configure quota values for the specified fields for a given user/group id.
273+ pub fn quotactl_set < P : ?Sized + NixPath > ( which : QuotaType , special : & P , id : c_int , dqblk : & Dqblk , fields : QuotaValidFlags ) -> Result < ( ) > {
110274 let mut dqblk_copy = * dqblk;
111- quotactl ( quota:: QuotaCmd ( quota:: Q_SETQUOTA , which) , Some ( special) , id, & mut dqblk_copy as * mut _ as * mut c_char )
275+ dqblk_copy. 0 . dqb_valid = fields. bits ( ) ;
276+ quotactl ( QuotaCmd ( QuotaSubCmd :: Q_SETQUOTA , which) , Some ( special) , id, & mut dqblk_copy as * mut _ as * mut c_char )
112277}
0 commit comments