/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: idspace.c,v 1.1.2.1 92/06/24 13:34:37 marker Exp $"
#ident "@(#)idspace.c	1.1 (Prime) 8/18/88"

/*	Copyright (c) 1984 1988 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/


/*
 * Idspace.c investigate free space in /, /usr, and /tmp
 *
 * Usage: idspace checks /, /usr (if it is a separate filesystem), and
 *        /tmp (if it is a separate filesystem). It uses the required
 *        space for a kernel reconfiguration as default as follows:
 *
 *	"idspace" - Check for / = (sizeof)unix + 400 blk & 100 inodes, and
 *                         /usr = 400 blocks, 100 inodes (if /usr is a filesys)
 *                         /tmp = 400 blocks, 100 inodes (if /tmp is a filesys)
 *
 *      "idspace -r 3000" - Check for / = 3000 blocks and 100 inodes.
 *      "idspace -u 4000 -i 300" - Check for /usr = 4000 blocks and 300 inodes.
 *
 * exit 0 - success
 *	1 - command syntax error, or needed file does not exist.
 *	2 - file system has insufficient space or inodes.
 *	3 - requested file system does not exist.
 *
 */

#include <stdio.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <mnttab.h>
#include <sys/stat.h>
#include <ustat.h>

/* error messages */
#define USAGE		"Usage:  idspace [-u blocks | -t blocks | -r blocks] [-i inodes]"
/* CChan. Next line changed from /etc/mnttab */ 
#define MNTTAB "/etc/mtab"
#define NEEDBLK	400
#define NEEDINO	100

char fbuf[512];
char errbuf[200];
struct	mnttab	M[NMOUNT];
char linebuf[128];
struct ustat	Fs_info, *Fs;
int debug;		/* debug flag */

char iflag=0;		/* over ride default count */
char rflag=0;		/* check root file system only */
char uflag=0;		/* check /usr file system only */
char tflag=0;		/* check /tmp file system only */
char onlyflag=0;	/* check one system only; u, t, r used */

int rootblk;
int usrblk = NEEDBLK;
int tmpblk = NEEDBLK;
int inodecnt = NEEDINO;
int usrfound=0;
int tmpfound=0;
int rootfound=0;

struct stat pstat;
extern void exit();
extern char *optarg;
extern int optind;
extern int errno;

main(argc, argv)
int argc;
char *argv[];
{
	register i, m;
	char	 dev[40];
	/* CChan. The next two line were added. */
	char	fsname[128];
	FILE	*fi;

	while ((m = getopt(argc, argv, "?#r:u:t:i:")) != EOF)
		switch (m) {
		case 'i':
			iflag++; 
			inodecnt=atoi(optarg);
			break;
		case 'r':
			rflag++; 
			onlyflag++;
			rootblk=atoi(optarg);
			break;
		case 'u':
			uflag++; 
			onlyflag++;
			usrblk=atoi(optarg);
			break;
		case 't':
			tflag++; 
			onlyflag++;
			tmpblk=atoi(optarg);
			break;
		case '#':
			debug++;
			break;
		case '?':
			fprintf(stderr, "%s\n", USAGE);
			exit(1);
		}

	if (onlyflag > 1){
		fprintf(stderr,"only one of -r, -u, -t options at a time.\n"); 
		error(USAGE, 1);
	}

	if (!onlyflag){
		if(stat("/unix", &pstat))
			error("Can't obtain size of /unix.", 1);
		rootblk=pstat.st_size/512 + NEEDBLK;	/* free space needed to hold new unix */
		if (debug)
			fprintf (stderr,"root free space needed (/unix + %d) = %d blocks\n", NEEDBLK, rootblk);

	}
	/* CChan. Changed to handle RISC/OS style mount table */
	if ((fi = fopen(MNTTAB, "r")) == (FILE *) NULL ) {
		sprintf(errbuf,"df: cannot open %s",MNTTAB);
		error(errbuf,1);
	}
	while (fgets( linebuf, sizeof(linebuf), fi) != (char *) 0) {
		if ( sscanf( linebuf, "%s %s", dev, fsname ) < 2 )
			break;
		else
			checkit( dev, fsname );
	}

	fclose(fi);
	/* CChan. End of change for RISC/OS style mount table */

	if (rflag)	/* This case can't happen */
		if (!rootfound)
			error("Can not find / file system",3);
	if (uflag)
		if (!usrfound)
			error("Can not find /usr file system",3);
	if (tflag)
		if (!tmpfound)
			error("Can not find /tmp file system",3);
	exit(0);
}

checkit(dev, fs_name)
char *dev, *fs_name;
{
	int fd;

	if((fd = open(dev, 0)) < 0) {
		fprintf(stderr,"df: cannot open %s\n",dev);
		return;
	}
	Fs = &Fs_info;
	if(stat(dev, &pstat) < 0) {
		sprintf(errbuf, "df: cannot stat %s", dev);
		error(errbuf,1);
	}
	if(ustat(pstat.st_rdev, Fs) < 0) {
		fprintf(stderr, "df: cannot ustat %s\n", dev);
		return;
	}
	if (!onlyflag || rflag){
		if (!strcmp(fs_name, "/")){
			rootfound++;
			if (debug)
				fprintf (stderr,"checking / (root) free space.\n");
			if(Fs->f_tfree<rootblk || Fs->f_tinode <inodecnt)
				nospace("/ (root)", rootblk, inodecnt);
		}
	}
	if (!onlyflag || uflag){
		if (!strcmp(fs_name, "/usr")){
			usrfound++;
			if (debug)
				fprintf (stderr,"checking /usr free space.\n");
			if(Fs->f_tfree<usrblk || Fs->f_tinode <inodecnt)
				nospace("/usr", usrblk, inodecnt);
		}
	}
	if (!onlyflag || tflag){
		if (!strcmp(fs_name, "/tmp")){
			tmpfound++;
			if (debug)
				fprintf (stderr,"checking /tmp free space.\n");
			if(Fs->f_tfree<tmpblk || Fs->f_tinode <inodecnt)
				nospace("/tmp", tmpblk, inodecnt);
		}
	}
	close(fd);
}

nospace(bdev, blocks, inodes)
char *bdev;
int blocks;
int inodes;
{
	sprintf(errbuf, "Not enough free space or i-nodes in %s file system.\n         %d blocks, %d inodes are needed.", bdev, blocks, inodes);
	error(errbuf,2);
}

/* print error message */

error(msg,err)
char *msg;
int err;
{
	fprintf(stderr, "idspace: %s\n", msg);
	exit(err);
}
