2 * by Manuel Bouyer (bouyer@ensta.fr)
4 * There is no copyright, you can use it as you want.
10 #include <sys/param.h>
11 #include <sys/mount.h>
14 #include <sys/socket.h>
16 #include <ufs/ufs/quota.h>
18 #include <rpcsvc/rquota.h>
19 #include <arpa/inet.h>
36 static void rquota_service_1(struct svc_req *request, SVCXPRT *transp);
37 static void rquota_service_2(struct svc_req *request, SVCXPRT *transp);
38 static void sendquota(struct svc_req *request, SVCXPRT *transp);
39 static void sendquota_extended(struct svc_req *request, SVCXPRT *transp);
40 static int getfsquota(int type, long id, char *path, struct dqblk *dqblk);
42 static int from_inetd = 1;
50 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
55 main(int argc, char **argv)
59 struct sockaddr_storage from;
64 while ((ch = getopt(argc, argv, "d")) != -1) {
74 fromlen = sizeof(from);
75 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
81 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
82 (void)signal(SIGINT, cleanup);
83 (void)signal(SIGTERM, cleanup);
84 (void)signal(SIGHUP, cleanup);
87 openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON);
89 /* create and register the service */
91 transp = svc_tli_create(0, NULL, NULL, 0, 0);
93 syslog(LOG_ERR, "couldn't create udp service.");
97 ok = svc_reg(transp, RQUOTAPROG, RQUOTAVERS,
98 rquota_service_1, NULL);
100 vers = EXT_RQUOTAVERS;
101 ok = svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
102 rquota_service_2, NULL);
106 ok = svc_create(rquota_service_1,
107 RQUOTAPROG, RQUOTAVERS, "udp");
109 vers = EXT_RQUOTAVERS;
110 ok = svc_create(rquota_service_2,
111 RQUOTAPROG, EXT_RQUOTAVERS, "udp");
117 "unable to register (RQUOTAPROG, %s, %s)",
118 vers == RQUOTAVERS ? "RQUOTAVERS" : "EXT_RQUOTAVERS",
119 from_inetd ? "(inetd)" : "udp");
124 syslog(LOG_ERR, "svc_run returned");
129 rquota_service_2(struct svc_req *request, SVCXPRT *transp)
132 switch (request->rq_proc) {
134 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
136 case RQUOTAPROC_GETQUOTA:
137 case RQUOTAPROC_GETACTIVEQUOTA:
138 sendquota_extended(request, transp);
141 svcerr_noproc(transp);
149 rquota_service_1(struct svc_req *request, SVCXPRT *transp)
152 switch (request->rq_proc) {
154 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
156 case RQUOTAPROC_GETQUOTA:
157 case RQUOTAPROC_GETACTIVEQUOTA:
158 sendquota(request, transp);
161 svcerr_noproc(transp);
168 /* read quota for the specified id, and send it */
170 sendquota(struct svc_req *request, SVCXPRT *transp)
172 struct getquota_args getq_args;
173 struct getquota_rslt getq_rslt;
175 struct timeval timev;
178 bzero(&getq_args, sizeof(getq_args));
179 if (!svc_getargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
180 svcerr_decode(transp);
183 if (request->rq_cred.oa_flavor != AUTH_UNIX) {
185 getq_rslt.status = Q_EPERM;
186 } else if (!getfsquota(USRQUOTA, getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
187 /* failed, return noquota */
188 getq_rslt.status = Q_NOQUOTA;
190 gettimeofday(&timev, NULL);
191 getq_rslt.status = Q_OK;
192 getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
193 scale = 1 << flsll(dqblk.dqb_bhardlimit >> 32);
194 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize =
196 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
197 dqblk.dqb_bhardlimit / scale;
198 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
199 dqblk.dqb_bsoftlimit / scale;
200 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
201 dqblk.dqb_curblocks / scale;
202 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
203 dqblk.dqb_ihardlimit;
204 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
205 dqblk.dqb_isoftlimit;
206 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
208 getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
209 dqblk.dqb_btime - timev.tv_sec;
210 getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
211 dqblk.dqb_itime - timev.tv_sec;
213 if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt))
214 svcerr_systemerr(transp);
215 if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
216 syslog(LOG_ERR, "unable to free arguments");
222 sendquota_extended(struct svc_req *request, SVCXPRT *transp)
224 struct ext_getquota_args getq_args;
225 struct getquota_rslt getq_rslt;
227 struct timeval timev;
230 bzero(&getq_args, sizeof(getq_args));
231 if (!svc_getargs(transp, (xdrproc_t)xdr_ext_getquota_args, &getq_args)) {
232 svcerr_decode(transp);
235 if (request->rq_cred.oa_flavor != AUTH_UNIX) {
237 getq_rslt.status = Q_EPERM;
238 } else if (!getfsquota(getq_args.gqa_type, getq_args.gqa_id, getq_args.gqa_pathp, &dqblk)) {
239 /* failed, return noquota */
240 getq_rslt.status = Q_NOQUOTA;
242 gettimeofday(&timev, NULL);
243 getq_rslt.status = Q_OK;
244 getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
245 scale = 1 << flsll(dqblk.dqb_bhardlimit >> 32);
246 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize =
248 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
249 dqblk.dqb_bhardlimit / scale;
250 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
251 dqblk.dqb_bsoftlimit / scale;
252 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
253 dqblk.dqb_curblocks / scale;
254 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
255 dqblk.dqb_ihardlimit;
256 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
257 dqblk.dqb_isoftlimit;
258 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
260 getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
261 dqblk.dqb_btime - timev.tv_sec;
262 getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
263 dqblk.dqb_itime - timev.tv_sec;
265 if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt))
266 svcerr_systemerr(transp);
267 if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
268 syslog(LOG_ERR, "unable to free arguments");
274 * gets the quotas for id, filesystem path.
275 * Return 0 if fail, 1 otherwise
278 getfsquota(int type, long id, char *path, struct dqblk *dqblk)
280 struct quotafile *qf;
282 * Remote quota checking is limited to mounted filesystems.
283 * Since UFS and ZFS support the quota system calls, we
284 * only need to make an fstab object that has the path, and
285 * a blank name for the filesystem type.
286 * This allows the quota_open() call to work the way we
289 * The static char declaration is because compiler warnings
290 * don't allow passing a const char * to a char *.
293 static char blank[] = "";
297 fst.fs_mntops = blank;
298 fst.fs_vfstype = blank;
300 if (type != USRQUOTA && type != GRPQUOTA)
303 qf = quota_open(&fst, type, O_RDONLY);
305 warnx("quota_open(<%s, %s>, %d) returned %p",
306 fst.fs_file, fst.fs_mntops, type,
311 rv = quota_read(qf, dqblk, id) == 0;
314 warnx("getfsquota(%d, %ld, %s, %p) -> %d",
315 type, id, path, dqblk, rv);