/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:quotaconvert.c 12.0$ */
/* $ACIS:quotaconvert.c 12.0$ */
/* $Source: /ibm/acis/usr/src/local/RCS/quotaconvert.c,v $ */

#ifndef lint
static char *rcsid = "$Header:quotaconvert.c 12.0$";
#endif

#include <sys/nfs_defines.h>

/*
 * Simple utility to convert Berkeley/ACIS 4.3 style quota files into
 * Sun style quota files.  The quota systems in the two systems are
 * very similar but not compatible.  We decided it would be easier to
 * just convert the quota files than to convert the quota system in
 * the kernel.  We just copy the limits from one file to another
 * and zero out the warning areas, which are different.
 * Since this program will be used very infrequently it isn't very
 * polished.  If it doesn't do exactly what you need it should be easy
 * to revise.
 *
 * To use, cd to the directory where the quotas file is and
 * run this program.  The old quotas file will be moved to quotas.old
 * and a new quotas file will be created.
 *
 * Recall that quotas files will have holes in them if your uid space is
 * sparse.  If you use cp to copy a quotas file it will allocate actual
 * disk space to fill the holes.  It is ok to copy an old quota file and
 * then convert it to a new one if you have the space.  The conversion
 * will win back the disk space for you.
 */

#include <stdio.h>
#include <sys/types.h>

/* copied from /sys/h/quota.h */
struct	dqblk_berk {
	u_long	dqb_bhardlimit;	/* absolute limit on disc blks alloc */
	u_long	dqb_bsoftlimit;	/* preferred limit on disc blks */
	u_long	dqb_curblocks;	/* current block count */
	u_short	dqb_ihardlimit;	/* maximum # allocated inodes + 1 */
	u_short	dqb_isoftlimit;	/* preferred inode limit */
	u_short	dqb_curinodes;	/* current # allocated inodes */
	u_char	dqb_bwarn;	/* # warnings left about excessive disc use */
	u_char	dqb_iwarn;	/* # warnings left about excessive inodes */
};

/* copied from /sys/ufs/quota.h */
struct	dqblk_sun {
	u_long	dqb_bhardlimit;	/* absolute limit on disk blks alloc */
	u_long	dqb_bsoftlimit;	/* preferred limit on disk blks */
	u_long	dqb_curblocks;	/* current block count */
	u_long	dqb_fhardlimit;	/* maximum # allocated files + 1 */
	u_long	dqb_fsoftlimit;	/* preferred file limit */
	u_long	dqb_curfiles;	/* current # allocated files */
	u_long	dqb_btimelimit;	/* time limit for excessive disk use */
	u_long	dqb_ftimelimit;	/* time limit for excessive files */
};

char	quotafile[] = "quotas";
char	savequotafile[] = "quotas.old";

main(argc, argv)
int argc;
char *argv[];
{
	FILE *fpold, *fpnew;
	struct dqblk_berk dq_berk;
	struct dqblk_sun dq_sun;
	uid_t uid;
	int done = 0;

	if (argc != 1) {
		printf("Usage: %s (from within directory where quotas file resides)\n", argv[0]);
		exit(1);
	}

	if ((fpold = fopen(quotafile, "r")) == (FILE *)NULL) {
		perror(quotafile);
		exit(1);
	}
	fclose(fpold);
	if (rename(quotafile, savequotafile) != 0) {
		perror(savequotafile);
		exit(1);
	}
	if ((fpold = fopen(savequotafile, "r")) == (FILE *)NULL) {
		perror(savequotafile);
		exit(1);
	}
	if ((fpnew = fopen(quotafile, "w")) == (FILE *)NULL) {
		perror(quotafile);
		exit(1);
	}

	for (uid = 0; !done; ++uid) {

		/* read a quota record */
		if (fread(&dq_berk, sizeof(dq_berk), 1, fpold) != 1)
			++done;
		/* if it is zero it doesn't count */
		else if (dq_berk.dqb_bsoftlimit != 0 || dq_berk.dqb_isoftlimit != 0) {
			printf("uid %d: \thard %d soft %d cur %d hardi %d softi %d curi %d\n", uid, dq_berk.dqb_bhardlimit/2, dq_berk.dqb_bsoftlimit/2, dq_berk.dqb_curblocks/2, dq_berk.dqb_ihardlimit/2, dq_berk.dqb_isoftlimit/2, dq_berk.dqb_curinodes/2);
			dq_sun.dqb_bhardlimit = dq_berk.dqb_bhardlimit;	
			dq_sun.dqb_bsoftlimit = dq_berk.dqb_bsoftlimit;	
			dq_sun.dqb_curblocks = dq_berk.dqb_curblocks;	
			dq_sun.dqb_fhardlimit = dq_berk.dqb_ihardlimit;	
			dq_sun.dqb_fsoftlimit = dq_berk.dqb_isoftlimit;	
			dq_sun.dqb_curfiles = dq_berk.dqb_curinodes;	
			dq_sun.dqb_btimelimit = 0;
			dq_sun.dqb_ftimelimit = 0;

			/* seek over holes */
			if (fseek(fpnew, (long)(uid * sizeof(dq_sun)), 0)) {
				perror("bad seek in quotas file");
				exit(1);
			}

			if (fwrite(&dq_sun, sizeof(dq_sun), 1, fpnew) != 1) {
				perror(quotafile);
				exit(1);
			}
		}
	}
}
