]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/nfsquota.c
Merge master
[netatalk.git] / etc / afpd / nfsquota.c
1 /*
2  * $Id: nfsquota.c,v 1.13 2009-10-13 22:55:37 didg Exp $
3  *
4  * parts of this are lifted from the bsd quota program and are
5  * therefore under the following copyright:
6  *
7  * Copyright (c) 1980, 1990, 1993
8  *      The Regents of the University of California.  All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Robert Elz at The University of Melbourne.
12  *
13  * Ported for AIX (jfs) by Joerg Schumacher (J.Schumacher@tu-bs.de) at the
14  * Technische Universitaet Braunschweig, FRG
15  */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif /* HAVE_CONFIG_H */
20
21 #if !defined(NO_QUOTA_SUPPORT) && !defined(HAVE_LIBQUOTA)
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/param.h> /* for DEV_BSIZE */
27 #include <sys/time.h>  /* <rpc/rpc.h> on ultrix doesn't include this */
28 #ifdef HAVE_NETDB_H
29 #include <netdb.h>
30 #endif /* HAVE_NETDB_H */
31 #include <netinet/in.h>
32 #ifndef PORTMAP
33 #define PORTMAP 1
34 #endif
35 #include <rpc/rpc.h>
36 #include <rpc/pmap_prot.h>
37 #include <rpcsvc/rquota.h>
38
39
40 #include <atalk/afp.h>
41 #include <atalk/logger.h>
42
43 #include "unix.h"
44
45 /* lifted (with modifications) from the bsd quota program */
46 static int
47 callaurpc(struct vol *vol,
48     u_long prognum, u_long versnum, u_long procnum,
49     xdrproc_t inproc, char *in, 
50     xdrproc_t outproc, char *out)
51 {
52     enum clnt_stat clnt_stat;
53     struct timeval tottimeout;
54
55     if (!vol->v_nfsclient) {
56         struct hostent *hp;
57         struct sockaddr_in server_addr;
58         struct timeval timeout;
59         int socket = RPC_ANYSOCK;
60
61         if ((hp = gethostbyname(vol->v_gvs)) == NULL)
62             return ((int) RPC_UNKNOWNHOST);
63         timeout.tv_usec = 0;
64         timeout.tv_sec = 6;
65         memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
66         server_addr.sin_family = AF_INET;
67         server_addr.sin_port =  0;
68
69         if ((vol->v_nfsclient = (void *)
70                                 clntudp_create(&server_addr, prognum, versnum,
71                                                timeout, &socket)) == NULL)
72             return ((int) rpc_createerr.cf_stat);
73
74         ((CLIENT *) vol->v_nfsclient)->cl_auth = authunix_create_default();
75     }
76
77     tottimeout.tv_sec = 10;
78     tottimeout.tv_usec = 0;
79     clnt_stat = clnt_call((CLIENT *) vol->v_nfsclient, procnum,
80                           inproc, in, outproc, out, tottimeout);
81     return ((int) clnt_stat);
82 }
83
84
85 /* sunos 4 machines structure things a little differently. */
86 #ifdef USE_OLD_RQUOTA
87 #define GQR_STATUS gqr_status
88 #define GQR_RQUOTA gqr_rquota
89 #else /* USE_OLD_RQUOTA */
90 #define GQR_STATUS status
91 #define GQR_RQUOTA getquota_rslt_u.gqr_rquota
92 #endif /* USE_OLD_RQUOTA */
93
94 int getnfsquota(struct vol *vol, const int uid, const uint32_t bsize,
95                 struct dqblk *dqp)
96 {
97
98     struct getquota_args gq_args;
99     struct getquota_rslt gq_rslt;
100     struct timeval tv;
101     char *hostpath;
102
103     /* figure out the host and path */
104     if ((hostpath = strchr(vol->v_gvs, ':')) == NULL) {
105         LOG(log_error, logtype_afpd, "can't find hostname for %s", vol->v_gvs);
106         return AFPERR_PARAM;
107     }
108
109     if (*(hostpath + 1) != '/')
110         return AFPERR_PARAM;
111
112     /* separate host from hostpath */
113     *hostpath = '\0';
114
115     gq_args.gqa_pathp = hostpath + 1;
116     gq_args.gqa_uid = uid;
117
118     if(callaurpc(vol, RQUOTAPROG, RQUOTAVERS, RQUOTAPROC_GETQUOTA,
119                  (xdrproc_t) xdr_getquota_args, (char *) &gq_args,
120                  (xdrproc_t) xdr_getquota_rslt, (char *) &gq_rslt) != 0) {
121         LOG(log_info, logtype_afpd, "nfsquota: can't retrieve nfs quota information. \
122             make sure that rpc.rquotad is running on %s.", vol->v_gvs);
123         *hostpath = ':';
124         return AFPERR_PARAM;
125     }
126
127     switch (gq_rslt.GQR_STATUS) {
128     case Q_NOQUOTA:
129         break;
130
131     case Q_EPERM:
132         LOG(log_error, logtype_afpd, "nfsquota: quota permission error, host: %s",
133             vol->v_gvs);
134         break;
135
136     case Q_OK: /* we only copy the bits that we need. */
137         gettimeofday(&tv, NULL);
138
139 #if defined(__svr4__) || defined(TRU64)
140         /* why doesn't using bsize work? */
141 #define NFS_BSIZE gq_rslt.GQR_RQUOTA.rq_bsize / DEV_BSIZE
142 #else /* __svr4__ || TRU64 */
143         /* NOTE: linux' rquotad program doesn't currently report the
144         * correct rq_bsize. */
145         /* NOTE: This is integer division and can introduce rounding errors */
146 #define NFS_BSIZE gq_rslt.GQR_RQUOTA.rq_bsize / bsize
147 #endif /* __svr4__  || TRU64 */
148
149         dqp->dqb_bhardlimit =
150             gq_rslt.GQR_RQUOTA.rq_bhardlimit*NFS_BSIZE;
151         dqp->dqb_bsoftlimit =
152             gq_rslt.GQR_RQUOTA.rq_bsoftlimit*NFS_BSIZE;
153         dqp->dqb_curblocks =
154             gq_rslt.GQR_RQUOTA.rq_curblocks*NFS_BSIZE;
155
156 #ifdef ultrix
157         dqp->dqb_bwarn = gq_rslt.GQR_RQUOTA.rq_btimeleft;
158 #else /* ultrix */
159         dqp->dqb_btimelimit =
160             tv.tv_sec + gq_rslt.GQR_RQUOTA.rq_btimeleft;
161 #endif /* ultrix */
162
163         *hostpath = ':';
164         return AFP_OK;
165         break;
166
167     default:
168         LOG(log_info, logtype_afpd, "bad rpc result, host: %s", vol->v_gvs);
169         break;
170     }
171
172     *hostpath = ':';
173     return AFPERR_PARAM;
174 }
175 #endif /* ! NO_QUOTA_SUPPORT && !HAVE_LIBQUOTA */