File: FsQuota.rst

package info (click to toggle)
python-fsquota 0.1.0%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 392 kB
  • sloc: ansic: 2,670; python: 545; makefile: 8
file content (330 lines) | stat: -rw-r--r-- 13,379 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
===========================================================
FsQuota - Interface to file system quotas on UNIX platforms
===========================================================

SYNOPSIS
========

::

    import FsQuota

    qObj = FsQuota.Quota(path [,rpc_host=hostname])

    (bcount, bsoft, bhard, btime,
     icount, isoft, ihard, itime) =
        qObj.query(uid [,grpquota=1] [,prjquota=1])

    qObj.setqlim(uid, bsoft, bhard, isoft, ihard
                 [,timereset=1]
                 [,grpquota=1] [,prjquota=1])

    qObj.sync()

    qObj.rpc_opt([option keywords])

    for dev, path, type, opts in FsQuota.MntTab(): ...

FsQuota Module
==============

The **FsQuota** module provides two classes that allow accessing file
system quotas from Python scripts:

Instances of the **Quota** class take as main init parameter a path of a
mount point (or any path below the mount point). The instance can then be
used to query or modify quota of users or groups within that file system.
The class is designed portably, so that the same interfaces work across
all file system types and UNIX platforms. (Although there are some extra
options during initialization for certain file systems.)

Instances of the **MntTab** class allow iterating across the mount
table.  For each entry in the table, it provides the file system type,
mount  point and options. (Note this class is usually not required to work
with the Quota class.  It is provided here just for convenience, as the
functionality is actually used internally by the Quota class.)

Class FsQuota.Quota
===================

::

    qObj = FsQuota.Quota(path)
    qObj = FsQuota.Quota(remote_path, rpc_host=remote_host)

Creates a Quota object that then is used for querying or modifying
quotas. In case of special file systems which are known not to suport
quota, the creation may raise exception **FsQuota.error**. However note
the absence of an exception is not a guarantee that the file system
actually supports quota limits.

Internal behavior: Most importantly, the initialization determines the
file system type and thus the access method to be used in following
quota operations. Many platforms use the **quotactl** syscall, but even
then the type of device parameter to be passed varies from system to
system. It may be the path of a device file (e.g. `/dev/sda1`) or the
path of the mount point or the quotas file at the top of the file system
(e.g. `/home/quotas`). For the rare cases you need this information,
it can be queried via the **Quota.dev** attribute.

The given mount point may also be on a remote file system (e.g. mounted
via Network File System, NFS), which has the class transparently query
the given host via a remote procedure call (RPC).  Note: RPC queries
require *rquotad(1m)* to be running on the target system. If the daemon
or host are down, the operations time out after a configurable delay.

When parameter **rpc_host** is specified, the automatic detection of file
system type is omitted. In this case the following operations will
address the file system containing the given path on the given remote host
using RPC. This mode should normally not be needed, but could for example
be used for accessing file systems that are not mounted locally. See also
the **rpc_opt()** method for additional RPC configuration options.

Quota.query()
-------------

::

    (bcount,bsoft,bhard,btime, icount,isoft,ihard,itime)
        = qObj.query(uid, [keyword_options...])

Get current usage and quota limits for blocks and files respectively,
owned by the given user. The user is specified by a numeric UID.
The result is a named tuple of type **FsQuota.QueryResult**, so that
members can be accessed via name as well as via indices:

0. **bcount**: Number of 1 kB blocks currently used by inodes owned by the user.
1. **bsoft**: Soft limit for block count (or 0 if none)
2. **bhard**: Hard limit for block count (or 0 if none)
3. **btime**: Time when an exceeded soft block limit turns into a hard limit.
   This value is meaningless when the soft limit is not exceeded.
4. **icount**: Number of inodes (i.e. files) currently owned by the user.
5. **isoft**: Soft limit for inode count (or 0 if none)
6. **ihard**: Hard limit for inode count (or 0 if none)
7. **itime**: Time when an exceeded soft inode limit turns into a hard limit.
   This value is meaningless when the soft limit is not exceeded.

When a hard limit is reached, the OS will reject any further write with
errno *EDQUOT* (or *ENOSPC* on older systems).  If the soft limit is
exceeded, but hard limit not exceeded, writes by this user will fail only
after the time indicated by *btime* or *itime* respectively is
reached.  The time is usually set to 7 days after exceeding the soft limit
for the first time. These times are expressed as elapsed seconds since
00:00 1/Jan/1970 GMT.

Note when hard and soft limits are both zero, this means there is no limit
for that user. (On some platforms the query may fail with error code
*ESRCH* in that case; most however still report valid usage values.)

Optional keyword-only parameters:

:grpquota:
    When parameter **grpquota** is present and set to a value that evaluates to
    *True*, the value in *uid* is taken as GID and group quotas are queried.
    Group quotas may not be supported across all platforms (e.g. Linux and
    other BSD based Unix variants, OSF/1 and  AIX - check the quotactl(2) man
    page on your systems).

:prjquota:
    When parameter **prjquota** is present and set to a value that evaluates to
    *True*, project quotas are queried; this is currently only supported for
    XFS. Exception **FsQuota.error(ENOTSUP)** is raised for unsupported
    file-systems.

It is an error to select both group and project quota in the same query.

Method Quota.setqlim()
----------------------

::

    qObj.setqlim(uid, bsoft, bhard, isoft, ihard [,keyword options...])

Sets quota limits for the given user. Meanings of parameters *uid*,
*bsoft*, *bhard*, *isoft* and *ihard* are the same as for the **query()**
method.

Note all the limit values are optional and default to zero. The parameters
can also be passed in form of keyword parameters. For example
`qObj.setqlim(uid, isoft=10,ihard=20)` would limit inode counts to 10
soft, 20 hard, but remove limits for block count. (Note it's not possible
to set only block or inode limits repsectively; to do so query current
limits first and then pass those values to setqlim if you want to keep
them unchanged.)

Note: if you want to set the quota of a particular user to zero, i.e.
no write permission, you must not set all limits to zero, since that
is equivalent to unlimited access. Instead set only the hard limit
to 0 and the soft limit to a non-zero value.

Optional keyword-only parameters:

:timereset:
    Optional parameter **timereset** defines how time limits are
    initialized: When the assigned value is *False*, time limits are set to
    `NOT STARTED` (i.e. the time limits are not initialized until the first
    write attempt by this user). This is the default when the parameter is
    omitted. When assigned *True*, the time limits are set to `7.0 days`.
    More alternatives (i.e. setting a specific time) aren't available in most
    implementations.

:grpquota:
    When parameter **grpquota** is present and set to True, parameter *uid* is
    interpreted as GID and the the limit of the corresponding group is
    modified. This is not supported on all platforms.

:prjquota:
    When parameter **prjquota** is present and set to True, project quotas are
    modified; this is currently only supported for XFS.  Exception
    **FsQuota.error(ENOTSUP)** is raised for unsupported file-systems.

It is an error to select both group and project quota in the same query.

Note that the class does not support setting quotas via RPC (even
though some implementations of *rpc.rquotad(8)* allow optionally
enabling this, but it seems a bad idea for security.)

Method Quota.sync()
-------------------

::

    qObj.sync()

Have the kernel update the quota file on disk, in particular after
modifying quota limits.

A secondary purpose of this method is checking if quota support is
enabled in the kernel (and on some platforms, for a particular file
system; on others however the call succeeds even if quota is not enabled
in the given file system.) Read the **quotaon(1m)** man page on how to
enable quotas on a file system.

Method Quota.rpc_opt()
----------------------

::

    qObj.rpc_opt([keyword options...])

This method allows configuring networking and authentication parameters
for queries of network file system quotas via RPC. The options have no
effect when targeting other file system types. The following keyword-only
parameters are available:

:rpc_port:
    Sets the port used by *rpc.rquotad(8)*; default value is zero, which
    which means the remote host's portmapper (aka rpcbind) is used. (Note
    in case of the latter you can find out the port using *rpcinfo -p host*)

:rpc_use_tcp:
    If *True*, use TCP; if *False* use UDP (default).

:rpc_timeout:
    Timeout value in milliseconds in case the remote host does not respond.

:auth_uid:
    UID value (i.e. user identifier) to provide for authentication.
    If not specified, this defaults to the UID of the current process.
    For example, you could set the UID here that you later want to
    query, for circumventing a permission error.

:auth_gid:
    GID value (i.e. group identifier) to provide for authentication.
    If not specified, this defaults to the GID of the current process.

:auth_hostname:
    Hostname to provide for authentication.
    If not specified or empty, this defaults to the name of the local machine.

Note for resetting to default authentication, set both **auth_uid** and
**auth_gid** to value -1 (even if you previously changed only one, as the
opposite is filled in automatically if missing).

Attribute Quota.dev
-------------------

This attribute provides the device argument used internally by **query()**
and **setqlim()** methods for the selected file system.

Attribute Quota.is_nfs
----------------------

This attribute indicates 1 is the file system is NFS, else 0.

Class FsQuota.MntTab()
======================

This class defines objects that can be used as an iterator which lists all
entries in the mount table. Each object returned by iteration is a named
tuple of type **FsQuota.MntEnt** with the following entries of type
string:

0. **mnt_fsname**: Name of the filesystem (e.g. device name)
1. **mnt_dir**: Filesystem path prefix (aka mount point)
2. **mnt_type**: Mount type (aka file system type)
3. **mnt_opts**: Mount options, separated by colon.

Note the mount table contains information about all currently mounted
(local or remote) file systems.  The format and location of this table
varies from system to system (e.g. it may be in file `/etc/mtab`).
This iterator provides a portable way to read it. (On some systems,
like **OSF/1**, this table isn't accessible as a file at all, i.e. only
via C library interfaces). Internally, the iterator will call
*setmntent(3)* or the equivalent of your platform upon initialization,
call *getmntent(3)* during iteration, and call *endmntent(3)* upon
deallocation.

Hint: For finding the mount table entry corresponding to a given path
(e.g. to determine the file system type), you can compare the device ID
indicated by *os.stat(path).st_dev* of the mount points returned from
iteration with that of the path in question.

ERROR HANDLING
==============

All methods raise exception **FsQuota.error** upon errors. The exception
class is derived from exception **OSError** and thus contains firstly a
numerical error code in attribute **errno** (copied from *errno* in most
cases), secondly a derived error message in attribute **strerror**, and
when applicable, thirdly a file name in attribute **filename**.

Note the error string is adapted to the context of quota operations and
therefore not always identical to the text returned by
**strerror(ex.errno)**.  This is necessary as normal error descriptions
don't always make sense for quota errors (e.g. *ESRCH*: *No such process*,
here: *No quota for this user*)

AUTHORS
=======

This module is derived from an equivalent extension module for Perl,
created 1995 by T. Zoerner (email: tomzo AT users.sourceforge.net)
and since then continuously improved and ported to many more
operating systems and file systems - and now ported to Python.
Numerous people have contributed to this process in the past;
for a complete list of names please see the CHANGES document.

LICENSE
=======

Copyright (C) 1995-2020 T. Zoerner

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 GPL, or any later
version, see http://www.opensource.org/licenses/).

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.

SEE ALSO
========

python3(1), edquota(8),
quotactl(2) or quotactl(7I),
mount(8), mtab(4) or mnttab(4), quotaon(8),
setmntent(3), getmntent(3) or getmntinfo(3), endmntent(3),
rpc(3), rquotad(8) or rpc.rquotad(8), rpcinfo(7).