quotafile.c revision 187914
1/*-
2 * Copyright (c) 2008 Dag-Erling Co��dan Sm��rgrav
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.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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 *
27 * $FreeBSD: projects/quota64/lib/libutil/quotafile.c 187914 2009-01-30 13:54:03Z des $
28 */
29
30#include <sys/types.h>
31#include <sys/endian.h>
32#include <sys/stat.h>
33
34#include <ufs/ufs/quota.h>
35
36#include <errno.h>
37#include <fcntl.h>
38#include <grp.h>
39#include <pwd.h>
40#include <libutil.h>
41#include <stdint.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46struct quotafile {
47	int fd;
48	int type; /* 32 or 64 */
49};
50
51struct quotafile *
52quota_open(const char *fn)
53{
54	struct quotafile *qf;
55	struct dqhdr64 dqh;
56	int serrno;
57
58	if ((qf = calloc(1, sizeof(*qf))) == NULL)
59		return (NULL);
60	if ((qf->fd = open(fn, O_RDWR)) < 0) {
61		serrno = errno;
62		free(qf);
63		errno = serrno;
64		return (NULL);
65	}
66	qf->type = 32;
67	switch (read(qf->fd, &dqh, sizeof(dqh))) {
68	case -1:
69		serrno = errno;
70		close(qf->fd);
71		free(qf);
72		errno = serrno;
73		return (NULL);
74	case sizeof(dqh):
75		if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
76			/* no magic, assume 32 bits */
77			qf->type = 32;
78			return (qf);
79		}
80		if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION ||
81		    be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) ||
82		    be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) {
83			/* correct magic, wrong version / lengths */
84			close(qf->fd);
85			free(qf);
86			errno = EINVAL;
87			return (NULL);
88		}
89		qf->type = 64;
90		return (qf);
91	default:
92		qf->type = 32;
93		return (qf);
94	}
95	/* not reached */
96}
97
98struct quotafile *
99quota_create(const char *fn)
100{
101	struct quotafile *qf;
102	struct dqhdr64 dqh;
103	struct group *grp;
104	int serrno;
105
106	if ((qf = calloc(1, sizeof(*qf))) == NULL)
107		return (NULL);
108	if ((qf->fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
109		serrno = errno;
110		free(qf);
111		errno = serrno;
112		return (NULL);
113	}
114	qf->type = 64;
115	memset(&dqh, 0, sizeof(dqh));
116	memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
117	dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
118	dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
119	dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
120	if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
121		serrno = errno;
122		unlink(fn);
123		close(qf->fd);
124		free(qf);
125		errno = serrno;
126		return (NULL);
127	}
128	grp = getgrnam(QUOTAGROUP);
129	fchown(qf->fd, 0, grp ? grp->gr_gid : 0);
130	fchmod(qf->fd, 0640);
131	return (qf);
132}
133
134void
135quota_close(struct quotafile *qf)
136{
137
138	close(qf->fd);
139	free(qf);
140}
141
142static int
143quota_read32(struct quotafile *qf, struct dqblk *dqb, int id)
144{
145	struct dqblk32 dqb32;
146	off_t off;
147
148	off = id * sizeof(struct dqblk32);
149	if (lseek(qf->fd, off, SEEK_SET) == -1)
150		return (-1);
151	switch (read(qf->fd, &dqb32, sizeof(dqb32))) {
152	case 0:
153		memset(&dqb, 0, sizeof(*dqb));
154		return (0);
155	case sizeof(dqb32):
156		dqb->dqb_bhardlimit = dqb32.dqb_bhardlimit;
157		dqb->dqb_bsoftlimit = dqb32.dqb_bsoftlimit;
158		dqb->dqb_curblocks = dqb32.dqb_curblocks;
159		dqb->dqb_ihardlimit = dqb32.dqb_ihardlimit;
160		dqb->dqb_isoftlimit = dqb32.dqb_isoftlimit;
161		dqb->dqb_curinodes = dqb32.dqb_curinodes;
162		dqb->dqb_btime = dqb32.dqb_btime;
163		dqb->dqb_itime = dqb32.dqb_itime;
164		return (0);
165	default:
166		return (-1);
167	}
168}
169
170static int
171quota_read64(struct quotafile *qf, struct dqblk *dqb, int id)
172{
173	struct dqblk64 dqb64;
174	off_t off;
175
176	off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64);
177	if (lseek(qf->fd, off, SEEK_SET) == -1)
178		return (-1);
179	switch (read(qf->fd, &dqb64, sizeof(dqb64))) {
180	case 0:
181		memset(&dqb, 0, sizeof(*dqb));
182		return (0);
183	case sizeof(dqb64):
184		dqb->dqb_bhardlimit = be64toh(dqb64.dqb_bhardlimit);
185		dqb->dqb_bsoftlimit = be64toh(dqb64.dqb_bsoftlimit);
186		dqb->dqb_curblocks = be64toh(dqb64.dqb_curblocks);
187		dqb->dqb_ihardlimit = be64toh(dqb64.dqb_ihardlimit);
188		dqb->dqb_isoftlimit = be64toh(dqb64.dqb_isoftlimit);
189		dqb->dqb_curinodes = be64toh(dqb64.dqb_curinodes);
190		dqb->dqb_btime = be64toh(dqb64.dqb_btime);
191		dqb->dqb_itime = be64toh(dqb64.dqb_itime);
192		return (0);
193	default:
194		return (-1);
195	}
196}
197
198int
199quota_read(struct quotafile *qf, struct dqblk *dqb, int id)
200{
201
202	switch (qf->type) {
203	case 32:
204		return quota_read32(qf, dqb, id);
205	case 64:
206		return quota_read64(qf, dqb, id);
207	default:
208		errno = EINVAL;
209		return (-1);
210	}
211	/* not reached */
212}
213
214#define CLIP32(u64) ((u64) > UINT32_MAX ? UINT32_MAX : (uint32_t)(u64))
215
216static int
217quota_write32(struct quotafile *qf, const struct dqblk *dqb, int id)
218{
219	struct dqblk32 dqb32;
220	off_t off;
221
222	dqb32.dqb_bhardlimit = CLIP32(dqb->dqb_bhardlimit);
223	dqb32.dqb_bsoftlimit = CLIP32(dqb->dqb_bsoftlimit);
224	dqb32.dqb_curblocks = CLIP32(dqb->dqb_curblocks);
225	dqb32.dqb_ihardlimit = CLIP32(dqb->dqb_ihardlimit);
226	dqb32.dqb_isoftlimit = CLIP32(dqb->dqb_isoftlimit);
227	dqb32.dqb_curinodes = CLIP32(dqb->dqb_curinodes);
228	dqb32.dqb_btime = CLIP32(dqb->dqb_btime);
229	dqb32.dqb_itime = CLIP32(dqb->dqb_itime);
230
231	off = id * sizeof(struct dqblk32);
232	if (lseek(qf->fd, off, SEEK_SET) == -1)
233		return (-1);
234	return (write(qf->fd, &dqb32, sizeof(dqb32)));
235}
236
237static int
238quota_write64(struct quotafile *qf, const struct dqblk *dqb, int id)
239{
240	struct dqblk64 dqb64;
241	off_t off;
242
243	dqb64.dqb_bhardlimit = htobe64(dqb->dqb_bhardlimit);
244	dqb64.dqb_bsoftlimit = htobe64(dqb->dqb_bsoftlimit);
245	dqb64.dqb_curblocks = htobe64(dqb->dqb_curblocks);
246	dqb64.dqb_ihardlimit = htobe64(dqb->dqb_ihardlimit);
247	dqb64.dqb_isoftlimit = htobe64(dqb->dqb_isoftlimit);
248	dqb64.dqb_curinodes = htobe64(dqb->dqb_curinodes);
249	dqb64.dqb_btime = htobe64(dqb->dqb_btime);
250	dqb64.dqb_itime = htobe64(dqb->dqb_itime);
251
252	off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64);
253	if (lseek(qf->fd, off, SEEK_SET) == -1)
254		return (-1);
255	return (write(qf->fd, &dqb64, sizeof(dqb64)));
256}
257
258int
259quota_write(struct quotafile *qf, const struct dqblk *dqb, int id)
260{
261
262	switch (qf->type) {
263	case 32:
264		return quota_write32(qf, dqb, id);
265	case 64:
266		return quota_write64(qf, dqb, id);
267	default:
268		errno = EINVAL;
269		return (-1);
270	}
271	/* not reached */
272}
273