Subject: Disklabels arrive for 2.11BSD (#255 part 6 of 18)
Index:	sys,bin,usr.lib,(many more)/<many> 2.11BSD

Description:
	The moving the partitions tables out of the disk drivers and to
	a disklabel residing on the media has been on the wish list for
	many many years.

	Disklabels have finally arrived for 2.11BSD!

Repeat-By:
	Observation.  Also a reading of the setup and installation
	documentation for previous 2BSD releases (2.9, 2.10, 2.11)
	all have a paragraph similar to this present:

"It is possible to change the partitions by changing the code for the
table in the disk driver.  Since it's desirable to do this, these tables
really should be read off each pack...."

Fix:
	This is part 6 of 18.  Gather all parts before doing anything
	except reading the instructions which are in #250 (part 1).

	Updated by this part are:

/usr/src/etc/restor/restor.c
/usr/src/etc/restor/Makefile
/usr/src/etc/newfs.c
/usr/src/etc/mkfs.c

	'newfs' was almost rewritten based on the 4.4-Lite reference model.

	NOTE: The newfs program no longer installs sector 0 bootblocks.  That
	      functionality has been relocated to the 'disklabel' program.

	      When creating a filesystem on a disk for which the device driver
	      does not support labels you must now use the '-T' option to 
	      force 'newfs' to scan /etc/disktab.  OTHERWISE newfs will only
	      make a filesystem if a label is found on the disk.

	      The newfs man page has been updated to reflect the above 
	      changes.

	'restor' must always be built split I/D so some minor changes were
	made to restor.c, nothing major changed.

	restor/Makefile had some minor work done to him, a 'lint' target
	was added.

	'mkfs' had major changes made to deal with disklabels when being
	built for standalone use.  If no label is found the standalone
	mkfs program will refuse to write to the disk.

	WARNING:  do not run 'mkfs' manually (when the kernel is running)
		  unless you are absolutely certain you know what you are
		  doing.  Use 'newfs' instead.  The 'newfs' program has
		  several safety checks and looks for the partition information
		  in the disklabel, etc.

	Cut where indicated and save to a file (/tmp/255).  Then:

		patch -p0 < /tmp/255
		rm /tmp/255

---------------------------cut here----------------------
*** /usr/src/etc/restor/restor.c.old	Sat Apr 13 17:02:58 1991
--- /usr/src/etc/restor/restor.c	Fri Jun  9 23:08:29 1995
***************
*** 1,8 ****
  /*
!  *	NOTE:	This Program is must be loaded 407
!  *		to run standalone.  Make sure to keep
!  *		the size under 48K or it will run out
!  *		of stack space
   */
  
  #include <sys/param.h>
--- 1,11 ----
  /*
!  * 1995/06/09 - standalone restor must be loaded split I/D because the
!  *		disklabel handling increased the size of standalone programs.
!  *		This is not too much of a problem since the Kernel has been
!  *		required to be split I/D for several years.
!  *
!  *		Since split I/D is now required the NCACHE parameter is no
!  *		longer ifdef'd on STANDALONE (and is always 3 instead of 1).
   */
  
  #include <sys/param.h>
***************
*** 13,23 ****
  #endif
  #define BITS	8
  #define MAXXTR	60
- #ifndef	STANDALONE
  #define NCACHE	3
- #else
- #define NCACHE	1	/* Size reduction as refered to above */
- #endif
  #define	flsht()	(bct = NTREC + 1)
  
  #ifndef STANDALONE
--- 16,22 ----
*** /usr/src/etc/restor/Makefile.old	Mon Jan 18 08:46:49 1993
--- /usr/src/etc/restor/Makefile	Thu Jun  8 22:38:41 1995
***************
*** 1,12 ****
  #
! # restor makefile
  #
  
- # If SEPFLAG is not "-i" then DEFS must include "-DNONSEPARATE" on the
- # PDP-11.  Ex:
- #	SEPFLAG= -n
- #	DEFS= -DNONSEPARATE
- 
  SEPFLAG= -i
  DEFS= 
  CFLAGS=	-O -I. ${DEFS}
--- 1,7 ----
  #
! # restor makefile - SEPFLAG must be -i, restor will not run unless built -i
  #
  
  SEPFLAG= -i
  DEFS= 
  CFLAGS=	-O -I. ${DEFS}
***************
*** 28,30 ****
--- 23,28 ----
  	for i in ${SRCS}; do \
  		ctags -a -f tags $$cwd/$$i; \
  	done
+ 
+ lint:
+ 	lint -haxcz restor.c
*** /usr/src/etc/newfs.c.old	Sat Dec 28 21:43:26 1991
--- /usr/src/etc/newfs.c	Wed Apr 26 17:46:48 1995
***************
*** 1,3 ****
--- 1,5 ----
+ #define	COMPAT
+ 
  /*
   * Copyright (c) 1983 Regents of the University of California.
   * All rights reserved.  The Berkeley software License Agreement
***************
*** 9,61 ****
  "@(#) Copyright (c) 1983 Regents of the University of California.\n\
   All rights reserved.\n";
  
! static char sccsid[] = "@(#)newfs.c	6.0 (2.11BSD) 12/28/91";
  #endif
  
  /*
   * newfs: friendly front end to mkfs
   */
  #include <sys/param.h>
  #include <sys/stat.h>
! #include <stdio.h>
! #include <disktab.h>
  
  main(argc, argv)
  	int	argc;
  	char	**argv;
  {
! 	extern char	*optarg;
! 	extern int	optind;
! 	register struct disktab	*dp;
  	register struct partition	*pp;
! 	register char	*cp;
  	struct stat	st;
  	long	fssize;
  	int	ch, status, logsec, m;
! 	int	just_looking, copy_boot;
! 	char	*uboot;
! 	char	device[MAXPATHLEN], cmd[BUFSIZ],
! 		*index(), *rindex();
  
- 	just_looking = 0;
- 	copy_boot = 0;
  	m = 0;
! 	uboot = (char *)0;
! 	while ((ch = getopt(argc,argv,"NvbB:m:")) != EOF)
  		switch((char)ch) {
  		case 'N':
  		case 'v':
! 			++just_looking;
  			break;
! 		case 'B':
! 			uboot = optarg;
! 			/*FALLTHROUGH*/
! 		case 'b':
! 			++copy_boot;
  			break;
  		case 'm':
  			m = atoi(optarg);
  			break;
  		case '?':
  		default:
  			usage();
--- 11,87 ----
  "@(#) Copyright (c) 1983 Regents of the University of California.\n\
   All rights reserved.\n";
  
! static char sccsid[] = "@(#)newfs.c	6.1 (2.11BSD) 4/26/95";
  #endif
  
  /*
   * newfs: friendly front end to mkfs
+  *
+  *  The installation of bootblocks has been moved to 'disklabel(8)'.  This
+  *  program expects to find a disklabel present which will contain the
+  *  geometry and partition size information.  If 'newfs' is being run on
+  *  a system without disklabels implemented in the kernel you must specify
+  *  "-T diskname" (where 'diskname' is an entry in /etc/disktab).
   */
+ 
+ #include <stdio.h>
  #include <sys/param.h>
  #include <sys/stat.h>
! #include <sys/ioctl.h>
! #include <sys/disklabel.h>
! #include <sys/disk.h>
! #include <sys/file.h>
  
+ #include <ctype.h>
+ #include <paths.h>
+ #include <syslog.h>
+ #include <varargs.h>
+ 
+ #ifdef	COMPAT
+ 	char	*disktype;
+ 	int	unlabeled;
+ #endif
+ 	int	Nflag;
+ 	struct	disklabel *getdisklabel();
+ 
+ extern	char	*optarg, *__progname;
+ extern	long	atol();
+ extern	int	optind, errno;
+ 
  main(argc, argv)
  	int	argc;
  	char	**argv;
  {
! 	register struct disklabel	*lp;
  	register struct partition	*pp;
! 	char	*cp;
  	struct stat	st;
  	long	fssize;
  	int	ch, status, logsec, m;
! 	int	fsi;
! 	char	device[MAXPATHLEN], cmd[BUFSIZ], *index(), *rindex();
! 	char	*special;
  
  	m = 0;
! 	while ((ch = getopt(argc,argv,"T:Nvm:s:")) != EOF)
  		switch((char)ch) {
  		case 'N':
  		case 'v':
! 			Nflag = 1;
  			break;
! #ifdef	COMPAT
! 		case 'T':
! 			disktype = optarg;
  			break;
+ #endif
  		case 'm':
  			m = atoi(optarg);
  			break;
+ 		case 's':
+ 			fssize = atol(optarg);
+ 			if (fssize <= 0)
+ 				fatal("%s: bad file system size", optarg);
+ 			break;
  		case '?':
  		default:
  			usage();
***************
*** 63,144 ****
  
  	argc -= optind;
  	argv += optind;
! 	if (argc != 2)
  		usage();
  
  	/* figure out device name */
! 	cp = rindex(argv[0], '/');
! 	if (cp)
! 		++cp;
! 	else
! 		cp = argv[0];
! 	if (*cp == 'r' && cp[1] != 'a' && cp[1] != 'b')
! 		++cp;
! 	sprintf(device, "/dev/r%s", cp);
! 
! 	/* see if it exists and of a legal type */
! 	if (stat(device, &st)) {
! 		fprintf(stderr, "newfs: ");
! 		perror(device);
! 		exit(1);
  	}
- 	if ((st.st_mode & S_IFMT) != S_IFCHR) {
- 		fprintf(stderr, "newfs: %s: not a character device.\n", device);
- 		exit(1);
- 	}
  
! 	/* see if disk is in disktab table */
! 	dp = getdiskbyname(argv[1]);
! 	if (dp == 0) {
! 		fprintf(stderr, "newfs: %s not in /etc/disktab.\n", argv[1]);
! 		exit(1);
! 	}
  
! 	/* grab partition letter */
  	cp = index(argv[0], '\0') - 1;
! 	if (cp == 0 || *cp < 'a' || *cp > 'h') {
! 		fprintf(stderr, "newfs: %s: can't figure out file system partition.\n", argv[0]);
! 		exit(1);
! 	}
  
! 	/* get default partition size */
! 	pp = &dp->d_partitions[*cp - 'a'];
! 	fssize = pp->p_size;
! 	if (fssize < 0) {
! 		fprintf(stderr, "newfs: %s: no default size for `%c' partition.\n", argv[1], *cp);
! 		exit(1);
! 	}
  	/*
  	 * Convert from sectors to logical blocks.  Note that sector size
  	 * must evenly devide DEV_BSIZE!!!!!
  	 */
! 	logsec = DEV_BSIZE/dp->d_secsize;
  	fssize /= logsec;
  
  	/* build command */
  	if (m <= 0 || m > 31)
  		m = 2;
! 	sprintf(cmd, "/etc/mkfs %s %ld %d %d", device, fssize, m,
! 	    (dp->d_ntracks * dp->d_nsectors) / logsec);
  	printf("newfs: %s\n", cmd);
! 	if (just_looking)
  		exit(0);
  	if (status = system(cmd))
  		exit(status >> 8);
  
! 	/* copy boot if requested */
! 	if (copy_boot) {
! 		if (!uboot && !(uboot = dp->d_uboot)) {
! 			fprintf(stderr, "newfs: no default boot block available for an %s.\n",
! 				argv[1]);
! 			exit(1);
  		}
! 		sprintf(cmd, "/bin/dd if=%s of=%s bs=512 count=1 conv=sync",
! 		    uboot, device);
! 		if (status = system(cmd))
! 			exit(status >> 8);
  	}
! 	exit(0);
  }
  
  static
--- 89,206 ----
  
  	argc -= optind;
  	argv += optind;
! 	if (argc != 2 && argc != 1)
  		usage();
  
  	/* figure out device name */
! 	special = argv[0];
! 	cp = rindex(special, '/');
! 	if (cp == 0) {
! 		/*
! 		 * No path prefix; try /dev/r%s then /dev/%s
! 		 */
! 		 (void)sprintf(device, "%s/r%s", _PATH_DEV, special);
! 		 if (stat(device, &st) == -1)
! 			(void)sprintf(device, "%s/%s", _PATH_DEV, special);
! 		special = device;
  	}
  
! 	fsi = open(special, O_RDONLY);
! 	if (fsi < 0)
! 		fatal("%s: %s", special, strerror(errno));
  
! 	/* see if it exists and of a legal type */
! 	if (fstat(fsi, &st) == -1)
! 		fatal("%s: %s", special, strerror(errno));
! 	if ((st.st_mode & S_IFMT) != S_IFCHR)
! 		fatal("%s: not a character device", special);
  	cp = index(argv[0], '\0') - 1;
! 	if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp))
! 		fatal("%s: can't figure out file system partition", argv[0]);
  
! #ifdef	COMPAT
! 	if (disktype == NULL)
! 		disktype = argv[1];
! #endif
! 	lp = getdisklabel(special, fsi);
! 	if (isdigit(*cp))
! 		pp = &lp->d_partitions[0];
! 	else
! 		pp = &lp->d_partitions[*cp - 'a'];
! 	if (pp->p_size <= 0)
! 		fatal("%s: '%c' partition is unavailable", argv[0], *cp);
! #ifdef	nothere
! 	if (pp->p_fstype == FS_BOOT)
! 		fatal("%s: '%c' partition  overlaps boot program",argv[0], *cp);
! #endif
! 
! 	if (fssize == 0)
! 		fssize = pp->p_size;
! 	if (fssize > pp->p_size)
! 		fatal("%s: maximum file system size on '%c' partition is %ld",
! 			argv[0], *cp, pp->p_size);
  	/*
  	 * Convert from sectors to logical blocks.  Note that sector size
  	 * must evenly devide DEV_BSIZE!!!!!
  	 */
! 
! 	/*
! 	 * getdisklabel(3) forces the sector size to 512 because any other
! 	 * choice would wreck havoc in the disklabel(8) program and result
! 	 * in corrupted/destroyed filesystems.  DEV_BSIZE had better be
! 	 * 1024!
! 	*/
! 	if (lp->d_secsize != 512)
! 		fatal("%s: sector size not 512", argv[0]);
! 	logsec = DEV_BSIZE/lp->d_secsize;
  	fssize /= logsec;
  
  	/* build command */
  	if (m <= 0 || m > 31)
  		m = 2;
! 	sprintf(cmd, "/etc/mkfs %s %ld %d %d", special, fssize, m,
! 	    	lp->d_secpercyl / logsec);
  	printf("newfs: %s\n", cmd);
! 
! 	close(fsi);
! 
! 	if (Nflag)
  		exit(0);
+ 
  	if (status = system(cmd))
  		exit(status >> 8);
+ 	exit(0);
+ }
  
! #ifdef COMPAT
! char lmsg[] = "%s: can't read disk label; disk type must be specified";
! #else
! char lmsg[] = "%s: can't read disk label";
! #endif
! 
! struct disklabel *
! getdisklabel(s, fd)
! 	char *s;
! 	int fd;
! {
! 	static struct disklabel lab;
! 
! 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
! #ifdef COMPAT
! 		if (disktype) {
! 			struct disklabel *lp, *getdiskbyname();
! 
! 			unlabeled++;
! 			lp = getdiskbyname(disktype);
! 			if (lp == NULL)
! 				fatal("%s: unknown disk type", disktype);
! 			return (lp);
  		}
! #endif
! 		warn("ioctl (GDINFO)");
! 		fatal(lmsg, s);
  	}
! 	return (&lab);
  }
  
  static
***************
*** 145,150 ****
  usage()
  {
  
! 	fputs("usage: newfs [ -N ] [ -b ] [ -B boot-block ] [-m free-list-gap] special-device device-type\n", stderr);
  	exit(1);
  }
--- 207,239 ----
  usage()
  {
  
! 	fprintf(stderr,"usage: %s [-N] [-m freelist-gap] [-s filesystem size] ",
! 		__progname);
! #ifdef	COMPAT
! 	fputs("[-T disk-type] ", stderr);
! #endif
! 	fputs("special-device\n", stderr);
  	exit(1);
+ }
+ 
+ /*VARARGS*/
+ void
+ fatal(fmt, va_alist)
+ 	char *fmt;
+ 	va_dcl
+ {
+ 	va_list ap;
+ 
+ 	va_start(ap);
+ 
+ 	if (fcntl(fileno(stderr), F_GETFL) < 0) {
+ 		openlog(__progname, LOG_CONS, LOG_DAEMON);
+ 		vsyslog(LOG_ERR, fmt, ap);
+ 		closelog();
+ 	} else {
+ 		vwarnx(fmt, ap);
+ 	}
+ 	va_end(ap);
+ 	exit(1);
+ 	/*NOTREACHED*/
  }
*** /usr/src/etc/mkfs.c.old	Thu Jan  6 20:54:41 1994
--- /usr/src/etc/mkfs.c	Mon Jun 12 21:47:18 1995
***************
*** 1,7 ****
! char	*sccsid = "@(#)mkfs.c	2.7";
  
  /*
!  * Make a file system prototype.
   * usage: mkfs filsys size [ m n ]
   */
  #include <sys/param.h>
--- 1,7 ----
! char	*sccsid = "@(#)mkfs.c	2.8 1995/06/12";
  
  /*
!  * Make a file system.  Normally run by 'newfs' and not directly by users.
   * usage: mkfs filsys size [ m n ]
   */
  #include <sys/param.h>
***************
*** 11,25 ****
   * See /sys/h/localtimes.h and /sys/conf.
  */
  #undef	EXTERNALITIMES
- #ifndef STANDALONE
- #include <stdio.h>
- #endif
  
  #include <sys/file.h>
- #include <sys/fs.h>
- #include <sys/inode.h>
  #include <sys/dir.h>
  #include <sys/stat.h>
  
  #define	UMASK	0755
  #define	NIPB	(DEV_BSIZE/sizeof(struct dinode))
--- 11,27 ----
   * See /sys/h/localtimes.h and /sys/conf.
  */
  #undef	EXTERNALITIMES
  
  #include <sys/file.h>
  #include <sys/dir.h>
  #include <sys/stat.h>
+ #ifndef STANDALONE
+ #include <stdio.h>
+ #include <sys/fs.h>
+ #include <sys/inode.h>
+ #else
+ #include "saio.h"
+ #endif
  
  #define	UMASK	0755
  #define	NIPB	(DEV_BSIZE/sizeof(struct dinode))
***************
*** 30,35 ****
--- 32,39 ----
  #ifdef STANDALONE
  int	fin;
  char	module[] = "Mkfs";
+ extern	char	*ltoa();
+ extern	struct	iob	iob[];
  #endif
  
  int	fsi;
***************
*** 47,56 ****
  } filsys;
  
  int	f_n	= 100;
! int	f_m	= 5;
  
! daddr_t	alloc();
  
  main(argc,argv)
  int	argc;
  char	**argv;
--- 51,62 ----
  } filsys;
  
  int	f_n	= 100;
! int	f_m	= 2;
  
! 	daddr_t	alloc();
  
+ extern	long	atol();
+ 
  main(argc,argv)
  int	argc;
  char	**argv;
***************
*** 58,63 ****
--- 64,74 ----
  register int f, c;
  	long n;
  register char *size;
+ #ifdef	STANDALONE
+ 	struct	disklabel *lp;
+ 	struct	partition *pp;
+ 	struct	iob	*io;
+ #endif
  
  #ifndef STANDALONE
  	time(&utime);
***************
*** 66,71 ****
--- 77,90 ----
  		exit(1);
  	}
  	size = argv[2];
+ /*
+  * NOTE: this will fail if the device is currently mounted and the system
+  * is at securelevel 1 or higher.
+  *
+  * We do not get the partition information because 'newfs' has already
+  * done so and invoked us.  This program should not be run manually unless
+  * you are absolutely sure you know what you are doing - use 'newfs' instead.
+ */
  	fso = creat(argv[1], 0666);
  	if(fso < 0) {
  		printf("%s: cannot create\n", argv[1]);
***************
*** 77,82 ****
--- 96,106 ----
  		exit(1);
  	}
  #else
+ /*
+  * Something more modern than January 1, 1970 - the date that the new 
+  * standalone mkfs worked.  1995/06/08 2121.
+ */
+ 	utime = 802671684L;
  	printf("%s\n",module);
  	do {
  		printf("file system: ");
***************
*** 85,97 ****
  		fsi = open(buf, 0);
  	} while (fso < 0 || fsi < 0);
  
! 	printf("file sys size: ");
  	size = buf+128;
  	gets(size);
  	printf("interleaving factor (m; %d default): ", f_m);
  	gets(buf);
  	if (buf[0])
  		f_m = atoi(buf);
  	printf("interleaving modulus (n; %d default): ", f_n);
  	gets(buf);
  	if (buf[0])
--- 109,175 ----
  		fsi = open(buf, 0);
  	} while (fso < 0 || fsi < 0);
  
! /*
!  * If the underlying driver supports disklabels then do not make a file
!  * system unless: there is a valid label present, the specified partition
!  * is of type FS_V71K, and the size is not zero.
!  *
!  * The 'open' above will have already fetched the label if the driver supports
!  * labels - the check below will only fail if the driver doesn't do labels
!  * or if the drive blew up in the millisecond since the last read.
! */
! 	io = &iob[fsi - 3];
! 	lp = &io->i_label;
! 	pp = &lp->d_partitions[io->i_part];
! 
! 	if	(devlabel(io, READLABEL) < 0)
! 		{
! /*
!  * The driver does not implement labels.  The 'iob' structure still contains
!  * a label structure so initialize the items that will be looked at later.
! */
! 		pp->p_size = 0;
! 		lp->d_secpercyl = 0;
! 		goto nolabels;
! 		}
! 	if	(lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
! 		 dkcksum(lp))
! 		{
! 		printf("'%s' is either unlabeled or the label is corrupt.\n",
! 			buf);
! 		printf("Since the driver for '%s' supports disklabels you\n",
! 			buf);
! 		printf("must use the standalone 'disklabel' before making\n");
! 		printf("a filesystem on '%s'\n", buf);
! 		return;
! 		}
! 	if	(pp->p_fstype != FS_V71K)
! 		{
! 		printf("%s is not a 2.11BSD (FS_V71K) partition.", buf);
! 		return;
! 		}
! 	if	(pp->p_size == 0)
! 		{
! 		printf("%s is a zero length partition.\n", buf);
! 		return;
! 		}
! nolabels:
! 	printf("file sys size [%D]: ", dbtofsb(pp->p_size));
  	size = buf+128;
  	gets(size);
+ 	if	(size[0] == '\0')
+ 		strcpy(size, ltoa(dbtofsb(pp->p_size)));
+ 	if	(pp->p_size && atol(size) > pp->p_size)
+ 		{
+ 		printf("specified size is larger than the disklabel says.\n");
+ 		return;
+ 		}
  	printf("interleaving factor (m; %d default): ", f_m);
  	gets(buf);
  	if (buf[0])
  		f_m = atoi(buf);
+ 	if	(lp->d_secpercyl)
+ 		f_n = dbtofsb(lp->d_secpercyl);
  	printf("interleaving modulus (n; %d default): ", f_n);
  	gets(buf);
  	if (buf[0])
***************
*** 112,117 ****
--- 190,200 ----
  		n = n*10 + (c-'0');
  	}
  	filsys.fs.fs_fsize = n;
+ 	if	(!n)
+ 		{
+ 		printf("Can't make zero length filesystem\n");
+ 		return;
+ 		}
  	/*
  	 * Minor hack for standalone root and other
  	 * small filesystems: reduce ilist size.
***************
*** 139,145 ****
  	filsys.fs.fs_cyl = f_n;
  	printf("m/n = %d %d\n", f_m, f_n);
  	if(filsys.fs.fs_isize >= filsys.fs.fs_fsize) {
! 		printf("%ld/%ld: bad ratio\n", filsys.fs.fs_fsize, filsys.fs.fs_isize-2);
  		exit(1);
  	}
  	filsys.fs.fs_tfree = 0;
--- 222,228 ----
  	filsys.fs.fs_cyl = f_n;
  	printf("m/n = %d %d\n", f_m, f_n);
  	if(filsys.fs.fs_isize >= filsys.fs.fs_fsize) {
! 		printf("%D/%D: bad ratio\n", filsys.fs.fs_fsize, filsys.fs.fs_isize-2);
  		exit(1);
  	}
  	filsys.fs.fs_tfree = 0;
