version 1.4, 2011/11/25 16:55:05 |
version 1.5, 2012/01/09 15:31:11 |
Line 46 __RCSID("$NetBSD$"); |
|
Line 46 __RCSID("$NetBSD$"); |
|
#endif |
#endif |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
/* |
|
* Disk quota reporting program. |
|
*/ |
|
#include <sys/param.h> |
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <sys/mount.h> |
|
|
#include <ctype.h> |
|
#include <err.h> |
|
#include <errno.h> |
|
#include <netdb.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <time.h> |
#include <errno.h> |
#include <unistd.h> |
|
|
|
|
#include <quota.h> |
#include <quota/quota.h> |
#include <quota/quota.h> |
#include <quota/quotaprop.h> |
|
|
|
#include <rpc/rpc.h> |
#include "quotapvt.h" |
#include <rpc/pmap_prot.h> |
|
#include <rpcsvc/rquota.h> |
|
|
|
/* convert a rquota limit to our semantic */ |
|
static uint64_t |
|
rqlim2qlim(uint32_t lim) |
|
{ |
|
if (lim == 0) |
|
return UQUAD_MAX; |
|
else |
|
return (lim - 1); |
|
} |
|
|
|
static int |
|
callaurpc(const char *host, rpcprog_t prognum, rpcvers_t versnum, |
|
rpcproc_t procnum, xdrproc_t inproc, void *in, xdrproc_t outproc, void *out) |
|
{ |
|
struct sockaddr_in server_addr; |
|
enum clnt_stat clnt_stat; |
|
struct hostent *hp; |
|
struct timeval timeout, tottimeout; |
|
|
|
CLIENT *client = NULL; |
|
int sock = RPC_ANYSOCK; |
|
|
|
if ((hp = gethostbyname(host)) == NULL) |
|
return (int) RPC_UNKNOWNHOST; |
|
timeout.tv_usec = 0; |
|
timeout.tv_sec = 6; |
|
memmove(&server_addr.sin_addr, hp->h_addr, hp->h_length); |
|
server_addr.sin_family = AF_INET; |
|
server_addr.sin_port = 0; |
|
|
|
if ((client = clntudp_create(&server_addr, prognum, |
|
versnum, timeout, &sock)) == NULL) |
|
return (int) rpc_createerr.cf_stat; |
|
|
|
client->cl_auth = authunix_create_default(); |
|
tottimeout.tv_sec = 25; |
|
tottimeout.tv_usec = 0; |
|
clnt_stat = clnt_call(client, procnum, inproc, in, |
|
outproc, out, tottimeout); |
|
|
|
return (int) clnt_stat; |
|
} |
|
|
|
int |
int |
getnfsquota(const char *mp, struct quotaval *qv, |
getnfsquota(const char *mp, struct quotaval *qv, |
uint32_t id, const char *class) |
uint32_t id, const char *class) |
{ |
{ |
struct getquota_args gq_args; |
struct statvfs *mounts; |
struct ext_getquota_args ext_gq_args; |
size_t size; |
struct getquota_rslt gq_rslt; |
int nummounts, i, ret; |
struct timeval tv; |
int serrno; |
char *host, *path; |
|
int ret, rpcqtype; |
|
|
|
if (strcmp(class, QUOTADICT_CLASS_USER) == 0) |
|
rpcqtype = RQUOTA_USRQUOTA; |
|
else if (strcmp(class, QUOTADICT_CLASS_GROUP) == 0) |
|
rpcqtype = RQUOTA_GRPQUOTA; |
|
else { |
|
errno = EINVAL; |
|
return -1; |
|
} |
|
|
|
/* |
/* |
* must be some form of "hostname:/path" |
* For some reason getnfsquota was defined so that the mount |
|
* information passed in is the f_mntfromname (containing the |
|
* remote host and path) from statvfs. The only way to convert |
|
* this back to something generally useful is to search the |
|
* available mounts for something that matches. Sigh. |
|
* |
|
* Note that we can't use getmntinfo(3) as the caller probably |
|
* is and another use would potentially interfere. |
*/ |
*/ |
path = strdup(mp); |
|
if (path == NULL) { |
nummounts = getvfsstat(NULL, (size_t)0, MNT_NOWAIT); |
errno = ENOMEM; |
if (nummounts < 0) { |
return -1; |
return -1; |
} |
} |
host = strsep(&path, ":"); |
if (nummounts == 0) { |
if (path == NULL) { |
errno = ENOENT; |
free(host); |
|
errno = EINVAL; |
|
return -1; |
return -1; |
} |
} |
|
size = nummounts * sizeof(mounts[0]); |
ext_gq_args.gqa_pathp = path; |
mounts = malloc(size); |
ext_gq_args.gqa_id = id; |
if (mounts == NULL) { |
ext_gq_args.gqa_type = rpcqtype; |
return -1; |
ret = callaurpc(host, RQUOTAPROG, EXT_RQUOTAVERS, |
} |
RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_ext_getquota_args, |
nummounts = getvfsstat(mounts, size, MNT_NOWAIT); |
&ext_gq_args, (xdrproc_t)xdr_getquota_rslt, &gq_rslt); |
if (nummounts < 0) { |
if (ret == RPC_PROGVERSMISMATCH && rpcqtype == RQUOTA_USRQUOTA) { |
serrno = errno; |
/* try RQUOTAVERS */ |
free(mounts); |
gq_args.gqa_pathp = path; |
errno = serrno; |
gq_args.gqa_uid = id; |
|
ret = callaurpc(host, RQUOTAPROG, RQUOTAVERS, |
|
RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, |
|
&gq_args, (xdrproc_t)xdr_getquota_rslt, &gq_rslt); |
|
} |
|
free(host); |
|
|
|
if (ret != RPC_SUCCESS) { |
|
return 0; |
|
} |
|
|
|
switch (gq_rslt.status) { |
|
case Q_NOQUOTA: |
|
break; |
|
case Q_EPERM: |
|
errno = EACCES; |
|
return -1; |
return -1; |
case Q_OK: |
} |
gettimeofday(&tv, NULL); |
|
|
|
/* blocks*/ |
/* |
qv[QUOTA_LIMIT_BLOCK].qv_hardlimit = rqlim2qlim( |
* Note: if the size goes up, someone added a new mount; it |
gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit * |
* can't be the one we're looking for. Assume it will end up |
(gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE)); |
* at the end of the list so we don't need to refetch the |
qv[QUOTA_LIMIT_BLOCK].qv_softlimit = rqlim2qlim( |
* info, and reset nummounts to avoid chugging off the end |
gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit * |
* of the array. |
(gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE)); |
*/ |
qv[QUOTA_LIMIT_BLOCK].qv_usage = |
if (nummounts * sizeof(mounts[0]) > size) { |
gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks * |
nummounts = size / sizeof(mounts[0]); |
(gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize / DEV_BSIZE); |
|
qv[QUOTA_LIMIT_BLOCK].qv_expiretime = (tv.tv_sec + |
|
gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft); |
|
|
|
/* inodes */ |
|
qv[QUOTA_LIMIT_FILE].qv_hardlimit = rqlim2qlim( |
|
gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit); |
|
qv[QUOTA_LIMIT_FILE].qv_softlimit = rqlim2qlim( |
|
gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit); |
|
qv[QUOTA_LIMIT_FILE].qv_usage = |
|
gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles; |
|
qv[QUOTA_LIMIT_FILE].qv_expiretime = (int)(tv.tv_sec + |
|
gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft); |
|
|
|
qv[QUOTA_LIMIT_BLOCK].qv_grace = |
|
qv[QUOTA_LIMIT_FILE].qv_grace = 0; |
|
return 1; |
|
default: |
|
/* XXX sert errno and return -1 ? */ |
|
break; |
|
} |
} |
return 0; |
|
|
for (i=0; i<nummounts; i++) { |
|
if (!strcmp(mounts[i].f_mntfromname, mp)) { |
|
ret = __quota_getquota(mounts[i].f_mntonname, |
|
qv, id, class); |
|
serrno = errno; |
|
free(mounts); |
|
errno = serrno; |
|
return ret; |
|
} |
|
} |
|
free(mounts); |
|
errno = ENOENT; |
|
return -1; |
} |
} |