Table of Contents

Enable Quota

# 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

PAM setquota

# 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

Set Quota Utility

Usage for setquota

# 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

Makefile

* 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

setquota.c

#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, &param);
 
  // 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;
}