We've just turned on user quotas and I am trying to figure out a way to allow users to check their current disk usage and quota limit. Since the filer is running rquotad, this would seem to be the way to go. But alas, the filer rquotad apparently wants quota [path] instead of quota [uid], just like its command line quota report.
Really? That's not what the quota daemon code in ONTAP appears to do - prior to 5.0, it *ignored* the pathname sent over the wire (you only had one file system) and used only the UID, and, in 5.0, it gets the (internal) file system ID of the file system on which the pathname resides, and looks up the quota for the UID in question.
I've attached a source to a program that should build under SunOS 4.x, (sufficiently recent) SunOS 5.x, and Digital UNIX 4.x (and maybe earlier) if you have a compiler that handles function prototypes (it built with GCC on SunOS 4.1.4 and 5.5.1 and Digital UNIX 4.0C) - and, if you remove the stuff to get quotas from local file systems, or rewrite it for your particular OS, should compile under them as well, if you also have "rpcgen" and an ONC RPC library.
Tweak the stuff at the beginning of the Makefile to get it to build.
The first argument is:
for a local file system, the pathname of the mount point;
for a file system on an NFS server, the host name of the NFS server, a colon, and the directory on the server.
The second argument is the user name or UID of the user whose quota is to be checked.
Try running that against the filer (using the "<hostname>:<directory>" syntax), and see what it returns. (I've not tested its ability to get quotas for local file systems, as we don't have any local file systems handy with quotas on them....)
Has anyone figured out a way to allow a general user to check their disk usage and quota limits?
On some flavors of UNIX, the "quota" command should do it. "quota", with no arguments, should report, for all local file systems with quotas, and all NFS file systems not mounted with "noquota" (and mounted from a server with a quota daemon), quota information for the user in question.
On others (I think some lack a "quota" command), you can probably cannibalize the attached program and turn it into a "quota" command, which may involve
making it loop through all file systems on which you can get quotas (NFS and maybe local);
adapting the local file system quota code to your particular flavor of UNIX.
(Then ship it back to the supplier of that flavor of UNIX and tell them to call it "quota"....)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Makefile quotatest.c rquota.x # Wrapped by guy@tooting on Sat May 23 17:48:46 1998 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file "'Makefile'" else echo shar: Extracting "'Makefile'" (908 characters) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# X# Options for GCC: X# XCC=gcc XDEBUG=-g XOPT=-O2 XCHECKS=-Wall X X# X# Options for SunOS 4.x: X# X# LIBS= X# OSVERS=-DSUNOS4 X X# X# Options for Digital UNIX 4.x (and maybe earlier): X# XLIBS= XOSVERS=-DDUNIX X X# X# Options for SunOS 5.x: X# X# LIBS=-lsocket -lnsl X# OSVERS=-DSUNOS5 X XCFLAGS=$(OPT) $(DEBUG) $(OSVERS) $(CHECKS) X XOBJS=quotatest.o rquota_xdr.o rquota_clnt.o X Xquotatest: $(OBJS) X $(CC) -o quotatest $(OBJS) $(LIBS) X Xquotatest.o: quotatest.c rquota.h X Xrquota_xdr.o: rquota_xdr.c rquota.h X Xrquota_clnt.o: rquota_clnt.c rquota.h X Xrquota_xdr.c: rquota.x X rpcgen -o rquota_xdr.c -c rquota.x X Xrquota_clnt.c: rquota.x X rpcgen -o rquota_clnt.c -l rquota.x X Xrquota.h: rquota.x X rpcgen -o rquota.h -h rquota.x X Xclean: X rm -f quotatest quotatest.o rquota_xdr.o rquota_clnt.o \ X rquota_xdr.c rquota_clnt.c rquota.h X Xlint: quotatest.c rquota_xdr.c rquota_clnt.c rquota.h X lint -hbaxz quotatest.c rquota_xdr.c rquota_clnt.c END_OF_FILE if test 908 -ne `wc -c <'Makefile'`; then echo shar: "'Makefile'" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'quotatest.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file "'quotatest.c'" else echo shar: Extracting "'quotatest.c'" (6640 characters) sed "s/^X//" >'quotatest.c' <<'END_OF_FILE' X#include <stdio.h> X#include <ctype.h> X#include <sys/types.h> X#include <string.h> X#include <pwd.h> X X#if defined(SUNOS4) || defined(DUNIX) X#include <ufs/quota.h> X#if defined(SUNOS4) X#include <mntent.h> X#endif X#elif defined(SUNOS5) X#include <unistd.h> X#include <errno.h> X#include <sys/fs/ufs_quota.h> X#endif X X#include <rpc/rpc.h> X#include "rquota.h" X Xextern long strtol(); X Xstatic int show_local_quota(char *fs, uid_t uid); Xstatic int getquota(char *mntpoint, uid_t uid, struct dqblk *dqbp); Xstatic int show_nfs_quota(char *host, char *fs, uid_t uid); Xstatic void showquota(getquota_rslt *resultp); X Xgetquota_rslt *rquotaproc_getquota_1(); Xgetquota_rslt *rquotaproc_getactivequota_1(); X Xint Xmain(argc, argv) X int argc; X char **argv; X{ X char *host; X char *fs; X uid_t uid; X char *p; X struct passwd *pw; X X if (argc != 3) { X (void) fprintf(stderr, "Usage: quotatest <fs> <user>\n"); X return 1; X } X X host = argv[1]; X fs = strchr(argv[1], ':'); X if (fs == NULL) { X /* X * No "host:"; it's a local file system. X */ X host = NULL; X fs = argv[1]; X } else X *fs++ = '\0'; X X if (isdigit((unsigned char)(*argv[2]))) { X uid = strtol(argv[2], &p, 10); X if (p == argv[2] || *p != '\0') { X (void) fprintf(stderr, X "quotatest: %s is not a valid user ID number\n", X argv[2]); X return 1; X } X } else { X pw = getpwnam(argv[2]); X if (pw == NULL) { X (void) fprintf(stderr, X "quotatest: No such user %s\n", argv[2]); X return 2; X } X uid = pw->pw_uid; X } X X if (host == NULL) X return show_local_quota(fs, uid); X else X return show_nfs_quota(host, fs, uid); X} X Xstatic int Xshow_local_quota(char *mntpoint, uid_t uid) X{ X struct dqblk quotablk; X X if (getquota(mntpoint, uid, "ablk) != 0) X return 2; X (void) printf("bhardlimit = %lu\n", X (unsigned long)quotablk.dqb_bhardlimit); X (void) printf("bsoftlimit = %lu\n", X (unsigned long)quotablk.dqb_bsoftlimit); X (void) printf("curblocks = %lu\n", X (unsigned long)quotablk.dqb_curblocks); X#if defined(SUNOS4) || defined(SUNOS5) X (void) printf("fhardlimit = %lu\n", X (unsigned long)quotablk.dqb_fhardlimit); X (void) printf("fsoftlimit = %lu\n", X (unsigned long)quotablk.dqb_fsoftlimit); X (void) printf("curfiles = %lu\n", X (unsigned long)quotablk.dqb_curfiles); X (void) printf("btimeleft = %lu\n", X (unsigned long)quotablk.dqb_btimelimit); X (void) printf("ftimeleft = %lu\n", X (unsigned long)quotablk.dqb_ftimelimit); X#elif defined(DUNIX) X /* X * Thanks for changing the names, Digital. I really appreciate X * it.... X */ X (void) printf("ihardlimit = %lu\n", X (unsigned long)quotablk.dqb_ihardlimit); X (void) printf("isoftlimit = %lu\n", X (unsigned long)quotablk.dqb_isoftlimit); X (void) printf("curinodes = %lu\n", X (unsigned long)quotablk.dqb_curinodes); X (void) printf("btime = %lu\n", X (unsigned long)quotablk.dqb_btime); X (void) printf("itime = %lu\n", X (unsigned long)quotablk.dqb_itime); X#endif X return 0; X} X Xstatic int Xgetquota(char *mntpoint, uid_t uid, struct dqblk *dqbp) X{ X#if defined(SUNOS4) X FILE *mtab; X struct mntent *mnt; X X mtab = setmntent(MOUNTED, "r"); X if (mtab == NULL) { X perror("quotatest: Can't open /etc/mtab"); X return -1; X } X while ((mnt = getmntent(mtab)) != NULL) { X if (strcmp(mnt->mnt_type, MNTTYPE_42) != 0) X continue; /* not BSD */ X if (strcmp(mntpoint, mnt->mnt_dir) != 0) X continue; /* not us */ X goto found; X } X (void) fprintf(stderr, "quotatest: No file system %s\n", mntpoint); X (void) endmntent(mtab); X return -1; X Xfound: X (void) endmntent(mtab); X if (quotactl(Q_GETQUOTA, mnt->mnt_fsname, uid, (caddr_t)dqbp) < 0) { X perror("quotatest: Can't get quota"); X return -1; X } X return 0; X#elif defined(DUNIX) X if (quotactl(mntpoint, QCMD(Q_GETQUOTA, USRQUOTA), uid, X (caddr_t)dqbp) < 0) { X perror("quotatest: Can't get quota"); X return -1; X } X return 0; X#elif defined(SUNOS5) X int fd; X char quotafile[MAXPATHLEN+1]; X struct quotctl quotctl; X X if (strlen(mntpoint) + sizeof "/quota" > MAXPATHLEN+1) { X fprintf(stderr, "quotatest: Mount point name %s too long\n", X mntpoint); X return -1; X } X strcpy(quotafile, mntpoint); X strcat(quotafile, "/quota"); X fd = open(quotafile, O_RDONLY); X if (fd < 0) { X fprintf(stderr, "quotatest: Can't open quota file %s: %s\n", X quotafile, strerror(errno)); X return -1; X } X quotctl.op = Q_GETQUOTA; X quotctl.uid = uid; X quotctl.addr = (caddr_t)dqbp; X if (ioctl(fd, Q_QUOTACTL, (caddr_t)"ctl) < 0) { X perror("quotatest: Can't get quota"); X return -1; X } X return 0; X#endif X} X Xstatic int Xshow_nfs_quota(char *host, char *fs, uid_t uid) X{ X CLIENT *clnt; X getquota_args args; X getquota_rslt *resultp; X X clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp"); X if (clnt == NULL) { X (void) fprintf(stderr, X "quotatest: Can't get at rquota server on %s: %s\n", X host, clnt_spcreateerror("")); X return 2; X } X X auth_destroy(clnt->cl_auth); X clnt->cl_auth = authunix_create_default(); X X args.gqa_pathp = fs; X args.gqa_uid = uid; X resultp = rquotaproc_getquota_1(&args, clnt); X if (resultp == NULL) { X clnt_perror(clnt, "Can't make getquota call to rquota on netapp"); X return 2; X } X (void) printf("Result of getquota call:\n"); X showquota(resultp); X X args.gqa_pathp = fs; X args.gqa_uid = uid; X resultp = rquotaproc_getactivequota_1(&args, clnt); X if (resultp == NULL) { X clnt_perror(clnt, "Can't make getactivequota call to rquota on netapp"); X return 2; X } X (void) printf("Result of getactivequota call:\n"); X showquota(resultp); X return 0; X} X Xstatic void Xshowquota(getquota_rslt *resultp) X{ X switch (resultp->status) { X X case Q_OK: X (void) printf("bsize = %d\n", X resultp->getquota_rslt_u.gqr_rquota.rq_bsize); X (void) printf("active = %s\n", X resultp->getquota_rslt_u.gqr_rquota.rq_active ? X "yes" : "no"); X (void) printf("bhardlimit = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_bhardlimit); X (void) printf("bsoftlimit = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_bsoftlimit); X (void) printf("curblocks = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_curblocks); X (void) printf("fhardlimit = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_fhardlimit); X (void) printf("fsoftlimit = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_fsoftlimit); X (void) printf("curfiles = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_curfiles); X (void) printf("btimeleft = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_btimeleft); X (void) printf("ftimeleft = %u\n", X resultp->getquota_rslt_u.gqr_rquota.rq_ftimeleft); X break; X X case Q_NOQUOTA: X (void) printf("No quota for you\n"); X break; X X case Q_EPERM: X (void) printf("No permission\n"); X break; X } X} END_OF_FILE if test 6640 -ne `wc -c <'quotatest.c'`; then echo shar: "'quotatest.c'" unpacked with wrong size! fi # end of 'quotatest.c' fi if test -f 'rquota.x' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file "'rquota.x'" else echo shar: Extracting "'rquota.x'" (1526 characters) sed "s/^X//" >'rquota.x' <<'END_OF_FILE' X/* @(#)rquota.x 1.4 88/02/08 Copyr 1987 Sun Micro */ X X/* X * Remote quota protocol X * Requires unix authentication X */ X Xconst RQ_PATHLEN = 1024; X Xstruct getquota_args { X string gqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */ X int gqa_uid; /* inquire about quota for uid */ X}; X X/* X * remote quota structure X */ Xstruct rquota { X int rq_bsize; /* block size for block counts */ X bool rq_active; /* indicates whether quota is active */ X unsigned int rq_bhardlimit; /* absolute limit on disk blks alloc */ X unsigned int rq_bsoftlimit; /* preferred limit on disk blks */ X unsigned int rq_curblocks; /* current block count */ X unsigned int rq_fhardlimit; /* absolute limit on allocated files */ X unsigned int rq_fsoftlimit; /* preferred file limit */ X unsigned int rq_curfiles; /* current # allocated files */ X unsigned int rq_btimeleft; /* time left for excessive disk use */ X unsigned int rq_ftimeleft; /* time left for excessive files */ X}; X Xenum gqr_status { X Q_OK = 1, /* quota returned */ X Q_NOQUOTA = 2, /* noquota for uid */ X Q_EPERM = 3 /* no permission to access quota */ X}; X Xunion getquota_rslt switch (gqr_status status) { Xcase Q_OK: X rquota gqr_rquota; /* valid if status == Q_OK */ Xcase Q_NOQUOTA: X void; Xcase Q_EPERM: X void; X}; X Xprogram RQUOTAPROG { X version RQUOTAVERS { X /* X * Get all quotas X */ X getquota_rslt X RQUOTAPROC_GETQUOTA(getquota_args) = 1; X X /* X * Get active quotas only X */ X getquota_rslt X RQUOTAPROC_GETACTIVEQUOTA(getquota_args) = 2; X } = 1; X} = 100011; END_OF_FILE if test 1526 -ne `wc -c <'rquota.x'`; then echo shar: "'rquota.x'" unpacked with wrong size! fi # end of 'rquota.x' fi echo shar: End of shell archive. exit 0