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;
182 * Initialize new quotafile
184 static int v1_new_io(struct quota_handle *h)
186 struct v1_disk_dqblk ddqblk;
188 /* Write at least roots dquot with grace times */
189 memset(&ddqblk, 0, sizeof(ddqblk));
190 ddqblk.dqb_btime = MAX_DQ_TIME;
191 ddqblk.dqb_itime = MAX_IQ_TIME;
192 h->qh_info.dqi_bgrace = MAX_DQ_TIME;
193 h->qh_info.dqi_igrace = MAX_IQ_TIME;
194 lseek(h->qh_fd, 0, SEEK_SET);
195 if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
201 * Write information (grace times to file)
203 static int v1_write_info(struct quota_handle *h)
206 errstr(_("Trying to write info to readonly quotafile on %s.\n"), h->qh_quotadev);
210 if (QIO_ENABLED(h)) {
211 if (kernel_iface == IFACE_GENERIC) {
212 if (vfs_set_info(h, IIF_BGRACE | IIF_IGRACE) < 0)
216 struct v1_kern_dqblk kdqblk;
218 if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
220 kdqblk.dqb_btime = h->qh_info.dqi_bgrace;
221 kdqblk.dqb_itime = h->qh_info.dqi_igrace;
222 if (quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
227 struct v1_disk_dqblk ddqblk;
229 lseek(h->qh_fd, 0, SEEK_SET);
230 if (read(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
232 ddqblk.dqb_btime = h->qh_info.dqi_bgrace;
233 ddqblk.dqb_itime = h->qh_info.dqi_igrace;
234 lseek(h->qh_fd, 0, SEEK_SET);
235 if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
242 * Read a dqblk struct from the quotafile.
243 * User can use 'errno' to detect errstr.
245 static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id)
247 struct v1_disk_dqblk ddqblk;
248 struct dquot *dquot = get_empty_dquot();
252 if (QIO_ENABLED(h)) { /* Does kernel use the file? */
253 if (kernel_iface == IFACE_GENERIC) {
254 if (vfs_get_dquot(dquot) < 0) {
260 struct v1_kern_dqblk kdqblk;
262 if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) {
266 v1_kern2utildqblk(&dquot->dq_dqb, &kdqblk);
270 lseek(h->qh_fd, (long)V1_DQOFF(id), SEEK_SET);
271 switch (read(h->qh_fd, &ddqblk, sizeof(ddqblk))) {
274 * Convert implicit 0 quota (EOF) into an
275 * explicit one (zero'ed dqblk)
277 memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk));
279 case sizeof(struct v1_disk_dqblk): /* OK */
280 v1_disk2memdqblk(&dquot->dq_dqb, &ddqblk);
291 * Write a dqblk struct to the quotafile.
292 * User can process use 'errno' to detect errstr
294 static int v1_commit_dquot(struct dquot *dquot, int flags)
296 struct v1_disk_dqblk ddqblk;
297 struct quota_handle *h = dquot->dq_h;
300 errstr(_("Trying to write quota to readonly quotafile on %s\n"), h->qh_quotadev);
304 if (QIO_ENABLED(h)) { /* Kernel uses same file? */
305 if (kernel_iface == IFACE_GENERIC) {
306 if (vfs_set_dquot(dquot, flags) < 0)
310 struct v1_kern_dqblk kdqblk;
313 if (flags == COMMIT_USAGE)
315 else if (flags == COMMIT_LIMITS)
317 else if (flags & COMMIT_TIMES) {
323 v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
324 if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, dquot->dq_id,
325 (void *)&kdqblk) < 0)
330 v1_mem2diskdqblk(&ddqblk, &dquot->dq_dqb);
331 lseek(h->qh_fd, (long)V1_DQOFF(dquot->dq_id), SEEK_SET);
332 if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
339 * Scan all dquots in file and call callback on each
341 #define SCANBUFSIZE 256
343 static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *, char *))
345 int rd, scanbufpos = 0, scanbufsize = 0;
346 char scanbuf[sizeof(struct v1_disk_dqblk)*SCANBUFSIZE];
347 struct v1_disk_dqblk *ddqblk;
348 struct dquot *dquot = get_empty_dquot();
351 if (QIO_ENABLED(h)) /* Kernel uses same file? */
352 if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC, h->qh_type),
353 h->qh_quotadev, 0, NULL) < 0)
354 die(4, _("Cannot sync quotas on device %s: %s\n"), h->qh_quotadev,
356 memset(dquot, 0, sizeof(*dquot));
358 lseek(h->qh_fd, 0, SEEK_SET);
359 for(id = 0; ; id++, scanbufpos++) {
360 if (scanbufpos >= scanbufsize) {
361 rd = read(h->qh_fd, scanbuf, sizeof(scanbuf));
362 if (rd < 0 || rd % sizeof(struct v1_disk_dqblk))
367 scanbufsize = rd / sizeof(struct v1_disk_dqblk);
369 ddqblk = ((struct v1_disk_dqblk *)scanbuf) + scanbufpos;
370 if ((ddqblk->dqb_ihardlimit | ddqblk->dqb_isoftlimit |
371 ddqblk->dqb_bhardlimit | ddqblk->dqb_bsoftlimit |
372 ddqblk->dqb_curblocks | ddqblk->dqb_curinodes |
373 ddqblk->dqb_itime | ddqblk->dqb_btime) == 0)
375 v1_disk2memdqblk(&dquot->dq_dqb, ddqblk);
377 if ((rd = process_dquot(dquot, NULL)) < 0) {
382 if (!rd) { /* EOF? */
388 return -1; /* Some read errstr... */