X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Frquotad%2Frquota_server.c;h=f8bd8f18ab956f1fe47ff3b568f75ecc0c5aeda7;hp=08c4f8c8c9eb750069829c879e96e449589226ea;hb=a5f020dda1a93657eae1b297a67d054269a3ef0c;hpb=8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9 diff --git a/utils/rquotad/rquota_server.c b/utils/rquotad/rquota_server.c index 08c4f8c..f8bd8f1 100644 --- a/utils/rquotad/rquota_server.c +++ b/utils/rquotad/rquota_server.c @@ -18,14 +18,25 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include "config.h" + +#ifdef HAVE_CONFIG_H +#include +#endif #include #include "rquota.h" #include #include #include +/* Unfortunately we cannot trust sys/quota.h to have + * what we need, either the old interface could be missing + * (SLES9) or the new (SLES8 and others). + * So we will just put it explicitly below + */ +#if 0 #include +#endif +#include #include #include #include @@ -37,73 +48,60 @@ #define TYPE_EXTENDED 0x01 #define ACTIVE 0x02 -#ifdef ELM -#define _PATH_DEV_DSK "/dev/dsk/" -#else -#define _PATH_DEV_DSK "/dev/" +#ifndef MNTTYPE_AUTOFS +#define MNTTYPE_AUTOFS "autofs" #endif +#ifndef BLOCK_SIZE +#define BLOCK_SIZE 1024 +#endif + +#define MAXQUOTAS 2 +#define USRQUOTA 0 /* element used for user quotas */ +#define GRPQUOTA 1 /* element used for group quotas */ + +struct dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +}; + +struct if_dqblk { + u_int64_t dqb_bhardlimit; + u_int64_t dqb_bsoftlimit; + u_int64_t dqb_curspace; + u_int64_t dqb_ihardlimit; + u_int64_t dqb_isoftlimit; + u_int64_t dqb_curinodes; + u_int64_t dqb_btime; + u_int64_t dqb_itime; + u_int32_t dqb_valid; +}; + +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#define Q_GETQUOTA 0x0300 /* get limits and usage */ +#define Q_SETQUOTA 0x0400 /* set limits and usage */ + +#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ +#define Q_GETQUOTA_NEW 0x800007 /* get user quota structure */ +#define Q_SETQUOTA_NEW 0x800008 /* set user quota structure */ +#define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk))) + +extern int quotactl (int __cmd, const char *__special, int __id, + caddr_t __addr) __THROW; /* * Global unix authentication credentials. */ extern struct authunix_parms *unix_cred; -char *nfsmount_to_devname(char *pathname, int *blksize) -{ - DIR *dp; - dev_t device; - struct stat st; - struct dirent *de; - static char *devicename = NULL; - static int devicelen = 0; - - if (stat(pathname, &st) == -1) - return (char *)0; - - device = st.st_dev; - *blksize = st.st_blksize; - - /* - * search for devicename in _PATH_DEV_DSK dir. - */ - if ((dp = opendir(_PATH_DEV_DSK)) == (DIR *)0) - return (char *)0; - - while ((de = readdir(dp)) != (struct dirent *)0) { - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) - continue; - - if (devicelen == 0) { - devicelen = sizeof (_PATH_DEV_DSK) + strlen (de->d_name) + 1; - devicename = (char *) xmalloc (devicelen); - } - else { - int newlen = sizeof (_PATH_DEV_DSK) + strlen (de->d_name) + 1; - if (newlen > devicelen) { - devicelen = newlen; - devicename = (char *) xrealloc (devicename, devicelen); - } - } - - strcpy(devicename, _PATH_DEV_DSK); - strcat(devicename, de->d_name); - if (stat(devicename, &st) == -1) - continue; - - if (!S_ISBLK(st.st_mode)) - continue; - - if ((device == st.st_rdev) && S_ISBLK(st.st_mode)) - break; - } - closedir(dp); - - if (de != (struct dirent *)0) { - return devicename; - } else - return (char *)0; -} - int in_group (gid_t *gids, u_int len, gid_t gid) { int cnt = 0; @@ -124,10 +122,12 @@ getquota_rslt *getquotainfo(int flags, caddr_t *argp, struct svc_req *rqstp) ext_getquota_args *ext_args; } arguments; FILE *fp; - struct dqblk dq_dqb; struct mntent *mnt; - char *pathname, *devicename, *qfpathname; + char *pathname, *qfpathname; int fd, err, id, type; + struct stat stm, stn; + struct rquota *rquota; + struct if_dqblk dqb; /* * First check authentication. @@ -160,46 +160,75 @@ getquota_rslt *getquotainfo(int flags, caddr_t *argp, struct svc_req *rqstp) } } - /* - * Convert a nfs_mountpoint to a local devicename. - */ - if ((devicename = nfsmount_to_devname(pathname, - &result.getquota_rslt_u.gqr_rquota.rq_bsize)) == (char *)0) { - result.status = Q_NOQUOTA; - return(&result); - } - fp = setmntent(MNTTAB, "r"); while ((mnt = getmntent(fp)) != (struct mntent *)0) { - if (strcmp(devicename, mnt->mnt_fsname)) - continue; + if (stat(mnt->mnt_dir, &stm) == -1) + continue; + + if (stat(pathname, &stn) == -1) + break; + else if (stm.st_dev != stn.st_dev) + continue; + + if (mnt->mnt_fsname [0] != '/' + || strcasecmp (mnt->mnt_type, MNTTYPE_NFS) == 0 + || strcasecmp (mnt->mnt_type, MNTTYPE_AUTOFS) == 0 + || strcasecmp (mnt->mnt_type, MNTTYPE_SWAP) == 0 + || strcasecmp (mnt->mnt_type, MNTTYPE_IGNORE) == 0) + break; + + /* All blocks reported are in BLOCK_SIZE. */ + result.getquota_rslt_u.gqr_rquota.rq_bsize = BLOCK_SIZE; if (hasquota(mnt, type, &qfpathname)) { - if ((err = quotactl(QCMD(Q_GETQUOTA, type), devicename, id, - (caddr_t)&dq_dqb)) == -1 && !(flags & ACTIVE)) { - if ((fd = open(qfpathname, O_RDONLY)) < 0) - { - free(qfpathname); - continue; - } - free(qfpathname); - lseek(fd, (long) dqoff(id), L_SET); - switch (read(fd, &dq_dqb, sizeof(struct dqblk))) { - case 0:/* EOF */ - /* - * Convert implicit 0 quota (EOF) into an - * explicit one (zero'ed dqblk) - */ - memset((caddr_t)&dq_dqb, 0, sizeof(struct dqblk)); - break; - case sizeof(struct dqblk): /* OK */ - break; - default: /* ERROR */ - close(fd); - continue; - } - close(fd); - } + int fmt; + if (quotactl(QCMD(Q_GETFMT, type), mnt->mnt_fsname, 0, (caddr_t)&fmt)==0) { + /* new style interface + * Don't bother trying to read from the file + */ + err = quotactl(QCMD(Q_GETQUOTA_NEW, type), + mnt->mnt_fsname, id, (caddr_t)&dqb); + if (err) memset(&dqb, 0, sizeof(dqb)); + } else { + /* old style */ + struct dqblk dq_dqb; + + if ((err = quotactl(QCMD(Q_GETQUOTA, type), mnt->mnt_fsname, + id, (caddr_t)&dq_dqb)) == -1 + && !(flags & ACTIVE)) { + if ((fd = open(qfpathname, O_RDONLY)) < 0) + { + free(qfpathname); + continue; + } + lseek(fd, (long) dqoff(id), L_SET); + switch (read(fd, &dq_dqb, sizeof(struct dqblk))) { + case 0:/* EOF */ + /* + * Convert implicit 0 quota (EOF) into an + * explicit one (zero'ed dqblk) + */ + memset((caddr_t)&dq_dqb, 0, sizeof(struct dqblk)); + break; + case sizeof(struct dqblk): /* OK */ + break; + default: /* ERROR */ + close(fd); + free(qfpathname); + continue; + } + close(fd); + } + dqb.dqb_bhardlimit = dq_dqb.dqb_bhardlimit; + dqb.dqb_bsoftlimit = dq_dqb.dqb_bsoftlimit; + dqb.dqb_curspace = dq_dqb.dqb_curblocks * 1024; + dqb.dqb_ihardlimit = dq_dqb.dqb_ihardlimit; + dqb.dqb_isoftlimit = dq_dqb.dqb_isoftlimit; + dqb.dqb_curinodes = dq_dqb.dqb_curinodes; + dqb.dqb_btime = dq_dqb.dqb_btime; + dqb.dqb_itime = dq_dqb.dqb_itime; + } + free(qfpathname); endmntent(fp); if (err && (flags & ACTIVE)) { @@ -211,10 +240,18 @@ getquota_rslt *getquotainfo(int flags, caddr_t *argp, struct svc_req *rqstp) result.getquota_rslt_u.gqr_rquota.rq_active = (err == 0) ? TRUE : FALSE; /* * Make a copy of the info into the last part of the remote quota - * struct which is exactly the same. + * struct might not be exactly the same on all architectures... */ - memcpy((caddr_t *)&result.getquota_rslt_u.gqr_rquota.rq_bhardlimit, - (caddr_t *)&dq_dqb, sizeof(struct dqblk)); + + rquota = &result.getquota_rslt_u.gqr_rquota; + rquota->rq_bhardlimit = dqb.dqb_bhardlimit; + rquota->rq_bsoftlimit = dqb.dqb_bsoftlimit;; + rquota->rq_curblocks = dqb.dqb_curspace/1024; + rquota->rq_fhardlimit = dqb.dqb_ihardlimit; + rquota->rq_fsoftlimit = dqb.dqb_isoftlimit; + rquota->rq_curfiles = dqb.dqb_curinodes; + rquota->rq_btimeleft = dqb.dqb_btime; + rquota->rq_ftimeleft = dqb.dqb_itime; return(&result); } @@ -225,22 +262,22 @@ getquota_rslt *getquotainfo(int flags, caddr_t *argp, struct svc_req *rqstp) return(&result); } -getquota_rslt *rquotaproc_getquota_1(getquota_args *argp, struct svc_req *rqstp) +getquota_rslt *rquotaproc_getquota_1_svc(getquota_args *argp, struct svc_req *rqstp) { return(getquotainfo(0, (caddr_t *)argp, rqstp)); } -getquota_rslt *rquotaproc_getactivequota_1(getquota_args *argp, struct svc_req *rqstp) +getquota_rslt *rquotaproc_getactivequota_1_svc(getquota_args *argp, struct svc_req *rqstp) { return(getquotainfo(ACTIVE, (caddr_t *)argp, rqstp)); } -getquota_rslt *rquotaproc_getquota_2(ext_getquota_args *argp, struct svc_req *rqstp) +getquota_rslt *rquotaproc_getquota_2_svc(ext_getquota_args *argp, struct svc_req *rqstp) { return(getquotainfo(TYPE_EXTENDED, (caddr_t *)argp, rqstp)); } -getquota_rslt *rquotaproc_getactivequota_2(ext_getquota_args *argp, struct svc_req *rqstp) +getquota_rslt *rquotaproc_getactivequota_2_svc(ext_getquota_args *argp, struct svc_req *rqstp) { return(getquotainfo(TYPE_EXTENDED | ACTIVE, (caddr_t *)argp, rqstp)); }