Home | History | Annotate | Line # | Download | only in kern
vfs_quotactl.c revision 1.7
      1 /*	$NetBSD: vfs_quotactl.c,v 1.7 2012/01/29 06:37:30 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1991, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  * (c) UNIX System Laboratories, Inc.
      7  * All or some portions of this file are derived from material licensed
      8  * to the University of California by American Telephone and Telegraph
      9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     10  * the permission of UNIX System Laboratories, Inc.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  *	@(#)ufs_vfsops.c	8.8 (Berkeley) 5/20/95
     37  *	From NetBSD: ufs_vfsops.c,v 1.42 2011/03/24 17:05:46 bouyer Exp
     38  */
     39 
     40 /*
     41  * Copyright (c) 1982, 1986, 1990, 1993, 1995
     42  *	The Regents of the University of California.  All rights reserved.
     43  *
     44  * This code is derived from software contributed to Berkeley by
     45  * Robert Elz at The University of Melbourne.
     46  *
     47  * Redistribution and use in source and binary forms, with or without
     48  * modification, are permitted provided that the following conditions
     49  * are met:
     50  * 1. Redistributions of source code must retain the above copyright
     51  *    notice, this list of conditions and the following disclaimer.
     52  * 2. Redistributions in binary form must reproduce the above copyright
     53  *    notice, this list of conditions and the following disclaimer in the
     54  *    documentation and/or other materials provided with the distribution.
     55  * 3. Neither the name of the University nor the names of its contributors
     56  *    may be used to endorse or promote products derived from this software
     57  *    without specific prior written permission.
     58  *
     59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     69  * SUCH DAMAGE.
     70  *
     71  *	@(#)ufs_quota.c	8.5 (Berkeley) 5/20/95
     72  *	From NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer Exp
     73  */
     74 
     75 /*
     76  * Note that both of the copyrights above are moderately spurious;
     77  * this code should almost certainly have the Copyright 2010 Manuel
     78  * Bouyer notice and license found in e.g. sys/ufs/ufs/quota2_subr.c.
     79  * However, they're what was on the files this code was sliced out of.
     80  */
     81 
     82 #include <sys/cdefs.h>
     83 __KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.7 2012/01/29 06:37:30 dholland Exp $");
     84 
     85 #include <sys/mount.h>
     86 #include <sys/quotactl.h>
     87 #include <quota/quotaprop.h>
     88 
     89 static int
     90 vfs_quotactl_getversion(struct mount *mp,
     91 			prop_dictionary_t cmddict, int q2type,
     92 			prop_array_t datas)
     93 {
     94 	prop_array_t replies;
     95 	prop_dictionary_t data;
     96 	int q2version;
     97 	struct vfs_quotactl_args args;
     98 	int error;
     99 
    100 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    101 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    102 
    103 	args.qc_type = QCT_GETVERSION;
    104 	args.u.getversion.qc_version_ret = &q2version;
    105 	error = VFS_QUOTACTL(mp, QUOTACTL_GETVERSION, &args);
    106 	if (error) {
    107 		return error;
    108 	}
    109 
    110 	data = prop_dictionary_create();
    111 	if (data == NULL) {
    112 		return ENOMEM;
    113 	}
    114 
    115 	if (!prop_dictionary_set_int8(data, "version", q2version)) {
    116 		prop_object_release(data);
    117 		return ENOMEM;
    118 	}
    119 
    120 	replies = prop_array_create();
    121 	if (replies == NULL) {
    122 		prop_object_release(data);
    123 		return ENOMEM;
    124 	}
    125 
    126 	if (!prop_array_add_and_rel(replies, data)) {
    127 		prop_object_release(data);
    128 		prop_object_release(replies);
    129 		return ENOMEM;
    130 	}
    131 
    132 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    133 		prop_object_release(replies);
    134 		return ENOMEM;
    135 	}
    136 
    137 	return error;
    138 }
    139 
    140 static int
    141 vfs_quotactl_quotaon(struct mount *mp,
    142 		     prop_dictionary_t cmddict, int q2type,
    143 		     prop_array_t datas)
    144 {
    145 	struct vfs_quotactl_args args;
    146 
    147 	args.qc_type = QCT_PROPLIB;
    148 	args.u.proplib.qc_cmddict = cmddict;
    149 	args.u.proplib.qc_q2type = q2type;
    150 	args.u.proplib.qc_datas = datas;
    151 	return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args);
    152 }
    153 
    154 static int
    155 vfs_quotactl_quotaoff(struct mount *mp,
    156 			prop_dictionary_t cmddict, int q2type,
    157 			prop_array_t datas)
    158 {
    159 	struct vfs_quotactl_args args;
    160 
    161 	args.qc_type = QCT_PROPLIB;
    162 	args.u.proplib.qc_cmddict = cmddict;
    163 	args.u.proplib.qc_q2type = q2type;
    164 	args.u.proplib.qc_datas = datas;
    165 	return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args);
    166 }
    167 
    168 static int
    169 vfs_quotactl_get(struct mount *mp,
    170 			prop_dictionary_t cmddict, int q2type,
    171 			prop_array_t datas)
    172 {
    173 	prop_object_iterator_t iter;
    174 	prop_dictionary_t data;
    175 	uint32_t id;
    176 	int defaultq;
    177 	const char *idstr;
    178 	prop_array_t replies;
    179 	struct vfs_quotactl_args args;
    180 	int error;
    181 
    182 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    183 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    184 
    185 	replies = prop_array_create();
    186 	if (replies == NULL) {
    187 		return ENOMEM;
    188 	}
    189 
    190 	iter = prop_array_iterator(datas);
    191 	if (iter == NULL) {
    192 		prop_object_release(replies);
    193 		return ENOMEM;
    194 	}
    195 
    196 	while ((data = prop_object_iterator_next(iter)) != NULL) {
    197 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
    198 			if (!prop_dictionary_get_cstring_nocopy(data, "id",
    199 			    &idstr))
    200 				continue;
    201 			if (strcmp(idstr, "default")) {
    202 				error = EINVAL;
    203 				goto fail;
    204 			}
    205 			id = 0;
    206 			defaultq = 1;
    207 		} else {
    208 			defaultq = 0;
    209 		}
    210 
    211 		args.qc_type = QCT_GET;
    212 		args.u.get.qc_q2type = q2type;
    213 		args.u.get.qc_id = id;
    214 		args.u.get.qc_defaultq = defaultq;
    215 		args.u.get.qc_replies = replies;
    216 		error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args);
    217 		if (error == EPERM) {
    218 			/* XXX does this make sense? */
    219 			continue;
    220 		} else if (error == ENOENT) {
    221 			/* XXX does *this* make sense? */
    222 			continue;
    223 		} else if (error) {
    224 			goto fail;
    225 		}
    226 	}
    227 
    228 	prop_object_iterator_release(iter);
    229 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    230 		error = ENOMEM;
    231 	} else {
    232 		error = 0;
    233 	}
    234 
    235 	return error;
    236 
    237  fail:
    238 	prop_object_iterator_release(iter);
    239 	prop_object_release(replies);
    240 	return error;
    241 }
    242 
    243 static int
    244 vfs_quotactl_set(struct mount *mp,
    245 			prop_dictionary_t cmddict, int q2type,
    246 			prop_array_t datas)
    247 {
    248 	struct vfs_quotactl_args args;
    249 
    250 	args.qc_type = QCT_PROPLIB;
    251 	args.u.proplib.qc_cmddict = cmddict;
    252 	args.u.proplib.qc_q2type = q2type;
    253 	args.u.proplib.qc_datas = datas;
    254 	return VFS_QUOTACTL(mp, QUOTACTL_SET, &args);
    255 }
    256 
    257 static int
    258 vfs_quotactl_getall(struct mount *mp,
    259 			prop_dictionary_t cmddict, int q2type,
    260 			prop_array_t datas)
    261 {
    262 	struct vfs_quotactl_args args;
    263 
    264 	args.qc_type = QCT_PROPLIB;
    265 	args.u.proplib.qc_cmddict = cmddict;
    266 	args.u.proplib.qc_q2type = q2type;
    267 	args.u.proplib.qc_datas = datas;
    268 	return VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
    269 }
    270 
    271 static int
    272 vfs_quotactl_clear(struct mount *mp,
    273 			prop_dictionary_t cmddict, int q2type,
    274 			prop_array_t datas)
    275 {
    276 	struct vfs_quotactl_args args;
    277 
    278 	args.qc_type = QCT_PROPLIB;
    279 	args.u.proplib.qc_cmddict = cmddict;
    280 	args.u.proplib.qc_q2type = q2type;
    281 	args.u.proplib.qc_datas = datas;
    282 	return VFS_QUOTACTL(mp, QUOTACTL_CLEAR, &args);
    283 }
    284 
    285 static int
    286 vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict)
    287 {
    288 	int error;
    289 	const char *cmd, *type;
    290 	prop_array_t datas;
    291 	int q2type;
    292 
    293 	if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
    294 		return EINVAL;
    295 	if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
    296 		return EINVAL;
    297 
    298 	if (!strcmp(type, QUOTADICT_CLASS_USER)) {
    299 		q2type = QUOTA_CLASS_USER;
    300 	} else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) {
    301 		q2type = QUOTA_CLASS_GROUP;
    302 	} else {
    303 		/* XXX this is a bad errno for this case */
    304 		return EOPNOTSUPP;
    305 	}
    306 
    307 	datas = prop_dictionary_get(cmddict, "data");
    308 	if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
    309 		return EINVAL;
    310 
    311 	prop_object_retain(datas);
    312 	prop_dictionary_remove(cmddict, "data"); /* prepare for return */
    313 
    314 	if (strcmp(cmd, "get version") == 0) {
    315 		error = vfs_quotactl_getversion(mp, cmddict, q2type, datas);
    316 	} else if (strcmp(cmd, "quotaon") == 0) {
    317 		error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas);
    318 	} else if (strcmp(cmd, "quotaoff") == 0) {
    319 		error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas);
    320 	} else if (strcmp(cmd, "get") == 0) {
    321 		error = vfs_quotactl_get(mp, cmddict, q2type, datas);
    322 	} else if (strcmp(cmd, "set") == 0) {
    323 		error = vfs_quotactl_set(mp, cmddict, q2type, datas);
    324 	} else if (strcmp(cmd, "getall") == 0) {
    325 		error = vfs_quotactl_getall(mp, cmddict, q2type, datas);
    326 	} else if (strcmp(cmd, "clear") == 0) {
    327 		error = vfs_quotactl_clear(mp, cmddict, q2type, datas);
    328 	} else {
    329 		/* XXX this a bad errno for this case */
    330 		error = EOPNOTSUPP;
    331 	}
    332 
    333 	error = (prop_dictionary_set_int8(cmddict, "return",
    334 	    error) ? 0 : ENOMEM);
    335 	prop_object_release(datas);
    336 
    337 	return error;
    338 }
    339 
    340 int
    341 vfs_quotactl(struct mount *mp, prop_dictionary_t dict)
    342 {
    343 	prop_dictionary_t cmddict;
    344 	prop_array_t commands;
    345 	prop_object_iterator_t iter;
    346 	int error;
    347 
    348 	error = quota_get_cmds(dict, &commands);
    349 	if (error) {
    350 		return error;
    351 	}
    352 
    353 	iter = prop_array_iterator(commands);
    354 	if (iter == NULL) {
    355 		return ENOMEM;
    356 	}
    357 
    358 	while ((cmddict = prop_object_iterator_next(iter)) != NULL) {
    359 		if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) {
    360 			/* XXX shouldn't this be an error? */
    361 			continue;
    362 		}
    363 		error = vfs_quotactl_cmd(mp, cmddict);
    364 		if (error) {
    365 			break;
    366 		}
    367 	}
    368 	prop_object_iterator_release(iter);
    369 	return error;
    370 }
    371