# yum install quota # Edit /etc/fstab, remount drive, add usrquota,grpquota to mount option /dev/mapper/vg_data-lv_srv /home ext4 defaults,usrjquota=aquota.user,grpjquota=aquota.group,jqfmt=vfsv0 1 2 remount -o /home quotacheck /home quotaon -avug # Verify repquota /home
# Download files from http://code.google.com/p/pam-setquota/downloads/list # un pack, patch: patch pam_setquota/pam_setquota.c -p0 < setquota.patch # Install dev packages yum install pam-devel.x86_64 quota-devel.x86_64 yum groupinstall "Development Tools" # Add this line to Makefile gcc command (uname -r to get kernel) # -> gcc -I/usr/src/kernels/2.6.32-431.5.1.el6.x86_64/include/ make && cp pam_setquota.so /lib64/security # Now edit /etc/pam.d/system-auth && password-auth # Add session line underneath pam_mkhomedir.so session required pam_setquota.so bsoftlimit=307200 bhardlimit=512000 isoftlimit=0 ihardlimit=0 startuid=10000 enduid=0 fs=/home overwrite=1 # Check su - somebody exit repquota /home
# Usage for setquota # Read user limits setquota cmd=read obj=user user=pfowler # Read group limits setquota cmd=read obj=group group=linuxusers # Set initial user limits (300MB soft, 500MB hard) setquota cmd=write obj=user user=pfowler bsoftlimit=307200 bhardlimit=512000 # Overwrite existing user limits (300MB soft, 500MB hard) setquota cmd=write obj=user overwrite=1 user=pfowler bsoftlimit=307200 bhardlimit=512000
* Make sure to update the locate of linux/dqblk_v1.h
setquota: setquota.c gcc -I/usr/src/kernels/2.6.32-504.12.2.el6.x86_64/include/ -Wall -fPIC setquota.c -o setquota install: setquota.so install --mode=744 setquota /usr/local/bin clean: rm -f setquota.o setquota
#include <sys/types.h> #include <linux/quota.h> #include <linux/dqblk_v1.h> #include <linux/dqblk_v2.h> #include <pwd.h> #include <grp.h> #include <syslog.h> #include <errno.h> #include <mntent.h> #include <stdio.h> #include <string.h> #include <stdlib.h> struct quota_params { int id; uid_t uid; gid_t gid; char* user; char* group; char* fs; char* cmd; char* obj; int debug; int overwrite; }; static void _parse_params(int argc, char **argv, struct quota_params *p) { for (; argc-- > 0; ++argv) { if (strncmp (*argv, "user=", 5) == 0) p->user = (char*) *argv + 5; if (strncmp (*argv, "group=", 6) == 0) p->group = (char*) *argv + 6; else if (strncmp (*argv, "fs=",3) == 0) p->fs = (char*) *argv + 3; else if (strncmp (*argv, "cmd=",4) == 0) p->cmd = (char*) *argv + 4; else if (strncmp (*argv, "obj=",4) == 0) p->obj = (char*) *argv + 4; else if (strncmp (*argv, "overwrite=",10) == 0) p->overwrite = strtol (*argv + 10, NULL, 10); else if (strncmp (*argv, "debug=",6) == 0) p->debug = strtol (*argv + 6, NULL, 10); } } static void _parse_dqblk(int argc, char **argv, struct if_dqblk *p){ for (; argc-- > 0; ++argv) { if (strncmp (*argv, "bhardlimit=", 11) == 0) { p->dqb_bhardlimit = strtol (*argv + 11, NULL, 10); p->dqb_valid |= QIF_BLIMITS; } else if (strncmp (*argv, "bsoftlimit=", 11) == 0) { p->dqb_bsoftlimit = strtol (*argv + 11, NULL, 10); p->dqb_valid |= QIF_BLIMITS; } else if (strncmp (*argv, "ihardlimit=", 11) == 0) { p->dqb_ihardlimit = strtol (*argv + 11, NULL, 10); p->dqb_valid |= QIF_ILIMITS; } else if (strncmp (*argv, "isoftlimit=", 11) == 0) { p->dqb_isoftlimit = strtol (*argv + 11, NULL, 10); p->dqb_valid |= QIF_ILIMITS; } else if (strncmp (*argv, "btime=", 6) == 0) { p->dqb_btime = strtol (*argv + 6, NULL, 10); p->dqb_valid |= QIF_TIMES; } else if (strncmp (*argv, "itime=", 6) == 0) { p->dqb_itime = strtol (*argv + 6, NULL, 10); p->dqb_valid |= QIF_TIMES; } } } int main (int argc, char *argv[]) { const struct passwd *pwd; const struct group *grp; struct if_dqblk ndqblk; FILE *fd; char mntdevice[BUFSIZ], mntpoint[BUFSIZ]; const struct mntent *mnt; struct quota_params param = { .fs = NULL, .user = NULL, .group = NULL, .id = 0, .uid = 0, .gid = 0, .debug = 0, .cmd = NULL, .obj = NULL, .overwrite = 0, }; // Parse the command line parameters _parse_params(argc, argv, ¶m); // Check we got a read/write command if (param.cmd == NULL) { fprintf (stderr, "cmd= required (read, write)\n"); exit(1); } if (!((strncmp (param.cmd, "read",4) == 0) || (strncmp (param.cmd, "write",5) == 0))) { fprintf (stderr, "Require cmd=(read|write)\n"); exit (1); } // Check we got an object type to operate on (user|group) if (param.obj == NULL) { fprintf (stderr, "Require obj=(user|group)\n"); exit(1); } if (!((strncmp (param.obj, "user",4) == 0) || (strncmp (param.obj, "group",5) == 0))) { fprintf (stderr, "Require obj=(user|group)\n"); exit (1); } // If we are working with a user... if (strncmp (param.obj, "user",4) == 0) { // Check we got a username, and that it exists in database if (param.user == NULL) { fprintf( stderr, "user= required\n"); exit(1); } pwd = getpwnam(param.user); if (pwd == NULL) { fprintf( stderr, "%s not found\n", param.user); exit(1); } param.uid = pwd->pw_uid; param.id = param.uid; } // If we are working with a group... if (strncmp (param.obj, "group",4) == 0) { if (param.group == NULL) { fprintf( stderr, "group= required\n"); exit(1); } grp = getgrnam(param.group); if (grp == NULL) { fprintf( stderr, "%s not found\n", param.group); exit(1); } param.gid = grp->gr_gid; param.id = param.gid; } // Remove unnecessary '/' from end of fs parameter if (param.fs != NULL) { if (strlen(param.fs) > 1) { if (param.fs[strlen(param.fs) - 1] == '/') param.fs[strlen(param.fs) - 1] = '\0'; } } // Find out what device the filesystem is hosted on if ((fd = setmntent("/etc/mtab", "r")) == NULL) { fprintf( stderr, "Unable to open /etc/mtab"); exit (1); } *mntpoint = *mntdevice = '\0'; while ((mnt = getmntent(fd)) != NULL) { if (param.fs == NULL) { fprintf( stderr, "File system auto-detection not supported (use fs=)"); exit (1); } else if (((strncmp(param.fs, mnt->mnt_dir, strlen(mnt->mnt_dir)) == 0) && (strlen(param.fs) == strlen(mnt->mnt_dir))) || (strncmp(param.fs, mnt->mnt_fsname, strlen(mnt->mnt_fsname)) == 0) && ((strlen(param.fs) == strlen(mnt->mnt_fsname)))) { strncpy(mntdevice, mnt->mnt_fsname, sizeof (mntdevice)); } } if (*mntdevice == '\0') { fprintf( stderr, "Filesystem %s not found", param.fs); exit (1); } if (param.debug==1) { //printf ("username:%s\n", param.username); printf ("id:%d\n", param.id); printf ("fs:%s\n", param.fs); printf ("dev:%s\n", mntdevice); printf ("overwrite:%d\n", param.overwrite); //printf ("%s:%d\n", param.username, param.uid); } // Now do the quota stuff int qcmd = 0; if (strncmp (param.obj, "user",4) == 0) qcmd = QCMD(Q_GETQUOTA,USRQUOTA); else qcmd = QCMD(Q_GETQUOTA,GRPQUOTA); if (quotactl(qcmd, mntdevice, param.id, (void*) &ndqblk) == -1) { fprintf( stderr, "Failed to get limits : %s\n", strerror(errno)); } if (strncmp (param.cmd, "read",4) == 0) { printf ("curspace:%llu\n", ndqblk.dqb_curspace); printf ("bsoftlimit:%llu\n", ndqblk.dqb_bsoftlimit); printf ("bhardlimit:%llu\n", ndqblk.dqb_bhardlimit); printf ("btime:%llu\n", ndqblk.dqb_btime); printf ("curinodes:%llu\n", ndqblk.dqb_curinodes); printf ("isoftlimit:%llu\n", ndqblk.dqb_isoftlimit); printf ("ihardlimit:%llu\n", ndqblk.dqb_ihardlimit); printf ("itime:%llu\n", ndqblk.dqb_itime); printf ("valid:%d\n", ndqblk.dqb_valid); } if (strncmp (param.cmd, "read",4) == 0) return 0; // Parse new limits _parse_dqblk(argc, argv, &ndqblk); if (strncmp (param.obj, "user",4) == 0) qcmd = QCMD(Q_SETQUOTA,USRQUOTA); else qcmd = QCMD(Q_SETQUOTA,GRPQUOTA); if ( (ndqblk.dqb_bsoftlimit == 0 && ndqblk.dqb_bhardlimit == 0 && ndqblk.dqb_isoftlimit == 0 && ndqblk.dqb_ihardlimit == 0 ) || param.overwrite == 1 ) { if (quotactl(qcmd, mntdevice, param.id, (void*) &ndqblk) == -1) { fprintf(stderr, "failed to set limits : %s\n", strerror(errno)); exit(1); } } else { fprintf(stderr, "limits already set; use overwrite=1 to force\n"); exit(1); } return 0; }