/* Minix Filesystem Binary Configuration Program
 * Copyright 1995 S.N. Henson.
 */

#include <mintbind.h>
#include <nlist.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <st-out.h>
#include <macros.h>

#ifdef __STDC__
# define	P(s) s
#else
# define P(s) ()
#endif


/* csize.c */
int main P((int argc , char **argv ));
int usage P((void ));
int get_binfo P((char *fpath ));
int alert_err P((char *mess ));
int load_bin P((char *fpath ));
int save_bin P((char *fpath ));
int get_var P((void *ptr , int sym , int len ));
int put_var P((void *ptr , int sym , int len ));

#undef P
/* Symbol list */

struct nlist nl[] = {
{"_mfs_maj",0,0},
{"_mfs_min",0,0},
{"_mfs_plev",0,0},
{"_mfs_magic",0,0},
{"_ucache_size",0,0},
{"_scache_size",0,0},
{"_icache_size",0,0},
{0,0,0}
};

long ucache_size,scache_size,icache_size;
long mfs_magic;
unsigned short mfs_maj,mfs_min,mfs_plev;

FILE *mfs;

#define MFS_MAGIC 0x18970431
#define MFS_VERIFY 0x100
#define MFS_INFO   0x104

#define S_MAJ 0
#define S_MIN 1
#define S_PLEV 2
#define S_MAGIC 3
#define S_UCACHE 4
#define S_SCACHE 5
#define S_ICACHE 6




int main(argc,argv)
int argc;
char **argv;
{

if (argc != 2 && argc != 5) usage();
if (get_binfo (argv[1])) exit (0);
if (argc==2) {
  printf ("Minixfs version %d.%d Patch level %d\n", mfs_maj, mfs_min, mfs_plev);
  printf ("User   cache size %ldK\n", ucache_size);
  printf ("System cache size %ldK\n", scache_size);
  printf ("Inode  cache size %ldK\n", icache_size);
  exit (0);
}

ucache_size = atol (argv[2]);
scache_size = atol (argv[3]);
icache_size = atol (argv[4]);
save_bin (argv[1]);

exit (0);

}

usage ()
{
  fprintf (stderr, "Usage: csize minix.xfs [ucache scache icache]\n");
}

int get_binfo(fpath)
char *fpath;
{

	switch(nlist(fpath,nl))
	{
		case 0:			/* Got all symbols */
		break;

		case 1:			/* One symbol not found */
		if(nl[S_PLEV].n_type==0) break; /* OK if patchlevel */
		default:		/* More than one */
		alert_err("Can't Find All Symbols");
		return 1;
		
		case -1:	/* Some other error */
		switch(errno)
		{

			case EDOM:
			alert_err("Stripped Binary");
			break;

			case ENOEXEC:
			alert_err("Not Executable File");
			break;

			default:
			alert_err("Error Reading file");
		}
		return 1;
	}		

	if(load_bin(fpath))
	{
		alert_err("Error Reading Symbols");	
		return 1;
	}

	return 0;
}

alert_err (mess)
char *mess;
{
	fprintf (stderr, "csize: %s\n", mess);
}


/* Load all symbols from binary into variables */
#define HDR	sizeof(struct aexec)
#define N_OFF(x) (nl[x].n_value+HDR)
#define N_READ(x) (fread(&x,sizeof(x),1,mfs)!=1)

#define get_short(x,y) get_var(x,y,sizeof(short))
#define get_long(x,y)  get_var(x,y,sizeof(long))
#define put_short(x,y) put_var(x,y,sizeof(short))
#define put_long(x,y)  put_var(x,y,sizeof(long))

int load_bin(fpath)
char *fpath;
{	if(! (mfs=fopen(fpath,"rb"))) return 1;

	if( get_long(&mfs_magic,S_MAGIC) ) return 1;

	if(mfs_magic!=MFS_MAGIC)
	{
		fclose(mfs);
		return 1;
	}

	if( get_short(&mfs_maj,S_MAJ) ) return 1;
	if( get_short(&mfs_min,S_MIN) ) return 1;
	if( get_short(&mfs_plev,S_PLEV) ) return 1;	

	if( get_long(&ucache_size,S_UCACHE) ) return 1;
	if( get_long(&scache_size,S_SCACHE) ) return 1;
	if( get_long(&icache_size,S_ICACHE) ) return 1;

	fclose(mfs);
	return 0;
}

int save_bin(fpath)
char *fpath;
{
	if(! (mfs=fopen(fpath,"rb+"))) return 1;

	if( put_long(&ucache_size,S_UCACHE) ) return 1;
	if( put_long(&scache_size,S_SCACHE) ) return 1;
	if( put_long(&icache_size,S_ICACHE) ) return 1;

	fclose(mfs);
	return 0;
}


int get_var(ptr,sym,len)
void *ptr;
int sym;
int len;
{
	if(fseek(mfs,nl[sym].n_value+HDR,SEEK_SET))
	{
		fclose(mfs);
		return 1;
	}

	if(fread(ptr,len,1,mfs)!=1)
	{
		fclose(mfs);
		return 1;
	}
	return 0;
}

int put_var(ptr,sym,len)
void *ptr;
int sym;
int len;
{
	if(fseek(mfs,nl[sym].n_value+HDR,SEEK_SET))
	{
		fclose(mfs);
		return 1;
	}

	if(fwrite(ptr,len,1,mfs)!=1)
	{
		fclose(mfs);
		return 1;
	}
	return 0;
}


