Deleted Added
full compact
quotafile.c (188598) quotafile.c (188604)
1/*-
2 * Copyright (c) 2008 Dag-Erling Co��dan Sm��rgrav
1/*-
2 * Copyright (c) 2008 Dag-Erling Co��dan Sm��rgrav
3 * Copyright (c) 2008 Marshall Kirk McKusick
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.

--- 8 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer
11 * in this position and unchanged.

--- 8 unchanged lines hidden (view full) ---

20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
27 * $FreeBSD: projects/quota64/lib/libutil/quotafile.c 188598 2009-02-13 19:56:59Z mckusick $
28 * $FreeBSD: projects/quota64/lib/libutil/quotafile.c 188604 2009-02-14 08:08:08Z mckusick $
28 */
29
30#include <sys/types.h>
31#include <sys/endian.h>
32#include <sys/mount.h>
33#include <sys/stat.h>
34
35#include <ufs/ufs/quota.h>

--- 6 unchanged lines hidden (view full) ---

42#include <libutil.h>
43#include <stdint.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48
49struct quotafile {
29 */
30
31#include <sys/types.h>
32#include <sys/endian.h>
33#include <sys/mount.h>
34#include <sys/stat.h>
35
36#include <ufs/ufs/quota.h>

--- 6 unchanged lines hidden (view full) ---

43#include <libutil.h>
44#include <stdint.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50struct quotafile {
50 int fd;
51 int type; /* 32 or 64 */
51 int fd; /* -1 means using quotactl for access */
52 int wordsize; /* 32-bit or 64-bit limits */
53 int quotatype; /* USRQUOTA or GRPQUOTA */
54 char fsname[MAXPATHLEN + 1]; /* mount point of filesystem */
55 char qfname[MAXPATHLEN + 1]; /* quota file if not using quotactl */
52};
53
54static const char *qfextension[] = INITQFNAMES;
55
56};
57
58static const char *qfextension[] = INITQFNAMES;
59
60/*
61 * Check to see if a particular quota is to be enabled.
62 */
63static int
64hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize)
65{
66 char *opt;
67 char *cp;
68 struct statfs sfb;
69 char buf[BUFSIZ];
70 static char initname, usrname[100], grpname[100];
71
72 if (!initname) {
73 (void)snprintf(usrname, sizeof(usrname), "%s%s",
74 qfextension[USRQUOTA], QUOTAFILENAME);
75 (void)snprintf(grpname, sizeof(grpname), "%s%s",
76 qfextension[GRPQUOTA], QUOTAFILENAME);
77 initname = 1;
78 }
79 strcpy(buf, fs->fs_mntops);
80 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
81 if ((cp = index(opt, '=')))
82 *cp++ = '\0';
83 if (type == USRQUOTA && strcmp(opt, usrname) == 0)
84 break;
85 if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
86 break;
87 }
88 if (!opt)
89 return (0);
90 /*
91 * Ensure that the filesystem is mounted.
92 */
93 if (statfs(fs->fs_file, &sfb) != 0 ||
94 strcmp(fs->fs_file, sfb.f_mntonname)) {
95 return (0);
96 }
97 if (cp) {
98 strncpy(qfnamep, cp, qfbufsize);
99 } else {
100 (void)snprintf(qfnamep, qfbufsize, "%s/%s.%s", fs->fs_file,
101 QUOTAFILENAME, qfextension[type]);
102 }
103 return (1);
104}
105
56struct quotafile *
106struct quotafile *
57quota_open(const char *fn)
107quota_open(struct fstab *fs, int quotatype, int openflags)
58{
59 struct quotafile *qf;
60 struct dqhdr64 dqh;
108{
109 struct quotafile *qf;
110 struct dqhdr64 dqh;
61 int serrno;
111 struct group *grp;
112 int qcmd, serrno;
62
63 if ((qf = calloc(1, sizeof(*qf))) == NULL)
64 return (NULL);
113
114 if ((qf = calloc(1, sizeof(*qf))) == NULL)
115 return (NULL);
65 if ((qf->fd = open(fn, O_RDWR)) < 0) {
66 serrno = errno;
116 qf->quotatype = quotatype;
117 strncpy(qf->fsname, fs->fs_file, sizeof(qf->fsname));
118 qcmd = QCMD(Q_GETQUOTA, quotatype);
119 if (quotactl(fs->fs_file, qcmd, 0, &dqh) == 0) {
120 qf->wordsize = 64;
121 qf->fd = -1;
122 return (qf);
123 }
124 if (!hasquota(fs, quotatype, qf->qfname, sizeof(qf->qfname))) {
67 free(qf);
125 free(qf);
68 errno = serrno;
126 errno = EOPNOTSUPP;
69 return (NULL);
70 }
127 return (NULL);
128 }
71 qf->type = 32;
72 switch (read(qf->fd, &dqh, sizeof(dqh))) {
73 case -1:
129 if ((qf->fd = open(qf->qfname, openflags & O_ACCMODE)) < 0 &&
130 (openflags & O_CREAT) == 0) {
74 serrno = errno;
131 serrno = errno;
75 close(qf->fd);
76 free(qf);
77 errno = serrno;
78 return (NULL);
132 free(qf);
133 errno = serrno;
134 return (NULL);
79 case sizeof(dqh):
80 if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
81 /* no magic, assume 32 bits */
82 qf->type = 32;
83 return (qf);
84 }
85 if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION ||
86 be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) ||
87 be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) {
88 /* correct magic, wrong version / lengths */
135 }
136 /* File open worked, so process it */
137 if (qf->fd != -1) {
138 qf->wordsize = 32;
139 switch (read(qf->fd, &dqh, sizeof(dqh))) {
140 case -1:
141 serrno = errno;
89 close(qf->fd);
90 free(qf);
142 close(qf->fd);
143 free(qf);
91 errno = EINVAL;
144 errno = serrno;
92 return (NULL);
145 return (NULL);
146 case sizeof(dqh):
147 if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
148 /* no magic, assume 32 bits */
149 qf->wordsize = 32;
150 return (qf);
151 }
152 if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION ||
153 be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) ||
154 be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) {
155 /* correct magic, wrong version / lengths */
156 close(qf->fd);
157 free(qf);
158 errno = EINVAL;
159 return (NULL);
160 }
161 qf->wordsize = 64;
162 return (qf);
163 default:
164 qf->wordsize = 32;
165 return (qf);
93 }
166 }
94 qf->type = 64;
95 return (qf);
96 default:
97 qf->type = 32;
98 return (qf);
167 /* not reached */
99 }
168 }
100 /* not reached */
101}
102
103struct quotafile *
104quota_create(const char *fn)
105{
106 struct quotafile *qf;
107 struct dqhdr64 dqh;
108 struct group *grp;
109 int serrno;
110
111 if ((qf = calloc(1, sizeof(*qf))) == NULL)
112 return (NULL);
113 if ((qf->fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
169 /* Open failed above, but O_CREAT specified, so create a new file */
170 if ((qf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
114 serrno = errno;
115 free(qf);
116 errno = serrno;
117 return (NULL);
118 }
171 serrno = errno;
172 free(qf);
173 errno = serrno;
174 return (NULL);
175 }
119 qf->type = 64;
176 qf->wordsize = 64;
120 memset(&dqh, 0, sizeof(dqh));
121 memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
122 dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
123 dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
124 dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
125 if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
126 serrno = errno;
177 memset(&dqh, 0, sizeof(dqh));
178 memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
179 dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
180 dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
181 dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
182 if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
183 serrno = errno;
127 unlink(fn);
184 unlink(qf->qfname);
128 close(qf->fd);
129 free(qf);
130 errno = serrno;
131 return (NULL);
132 }
133 grp = getgrnam(QUOTAGROUP);
134 fchown(qf->fd, 0, grp ? grp->gr_gid : 0);
135 fchmod(qf->fd, 0640);
136 return (qf);
137}
138
139void
140quota_close(struct quotafile *qf)
141{
142
185 close(qf->fd);
186 free(qf);
187 errno = serrno;
188 return (NULL);
189 }
190 grp = getgrnam(QUOTAGROUP);
191 fchown(qf->fd, 0, grp ? grp->gr_gid : 0);
192 fchmod(qf->fd, 0640);
193 return (qf);
194}
195
196void
197quota_close(struct quotafile *qf)
198{
199
143 close(qf->fd);
200 if (qf->fd != -1)
201 close(qf->fd);
144 free(qf);
145}
146
147static int
148quota_read32(struct quotafile *qf, struct dqblk *dqb, int id)
149{
150 struct dqblk32 dqb32;
151 off_t off;

--- 46 unchanged lines hidden (view full) ---

198 default:
199 return (-1);
200 }
201}
202
203int
204quota_read(struct quotafile *qf, struct dqblk *dqb, int id)
205{
202 free(qf);
203}
204
205static int
206quota_read32(struct quotafile *qf, struct dqblk *dqb, int id)
207{
208 struct dqblk32 dqb32;
209 off_t off;

--- 46 unchanged lines hidden (view full) ---

256 default:
257 return (-1);
258 }
259}
260
261int
262quota_read(struct quotafile *qf, struct dqblk *dqb, int id)
263{
264 int qcmd;
206
265
207 switch (qf->type) {
266 if (qf->fd == -1) {
267 qcmd = QCMD(Q_GETQUOTA, qf->quotatype);
268 return (quotactl(qf->fsname, qcmd, id, dqb));
269 }
270 switch (qf->wordsize) {
208 case 32:
209 return quota_read32(qf, dqb, id);
210 case 64:
211 return quota_read64(qf, dqb, id);
212 default:
213 errno = EINVAL;
214 return (-1);
215 }

--- 15 unchanged lines hidden (view full) ---

231 dqb32.dqb_isoftlimit = CLIP32(dqb->dqb_isoftlimit);
232 dqb32.dqb_curinodes = CLIP32(dqb->dqb_curinodes);
233 dqb32.dqb_btime = CLIP32(dqb->dqb_btime);
234 dqb32.dqb_itime = CLIP32(dqb->dqb_itime);
235
236 off = id * sizeof(struct dqblk32);
237 if (lseek(qf->fd, off, SEEK_SET) == -1)
238 return (-1);
271 case 32:
272 return quota_read32(qf, dqb, id);
273 case 64:
274 return quota_read64(qf, dqb, id);
275 default:
276 errno = EINVAL;
277 return (-1);
278 }

--- 15 unchanged lines hidden (view full) ---

294 dqb32.dqb_isoftlimit = CLIP32(dqb->dqb_isoftlimit);
295 dqb32.dqb_curinodes = CLIP32(dqb->dqb_curinodes);
296 dqb32.dqb_btime = CLIP32(dqb->dqb_btime);
297 dqb32.dqb_itime = CLIP32(dqb->dqb_itime);
298
299 off = id * sizeof(struct dqblk32);
300 if (lseek(qf->fd, off, SEEK_SET) == -1)
301 return (-1);
239 return (write(qf->fd, &dqb32, sizeof(dqb32)) == sizeof(dqb32));
302 if (write(qf->fd, &dqb32, sizeof(dqb32)) == sizeof(dqb32))
303 return (0);
304 return (-1);
240}
241
242static int
243quota_write64(struct quotafile *qf, const struct dqblk *dqb, int id)
244{
245 struct dqblk64 dqb64;
246 off_t off;
247

--- 4 unchanged lines hidden (view full) ---

252 dqb64.dqb_isoftlimit = htobe64(dqb->dqb_isoftlimit);
253 dqb64.dqb_curinodes = htobe64(dqb->dqb_curinodes);
254 dqb64.dqb_btime = htobe64(dqb->dqb_btime);
255 dqb64.dqb_itime = htobe64(dqb->dqb_itime);
256
257 off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64);
258 if (lseek(qf->fd, off, SEEK_SET) == -1)
259 return (-1);
305}
306
307static int
308quota_write64(struct quotafile *qf, const struct dqblk *dqb, int id)
309{
310 struct dqblk64 dqb64;
311 off_t off;
312

--- 4 unchanged lines hidden (view full) ---

317 dqb64.dqb_isoftlimit = htobe64(dqb->dqb_isoftlimit);
318 dqb64.dqb_curinodes = htobe64(dqb->dqb_curinodes);
319 dqb64.dqb_btime = htobe64(dqb->dqb_btime);
320 dqb64.dqb_itime = htobe64(dqb->dqb_itime);
321
322 off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64);
323 if (lseek(qf->fd, off, SEEK_SET) == -1)
324 return (-1);
260 return (write(qf->fd, &dqb64, sizeof(dqb64)) == sizeof(dqb64));
325 if (write(qf->fd, &dqb64, sizeof(dqb64)) == sizeof(dqb64))
326 return (0);
327 return (-1);
261}
262
263int
328}
329
330int
264quota_write(struct quotafile *qf, const struct dqblk *dqb, int id)
331quota_write_usage(struct quotafile *qf, struct dqblk *dqb, int id)
265{
332{
333 struct dqblk dqbuf;
334 int qcmd;
266
335
267 switch (qf->type) {
336 if (qf->fd == -1) {
337 qcmd = QCMD(Q_SETUSE, qf->quotatype);
338 return (quotactl(qf->fsname, qcmd, id, dqb));
339 }
340 /*
341 * Have to do read-modify-write of quota in file.
342 */
343 if (quota_read(qf, &dqbuf, id) != 0)
344 return (-1);
345 /*
346 * Reset time limit if have a soft limit and were
347 * previously under it, but are now over it.
348 */
349 if (dqbuf.dqb_bsoftlimit && id != 0 &&
350 dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
351 dqb->dqb_curblocks >= dqbuf.dqb_bsoftlimit)
352 dqbuf.dqb_btime = 0;
353 if (dqbuf.dqb_isoftlimit && id != 0 &&
354 dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit &&
355 dqb->dqb_curinodes >= dqbuf.dqb_isoftlimit)
356 dqbuf.dqb_itime = 0;
357 dqbuf.dqb_curinodes = dqb->dqb_curinodes;
358 dqbuf.dqb_curblocks = dqb->dqb_curblocks;
359 /*
360 * Write it back.
361 */
362 switch (qf->wordsize) {
268 case 32:
363 case 32:
269 return quota_write32(qf, dqb, id);
364 return quota_write32(qf, &dqbuf, id);
270 case 64:
365 case 64:
271 return quota_write64(qf, dqb, id);
366 return quota_write64(qf, &dqbuf, id);
272 default:
273 errno = EINVAL;
274 return (-1);
275 }
276 /* not reached */
277}
278
367 default:
368 errno = EINVAL;
369 return (-1);
370 }
371 /* not reached */
372}
373
279/*
280 * Check to see if a particular quota is to be enabled.
281 */
282int
374int
283hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize)
375quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
284{
376{
285 char *opt;
286 char *cp;
287 struct statfs sfb;
288 char buf[BUFSIZ];
289 static char initname, usrname[100], grpname[100];
377 struct dqblk dqbuf;
378 int qcmd;
290
379
291 if (!initname) {
292 (void)snprintf(usrname, sizeof(usrname), "%s%s",
293 qfextension[USRQUOTA], QUOTAFILENAME);
294 (void)snprintf(grpname, sizeof(grpname), "%s%s",
295 qfextension[GRPQUOTA], QUOTAFILENAME);
296 initname = 1;
380 if (qf->fd == -1) {
381 qcmd = QCMD(Q_SETQUOTA, qf->quotatype);
382 return (quotactl(qf->fsname, qcmd, id, dqb));
297 }
383 }
298 strcpy(buf, fs->fs_mntops);
299 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
300 if ((cp = index(opt, '=')))
301 *cp++ = '\0';
302 if (type == USRQUOTA && strcmp(opt, usrname) == 0)
303 break;
304 if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
305 break;
306 }
307 if (!opt)
308 return (0);
309 /*
384 /*
310 * Ensure that the filesystem is mounted.
385 * Have to do read-modify-write of quota in file.
311 */
386 */
312 if (statfs(fs->fs_file, &sfb) != 0 ||
313 strcmp(fs->fs_file, sfb.f_mntonname)) {
314 return (0);
387 if (quota_read(qf, &dqbuf, id) != 0)
388 return (-1);
389 /*
390 * Reset time limit if have a soft limit and were
391 * previously under it, but are now over it
392 * or if there previously was no soft limit, but
393 * now have one and are over it.
394 */
395 if (dqbuf.dqb_bsoftlimit && id != 0 &&
396 dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
397 dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit)
398 dqb->dqb_btime = 0;
399 if (dqbuf.dqb_bsoftlimit == 0 && id != 0 &&
400 dqb->dqb_bsoftlimit > 0 &&
401 dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit)
402 dqb->dqb_btime = 0;
403 if (dqbuf.dqb_isoftlimit && id != 0 &&
404 dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit &&
405 dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit)
406 dqb->dqb_itime = 0;
407 if (dqbuf.dqb_isoftlimit == 0 && id !=0 &&
408 dqb->dqb_isoftlimit > 0 &&
409 dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit)
410 dqb->dqb_itime = 0;
411 dqb->dqb_curinodes = dqbuf.dqb_curinodes;
412 dqb->dqb_curblocks = dqbuf.dqb_curblocks;
413 /*
414 * Write it back.
415 */
416 switch (qf->wordsize) {
417 case 32:
418 return quota_write32(qf, dqb, id);
419 case 64:
420 return quota_write64(qf, dqb, id);
421 default:
422 errno = EINVAL;
423 return (-1);
315 }
424 }
316 if (cp) {
317 strncpy(qfnamep, cp, qfbufsize);
318 } else {
319 (void)snprintf(qfnamep, qfbufsize, "%s/%s.%s", fs->fs_file,
320 QUOTAFILENAME, qfextension[type]);
321 }
322 return (1);
425 /* not reached */
323}
426}