2 * Copyright (c) 1980, 1990 Regents of the University of California. All
5 * This code is derived from software contributed to Berkeley by Robert Elz at
6 * The University of Melbourne.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 2.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution. 3. All advertising
15 * materials mentioning features or use of this software must display the
16 * following acknowledgement: This product includes software developed by the
17 * University of California, Berkeley and its contributors. 4. Neither the
18 * name of the University nor the names of its contributors may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 #include "quotaio_v1.h"
48 #include "quotaio_generic.h"
50 static int v1_check_file(int fd, int type, int fmt);
51 static int v1_init_io(struct quota_handle *h);
52 static int v1_new_io(struct quota_handle *h);
53 static int v1_write_info(struct quota_handle *h);
54 static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id);
55 static int v1_commit_dquot(struct dquot *dquot, int flags);
56 static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname));
58 struct quotafile_ops quotafile_ops_1 = {
59 check_file: v1_check_file,
62 write_info: v1_write_info,
63 read_dquot: v1_read_dquot,
64 commit_dquot: v1_commit_dquot,
65 scan_dquots: v1_scan_dquots,
69 * Copy dquot from disk to memory
71 static inline void v1_disk2memdqblk(struct util_dqblk *m, struct v1_disk_dqblk *d)
73 m->dqb_ihardlimit = d->dqb_ihardlimit;
74 m->dqb_isoftlimit = d->dqb_isoftlimit;
75 m->dqb_bhardlimit = d->dqb_bhardlimit;
76 m->dqb_bsoftlimit = d->dqb_bsoftlimit;
77 m->dqb_curinodes = d->dqb_curinodes;
78 m->dqb_curspace = ((qsize_t)d->dqb_curblocks) * V1_DQBLK_SIZE;
79 m->dqb_itime = d->dqb_itime;
80 m->dqb_btime = d->dqb_btime;
84 * Copy dquot from memory to disk
86 static inline void v1_mem2diskdqblk(struct v1_disk_dqblk *d, struct util_dqblk *m)
88 d->dqb_ihardlimit = m->dqb_ihardlimit;
89 d->dqb_isoftlimit = m->dqb_isoftlimit;
90 d->dqb_bhardlimit = m->dqb_bhardlimit;
91 d->dqb_bsoftlimit = m->dqb_bsoftlimit;
92 d->dqb_curinodes = m->dqb_curinodes;
93 d->dqb_curblocks = m->dqb_curspace >> V1_DQBLK_SIZE_BITS;
94 d->dqb_itime = m->dqb_itime;
95 d->dqb_btime = m->dqb_btime;
98 /* Convert kernel quotablock format to utility one */
99 static inline void v1_kern2utildqblk(struct util_dqblk *u, struct v1_kern_dqblk *k)
101 u->dqb_ihardlimit = k->dqb_ihardlimit;
102 u->dqb_isoftlimit = k->dqb_isoftlimit;
103 u->dqb_bhardlimit = k->dqb_bhardlimit;
104 u->dqb_bsoftlimit = k->dqb_bsoftlimit;
105 u->dqb_curinodes = k->dqb_curinodes;
106 u->dqb_curspace = ((qsize_t)k->dqb_curblocks) << V1_DQBLK_SIZE_BITS;
107 u->dqb_itime = k->dqb_itime;
108 u->dqb_btime = k->dqb_btime;
111 /* Convert utility quotablock format to kernel one */
112 static inline void v1_util2kerndqblk(struct v1_kern_dqblk *k, struct util_dqblk *u)
114 k->dqb_ihardlimit = u->dqb_ihardlimit;
115 k->dqb_isoftlimit = u->dqb_isoftlimit;
116 k->dqb_bhardlimit = u->dqb_bhardlimit;
117 k->dqb_bsoftlimit = u->dqb_bsoftlimit;
118 k->dqb_curinodes = u->dqb_curinodes;
119 k->dqb_curblocks = (u->dqb_curspace + V1_DQBLK_SIZE - 1) >> V1_DQBLK_SIZE_BITS;
120 k->dqb_itime = u->dqb_itime;
121 k->dqb_btime = u->dqb_btime;
125 * Check whether quotafile is in our format
127 static int v1_check_file(int fd, int type, int fmt)
131 if (fstat(fd, &st) < 0)
133 if (!st.st_size || st.st_size % sizeof(struct v1_disk_dqblk))
141 static int v1_init_io(struct quota_handle *h)
143 if (QIO_ENABLED(h)) {
144 if (kernel_iface == IFACE_GENERIC) {
145 if (vfs_get_info(h) < 0)
149 struct v1_kern_dqblk kdqblk;
151 if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) {
152 if (errno == EPERM) { /* We have no permission to get this information? */
153 h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0; /* It hopefully won't be needed */
159 h->qh_info.dqi_bgrace = kdqblk.dqb_btime;
160 h->qh_info.dqi_igrace = kdqblk.dqb_itime;
165 struct v1_disk_dqblk ddqblk;
167 lseek(h->qh_fd, 0, SEEK_SET);
168 if (read(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
170 h->qh_info.dqi_bgrace = ddqblk.dqb_btime;
171 h->qh_info.dqi_igrace = ddqblk.dqb_itime;
173 if (!h->qh_info.dqi_bgrace)
174 h->qh_info.dqi_bgrace = MAX_DQ_TIME;
175 if (!h->qh_info.dqi_igrace)
176 h->qh_info.dqi_igrace = MAX_IQ_TIME;
177 h->qh_info.dqi_max_b_limit = ~(uint32_t)0;
178 h->qh_info.dqi_max_i_limit = ~(uint32_t)0;
179 h->qh_info.dqi_max_b_usage = ((uint64_t)(~(uint32_t)0)) << V1_DQBLK_SIZE_BITS;
180 h->qh_info.dqi_max_i_usage = ~(uint32_t)0;
186 * Initialize new quotafile
188 static int v1_new_io(struct quota_handle *h)
190 struct v1_disk_dqblk ddqblk;
192 /* Write at least roots dquot with grace times */
193 memset(&ddqblk, 0, sizeof(ddqblk));
194 ddqblk.dqb_btime = MAX_DQ_TIME;
195 ddqblk.dqb_itime = MAX_IQ_TIME;
196 h->qh_info.dqi_bgrace = MAX_DQ_TIME;
197 h->qh_info.dqi_igrace = MAX_IQ_TIME;
198 h->qh_info.dqi_max_b_limit = ~(uint32_t)0;
199 h->qh_info.dqi_max_i_limit = ~(uint32_t)0;
200 h->qh_info.dqi_max_b_usage = ((uint64_t)(~(uint32_t)0)) << V1_DQBLK_SIZE_BITS;
201 h->qh_info.dqi_max_i_usage = ~(uint32_t)0;
202 lseek(h->qh_fd, 0, SEEK_SET);
203 if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
209 * Write information (grace times to file)
211 static int v1_write_info(struct quota_handle *h)
214 errstr(_("Trying to write info to readonly quotafile on %s.\n"), h->qh_quotadev);
218 if (QIO_ENABLED(h)) {
219 if (kernel_iface == IFACE_GENERIC) {
220 if (vfs_set_info(h, IIF_BGRACE | IIF_IGRACE) < 0)
224 struct v1_kern_dqblk kdqblk;
226 if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
228 kdqblk.dqb_btime = h->qh_info.dqi_bgrace;
229 kdqblk.dqb_itime = h->qh_info.dqi_igrace;
230 if (quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
235 struct v1_disk_dqblk ddqblk;
237 lseek(h->qh_fd, 0, SEEK_SET);
238 if (read(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
240 ddqblk.dqb_btime = h->qh_info.dqi_bgrace;
241 ddqblk.dqb_itime = h->qh_info.dqi_igrace;
242 lseek(h->qh_fd, 0, SEEK_SET);
243 if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
250 * Read a dqblk struct from the quotafile.
251 * User can use 'errno' to detect errstr.
253 static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id)
255 struct v1_disk_dqblk ddqblk;
256 struct dquot *dquot = get_empty_dquot();
260 if (QIO_ENABLED(h)) { /* Does kernel use the file? */
261 if (kernel_iface == IFACE_GENERIC) {
262 if (vfs_get_dquot(dquot) < 0) {
268 struct v1_kern_dqblk kdqblk;
270 if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) {
274 v1_kern2utildqblk(&dquot->dq_dqb, &kdqblk);
278 lseek(h->qh_fd, (long)V1_DQOFF(id), SEEK_SET);
279 switch (read(h->qh_fd, &ddqblk, sizeof(ddqblk))) {
282 * Convert implicit 0 quota (EOF) into an
283 * explicit one (zero'ed dqblk)
285 memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk));
287 case sizeof(struct v1_disk_dqblk): /* OK */
288 v1_disk2memdqblk(&dquot->dq_dqb, &ddqblk);
299 * Write a dqblk struct to the quotafile.
300 * User can process use 'errno' to detect errstr
302 static int v1_commit_dquot(struct dquot *dquot, int flags)
304 struct v1_disk_dqblk ddqblk;
305 struct quota_handle *h = dquot->dq_h;
308 errstr(_("Trying to write quota to readonly quotafile on %s\n"), h->qh_quotadev);
312 if (QIO_ENABLED(h)) { /* Kernel uses same file? */
313 if (kernel_iface == IFACE_GENERIC) {
314 if (vfs_set_dquot(dquot, flags) < 0)
318 struct v1_kern_dqblk kdqblk;
321 if (flags == COMMIT_USAGE)
323 else if (flags == COMMIT_LIMITS)
325 else if (flags & COMMIT_TIMES) {
331 v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
332 if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, dquot->dq_id,
333 (void *)&kdqblk) < 0)
338 if (check_dquot_range(dquot) < 0) {
342 v1_mem2diskdqblk(&ddqblk, &dquot->dq_dqb);
343 lseek(h->qh_fd, (long)V1_DQOFF(dquot->dq_id), SEEK_SET);
344 if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
351 * Scan all dquots in file and call callback on each
353 #define SCANBUFSIZE 256
355 static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *, char *))
357 int rd, scanbufpos = 0, scanbufsize = 0;
358 char scanbuf[sizeof(struct v1_disk_dqblk)*SCANBUFSIZE];
359 struct v1_disk_dqblk *ddqblk;
360 struct dquot *dquot = get_empty_dquot();
363 memset(dquot, 0, sizeof(*dquot));
365 lseek(h->qh_fd, 0, SEEK_SET);
366 for(id = 0; ; id++, scanbufpos++) {
367 if (scanbufpos >= scanbufsize) {
368 rd = read(h->qh_fd, scanbuf, sizeof(scanbuf));
369 if (rd < 0 || rd % sizeof(struct v1_disk_dqblk))
374 scanbufsize = rd / sizeof(struct v1_disk_dqblk);
376 ddqblk = ((struct v1_disk_dqblk *)scanbuf) + scanbufpos;
377 if ((ddqblk->dqb_ihardlimit | ddqblk->dqb_isoftlimit |
378 ddqblk->dqb_bhardlimit | ddqblk->dqb_bsoftlimit |
379 ddqblk->dqb_curblocks | ddqblk->dqb_curinodes |
380 ddqblk->dqb_itime | ddqblk->dqb_btime) == 0)
382 v1_disk2memdqblk(&dquot->dq_dqb, ddqblk);
384 if ((rd = process_dquot(dquot, NULL)) < 0) {
389 if (!rd) { /* EOF? */
395 return -1; /* Some read errstr... */