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} ;
2
17
use libc:: { self , c_int, c_char} ;
18
+ use { Errno , Result , NixPath } ;
3
19
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 ) ;
11
21
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
+ }
14
70
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
18
128
}
19
129
}
20
130
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
55
143
}
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 ,
70
144
}
71
- }
72
145
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
+ }
74
231
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 < ( ) > {
76
233
unsafe {
77
234
Errno :: clear ( ) ;
78
235
let res = try!(
@@ -86,27 +243,35 @@ fn quotactl<P: ?Sized + NixPath>(cmd: quota::QuotaCmd, special: Option<&P>, id:
86
243
}
87
244
}
88
245
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 < ( ) > {
90
248
try!( quota_file. with_nix_path ( |path| {
91
249
let mut path_copy = path. to_bytes_with_nul ( ) . to_owned ( ) ;
92
250
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)
94
252
} ) )
95
253
}
96
254
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 ( ) )
99
258
}
100
259
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 ( ) )
103
263
}
104
264
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
107
270
}
108
271
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 < ( ) > {
110
274
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 )
112
277
}
0 commit comments