xref: /netbsd-src/lib/libquota/quota_kernel.c (revision 01e782f37167b4501f6fc58a33f0db9544efdeab)
1*01e782f3Sdholland /*	$NetBSD: quota_kernel.c,v 1.6 2014/06/28 22:27:50 dholland Exp $	*/
259b296daSdholland /*-
359b296daSdholland  * Copyright (c) 2012 The NetBSD Foundation, Inc.
459b296daSdholland  * All rights reserved.
559b296daSdholland  *
659b296daSdholland  * This code is derived from software contributed to The NetBSD Foundation
759b296daSdholland  * by David A. Holland.
859b296daSdholland  *
959b296daSdholland  * Redistribution and use in source and binary forms, with or without
1059b296daSdholland  * modification, are permitted provided that the following conditions
1159b296daSdholland  * are met:
1259b296daSdholland  * 1. Redistributions of source code must retain the above copyright
1359b296daSdholland  *    notice, this list of conditions and the following disclaimer.
1459b296daSdholland  * 2. Redistributions in binary form must reproduce the above copyright
1559b296daSdholland  *    notice, this list of conditions and the following disclaimer in the
1659b296daSdholland  *    documentation and/or other materials provided with the distribution.
1759b296daSdholland  *
1859b296daSdholland  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1959b296daSdholland  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2059b296daSdholland  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2159b296daSdholland  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2259b296daSdholland  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2359b296daSdholland  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2459b296daSdholland  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2559b296daSdholland  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2659b296daSdholland  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2759b296daSdholland  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2859b296daSdholland  * POSSIBILITY OF SUCH DAMAGE.
2959b296daSdholland  */
3059b296daSdholland 
3159b296daSdholland #include <sys/cdefs.h>
32*01e782f3Sdholland __RCSID("$NetBSD: quota_kernel.c,v 1.6 2014/06/28 22:27:50 dholland Exp $");
3359b296daSdholland 
3459b296daSdholland #include <stdlib.h>
3559b296daSdholland #include <err.h>
3659b296daSdholland #include <errno.h>
3759b296daSdholland #include <limits.h>
3859b296daSdholland 
3959b296daSdholland #include <quota.h>
4059b296daSdholland #include <sys/quotactl.h>
4159b296daSdholland 
4259b296daSdholland #include "quotapvt.h"
4359b296daSdholland 
4459b296daSdholland struct kernel_quotacursor {
4559b296daSdholland 	/* just wrap the kernel interface type */
4659b296daSdholland 	struct quotakcursor kcursor;
4759b296daSdholland };
4859b296daSdholland 
4959b296daSdholland static int
__quota_kernel_stat(struct quotahandle * qh,struct quotastat * stat)5059b296daSdholland __quota_kernel_stat(struct quotahandle *qh, struct quotastat *stat)
5159b296daSdholland {
5259b296daSdholland 	struct quotactl_args args;
5359b296daSdholland 
5459b296daSdholland 	args.qc_op = QUOTACTL_STAT;
55d2d6fa0aSdholland 	args.u.stat.qc_info = stat;
5659b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
5759b296daSdholland }
5859b296daSdholland 
5959b296daSdholland const char *
__quota_kernel_getimplname(struct quotahandle * qh)6059b296daSdholland __quota_kernel_getimplname(struct quotahandle *qh)
6159b296daSdholland {
6259b296daSdholland 	static struct quotastat stat;
6359b296daSdholland 
6459b296daSdholland 	if (__quota_kernel_stat(qh, &stat)) {
6559b296daSdholland 		return NULL;
6659b296daSdholland 	}
6759b296daSdholland 	return stat.qs_implname;
6859b296daSdholland }
6959b296daSdholland 
7059b296daSdholland unsigned
__quota_kernel_getrestrictions(struct quotahandle * qh)7159b296daSdholland __quota_kernel_getrestrictions(struct quotahandle *qh)
7259b296daSdholland {
7359b296daSdholland 	struct quotastat stat;
7459b296daSdholland 
7559b296daSdholland 	if (__quota_kernel_stat(qh, &stat)) {
7659b296daSdholland 		/* XXX no particularly satisfactory thing to do here */
7759b296daSdholland 		return 0;
7859b296daSdholland 	}
7959b296daSdholland 	return stat.qs_restrictions;
8059b296daSdholland }
8159b296daSdholland 
82832d4ca7Sdholland int
__quota_kernel_getnumidtypes(struct quotahandle * qh)8359b296daSdholland __quota_kernel_getnumidtypes(struct quotahandle *qh)
8459b296daSdholland {
8559b296daSdholland 	struct quotastat stat;
8659b296daSdholland 
8759b296daSdholland 	if (__quota_kernel_stat(qh, &stat)) {
8859b296daSdholland 		return 0;
8959b296daSdholland 	}
9059b296daSdholland 	return stat.qs_numidtypes;
9159b296daSdholland }
9259b296daSdholland 
9359b296daSdholland const char *
__quota_kernel_idtype_getname(struct quotahandle * qh,int idtype)9459b296daSdholland __quota_kernel_idtype_getname(struct quotahandle *qh, int idtype)
9559b296daSdholland {
9659b296daSdholland 	static struct quotaidtypestat stat;
9759b296daSdholland 	struct quotactl_args args;
9859b296daSdholland 
9959b296daSdholland 	args.qc_op = QUOTACTL_IDTYPESTAT;
10059b296daSdholland 	args.u.idtypestat.qc_idtype = idtype;
10159b296daSdholland 	args.u.idtypestat.qc_info = &stat;
10259b296daSdholland 	if (__quotactl(qh->qh_mountpoint, &args)) {
10359b296daSdholland 		return NULL;
10459b296daSdholland 	}
10559b296daSdholland 	return stat.qis_name;
10659b296daSdholland }
10759b296daSdholland 
108832d4ca7Sdholland int
__quota_kernel_getnumobjtypes(struct quotahandle * qh)10959b296daSdholland __quota_kernel_getnumobjtypes(struct quotahandle *qh)
11059b296daSdholland {
11159b296daSdholland 	struct quotastat stat;
11259b296daSdholland 
11359b296daSdholland 	if (__quota_kernel_stat(qh, &stat)) {
11459b296daSdholland 		return 0;
11559b296daSdholland 	}
11659b296daSdholland 	return stat.qs_numobjtypes;
11759b296daSdholland }
11859b296daSdholland 
11959b296daSdholland const char *
__quota_kernel_objtype_getname(struct quotahandle * qh,int objtype)12059b296daSdholland __quota_kernel_objtype_getname(struct quotahandle *qh, int objtype)
12159b296daSdholland {
12259b296daSdholland 	static struct quotaobjtypestat stat;
12359b296daSdholland 	struct quotactl_args args;
12459b296daSdholland 
12559b296daSdholland 	args.qc_op = QUOTACTL_OBJTYPESTAT;
12659b296daSdholland 	args.u.objtypestat.qc_objtype = objtype;
12759b296daSdholland 	args.u.objtypestat.qc_info = &stat;
12859b296daSdholland 	if (__quotactl(qh->qh_mountpoint, &args)) {
12959b296daSdholland 		return NULL;
13059b296daSdholland 	}
13159b296daSdholland 	return stat.qos_name;
13259b296daSdholland }
13359b296daSdholland 
13459b296daSdholland int
__quota_kernel_objtype_isbytes(struct quotahandle * qh,int objtype)13559b296daSdholland __quota_kernel_objtype_isbytes(struct quotahandle *qh, int objtype)
13659b296daSdholland {
13759b296daSdholland 	struct quotaobjtypestat stat;
13859b296daSdholland 	struct quotactl_args args;
13959b296daSdholland 
14059b296daSdholland 	args.qc_op = QUOTACTL_OBJTYPESTAT;
14159b296daSdholland 	args.u.objtypestat.qc_objtype = objtype;
14259b296daSdholland 	args.u.objtypestat.qc_info = &stat;
14359b296daSdholland 	if (__quotactl(qh->qh_mountpoint, &args)) {
14459b296daSdholland 		return 0;
14559b296daSdholland 	}
14659b296daSdholland 	return stat.qos_isbytes;
14759b296daSdholland }
14859b296daSdholland 
14959b296daSdholland int
__quota_kernel_quotaon(struct quotahandle * qh,int idtype)15059b296daSdholland __quota_kernel_quotaon(struct quotahandle *qh, int idtype)
15159b296daSdholland {
15259b296daSdholland 	struct quotactl_args args;
15359b296daSdholland 	const char *file;
15459b296daSdholland 	char path[PATH_MAX];
15559b296daSdholland 
15659b296daSdholland 	/*
15759b296daSdholland 	 * Note that while it is an error to call quotaon on something
15859b296daSdholland 	 * that isn't a volume with old-style quotas that expects
15959b296daSdholland 	 * quotaon to be called, it's not our responsibility to check
16059b296daSdholland 	 * for that; the filesystem will. Also note that it is not an
16159b296daSdholland 	 * error to call quotaon repeatedly -- apparently this is to
16259b296daSdholland 	 * permit changing the quota file in use on the fly or
16359b296daSdholland 	 * something. So all we need to do here is ask the oldfiles
16459b296daSdholland 	 * code if the mount option was set in fstab and fetch back
16559b296daSdholland 	 * the filename.
16659b296daSdholland 	 */
16759b296daSdholland 
16859b296daSdholland 	file = __quota_oldfiles_getquotafile(qh, idtype, path, sizeof(path));
16959b296daSdholland 	if (file == NULL) {
17059b296daSdholland 		/*
17159b296daSdholland 		 * This idtype (or maybe any idtype) was not enabled
17259b296daSdholland 		 * in fstab.
17359b296daSdholland 		 */
17459b296daSdholland 		errno = ENXIO;
17559b296daSdholland 		return -1;
17659b296daSdholland 	}
17759b296daSdholland 
17859b296daSdholland 	args.qc_op = QUOTACTL_QUOTAON;
17959b296daSdholland 	args.u.quotaon.qc_idtype = idtype;
18059b296daSdholland 	args.u.quotaon.qc_quotafile = file;
18159b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
18259b296daSdholland }
18359b296daSdholland 
18459b296daSdholland int
__quota_kernel_quotaoff(struct quotahandle * qh,int idtype)18559b296daSdholland __quota_kernel_quotaoff(struct quotahandle *qh, int idtype)
18659b296daSdholland {
18759b296daSdholland 	struct quotactl_args args;
18859b296daSdholland 
18959b296daSdholland 	args.qc_op = QUOTACTL_QUOTAOFF;
19059b296daSdholland 	args.u.quotaoff.qc_idtype = idtype;
19159b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
19259b296daSdholland }
19359b296daSdholland 
19459b296daSdholland int
__quota_kernel_get(struct quotahandle * qh,const struct quotakey * qk,struct quotaval * qv)19559b296daSdholland __quota_kernel_get(struct quotahandle *qh, const struct quotakey *qk,
19659b296daSdholland 		   struct quotaval *qv)
19759b296daSdholland {
19859b296daSdholland 	struct quotactl_args args;
19959b296daSdholland 
20059b296daSdholland 	args.qc_op = QUOTACTL_GET;
20159b296daSdholland 	args.u.get.qc_key = qk;
202d2d6fa0aSdholland 	args.u.get.qc_val = qv;
20359b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
20459b296daSdholland }
20559b296daSdholland 
20659b296daSdholland int
__quota_kernel_put(struct quotahandle * qh,const struct quotakey * qk,const struct quotaval * qv)20759b296daSdholland __quota_kernel_put(struct quotahandle *qh, const struct quotakey *qk,
20859b296daSdholland 		   const struct quotaval *qv)
20959b296daSdholland {
21059b296daSdholland 	struct quotactl_args args;
21159b296daSdholland 
21259b296daSdholland 	args.qc_op = QUOTACTL_PUT;
21359b296daSdholland 	args.u.put.qc_key = qk;
21459b296daSdholland 	args.u.put.qc_val = qv;
21559b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
21659b296daSdholland }
21759b296daSdholland 
21859b296daSdholland int
__quota_kernel_delete(struct quotahandle * qh,const struct quotakey * qk)21959b296daSdholland __quota_kernel_delete(struct quotahandle *qh, const struct quotakey *qk)
22059b296daSdholland {
22159b296daSdholland 	struct quotactl_args args;
22259b296daSdholland 
223*01e782f3Sdholland 	args.qc_op = QUOTACTL_DEL;
224*01e782f3Sdholland 	args.u.del.qc_key = qk;
22559b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
22659b296daSdholland }
22759b296daSdholland 
22859b296daSdholland struct kernel_quotacursor *
__quota_kernel_cursor_create(struct quotahandle * qh)22959b296daSdholland __quota_kernel_cursor_create(struct quotahandle *qh)
23059b296daSdholland {
23159b296daSdholland 	struct quotactl_args args;
23259b296daSdholland 	struct kernel_quotacursor *cursor;
23359b296daSdholland 	int sverrno;
23459b296daSdholland 
23559b296daSdholland 	cursor = malloc(sizeof(*cursor));
23659b296daSdholland 	if (cursor == NULL) {
23759b296daSdholland 		return NULL;
23859b296daSdholland 	}
23959b296daSdholland 
24059b296daSdholland 	args.qc_op = QUOTACTL_CURSOROPEN;
24159b296daSdholland 	args.u.cursoropen.qc_cursor = &cursor->kcursor;
24259b296daSdholland 	if (__quotactl(qh->qh_mountpoint, &args)) {
24359b296daSdholland 		sverrno = errno;
24459b296daSdholland 		free(cursor);
24559b296daSdholland 		errno = sverrno;
24659b296daSdholland 		return NULL;
24759b296daSdholland 	}
24859b296daSdholland 	return cursor;
24959b296daSdholland }
25059b296daSdholland 
25159b296daSdholland void
__quota_kernel_cursor_destroy(struct quotahandle * qh,struct kernel_quotacursor * cursor)25259b296daSdholland __quota_kernel_cursor_destroy(struct quotahandle *qh,
25359b296daSdholland 			      struct kernel_quotacursor *cursor)
25459b296daSdholland {
25559b296daSdholland 	struct quotactl_args args;
25659b296daSdholland 
25759b296daSdholland 	args.qc_op = QUOTACTL_CURSORCLOSE;
25859b296daSdholland 	args.u.cursorclose.qc_cursor = &cursor->kcursor;
25959b296daSdholland 	if (__quotactl(qh->qh_mountpoint, &args)) {
26059b296daSdholland 		/* XXX should we really print from inside the library? */
26159b296daSdholland 		warn("__quotactl cursorclose");
26259b296daSdholland 	}
26359b296daSdholland 	free(cursor);
26459b296daSdholland }
26559b296daSdholland 
26659b296daSdholland int
__quota_kernel_cursor_skipidtype(struct quotahandle * qh,struct kernel_quotacursor * cursor,int idtype)26759b296daSdholland __quota_kernel_cursor_skipidtype(struct quotahandle *qh,
26859b296daSdholland 				 struct kernel_quotacursor *cursor,
269832d4ca7Sdholland 				 int idtype)
27059b296daSdholland {
27159b296daSdholland 	struct quotactl_args args;
27259b296daSdholland 
27359b296daSdholland 	args.qc_op = QUOTACTL_CURSORSKIPIDTYPE;
27459b296daSdholland 	args.u.cursorskipidtype.qc_cursor = &cursor->kcursor;
27559b296daSdholland 	args.u.cursorskipidtype.qc_idtype = idtype;
27659b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
27759b296daSdholland }
27859b296daSdholland 
27959b296daSdholland int
__quota_kernel_cursor_get(struct quotahandle * qh,struct kernel_quotacursor * cursor,struct quotakey * key,struct quotaval * val)28059b296daSdholland __quota_kernel_cursor_get(struct quotahandle *qh,
28159b296daSdholland 			  struct kernel_quotacursor *cursor,
28259b296daSdholland 			  struct quotakey *key, struct quotaval *val)
28359b296daSdholland {
28459b296daSdholland 	int ret;
28559b296daSdholland 
28659b296daSdholland 	ret = __quota_kernel_cursor_getn(qh, cursor, key, val, 1);
28759b296daSdholland 	if (ret < 0) {
28859b296daSdholland 		return -1;
28959b296daSdholland 	}
29059b296daSdholland 	return 0;
29159b296daSdholland }
29259b296daSdholland 
29359b296daSdholland int
__quota_kernel_cursor_getn(struct quotahandle * qh,struct kernel_quotacursor * cursor,struct quotakey * keys,struct quotaval * vals,unsigned maxnum)29459b296daSdholland __quota_kernel_cursor_getn(struct quotahandle *qh,
29559b296daSdholland 			   struct kernel_quotacursor *cursor,
29659b296daSdholland 			   struct quotakey *keys, struct quotaval *vals,
29759b296daSdholland 			   unsigned maxnum)
29859b296daSdholland {
29959b296daSdholland 	struct quotactl_args args;
30059b296daSdholland 	unsigned ret;
30159b296daSdholland 
30231f4a06fSdholland 	if (maxnum > INT_MAX) {
30331f4a06fSdholland 		/* joker, eh? */
30431f4a06fSdholland 		errno = EINVAL;
30531f4a06fSdholland 		return -1;
30631f4a06fSdholland 	}
30731f4a06fSdholland 
30859b296daSdholland 	args.qc_op = QUOTACTL_CURSORGET;
30959b296daSdholland 	args.u.cursorget.qc_cursor = &cursor->kcursor;
31059b296daSdholland 	args.u.cursorget.qc_keys = keys;
31159b296daSdholland 	args.u.cursorget.qc_vals = vals;
31259b296daSdholland 	args.u.cursorget.qc_maxnum = maxnum;
31359b296daSdholland 	args.u.cursorget.qc_ret = &ret;
31431f4a06fSdholland 	if (__quotactl(qh->qh_mountpoint, &args) < 0) {
31531f4a06fSdholland 		return -1;
31631f4a06fSdholland 	}
31731f4a06fSdholland 	return ret;
31859b296daSdholland }
31959b296daSdholland 
32059b296daSdholland int
__quota_kernel_cursor_atend(struct quotahandle * qh,struct kernel_quotacursor * cursor)32159b296daSdholland __quota_kernel_cursor_atend(struct quotahandle *qh,
32259b296daSdholland 			    struct kernel_quotacursor *cursor)
32359b296daSdholland {
32459b296daSdholland 	struct quotactl_args args;
32559b296daSdholland 	int ret;
32659b296daSdholland 
32759b296daSdholland 	args.qc_op = QUOTACTL_CURSORATEND;
32859b296daSdholland 	args.u.cursoratend.qc_cursor = &cursor->kcursor;
32959b296daSdholland 	args.u.cursoratend.qc_ret = &ret;
33059b296daSdholland 	if (__quotactl(qh->qh_mountpoint, &args)) {
33159b296daSdholland 		/*
33259b296daSdholland 		 * Return -1 so naive callers, who test for the return
33359b296daSdholland 		 * value being nonzero, stop iterating, and
33459b296daSdholland 		 * sophisticated callers can tell an error from
33559b296daSdholland 		 * end-of-data.
33659b296daSdholland 		 */
33759b296daSdholland 		return -1;
33859b296daSdholland 	}
33959b296daSdholland 	return ret;
34059b296daSdholland }
34159b296daSdholland 
34259b296daSdholland int
__quota_kernel_cursor_rewind(struct quotahandle * qh,struct kernel_quotacursor * cursor)34359b296daSdholland __quota_kernel_cursor_rewind(struct quotahandle *qh,
34459b296daSdholland 			     struct kernel_quotacursor *cursor)
34559b296daSdholland {
34659b296daSdholland 	struct quotactl_args args;
34759b296daSdholland 
34859b296daSdholland 	args.qc_op = QUOTACTL_CURSORREWIND;
34959b296daSdholland 	args.u.cursorrewind.qc_cursor = &cursor->kcursor;
35059b296daSdholland 	return __quotactl(qh->qh_mountpoint, &args);
35159b296daSdholland }
352