2 * QUOTA An implementation of the diskquota system for the LINUX
3 * operating system. QUOTA is implemented using the BSD systemcall
4 * interface as the means of communication with the user level.
5 * Should work for all filesystems because of integration into the
6 * VFS layer of the operating system.
7 * This is based on the Melbourne quota system wich uses both user and
10 * This part does the lookup of the info.
12 * Version: $Id: rquota_server.c,v 2.9 1996/11/17 16:59:46 mvw Exp mvw $
14 * Author: Marco van Wieringen <mvw@planets.elm.net>
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version
19 * 2 of the License, or (at your option) any later version.
30 #include <sys/param.h>
31 /* Unfortunately we cannot trust sys/quota.h to have
32 * what we need, either the old interface could be missing
33 * (SLES9) or the new (SLES8 and others).
34 * So we will just put it explicitly below
37 #include <sys/quota.h>
39 #include <sys/mount.h>
48 #define TYPE_EXTENDED 0x01
51 #ifndef MNTTYPE_AUTOFS
52 #define MNTTYPE_AUTOFS "autofs"
56 #define BLOCK_SIZE 1024
60 #define USRQUOTA 0 /* element used for user quotas */
61 #define GRPQUOTA 1 /* element used for group quotas */
64 u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
65 u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
66 u_int32_t dqb_curblocks; /* current block count */
67 u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */
68 u_int32_t dqb_isoftlimit; /* preferred inode limit */
69 u_int32_t dqb_curinodes; /* current # allocated inodes */
70 time_t dqb_btime; /* time limit for excessive disk use */
71 time_t dqb_itime; /* time limit for excessive files */
75 u_int64_t dqb_bhardlimit;
76 u_int64_t dqb_bsoftlimit;
77 u_int64_t dqb_curspace;
78 u_int64_t dqb_ihardlimit;
79 u_int64_t dqb_isoftlimit;
80 u_int64_t dqb_curinodes;
86 #define SUBCMDMASK 0x00ff
88 #define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
90 #define Q_GETQUOTA 0x0300 /* get limits and usage */
91 #define Q_SETQUOTA 0x0400 /* set limits and usage */
93 #define Q_GETFMT 0x800004 /* get quota format used on given filesystem */
94 #define Q_GETQUOTA_NEW 0x800007 /* get user quota structure */
95 #define Q_SETQUOTA_NEW 0x800008 /* set user quota structure */
96 #define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk)))
98 extern int quotactl (int __cmd, const char *__special, int __id,
99 caddr_t __addr) __THROW;
101 * Global unix authentication credentials.
103 extern struct authunix_parms *unix_cred;
105 int in_group (gid_t *gids, u_int len, gid_t gid)
110 if (gids[cnt] == gid)
117 getquota_rslt *getquotainfo(int flags, caddr_t *argp, struct svc_req *rqstp)
119 static getquota_rslt result;
122 ext_getquota_args *ext_args;
126 char *pathname, *qfpathname;
127 int fd, err, id, type;
128 struct stat stm, stn;
129 struct rquota *rquota;
133 * First check authentication.
135 if (flags & TYPE_EXTENDED) {
136 arguments.ext_args = (ext_getquota_args *)argp;
137 id = arguments.ext_args->gqa_id;
138 type = arguments.ext_args->gqa_type;
139 pathname = arguments.ext_args->gqa_pathp;
141 if (type == USRQUOTA && unix_cred->aup_uid && unix_cred->aup_uid != id) {
142 result.status = Q_EPERM;
146 if (type == GRPQUOTA && unix_cred->aup_uid && unix_cred->aup_gid != id &&
147 !in_group((gid_t *)unix_cred->aup_gids, unix_cred->aup_len, id)) {
148 result.status = Q_EPERM;
152 arguments.args = (getquota_args *)argp;
153 id = arguments.args->gqa_uid;
155 pathname = arguments.args->gqa_pathp;
157 if (unix_cred->aup_uid && unix_cred->aup_uid != id) {
158 result.status = Q_EPERM;
163 fp = setmntent(MNTTAB, "r");
164 while ((mnt = getmntent(fp)) != (struct mntent *)0) {
165 if (stat(mnt->mnt_dir, &stm) == -1)
168 if (stat(pathname, &stn) == -1)
170 else if (stm.st_dev != stn.st_dev)
173 if (mnt->mnt_fsname [0] != '/'
174 || strcasecmp (mnt->mnt_type, MNTTYPE_NFS) == 0
175 || strcasecmp (mnt->mnt_type, MNTTYPE_AUTOFS) == 0
176 || strcasecmp (mnt->mnt_type, MNTTYPE_SWAP) == 0
177 || strcasecmp (mnt->mnt_type, MNTTYPE_IGNORE) == 0)
180 /* All blocks reported are in BLOCK_SIZE. */
181 result.getquota_rslt_u.gqr_rquota.rq_bsize = BLOCK_SIZE;
183 if (hasquota(mnt, type, &qfpathname)) {
185 if (quotactl(QCMD(Q_GETFMT, type), mnt->mnt_fsname, 0, (caddr_t)&fmt)==0) {
186 /* new style interface
187 * Don't bother trying to read from the file
189 err = quotactl(QCMD(Q_GETQUOTA_NEW, type),
190 mnt->mnt_fsname, id, (caddr_t)&dqb);
191 if (err) memset(&dqb, 0, sizeof(dqb));
196 if ((err = quotactl(QCMD(Q_GETQUOTA, type), mnt->mnt_fsname,
197 id, (caddr_t)&dq_dqb)) == -1
198 && !(flags & ACTIVE)) {
199 if ((fd = open(qfpathname, O_RDONLY)) < 0)
204 lseek(fd, (long) dqoff(id), L_SET);
205 switch (read(fd, &dq_dqb, sizeof(struct dqblk))) {
208 * Convert implicit 0 quota (EOF) into an
209 * explicit one (zero'ed dqblk)
211 memset((caddr_t)&dq_dqb, 0, sizeof(struct dqblk));
213 case sizeof(struct dqblk): /* OK */
222 dqb.dqb_bhardlimit = dq_dqb.dqb_bhardlimit;
223 dqb.dqb_bsoftlimit = dq_dqb.dqb_bsoftlimit;
224 dqb.dqb_curspace = dq_dqb.dqb_curblocks * 1024;
225 dqb.dqb_ihardlimit = dq_dqb.dqb_ihardlimit;
226 dqb.dqb_isoftlimit = dq_dqb.dqb_isoftlimit;
227 dqb.dqb_curinodes = dq_dqb.dqb_curinodes;
228 dqb.dqb_btime = dq_dqb.dqb_btime;
229 dqb.dqb_itime = dq_dqb.dqb_itime;
234 if (err && (flags & ACTIVE)) {
235 result.status = Q_NOQUOTA;
239 result.status = Q_OK;
240 result.getquota_rslt_u.gqr_rquota.rq_active = (err == 0) ? TRUE : FALSE;
242 * Make a copy of the info into the last part of the remote quota
243 * struct might not be exactly the same on all architectures...
246 rquota = &result.getquota_rslt_u.gqr_rquota;
247 rquota->rq_bhardlimit = dqb.dqb_bhardlimit;
248 rquota->rq_bsoftlimit = dqb.dqb_bsoftlimit;;
249 rquota->rq_curblocks = dqb.dqb_curspace/1024;
250 rquota->rq_fhardlimit = dqb.dqb_ihardlimit;
251 rquota->rq_fsoftlimit = dqb.dqb_isoftlimit;
252 rquota->rq_curfiles = dqb.dqb_curinodes;
253 rquota->rq_btimeleft = dqb.dqb_btime;
254 rquota->rq_ftimeleft = dqb.dqb_itime;
261 result.status = Q_NOQUOTA;
265 getquota_rslt *rquotaproc_getquota_1_svc(getquota_args *argp, struct svc_req *rqstp)
267 return(getquotainfo(0, (caddr_t *)argp, rqstp));
270 getquota_rslt *rquotaproc_getactivequota_1_svc(getquota_args *argp, struct svc_req *rqstp)
272 return(getquotainfo(ACTIVE, (caddr_t *)argp, rqstp));
275 getquota_rslt *rquotaproc_getquota_2_svc(ext_getquota_args *argp, struct svc_req *rqstp)
277 return(getquotainfo(TYPE_EXTENDED, (caddr_t *)argp, rqstp));
280 getquota_rslt *rquotaproc_getactivequota_2_svc(ext_getquota_args *argp, struct svc_req *rqstp)
282 return(getquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *)argp, rqstp));