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

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

#include <sys/nfs_defines.h>

/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
 All rights reserved.\n";
#endif not lint

#ifndef lint
static char sccsid[] = "@(#)newfs.c	5.2 (Berkeley) 9/11/85";
#endif not lint

#ifdef VFS
/* @(#)newfs.c	1.2 87/07/22 3.2/4.3NFSSRC */
#endif VFS

/*
 * newfs: friendly front end to mkfs
 */
#include <sys/param.h>
#include <sys/stat.h>

#ifdef VFS
#include <ufs/fs.h>
#else VFS
#ifndef NOT43
#include <sys/fs.h>
#else
#include <sys/fs1.h>
#endif
#endif VFS
#include <sys/dir.h>
#include <stdio.h>
#include <disktab.h>

#define	BOOTDIR	"/usr/mdec"	/* directory for boot blocks */

int	Nflag;			/* run mkfs without writing file system */
int	verbose;		/* show mkfs line before exec */
int	noboot;			/* do not fill boot blocks */
int	fssize;			/* file system size */
int	fsize;			/* fragment size */
int	bsize;			/* block size */
int	ntracks;		/* # tracks/cylinder */
int	nsectors;		/* # sectors/track */
int	sectorsize;		/* bytes/sector */
int	cpg;			/* cylinders/cylinder group */
int	minfree = -1;		/* free space threshold */
int	opt;			/* optimization preference (space or time) */
int	rpm;			/* revolutions/minute of drive */
int	density;		/* number of bytes per inode */

char	*av[20];		/* argv array and buffers for exec */
char	a2[20];
char	a3[20];
char	a4[20];
char	a5[20];
char	a6[20];
char	a7[20];
char	a8[20];
char	a9[20];
char	a10[20];
char	device[MAXPATHLEN];
char	cmd[BUFSIZ];

char	*index();
char	*rindex();
char	*sprintf();

char	*progname;

#ifdef ibm032
#include <sys/types.h>
#include <sys/ioctl.h>
#include <machine/dkio.h>
struct dkpart dkinfo;
#define MINARGC 1
#else
#define MINARGC 2
#endif


main(argc, argv)
	int argc;
	char *argv[];
{
	char *cp, *special;
	register struct disktab *dp = (struct disktab *) 0;
	register struct partition *pp;
	struct stat st;
	register int i;
	int status;
	char *disktype;

	progname = argv[0];

	argc--, argv++;
	while (argc > 0 && argv[0][0] == '-') {
		for (cp = &argv[0][1]; *cp; cp++)
			switch (*cp) {

			case 'v':
				verbose++;
				break;

			case 'N':
				Nflag++;
				/* fall through to */

			case 'n':
				noboot++;
				break;

			case 's':
				if (argc < 1)
					fatal("-s: missing file system size");
				argc--, argv++;
				fssize = atoi(*argv);
				if (fssize < 0)
					fatal("%s: bad file system size",
						*argv);
				goto next;

			case 't':
				if (argc < 1)
					fatal("-t: missing track total");
				argc--, argv++;
				ntracks = atoi(*argv);
				if (ntracks < 0)
					fatal("%s: bad total tracks", *argv);
				goto next;

			case 'o':
				if (argc < 1)
					fatal("-o: missing optimization preference");
				argc--, argv++;
				if (strcmp(*argv, "space") == 0)
					opt = FS_OPTSPACE;
				else if (strcmp(*argv, "time") == 0)
					opt = FS_OPTTIME;
				else
					fatal("%s: bad optimization preference %s",
					    *argv,
					    "(options are `space' or `time')");
				goto next;

			case 'b':
				if (argc < 1)
					fatal("-b: missing block size");
				argc--, argv++;
				bsize = atoi(*argv);
				if (bsize < 0 || bsize < MINBSIZE)
					fatal("%s: bad block size", *argv);
				goto next;

			case 'f':
				if (argc < 1)
					fatal("-f: missing frag size");
				argc--, argv++;
				fsize = atoi(*argv);
				if (fsize < 0)
					fatal("%s: bad frag size", *argv);
				goto next;

			case 'S':
				if (argc < 1)
					fatal("-S: missing sector size");
				argc--, argv++;
				sectorsize = atoi(*argv);
				if (sectorsize < 0)
					fatal("%s: bad sector size", *argv);
				goto next;

			case 'c':
				if (argc < 1)
					fatal("-c: missing cylinders/group");
				argc--, argv++;
				cpg = atoi(*argv);
				if (cpg < 0)
					fatal("%s: bad cylinders/group", *argv);
				goto next;

			case 'm':
				if (argc < 1)
					fatal("-m: missing free space %%\n");
				argc--, argv++;
				minfree = atoi(*argv);
				if (minfree < 0 || minfree > 99)
					fatal("%s: bad free space %%\n",
						*argv);
				goto next;

			case 'r':
				if (argc < 1)
					fatal("-r: missing revs/minute\n");
				argc--, argv++;
				rpm = atoi(*argv);
				if (rpm < 0)
					fatal("%s: bad revs/minute\n", *argv);
				goto next;

			case 'i':
				if (argc < 1)
					fatal("-i: missing bytes per inode\n");
				argc--, argv++;
				density = atoi(*argv);
				if (density < 0)
					fatal("%s: bad bytes per inode\n",
						*argv);
				goto next;

			default:
				fatal("-%c: unknown flag", *cp);
			}
next:
		argc--, argv++;
	}
	if (argc < MINARGC) 
		usage();			/* no return from here */
	special = argv[0];
	cp = rindex(special, '/');
	if (cp != 0)
		special = cp + 1;
	if (*special == 'r' && special[1] != 'a' && special[1] != 'b')
		special++;
	special = sprintf(device, "/dev/r%s", special);
	if (stat(special, &st) < 0) {
		fprintf(stderr, "%s: ",progname); perror(special);
		exit(2);
	}
	if ((st.st_mode & S_IFMT) != S_IFCHR)
		fatal("%s: not a character device", special);
#ifdef ibm032
/*
 * if disk partition information is available then use that 
 * for size (and also to provide a default disk name)
 */
	if ((i = open(special, 0)) < 0) {
		fprintf(stderr, "%s: ",progname); perror(special);
		exit(2);
	}
	if (ioctl(i, DKIOCGPART, &dkinfo) >= 0 && dkinfo.dk_size) {
		if (verbose)
			printf("device %s partition size %d, type %s\n",special,dkinfo.dk_size,dkinfo.dk_name);
		if (argc < 2) {
			if ((dp = getdiskbyname(disktype = dkinfo.dk_name)) == 0)
				fatal("%s: unknown disk type", dkinfo.dk_name);
		} else {
			if (dkinfo.dk_name[0] && strncmp(argv[1], dkinfo.dk_name, sizeof dkinfo.dk_name)) 
				fprintf(stderr,"%s: warning - actual disk type (%s) differs from one specified (%s)\n",progname,dkinfo.dk_name, argv[1]);
		}
		if (fssize == 0)
			fssize = dkinfo.dk_size;	/* use actual partition size */
	}
	close(i);
	if (dp == 0) {
		if (argc < 2)
			usage();
		else
			dp = getdiskbyname(disktype = argv[1]);
	}
#else
	dp = getdiskbyname(disktype = argv[1]);
#endif ibm032
	if (dp == 0)
		fatal("%s: unknown disk type", disktype);
	cp = index(argv[0], '\0') - 1;
	if (cp == 0 || *cp < 'a' || *cp > 'h')
		fatal("%s: can't figure out file system partition", argv[0]);
	pp = &dp->d_partitions[*cp - 'a'];
	if (fssize == 0) {
		fssize = pp->p_size;
		if (fssize < 0)
			fatal("%s: no default size for `%c' partition",
				disktype, *cp);
	}
	if (nsectors == 0) {
		nsectors = dp->d_nsectors;
		if (nsectors < 0)
			fatal("%s: no default #sectors/track", disktype);
	}
	if (ntracks == 0) {
		ntracks = dp->d_ntracks;
		if (ntracks < 0)
			fatal("%s: no default #tracks", disktype);
	}
	if (sectorsize == 0) {
		sectorsize = dp->d_secsize;
		if (sectorsize < 0)
			fatal("%s: no default sector size", disktype);
	}
	if (bsize == 0) {
		bsize = pp->p_bsize;
		if (bsize < 0)
			fatal("%s: no default block size for `%c' partition",
				disktype, *cp);
	}
	if (fsize == 0) {
		fsize = pp->p_fsize;
		if (fsize < 0)
			fatal("%s: no default frag size for `%c' partition",
				disktype, *cp);
	}
	if (rpm == 0) {
		rpm = dp->d_rpm;
		if (rpm < 0)
			fatal("%s: no default revolutions/minute value",
				disktype);
	}
	if (density <= 0)
		density = 2048;
	if (minfree < 0)
		minfree = 10;
	if (minfree < 10 && opt != FS_OPTSPACE) {
		fprintf(stderr, "setting optimization for space ");
		fprintf(stderr, "with minfree less than 10%%\n");
		opt = FS_OPTSPACE;
	}
	if (cpg == 0)
		cpg = 16;
	i = 0;
	if (Nflag)
		av[i++] = "-N";
	av[i++] = special;
	av[i++] = sprintf(a2, "%d", fssize);
	av[i++] = sprintf(a3, "%d", nsectors);
	av[i++] = sprintf(a4, "%d", ntracks);
	av[i++] = sprintf(a5, "%d", bsize);
	av[i++] = sprintf(a6, "%d", fsize);
	av[i++] = sprintf(a7, "%d", cpg);
	av[i++] = sprintf(a8, "%d", minfree);
	av[i++] = sprintf(a9, "%d", rpm / 60);
	av[i++] = sprintf(a10, "%d", density);
	av[i++] = opt == FS_OPTSPACE ? "s" : "t";
	av[i++] = 0;
	strcpy(cmd, "/etc/mkfs");
	for (i = 0; av[i] != 0; i++) {
		strcat(cmd, " ");
		strcat(cmd, av[i]);
	}
	if (verbose)
		printf("%s\n", cmd);
#ifdef ibm032
	/*
	 * using the c partition of the harddisk requires the bad block table
	 * to be checked.
	 */
	if (*cp == 'c') {
		printf("WARNING: building file system on a 'c' partition. May clobber special\ndisk tables.\n");
	}
	/*
	 * can't boot from the scsi or floppy
	 */
	if (strncmp(disktype,"scsi",4) == 0 || strncmp(disktype,"SCSI",4) == 0){
		noboot++;
	}
	if (strncmp(disktype,"fd",2) == 0 || strncmp(disktype,"FD",2) == 0){
		noboot++;
	}

#endif
	if (status = system(cmd))
		exit(status >> 8);
	if (*cp == 'a' && !noboot) {
		char type[3];
		struct stat sb;

#ifdef ibm032
		cp = index(special, '\0') - 1;
		*cp = 'c';		/* boot goes into c partition */
#endif
		cp = rindex(special, '/');
		if (cp == NULL)
			fatal("%s: can't figure out disk type from name",
				special);
		if (stat(special, &sb) >= 0 && (sb.st_mode & S_IFMT) == S_IFCHR)
			cp++;
		type[0] = *++cp;
		type[1] = *++cp;
		type[2] = '\0';
		installboot(special, type,disktype);
	}
	exit(0);
}

#ifdef ibm032
/*
 * we have space for boothd available from block nsectors*4 to
 * the end of cylinder 1. 
 * in the worst case (hd40m) this is 85-68=17 
 * plus the normal space at the start of hd0a
 */
#define HDBOOT_BLOCK	(nsectors*4)
#define HDBOOT_START (HDBOOT_BLOCK * DEV_BSIZE)
#define HDMIN_CYL	85		/* minimum cylinder size (hd40r) */
#define HDMAX_BOOT	68		/* boot start for worst case */
#define MAXBOOT ((HDMIN_CYL-HDMAX_BOOT) * DEV_BSIZE) + BBSIZE + DEV_BSIZE
#define BOOTBLOCK HDBOOT_BLOCK
#else
#define BOOTBLOCK 1
#define MAXBOOT BBSIZE
#endif

installboot(dev, type, typename)
	char *dev, *type;
	char *typename;
{
	int fd;
	char bootblock[MAXPATHLEN], standalonecode[MAXPATHLEN];
	char bootimage[MAXBOOT];
	int length;

#ifdef ibm032
	sprintf(bootblock, "%s/%sboot", BOOTDIR, typename);
#else
	sprintf(bootblock, "%s/%sboot", BOOTDIR, type);
#endif
	sprintf(standalonecode, "%s/boot%s", BOOTDIR, type);
	if (verbose) {
		printf("installing boot code\n");
		printf("sector 0 boot = %s\n", bootblock);
		printf("1st level boot = %s\n", standalonecode);
	}
	fd = open(bootblock, 0);
	if (fd < 0) {
		fprintf(stderr, "%s: ",progname); perror(bootblock);
		exit(1);
	}
	if ((length = read(fd, bootimage, DEV_BSIZE)) < 0) {
		fprintf(stderr, "%s: ",progname); perror(bootblock);
		exit(2);
	}
	if (length == 0) {
		fprintf(stderr, "%s: Warning - boot block (%s) is empty; not installed\n",
			progname, bootblock);
		close(fd);
		return;
	}
	testeof(fd,bootblock);
	close(fd);
	fd = open(standalonecode, 0);
	if (fd < 0) {
		fprintf(stderr, "%s: ",progname); perror(standalonecode);
		exit(1);
	}
	if (read(fd, &bootimage[DEV_BSIZE], MAXBOOT - DEV_BSIZE) < 0) {
		fprintf(stderr, "%s: ",progname); perror(standalonecode);
		exit(2);
	}
	testeof(fd,standalonecode);
	close(fd);
	fd = open(dev, 1);
	if (fd < 0) {
		fprintf(stderr, "%s: ",progname); perror(dev);
		exit(1);
	}
	if (write(fd, bootimage, DEV_BSIZE) != DEV_BSIZE) {
		fprintf(stderr, "%s: ",progname); perror(dev);
		exit(2);
	}
#ifdef ibm032
	;
	if (lseek(fd, HDBOOT_START, 0) < 0) {
		fprintf(stderr, "%s: ",progname); perror(dev);
		exit(2);
	}
#endif
	if (write(fd, &bootimage[DEV_BSIZE], MAXBOOT-DEV_BSIZE) != MAXBOOT-DEV_BSIZE) {
		fprintf(stderr, "%s: ",progname); perror(dev);
		exit(2);
	}
	close(fd);
}

/*VARARGS*/
fatal(fmt, arg1, arg2)
	char *fmt;
{

	fprintf(stderr, "%s: ",progname);
	fprintf(stderr, fmt, arg1, arg2);
	putc('\n', stderr);
	exit(10);
}

testeof(fd, name)
	char *name;
{
	char temp[DEV_BSIZE];

	if (read(fd, temp, sizeof temp) > 0)
		fprintf(stderr, "%s: WARNING - %s is too big\n",progname,name);

}

#ifdef ibm032

/*
 * check to insure that bad block table is not too large to support a 
 * C partition
 * (e.g. if the bad block table is too large it overlaps the superblock)
 * we allow room for MINSPARE additional bad blocks.
 */
#include <machineio/hdconfig.h>

#define MINSPARE	100		/* allow room for 100 more bad blocks */

check_size(special)
char *special;
{
	register int fd = open(special,0);
	struct hdbadtmp hdbad;

	if (fd < 0) {
		fprintf(stderr,"%s: ",progname);
		perror(special);
		exit(1);
	}
	lseek(fd, BAD_BLOCK_START * DEV_BSIZE, 0);
	if (read(fd, &hdbad, sizeof hdbad) !=  sizeof hdbad)
		perror("reading bad block table");
	if (!BAD_BLOCK_TABLE_OK(&hdbad)) {
		fprintf(stderr,"%s: %s - invalid bad block table\n",progname,special);
		exit(1);
	}
	if ((hdbad.hdcount+MINSPARE) * sizeof (struct hdmap) +
			BAD_BLOCK_START * DEV_BSIZE > BBSIZE) {
		fprintf(stderr,"%s: %s - too many bad blocks on this disk; (use a, b, and g instead)\n",progname,special);
		exit(1);
	}
	close(fd);
}
#endif ibm032

usage()
{
	fprintf(stderr, "usage: %s [ -v ] [ mkfs-options ] %s\n",
		progname,"special-device device-type");
	fprintf(stderr, "where mkfs-options are:\n");
	fprintf(stderr, "\t-N do not create file system, %s\n",
		"just print out parameters");
	fprintf(stderr, "\t-s file system size (sectors)\n");
	fprintf(stderr, "\t-b block size\n");
	fprintf(stderr, "\t-f frag size\n");
	fprintf(stderr, "\t-t tracks/cylinder\n");
	fprintf(stderr, "\t-c cylinders/group\n");
	fprintf(stderr, "\t-m minimum free space %%\n");
	fprintf(stderr, "\t-o optimization preference %s\n",
		"(`space' or `time')");
	fprintf(stderr, "\t-r revolutions/minute\n");
	fprintf(stderr, "\t-S sector size\n");
	fprintf(stderr, "\t-i number of bytes per inode\n");
	exit(1);
}
