]> git.proxmox.com Git - rustc.git/blob - vendor/nix/src/sys/quota.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / nix / src / sys / quota.rs
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::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags};
9 //! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user").unwrap();
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, QuotaValidFlags::QIF_BLIMITS).unwrap();
14 //! ```
15 use crate::errno::Errno;
16 use crate::{NixPath, Result};
17 use libc::{self, c_char, c_int};
18 use std::default::Default;
19 use std::{mem, ptr};
20
21 struct QuotaCmd(QuotaSubCmd, QuotaType);
22
23 impl QuotaCmd {
24 #[allow(unused_unsafe)]
25 fn as_int(&self) -> c_int {
26 unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
27 }
28 }
29
30 // linux quota version >= 2
31 libc_enum! {
32 #[repr(i32)]
33 enum QuotaSubCmd {
34 Q_SYNC,
35 Q_QUOTAON,
36 Q_QUOTAOFF,
37 Q_GETQUOTA,
38 Q_SETQUOTA,
39 }
40 }
41
42 libc_enum! {
43 /// The scope of the quota.
44 #[repr(i32)]
45 #[non_exhaustive]
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 #[non_exhaustive]
58 pub enum QuotaFmt {
59 /// Use the original quota format.
60 QFMT_VFS_OLD,
61 /// Use the standard VFS v0 quota format.
62 ///
63 /// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes.
64 QFMT_VFS_V0,
65 /// Use the VFS v1 quota format.
66 ///
67 /// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes.
68 QFMT_VFS_V1,
69 }
70 }
71
72 libc_bitflags!(
73 /// Indicates the quota fields that are valid to read from.
74 #[derive(Default)]
75 pub struct QuotaValidFlags: u32 {
76 /// The block hard & soft limit fields.
77 QIF_BLIMITS;
78 /// The current space field.
79 QIF_SPACE;
80 /// The inode hard & soft limit fields.
81 QIF_ILIMITS;
82 /// The current inodes field.
83 QIF_INODES;
84 /// The disk use time limit field.
85 QIF_BTIME;
86 /// The file quote time limit field.
87 QIF_ITIME;
88 /// All block & inode limits.
89 QIF_LIMITS;
90 /// The space & inodes usage fields.
91 QIF_USAGE;
92 /// The time limit fields.
93 QIF_TIMES;
94 /// All fields.
95 QIF_ALL;
96 }
97 );
98
99 /// Wrapper type for `if_dqblk`
100 #[repr(transparent)]
101 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
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 =
124 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
125 if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
126 Some(self.0.dqb_bhardlimit)
127 } else {
128 None
129 }
130 }
131
132 /// Set the absolute limit on disk quota blocks allocated.
133 pub fn set_blocks_hard_limit(&mut self, limit: u64) {
134 self.0.dqb_bhardlimit = limit;
135 }
136
137 /// Preferred limit on disk quota blocks
138 pub fn blocks_soft_limit(&self) -> Option<u64> {
139 let valid_fields =
140 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
141 if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
142 Some(self.0.dqb_bsoftlimit)
143 } else {
144 None
145 }
146 }
147
148 /// Set the preferred limit on disk quota blocks allocated.
149 pub fn set_blocks_soft_limit(&mut self, limit: u64) {
150 self.0.dqb_bsoftlimit = limit;
151 }
152
153 /// Current occupied space (bytes).
154 pub fn occupied_space(&self) -> Option<u64> {
155 let valid_fields =
156 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
157 if valid_fields.contains(QuotaValidFlags::QIF_SPACE) {
158 Some(self.0.dqb_curspace)
159 } else {
160 None
161 }
162 }
163
164 /// Maximum number of allocated inodes.
165 pub fn inodes_hard_limit(&self) -> Option<u64> {
166 let valid_fields =
167 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
168 if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
169 Some(self.0.dqb_ihardlimit)
170 } else {
171 None
172 }
173 }
174
175 /// Set the maximum number of allocated inodes.
176 pub fn set_inodes_hard_limit(&mut self, limit: u64) {
177 self.0.dqb_ihardlimit = limit;
178 }
179
180 /// Preferred inode limit
181 pub fn inodes_soft_limit(&self) -> Option<u64> {
182 let valid_fields =
183 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
184 if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
185 Some(self.0.dqb_isoftlimit)
186 } else {
187 None
188 }
189 }
190
191 /// Set the preferred limit of allocated inodes.
192 pub fn set_inodes_soft_limit(&mut self, limit: u64) {
193 self.0.dqb_isoftlimit = limit;
194 }
195
196 /// Current number of allocated inodes.
197 pub fn allocated_inodes(&self) -> Option<u64> {
198 let valid_fields =
199 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
200 if valid_fields.contains(QuotaValidFlags::QIF_INODES) {
201 Some(self.0.dqb_curinodes)
202 } else {
203 None
204 }
205 }
206
207 /// Time limit for excessive disk use.
208 pub fn block_time_limit(&self) -> Option<u64> {
209 let valid_fields =
210 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
211 if valid_fields.contains(QuotaValidFlags::QIF_BTIME) {
212 Some(self.0.dqb_btime)
213 } else {
214 None
215 }
216 }
217
218 /// Set the time limit for excessive disk use.
219 pub fn set_block_time_limit(&mut self, limit: u64) {
220 self.0.dqb_btime = limit;
221 }
222
223 /// Time limit for excessive files.
224 pub fn inode_time_limit(&self) -> Option<u64> {
225 let valid_fields =
226 QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
227 if valid_fields.contains(QuotaValidFlags::QIF_ITIME) {
228 Some(self.0.dqb_itime)
229 } else {
230 None
231 }
232 }
233
234 /// Set the time limit for excessive files.
235 pub fn set_inode_time_limit(&mut self, limit: u64) {
236 self.0.dqb_itime = limit;
237 }
238 }
239
240 fn quotactl<P: ?Sized + NixPath>(
241 cmd: QuotaCmd,
242 special: Option<&P>,
243 id: c_int,
244 addr: *mut c_char,
245 ) -> Result<()> {
246 unsafe {
247 Errno::clear();
248 let res = match special {
249 Some(dev) => dev.with_nix_path(|path| {
250 libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)
251 }),
252 None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)),
253 }?;
254
255 Errno::result(res).map(drop)
256 }
257 }
258
259 /// Turn on disk quotas for a block device.
260 pub fn quotactl_on<P: ?Sized + NixPath>(
261 which: QuotaType,
262 special: &P,
263 format: QuotaFmt,
264 quota_file: &P,
265 ) -> Result<()> {
266 quota_file.with_nix_path(|path| {
267 let mut path_copy = path.to_bytes_with_nul().to_owned();
268 let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
269 quotactl(
270 QuotaCmd(QuotaSubCmd::Q_QUOTAON, which),
271 Some(special),
272 format as c_int,
273 p,
274 )
275 })?
276 }
277
278 /// Disable disk quotas for a block device.
279 pub fn quotactl_off<P: ?Sized + NixPath>(
280 which: QuotaType,
281 special: &P,
282 ) -> Result<()> {
283 quotactl(
284 QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which),
285 Some(special),
286 0,
287 ptr::null_mut(),
288 )
289 }
290
291 /// Update the on-disk copy of quota usages for a filesystem.
292 ///
293 /// If `special` is `None`, then all file systems with active quotas are sync'd.
294 pub fn quotactl_sync<P: ?Sized + NixPath>(
295 which: QuotaType,
296 special: Option<&P>,
297 ) -> Result<()> {
298 quotactl(
299 QuotaCmd(QuotaSubCmd::Q_SYNC, which),
300 special,
301 0,
302 ptr::null_mut(),
303 )
304 }
305
306 /// Get disk quota limits and current usage for the given user/group id.
307 pub fn quotactl_get<P: ?Sized + NixPath>(
308 which: QuotaType,
309 special: &P,
310 id: c_int,
311 ) -> Result<Dqblk> {
312 let mut dqblk = mem::MaybeUninit::uninit();
313 quotactl(
314 QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which),
315 Some(special),
316 id,
317 dqblk.as_mut_ptr() as *mut c_char,
318 )?;
319 Ok(unsafe { Dqblk(dqblk.assume_init()) })
320 }
321
322 /// Configure quota values for the specified fields for a given user/group id.
323 pub fn quotactl_set<P: ?Sized + NixPath>(
324 which: QuotaType,
325 special: &P,
326 id: c_int,
327 dqblk: &Dqblk,
328 fields: QuotaValidFlags,
329 ) -> Result<()> {
330 let mut dqblk_copy = *dqblk;
331 dqblk_copy.0.dqb_valid = fields.bits();
332 quotactl(
333 QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which),
334 Some(special),
335 id,
336 &mut dqblk_copy as *mut _ as *mut c_char,
337 )
338 }