1/*	$NetBSD: quota_kernel.c,v 1.5 2014/06/12 21:39:45 joerg Exp $	*/
2/*-
3 * Copyright (c) 2012 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by David A. Holland.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: quota_kernel.c,v 1.5 2014/06/12 21:39:45 joerg Exp $");
33
34#include <stdlib.h>
35#include <err.h>
36#include <errno.h>
37#include <limits.h>
38
39#include <quota.h>
40#include <sys/quotactl.h>
41
42#include "quotapvt.h"
43
44struct kernel_quotacursor {
45	/* just wrap the kernel interface type */
46	struct quotakcursor kcursor;
47};
48
49static int
50__quota_kernel_stat(struct quotahandle *qh, struct quotastat *stat)
51{
52	struct quotactl_args args;
53
54	args.qc_op = QUOTACTL_STAT;
55	args.u.stat.qc_info = stat;
56	return __quotactl(qh->qh_mountpoint, &args);
57}
58
59const char *
60__quota_kernel_getimplname(struct quotahandle *qh)
61{
62	static struct quotastat stat;
63
64	if (__quota_kernel_stat(qh, &stat)) {
65		return NULL;
66	}
67	return stat.qs_implname;
68}
69
70unsigned
71__quota_kernel_getrestrictions(struct quotahandle *qh)
72{
73	struct quotastat stat;
74
75	if (__quota_kernel_stat(qh, &stat)) {
76		/* XXX no particularly satisfactory thing to do here */
77		return 0;
78	}
79	return stat.qs_restrictions;
80}
81
82int
83__quota_kernel_getnumidtypes(struct quotahandle *qh)
84{
85	struct quotastat stat;
86
87	if (__quota_kernel_stat(qh, &stat)) {
88		return 0;
89	}
90	return stat.qs_numidtypes;
91}
92
93const char *
94__quota_kernel_idtype_getname(struct quotahandle *qh, int idtype)
95{
96	static struct quotaidtypestat stat;
97	struct quotactl_args args;
98
99	args.qc_op = QUOTACTL_IDTYPESTAT;
100	args.u.idtypestat.qc_idtype = idtype;
101	args.u.idtypestat.qc_info = &stat;
102	if (__quotactl(qh->qh_mountpoint, &args)) {
103		return NULL;
104	}
105	return stat.qis_name;
106}
107
108int
109__quota_kernel_getnumobjtypes(struct quotahandle *qh)
110{
111	struct quotastat stat;
112
113	if (__quota_kernel_stat(qh, &stat)) {
114		return 0;
115	}
116	return stat.qs_numobjtypes;
117}
118
119const char *
120__quota_kernel_objtype_getname(struct quotahandle *qh, int objtype)
121{
122	static struct quotaobjtypestat stat;
123	struct quotactl_args args;
124
125	args.qc_op = QUOTACTL_OBJTYPESTAT;
126	args.u.objtypestat.qc_objtype = objtype;
127	args.u.objtypestat.qc_info = &stat;
128	if (__quotactl(qh->qh_mountpoint, &args)) {
129		return NULL;
130	}
131	return stat.qos_name;
132}
133
134int
135__quota_kernel_objtype_isbytes(struct quotahandle *qh, int objtype)
136{
137	struct quotaobjtypestat stat;
138	struct quotactl_args args;
139
140	args.qc_op = QUOTACTL_OBJTYPESTAT;
141	args.u.objtypestat.qc_objtype = objtype;
142	args.u.objtypestat.qc_info = &stat;
143	if (__quotactl(qh->qh_mountpoint, &args)) {
144		return 0;
145	}
146	return stat.qos_isbytes;
147}
148
149int
150__quota_kernel_quotaon(struct quotahandle *qh, int idtype)
151{
152	struct quotactl_args args;
153	const char *file;
154	char path[PATH_MAX];
155
156	/*
157	 * Note that while it is an error to call quotaon on something
158	 * that isn't a volume with old-style quotas that expects
159	 * quotaon to be called, it's not our responsibility to check
160	 * for that; the filesystem will. Also note that it is not an
161	 * error to call quotaon repeatedly -- apparently this is to
162	 * permit changing the quota file in use on the fly or
163	 * something. So all we need to do here is ask the oldfiles
164	 * code if the mount option was set in fstab and fetch back
165	 * the filename.
166	 */
167
168	file = __quota_oldfiles_getquotafile(qh, idtype, path, sizeof(path));
169	if (file == NULL) {
170		/*
171		 * This idtype (or maybe any idtype) was not enabled
172		 * in fstab.
173		 */
174		errno = ENXIO;
175		return -1;
176	}
177
178	args.qc_op = QUOTACTL_QUOTAON;
179	args.u.quotaon.qc_idtype = idtype;
180	args.u.quotaon.qc_quotafile = file;
181	return __quotactl(qh->qh_mountpoint, &args);
182}
183
184int
185__quota_kernel_quotaoff(struct quotahandle *qh, int idtype)
186{
187	struct quotactl_args args;
188
189	args.qc_op = QUOTACTL_QUOTAOFF;
190	args.u.quotaoff.qc_idtype = idtype;
191	return __quotactl(qh->qh_mountpoint, &args);
192}
193
194int
195__quota_kernel_get(struct quotahandle *qh, const struct quotakey *qk,
196		   struct quotaval *qv)
197{
198	struct quotactl_args args;
199
200	args.qc_op = QUOTACTL_GET;
201	args.u.get.qc_key = qk;
202	args.u.get.qc_val = qv;
203	return __quotactl(qh->qh_mountpoint, &args);
204}
205
206int
207__quota_kernel_put(struct quotahandle *qh, const struct quotakey *qk,
208		   const struct quotaval *qv)
209{
210	struct quotactl_args args;
211
212	args.qc_op = QUOTACTL_PUT;
213	args.u.put.qc_key = qk;
214	args.u.put.qc_val = qv;
215	return __quotactl(qh->qh_mountpoint, &args);
216}
217
218int
219__quota_kernel_delete(struct quotahandle *qh, const struct quotakey *qk)
220{
221	struct quotactl_args args;
222
223	args.qc_op = QUOTACTL_DEL;
224	args.u.del.qc_key = qk;
225	return __quotactl(qh->qh_mountpoint, &args);
226}
227
228struct kernel_quotacursor *
229__quota_kernel_cursor_create(struct quotahandle *qh)
230{
231	struct quotactl_args args;
232	struct kernel_quotacursor *cursor;
233	int sverrno;
234
235	cursor = malloc(sizeof(*cursor));
236	if (cursor == NULL) {
237		return NULL;
238	}
239
240	args.qc_op = QUOTACTL_CURSOROPEN;
241	args.u.cursoropen.qc_cursor = &cursor->kcursor;
242	if (__quotactl(qh->qh_mountpoint, &args)) {
243		sverrno = errno;
244		free(cursor);
245		errno = sverrno;
246		return NULL;
247	}
248	return cursor;
249}
250
251void
252__quota_kernel_cursor_destroy(struct quotahandle *qh,
253			      struct kernel_quotacursor *cursor)
254{
255	struct quotactl_args args;
256
257	args.qc_op = QUOTACTL_CURSORCLOSE;
258	args.u.cursorclose.qc_cursor = &cursor->kcursor;
259	if (__quotactl(qh->qh_mountpoint, &args)) {
260		/* XXX should we really print from inside the library? */
261		warn("__quotactl cursorclose");
262	}
263	free(cursor);
264}
265
266int
267__quota_kernel_cursor_skipidtype(struct quotahandle *qh,
268				 struct kernel_quotacursor *cursor,
269				 int idtype)
270{
271	struct quotactl_args args;
272
273	args.qc_op = QUOTACTL_CURSORSKIPIDTYPE;
274	args.u.cursorskipidtype.qc_cursor = &cursor->kcursor;
275	args.u.cursorskipidtype.qc_idtype = idtype;
276	return __quotactl(qh->qh_mountpoint, &args);
277}
278
279int
280__quota_kernel_cursor_get(struct quotahandle *qh,
281			  struct kernel_quotacursor *cursor,
282			  struct quotakey *key, struct quotaval *val)
283{
284	int ret;
285
286	ret = __quota_kernel_cursor_getn(qh, cursor, key, val, 1);
287	if (ret < 0) {
288		return -1;
289	}
290	return 0;
291}
292
293int
294__quota_kernel_cursor_getn(struct quotahandle *qh,
295			   struct kernel_quotacursor *cursor,
296			   struct quotakey *keys, struct quotaval *vals,
297			   unsigned maxnum)
298{
299	struct quotactl_args args;
300	unsigned ret;
301
302	if (maxnum > INT_MAX) {
303		/* joker, eh? */
304		errno = EINVAL;
305		return -1;
306	}
307
308	args.qc_op = QUOTACTL_CURSORGET;
309	args.u.cursorget.qc_cursor = &cursor->kcursor;
310	args.u.cursorget.qc_keys = keys;
311	args.u.cursorget.qc_vals = vals;
312	args.u.cursorget.qc_maxnum = maxnum;
313	args.u.cursorget.qc_ret = &ret;
314	if (__quotactl(qh->qh_mountpoint, &args) < 0) {
315		return -1;
316	}
317	return ret;
318}
319
320int
321__quota_kernel_cursor_atend(struct quotahandle *qh,
322			    struct kernel_quotacursor *cursor)
323{
324	struct quotactl_args args;
325	int ret;
326
327	args.qc_op = QUOTACTL_CURSORATEND;
328	args.u.cursoratend.qc_cursor = &cursor->kcursor;
329	args.u.cursoratend.qc_ret = &ret;
330	if (__quotactl(qh->qh_mountpoint, &args)) {
331		/*
332		 * Return -1 so naive callers, who test for the return
333		 * value being nonzero, stop iterating, and
334		 * sophisticated callers can tell an error from
335		 * end-of-data.
336		 */
337		return -1;
338	}
339	return ret;
340}
341
342int
343__quota_kernel_cursor_rewind(struct quotahandle *qh,
344			     struct kernel_quotacursor *cursor)
345{
346	struct quotactl_args args;
347
348	args.qc_op = QUOTACTL_CURSORREWIND;
349	args.u.cursorrewind.qc_cursor = &cursor->kcursor;
350	return __quotactl(qh->qh_mountpoint, &args);
351}
352