xref: /netbsd/lib/libquota/quota_kernel.c (revision 30cc8b98)
1 /*	$NetBSD: quota_kernel.c,v 1.6 2014/06/28 22:27:50 dholland 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.6 2014/06/28 22:27:50 dholland 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 
44 struct kernel_quotacursor {
45 	/* just wrap the kernel interface type */
46 	struct quotakcursor kcursor;
47 };
48 
49 static int
__quota_kernel_stat(struct quotahandle * qh,struct quotastat * stat)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 
59 const char *
__quota_kernel_getimplname(struct quotahandle * qh)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 
70 unsigned
__quota_kernel_getrestrictions(struct quotahandle * qh)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 
82 int
__quota_kernel_getnumidtypes(struct quotahandle * qh)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 
93 const char *
__quota_kernel_idtype_getname(struct quotahandle * qh,int idtype)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 
108 int
__quota_kernel_getnumobjtypes(struct quotahandle * qh)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 
119 const char *
__quota_kernel_objtype_getname(struct quotahandle * qh,int objtype)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 
134 int
__quota_kernel_objtype_isbytes(struct quotahandle * qh,int objtype)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 
149 int
__quota_kernel_quotaon(struct quotahandle * qh,int idtype)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 
184 int
__quota_kernel_quotaoff(struct quotahandle * qh,int idtype)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 
194 int
__quota_kernel_get(struct quotahandle * qh,const struct quotakey * qk,struct quotaval * qv)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 
206 int
__quota_kernel_put(struct quotahandle * qh,const struct quotakey * qk,const struct quotaval * qv)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 
218 int
__quota_kernel_delete(struct quotahandle * qh,const struct quotakey * qk)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 
228 struct kernel_quotacursor *
__quota_kernel_cursor_create(struct quotahandle * qh)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 
251 void
__quota_kernel_cursor_destroy(struct quotahandle * qh,struct kernel_quotacursor * cursor)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 
266 int
__quota_kernel_cursor_skipidtype(struct quotahandle * qh,struct kernel_quotacursor * cursor,int idtype)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 
279 int
__quota_kernel_cursor_get(struct quotahandle * qh,struct kernel_quotacursor * cursor,struct quotakey * key,struct quotaval * val)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 
293 int
__quota_kernel_cursor_getn(struct quotahandle * qh,struct kernel_quotacursor * cursor,struct quotakey * keys,struct quotaval * vals,unsigned maxnum)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 
320 int
__quota_kernel_cursor_atend(struct quotahandle * qh,struct kernel_quotacursor * cursor)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 
342 int
__quota_kernel_cursor_rewind(struct quotahandle * qh,struct kernel_quotacursor * cursor)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