geoff@utcs.uucp (11/30/85)
Index: etc/newfs.c 4.2BSD Index: man/man8/mkfs.8 4.2BSD Description: Newfs used to require that the special file name argument be of the form /dev/ra6t, which is unnecessarily and offensively restrictive. We have links, bearing the names of the file systems which live upon them, to the special files of the form /dev/ra7q and normally use the mnemonic names, such as /dev/usr. Our machines have varying disk layouts and models of disk and it is highly inconvenient to have to determine the other name of /dev/tmp if we want to newfs it, the moreso since newfs is the only program so afflicted. mkfs(8) didn't document its final parameter, bytes per i-node, nor that it silently limits certain values. installboot used to be undocumented. Repeat-By: Try to "newfs /dev/tmp ra81" and watch it fail. Read mkfs(8); note the absence of a description of the parameter following rps and the stunning silence regarding its sullen misbehaviour when given extreme values. Type "man installboot"; note the lack of a manual page. Fix: Apply the patches below to newfs.c and mkfs.8 respectively. The patch to newfs means that it will not install a boot program on a root partition, since this is now very difficult for newfs. This never belonged in newfs to start with and on the rare occasions that it is needed, can be done trivially by the undocumented /usr/mdec/installboot (source and de facto documentation in /sys/mdec/installboot.c). Connoisseurs of poor coding practices may note that the installboot function of newfs almost, but not quite, exactly duplicates the source of /sys/mdec/installboot.c, courtesy of code sharing via the editor. A brand-new, shiny installboot(8) is included. *** /tmp/,RCSt1009574 Sat Nov 30 08:33:49 1985 --- /tmp/,RCSt2009574 Sat Nov 30 08:33:51 1985 *************** *** 38,44 char a8[20]; char a9[20]; char a10[20]; - char device[MAXPATHLEN]; char cmd[BUFSIZ]; char *index(); --- 38,43 ----- char a8[20]; char a9[20]; char a10[20]; char cmd[BUFSIZ]; char *index(); *************** *** 53,58 register struct disktab *dp; register struct partition *pp; register int i; char *cp, *special; int status; struct stat st; --- 52,58 ----- register struct disktab *dp; register struct partition *pp; register int i; + int status, part = -1; char *cp, *special; struct stat st; *************** *** 54,60 register struct partition *pp; register int i; char *cp, *special; - int status; struct stat st; argc--, argv++; --- 54,59 ----- register int i; int status, part = -1; char *cp, *special; struct stat st; argc--, argv++; *************** *** 175,180 (void) fprintf(stderr, "\t-i number of bytes per inode\n"); exit(1); } special = argv[0]; cp = rindex(special, '/'); if (cp != 0) --- 174,186 ----- (void) fprintf(stderr, "\t-i number of bytes per inode\n"); exit(1); } + + /* + * If special file is a block device, try to use the raw device. + * Glue "/dev/r" onto the front of the last component of the + * special file name and hope for the best. The result must + * be a character special file or newfs quits. + */ special = argv[0]; if (stat(special, &st) >= 0 && (st.st_mode&S_IFMT) == S_IFBLK) { static char device[MAXPATHLEN]; *************** *** 176,187 exit(1); } 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) { (void) fprintf(stderr, "newfs: "); perror(special); exit(2); --- 182,196 ----- * be a character special file or newfs quits. */ special = argv[0]; ! if (stat(special, &st) >= 0 && (st.st_mode&S_IFMT) == S_IFBLK) { ! static char device[MAXPATHLEN]; ! ! cp = rindex(special, '/'); ! if (cp != NULL) /* name contains a slash */ ! special = cp + 1; /* point at last component */ ! (void) sprintf(device, "/dev/r%s", special); ! special = device; ! } if (stat(special, &st) < 0) { (void) fprintf(stderr, "newfs: "); perror(special); *************** *** 183,189 special++; special = sprintf(device, "/dev/r%s", special); if (stat(special, &st) < 0) { ! (void) fprintf(stderr, "newfs: "); perror(special); exit(2); } if ((st.st_mode & S_IFMT) != S_IFCHR) --- 192,199 ----- special = device; } if (stat(special, &st) < 0) { ! (void) fprintf(stderr, "newfs: "); ! perror(special); exit(2); } if ((st.st_mode & S_IFMT) != S_IFCHR) *************** *** 188,193 } if ((st.st_mode & S_IFMT) != S_IFCHR) fatal("%s: not a character device", special); dp = getdiskbyname(argv[1]); if (dp == 0) fatal("%s: unknown disk type", argv[1]); --- 198,211 ----- } if ((st.st_mode & S_IFMT) != S_IFCHR) fatal("%s: not a character device", special); + /* + * Compute disk partition from minor device number. + * This is arguably something that user code should not know + * but it's far cleaner than the previous algorithm. + */ + part = minor(st.st_rdev) % 8; + + /* Grub up the disktab entry */ dp = getdiskbyname(argv[1]); if (dp == 0) fatal("%s: unknown disk type", argv[1]); *************** *** 191,200 dp = getdiskbyname(argv[1]); if (dp == 0) fatal("%s: unknown disk type", argv[1]); ! 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) --- 209,217 ----- dp = getdiskbyname(argv[1]); if (dp == 0) fatal("%s: unknown disk type", argv[1]); ! ! pp = &dp->d_partitions[part]; ! if (fssize == 0) { fssize = pp->p_size; if (fssize < 0) *************** *** 234,239 fatal("%s: no default revolutions/minute value", argv[1]); } if (density <= 0) density = 2048; if (minfree < 0) --- 251,261 ----- fatal("%s: no default revolutions/minute value", argv[1]); } + + /* + * Almost all the useful work of newfs is done here. + * The getdiskbyname above is the rest of it. + */ if (density <= 0) density = 2048; if (minfree < 0) *************** *** 240,245 minfree = 10; if (cpg == 0) cpg = 16; i = 0; av[i++] = sprintf(a2, "%d", fssize); av[i++] = sprintf(a3, "%d", nsectors); --- 262,271 ----- minfree = 10; if (cpg == 0) cpg = 16; + + /* + * This code is broken; ANSI & Uglix sprintf's return ints. + */ i = 0; av[i++] = sprintf(a2, "%d", fssize); av[i++] = sprintf(a3, "%d", nsectors); *************** *** 260,266 (void) printf("%s\n", cmd); if (status = system(cmd)) exit(status); ! if (*cp == 'a' && !noboot) { char type[3]; struct stat sb; --- 286,294 ----- (void) printf("%s\n", cmd); if (status = system(cmd)) exit(status); ! ! if (part == 0 && !noboot) { /* root partition & okay */ ! #ifdef notdef /* would be nice, but needs AI */ char type[3]; struct stat sb; *************** *** 268,275 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'; --- 296,312 ----- if (cp == NULL) fatal("%s: can't figure out disk type from name", special); ! /* If special is a character (raw) device, */ ! if (stat(special, &sb) >= 0 && (sb.st_mode&S_IFMT) == S_IFCHR) ! cp++; /* use the block device */ ! /* ! * Copy 0002 characters for installboot. ! * This simple-minded copy assumes that the special file ! * name is of the form .../rra7q; this is unacceptable, ! * since it requires one to know the mapping from /dev/usr ! * to /dev/rra6t, which is error-prone and varies from ! * machine to machine. ! */ type[0] = *++cp; type[1] = *++cp; type[2] = '\0'; *************** *** 274,279 type[1] = *++cp; type[2] = '\0'; installboot(special, type); } exit(0); } --- 311,319 ----- type[1] = *++cp; type[2] = '\0'; installboot(special, type); + #else + fatal("no boot program installed; use /usr/mdec/installboot"); + #endif } exit(0); } *** /usr/man/man8/mkfs.8 Mon Apr 4 07:08:32 1983 --- mkfs.8 Sat Nov 30 08:20:08 1985 *************** *** 12,17 [ ncpg ] [ minfree ] [ rps ] .SH DESCRIPTION .B N.B.: file system are normally created with the --- 12,18 ----- [ ncpg ] [ minfree ] [ rps ] + [ bpino ] .SH DESCRIPTION .B N.B.: file system are normally created with the *************** *** 61,66 If a disk does not revolve at 60 revolutions per second, the .B rps parameter may be specified. Users with special demands for their file systems are referred to the paper cited below for a discussion of the tradeoffs in using different configurations. --- 62,74 ----- If a disk does not revolve at 60 revolutions per second, the .I rps parameter may be specified. + .I Bpino + is the number of data bytes per i-node: + an i-node will be allocated for every + .I bpino + bytes allocated to data, + subject to the BUGS below. + .PP Users with special demands for their file systems are referred to the paper cited below for a discussion of the tradeoffs in using different configurations. *************** *** 76,78 TR #7, September 1982. .SH BUGS There should be some way to specify bad blocks. --- 84,99 ----- TR #7, September 1982. .SH BUGS There should be some way to specify bad blocks. + .br + .I Mkfs + silently imposes upper and lower limits on various values. + It should tell its invoker what limits have been imposed. + In particular, + decreasing + .I bpino + to give a filesystem more i-nodes may exceed the limit on the + number of i-nodes per cylinder group (MAXIPG in <sys/fs.h>); + in such a case, + try decreasing + .I ncpg + too. .TH INSTALLBOOT 8 local .DA 30 Nov 1985 .SH NAME installboot \- installs a boot program in a file system .SH SYNOPSIS .B /usr/mdec/installboot bootblock bootprog special .SH DESCRIPTION .I Installboot concatentates .I bootblock and .I bootprog and writes at most BBSIZE bytes (from <sys/fs.h>) of them on the first bytes of .IR special . .SH FILES /usr/mdec/??boot boot blocks .br /usr/mdec/boot?? boot programs .SH SEE ALSO newfs(8), dd(1) .SH EXAMPLES cd /usr/mdec .br installboot raboot bootra /dev/ra0a .SH HISTORY .I Installboot comes undocumented with 4.2BSD. This manual page was written by Geoff Collyer. .SH BUGS There is no convenient way to determine the names of the boot blocks and boot programs without .I "a priori" knowledge of one's make of disk.