quota_nfs.c revision 1.1 1 1.1 dholland /* $NetBSD: quota_nfs.c,v 1.1 2012/01/09 15:29:56 dholland Exp $ */
2 1.1 dholland /*-
3 1.1 dholland * Copyright (c) 2011 Manuel Bouyer
4 1.1 dholland * All rights reserved.
5 1.1 dholland *
6 1.1 dholland * Redistribution and use in source and binary forms, with or without
7 1.1 dholland * modification, are permitted provided that the following conditions
8 1.1 dholland * are met:
9 1.1 dholland * 1. Redistributions of source code must retain the above copyright
10 1.1 dholland * notice, this list of conditions and the following disclaimer.
11 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 dholland * notice, this list of conditions and the following disclaimer in the
13 1.1 dholland * documentation and/or other materials provided with the distribution.
14 1.1 dholland *
15 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 1.1 dholland * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 1.1 dholland * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 1.1 dholland * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 1.1 dholland * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 1.1 dholland * POSSIBILITY OF SUCH DAMAGE.
26 1.1 dholland */
27 1.1 dholland
28 1.1 dholland #include <sys/cdefs.h>
29 1.1 dholland __RCSID("$NetBSD: quota_nfs.c,v 1.1 2012/01/09 15:29:56 dholland Exp $");
30 1.1 dholland
31 1.1 dholland #include <sys/types.h>
32 1.1 dholland #include <sys/param.h> /* XXX for DEV_BSIZE */
33 1.1 dholland #include <stdlib.h>
34 1.1 dholland #include <string.h>
35 1.1 dholland #include <limits.h>
36 1.1 dholland #include <netdb.h>
37 1.1 dholland #include <errno.h>
38 1.1 dholland
39 1.1 dholland #include <rpc/rpc.h>
40 1.1 dholland #include <rpc/pmap_prot.h>
41 1.1 dholland #include <rpcsvc/rquota.h>
42 1.1 dholland
43 1.1 dholland #include <quota.h>
44 1.1 dholland #include "quotapvt.h"
45 1.1 dholland
46 1.1 dholland static uint64_t
47 1.1 dholland rq_scale(uint32_t rqblocks, uint32_t rqsize)
48 1.1 dholland {
49 1.1 dholland return ((uint64_t)rqblocks * rqsize) / DEV_BSIZE;
50 1.1 dholland }
51 1.1 dholland
52 1.1 dholland static uint64_t
53 1.1 dholland rq_scalelimit(uint32_t rqval, uint32_t rqsize)
54 1.1 dholland {
55 1.1 dholland if (rqval == 0) {
56 1.1 dholland return QUOTA_NOLIMIT;
57 1.1 dholland } else {
58 1.1 dholland return rq_scale(rqval - 1, rqsize);
59 1.1 dholland }
60 1.1 dholland }
61 1.1 dholland
62 1.1 dholland static uint64_t
63 1.1 dholland rq_plainlimit(uint32_t rqval)
64 1.1 dholland {
65 1.1 dholland if (rqval == 0) {
66 1.1 dholland return QUOTA_NOLIMIT;
67 1.1 dholland } else {
68 1.1 dholland return rqval - 1;
69 1.1 dholland }
70 1.1 dholland }
71 1.1 dholland
72 1.1 dholland static void
73 1.1 dholland rquota_to_quotavals(const struct rquota *rq,
74 1.1 dholland struct quotaval *blocks, struct quotaval *files)
75 1.1 dholland {
76 1.1 dholland struct timeval now;
77 1.1 dholland
78 1.1 dholland gettimeofday(&now, NULL);
79 1.1 dholland
80 1.1 dholland /* blocks*/
81 1.1 dholland blocks->qv_hardlimit = rq_scalelimit(rq->rq_bhardlimit, rq->rq_bsize);
82 1.1 dholland blocks->qv_softlimit = rq_scalelimit(rq->rq_bsoftlimit, rq->rq_bsize);
83 1.1 dholland blocks->qv_usage = rq_scale(rq->rq_curblocks, rq->rq_bsize);
84 1.1 dholland blocks->qv_expiretime = rq->rq_btimeleft + now.tv_sec;
85 1.1 dholland blocks->qv_grace = QUOTA_NOTIME;
86 1.1 dholland
87 1.1 dholland /* inodes */
88 1.1 dholland files->qv_hardlimit = rq_plainlimit(rq->rq_fhardlimit);
89 1.1 dholland files->qv_softlimit = rq_plainlimit(rq->rq_fsoftlimit);
90 1.1 dholland files->qv_usage = rq->rq_curfiles;
91 1.1 dholland files->qv_expiretime = rq->rq_ftimeleft + now.tv_sec;
92 1.1 dholland files->qv_grace = QUOTA_NOTIME;
93 1.1 dholland }
94 1.1 dholland
95 1.1 dholland static int
96 1.1 dholland callaurpc(const char *host, rpcprog_t prognum, rpcvers_t versnum,
97 1.1 dholland rpcproc_t procnum, xdrproc_t inproc, void *in, xdrproc_t outproc, void *out)
98 1.1 dholland {
99 1.1 dholland struct sockaddr_in server_addr;
100 1.1 dholland enum clnt_stat clnt_stat;
101 1.1 dholland struct hostent *hp;
102 1.1 dholland struct timeval timeout, tottimeout;
103 1.1 dholland
104 1.1 dholland CLIENT *client = NULL;
105 1.1 dholland int sock = RPC_ANYSOCK;
106 1.1 dholland
107 1.1 dholland if ((hp = gethostbyname(host)) == NULL)
108 1.1 dholland return (int) RPC_UNKNOWNHOST;
109 1.1 dholland timeout.tv_usec = 0;
110 1.1 dholland timeout.tv_sec = 6;
111 1.1 dholland memmove(&server_addr.sin_addr, hp->h_addr, hp->h_length);
112 1.1 dholland server_addr.sin_family = AF_INET;
113 1.1 dholland server_addr.sin_port = 0;
114 1.1 dholland
115 1.1 dholland if ((client = clntudp_create(&server_addr, prognum,
116 1.1 dholland versnum, timeout, &sock)) == NULL)
117 1.1 dholland return (int) rpc_createerr.cf_stat;
118 1.1 dholland
119 1.1 dholland client->cl_auth = authunix_create_default();
120 1.1 dholland tottimeout.tv_sec = 25;
121 1.1 dholland tottimeout.tv_usec = 0;
122 1.1 dholland clnt_stat = clnt_call(client, procnum, inproc, in,
123 1.1 dholland outproc, out, tottimeout);
124 1.1 dholland
125 1.1 dholland return (int) clnt_stat;
126 1.1 dholland }
127 1.1 dholland
128 1.1 dholland int
129 1.1 dholland __quota_nfs_get(struct quotahandle *qh, const struct quotakey *qk,
130 1.1 dholland struct quotaval *qv)
131 1.1 dholland {
132 1.1 dholland struct getquota_args gq_args;
133 1.1 dholland struct ext_getquota_args ext_gq_args;
134 1.1 dholland struct getquota_rslt gq_rslt;
135 1.1 dholland struct quotaval blocks, inodes;
136 1.1 dholland char *host, *path;
137 1.1 dholland int ret, rpcqtype;
138 1.1 dholland int sverrno;
139 1.1 dholland
140 1.1 dholland switch (qk->qk_idtype) {
141 1.1 dholland case QUOTA_IDTYPE_USER:
142 1.1 dholland rpcqtype = RQUOTA_USRQUOTA;
143 1.1 dholland break;
144 1.1 dholland case QUOTA_IDTYPE_GROUP:
145 1.1 dholland rpcqtype = RQUOTA_GRPQUOTA;
146 1.1 dholland break;
147 1.1 dholland default:
148 1.1 dholland errno = EINVAL;
149 1.1 dholland return -1;
150 1.1 dholland }
151 1.1 dholland
152 1.1 dholland switch (qk->qk_objtype) {
153 1.1 dholland case QUOTA_OBJTYPE_BLOCKS:
154 1.1 dholland case QUOTA_OBJTYPE_FILES:
155 1.1 dholland break;
156 1.1 dholland default:
157 1.1 dholland errno = EINVAL;
158 1.1 dholland return -1;
159 1.1 dholland }
160 1.1 dholland
161 1.1 dholland /*
162 1.1 dholland * must be some form of "hostname:/path"
163 1.1 dholland */
164 1.1 dholland path = strdup(qh->qh_mountdevice);
165 1.1 dholland if (path == NULL) {
166 1.1 dholland errno = ENOMEM;
167 1.1 dholland return -1;
168 1.1 dholland }
169 1.1 dholland host = strsep(&path, ":");
170 1.1 dholland if (path == NULL) {
171 1.1 dholland free(host);
172 1.1 dholland errno = EINVAL;
173 1.1 dholland return -1;
174 1.1 dholland }
175 1.1 dholland
176 1.1 dholland ext_gq_args.gqa_pathp = path;
177 1.1 dholland ext_gq_args.gqa_id = qk->qk_id;
178 1.1 dholland ext_gq_args.gqa_type = rpcqtype;
179 1.1 dholland ret = callaurpc(host, RQUOTAPROG, EXT_RQUOTAVERS,
180 1.1 dholland RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_ext_getquota_args,
181 1.1 dholland &ext_gq_args, (xdrproc_t)xdr_getquota_rslt, &gq_rslt);
182 1.1 dholland if (ret == RPC_PROGVERSMISMATCH && rpcqtype == RQUOTA_USRQUOTA) {
183 1.1 dholland /* try RQUOTAVERS */
184 1.1 dholland gq_args.gqa_pathp = path;
185 1.1 dholland gq_args.gqa_uid = qk->qk_id;
186 1.1 dholland ret = callaurpc(host, RQUOTAPROG, RQUOTAVERS,
187 1.1 dholland RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args,
188 1.1 dholland &gq_args, (xdrproc_t)xdr_getquota_rslt, &gq_rslt);
189 1.1 dholland }
190 1.1 dholland sverrno = errno;
191 1.1 dholland free(host);
192 1.1 dholland
193 1.1 dholland if (ret != RPC_SUCCESS) {
194 1.1 dholland errno = sverrno;
195 1.1 dholland return -1;
196 1.1 dholland }
197 1.1 dholland
198 1.1 dholland switch (gq_rslt.status) {
199 1.1 dholland case Q_NOQUOTA:
200 1.1 dholland quotaval_clear(qv);
201 1.1 dholland return 0;
202 1.1 dholland break;
203 1.1 dholland case Q_EPERM:
204 1.1 dholland errno = EACCES;
205 1.1 dholland return -1;
206 1.1 dholland case Q_OK:
207 1.1 dholland rquota_to_quotavals(&gq_rslt.getquota_rslt_u.gqr_rquota,
208 1.1 dholland &blocks, &inodes);
209 1.1 dholland if (qk->qk_objtype == QUOTA_OBJTYPE_BLOCKS) {
210 1.1 dholland *qv = blocks;
211 1.1 dholland } else {
212 1.1 dholland *qv = inodes;
213 1.1 dholland }
214 1.1 dholland return 0;
215 1.1 dholland default:
216 1.1 dholland break;
217 1.1 dholland }
218 1.1 dholland /* XXX not exactly a good errno */
219 1.1 dholland errno = ERANGE;
220 1.1 dholland return -1;
221 1.1 dholland }
222 1.1 dholland
223