From FreeBSD's mkdosfs:

- KNF
	- cleaned up a few typos.
	- use the msdosfs header files.
	- separated Makefile and Makefile.boot, since we cannot build
	  bootcode.h (yet)
ToDo:
	- Make it work on hard disks; only works on floppies
	- Make it accept an msdos.sys io.sys and a command.com, to make
	  a real dos bootable disk.
This commit is contained in:
christos 1997-03-01 19:42:54 +00:00
parent edc5dadbab
commit d5fff03ed1
6 changed files with 694 additions and 0 deletions

View File

@ -0,0 +1,9 @@
# $NetBSD: Makefile,v 1.1 1997/03/01 19:42:54 christos Exp $
# Id: Makefile,v 1.3 1997/02/22 16:06:35 peter Exp
#
PROG=newfs_msdos
MAN=newfs_msdos.8
CFLAGS+= -I${.CURDIR}/../../sys/msdosfs -Wall -Wno-unused
.include <bsd.prog.mk>

View File

@ -0,0 +1,53 @@
###################################################################
#
# Everything below is solely intented for maintenance.
# As you can see, it requires as86/ld86 from the ``bcc'' package.
#
# For this reason, the bootcode.h target puts the result into
# ${.CURDIR}
AS86= as86
LD86= ld86
AS86FLAGS= -0
LD86FLAGS= -0 -s
CLEANFILES+= *.obj *.bin *.com
.SUFFIXES: .asm .obj .bin .com
.asm.obj:
${AS86} ${AS86FLAGS} -o ${.TARGET} ${.IMPSRC}
.obj.bin:
${LD86} ${LD86FLAGS} -T 0x7c00 -o ${.PREFIX}.tmp ${.IMPSRC}
dd bs=32 skip=1 of=${.TARGET} if=${.PREFIX}.tmp
rm -f ${.PREFIX}.tmp
# .com file is just for testing
.obj.com:
${LD86} ${LD86FLAGS} -T 0x100 -o ${.PREFIX}.tmp ${.IMPSRC}
dd bs=32 skip=1 of=${.TARGET} if=${.PREFIX}.tmp
rm -f ${.PREFIX}.tmp
## Do NOT depend this on bootcode.bin unless you've installed the
## bcc package!
bootcode.h: ## bootcode.bin
@echo converting bootcode.bin into bootcode.h...
@perl -e 'if(read(STDIN,$$buf,512)<512) { \
die "Read error on .bin file\n"; \
} \
@arr = unpack("C*",$$buf); \
print "#ifndef BOOTCODE_H\n"; \
print "#define BOOTCODE_H 1\n\n"; \
print "/*\n * This file has been generated\n"; \
print " * automatically. Do not edit.\n */\n\n"; \
print "static unsigned char bootcode[512] = {\n"; \
for($$i=0; $$i<512; $$i++) { \
printf "0x%02x, ",$$arr[$$i]; \
if($$i % 12 == 11) {print "\n";} \
} \
print "};\n\n"; \
print "#endif /* BOOTCODE_H */\n";' \
< bootcode.bin > ${.CURDIR}/bootcode.h
.include <bsd.prog.mk>

View File

@ -0,0 +1,103 @@
;;; $NetBSD: bootcode.asm,v 1.1 1997/03/01 19:42:56 christos Exp $
;;; Hello emacs, this looks like -*- asm -*- code, doesn't it?
;;;
;;; This forms a simple dummy boot program for use with a tool to
;;; format DOS floppies. All it does is displaying a message, and
;;; recover gracefully by re-initializing the CPU.
;;;
;;; Written by Joerg Wunsch, Dresden. Placed in the public domain.
;;; This software is provided as is, neither kind of warranty applies.
;;; Use at your own risk.
;;;
;;; (This is written in as86 syntax. as86 is part of Bruce Evans'
;;; bcc package.)
;;;
;;; Id: bootcode.asm,v 1.3 1997/02/22 16:06:36 peter Exp
;;;
;;; This code must be linked to address 0x7c00 in order to function
;;; correctly (the BIOS boot address).
;;;
;;; It's 16-bit code, and we don't care for a data segment.
use16
.text
entry _begin
_begin: jmp init ; jump to boot prog
nop ; historical baggage ;-)
;;;
;;; Reserve space for the "BIOS parameter block".
;;; This will be overwritten by the actual formatting routine.
;;;
bpb: .ascii "BSD 4.4" ; "OEM" name
.word 512 ; sector size
.byte 2 ; cluster size
.word 1 ; reserved sectors (just the boot sector)
.byte 2 ; FAT count
.word 112 ; # of entries in root dir
.word 1440 ; total number of sectors, MSDOS 3.3 or below
.byte 0xf9 ; "media descriptor"
.word 3 ; FAT size (sectors)
.word 9 ; sectors per track
.word 2 ; heads per cylinder
.word 0 ; hidden sectors
;; MSDOS 4.0++ -- only valid iff total number of sectors == 0
.word 0 ; unused
.long 0 ; total number of sectors
.short 0 ; physical drive (0, 1, ..., 0x80) %-)
.byte 0 ; "extented boot signature"
.long 0 ; volume serial number (i.e., garbage :)
.ascii " " ; label -- same as vol label in root dir
.ascii "FAT12 " ; file system ID
;;;
;;; Executable code starts here.
;;;
init:
;; First, display our message.
mov si, *message
lp1: seg cs
movb al, [si]
inc si
testb al, al
jz lp2 ; null-terminated string
movb bl, *7 ; display with regular attribute
movb ah, *0x0e ; int 0x10, fnc 0x0e -- emulate tty
int 0x10
jmp lp1
lp2: xorb ah, ah ; int 0x16, fnc 0x00 -- wait for keystroke
int 0x16
mov ax, *0x40 ; write 0x1234 to address 0x472 --
push ax ; tell the BIOS that this is a warm boot
pop dx
mov 0x72, *0x1234
jmpf 0xfff0,0xf000 ; jump to CPU initialization code
message:
.byte 7
.byte 0xc9
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xbb, 13, 10, 0xba
.ascii " Sorry, this disc does actually not contain "
.byte 0xba, 13, 10, 0xba
.ascii " a bootable system. "
.byte 0xba, 13, 10, 0xba
.ascii " Press any key to reboot. "
.byte 0xba, 13, 10, 0xc8
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd
.byte 0xbc, 13,10
.byte 0
;; Adjust the value below after changing the length of
;; the code above!
.space 0x1fe-0x161 ; pad to 512 bytes
.byte 0x55, 0xaa ; yes, we are bootable (cheating :)
end

View File

@ -0,0 +1,54 @@
#ifndef BOOTCODE_H
#define BOOTCODE_H 1
/*
* This file has been generated
* automatically. Do not edit.
*/
static unsigned char bootcode[512] = {
0xeb, 0x3c, 0x90, 0x42, 0x53, 0x44, 0x20, 0x20, 0x34, 0x2e, 0x34, 0x00,
0x02, 0x02, 0x01, 0x00, 0x02, 0x70, 0x00, 0xa0, 0x05, 0xf9, 0x03, 0x00,
0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x32, 0x20,
0x20, 0x20, 0xbe, 0x65, 0x7c, 0x2e, 0x8a, 0x04, 0x46, 0x84, 0xc0, 0x74,
0x08, 0xb3, 0x07, 0xb4, 0x0e, 0xcd, 0x10, 0xeb, 0xf0, 0x30, 0xe4, 0xcd,
0x16, 0xb8, 0x40, 0x00, 0x50, 0x5a, 0xc7, 0x06, 0x72, 0x00, 0x34, 0x12,
0xea, 0xf0, 0xff, 0x00, 0xf0, 0x07, 0xc9, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xbb, 0x0d, 0x0a, 0xba, 0x20, 0x20, 0x53,
0x6f, 0x72, 0x72, 0x79, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x64,
0x69, 0x73, 0x63, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x61, 0x63, 0x74,
0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f,
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x20, 0xba, 0x0d, 0x0a, 0xba, 0x20,
0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20,
0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xba, 0x0d, 0x0a,
0xba, 0x20, 0x20, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79,
0x20, 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x65, 0x62, 0x6f,
0x6f, 0x74, 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xba,
0x0d, 0x0a, 0xc8, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
0xcd, 0xbc, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, };
#endif /* BOOTCODE_H */

View File

@ -0,0 +1,137 @@
.\" $NetBSD: newfs_msdos.8,v 1.1 1997/03/01 19:42:57 christos Exp $
.\"
.\" Copyright (c) 1997 Christos Zoulas
.\" Copyright (c) 1995, 1996 Joerg Wunsch
.\"
.\" All rights reserved.
.\"
.\" This program is free software.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" Id: mkdosfs.1,v 1.5 1997/02/22 16:06:38 peter Exp
.\"
.Dd February 25, 1997
.Os
.Dt NEWFS_MSDOS 8
.Sh NAME
.Nm newfs_msdos
.Nd create an MS-DOS (FAT) file system
.Sh SYNOPSIS
.Nm
.Bq Fl f Ar capacity
.Bq Fl L Ar vollabel
.Ar device
.Sh DESCRIPTION
.Nm
establishes a file system structure on
.Ar device
that is understood by
.Xr mount_msdos
and some ancient program loader.
.Ar Device
will typically be the character device node for a floppy disk drive,
.Pq e.\ g. Pa /dev/rfd0 ,
although any existing writable file or device is acceptable. In case
of a regular file it is treated as a dumped image of an MS-DOS file
system; only the file system structure will be written to it, and it
won't be truncated.
.Pp
The options are as follows:
.Bl -tag -width 10n -offset indent
.It Fl f Ar capacity
Use defaults for a typical file system with
.Ar capacity
kilobytes. Currently, the values 360, 720, 1200, and 1440 are
recognized.
.Pp
If this option is not specified,
.Nm
attempts to determine the size of the
.Ar device .
This is not reliably possible in all cases, but is believed to work
for the more common situations.
.It Fl L Ar vollabel
Use
.Ar vollabel
to describe the file system, instead of the default
.Ql 4.4BSD .
.El
.Pp
The file system structure consists of three major areas:
.Bl -tag -width 10n -offset indent
.It Em The bootsector
This is the very first (512-byte) sector. It contains executable
code that normally would bootstrap an operating system when loaded.
Since it's beyond the scope of
.Nm
to install an operating system on the medium, this boot code will only
print a message that the disk does not contain a bootable system.
Inside the
.Em bootsector
is the
.Em BIOS parameter block (BPB) ,
where several statistical parameters of the file system are being
held.
.It Em The file allocation table(s) (FAT)
Sectors next to the
.Em bootsector
hold the FAT, which is used to register file system allocation,
as well as keeping pointer chains for the chunks constituting
one file. There are usually two identical copies of the FAT.
.It Em The root directory
The final structure is the root directory for this medium. It is
merely a space reservation, padded with 0's, and unfortunately fixed
in its size.
.Nm
initializes it to empty, and enters a volume label record into the
very first directory slot.
.Sh DIAGNOSTICS
An exit status of 0 is returned upon successful operation. Exit status
1 is returned on any errors during file system creation, and an exit status
of 2 reflects invalid arguments given to the program (along with an
appropriate information written to diagnostic output).
.Sh SEE ALSO
.Xr fdformat 1 ,
.Xr mount_msdos 8 ,
.Xr newfs 8 .
.Sh BUGS
There is currently no way to specify obscure file system parameters.
Thus, only media with one of the supported capacity values can be
formatted. For the same reason, it's not possible to handle hard disk
partitions. More options should be added to allow this. More entries
should be added to the table of known formats, too.
.Pp
No attempt is made to handle media defects. However, this is beyond
the scope of
.Nm
and should better be handled by the (nonexistent)
.Xr dosfsck 1
utility.
.Sh HISTORY
.Nm
appeared in FreeBSD-2.2.
.\" .Fx 2.2 .
.Sh AUTHOR
The program has been contributed by
.if n Joerg Wunsch,
.if t J\(:org Wunsch,
Dresden.

View File

@ -0,0 +1,338 @@
/* $NetBSD: newfs_msdos.c,v 1.1 1997/03/01 19:42:57 christos Exp $ */
/*
* Copyright (c) 1997 Christos Zoulas
* Copyright (c) 1995, 1996 Joerg Wunsch
*
* All rights reserved.
*
* This program is free software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Create an MS-DOS (FAT) file system.
*
* Id: mkdosfs.c,v 1.4 1997/02/22 16:06:38 peter Exp
*/
#ifndef lint
static char rcsid[] = "$NetBSD: newfs_msdos.c,v 1.1 1997/03/01 19:42:57 christos Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <memory.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
/* From msdosfs */
#include <direntry.h>
#include <bpb.h>
#include <bootsect.h>
#include "bootcode.h"
struct descrip {
/* our database key */
unsigned kilobytes;
/* MSDOS 3.3 BPB fields */
u_short sectsiz;
u_char clustsiz;
u_short ressecs;
u_char fatcnt;
u_short rootsiz;
u_short totsecs;
u_char media;
u_short fatsize;
u_short trksecs;
u_short headcnt;
u_short hidnsec;
/* MSDOS 4 BPB extensions */
u_long ext_totsecs;
u_short ext_physdrv;
u_char ext_extboot;
char ext_label[11];
char ext_fsysid[8];
};
static struct descrip table[] = {
/* NB: must be sorted, starting with the largest format! */
/*
* KB sec cls res fat rot tot med fsz spt hds hid
* tot phs ebt label fsysid
*/
{ 1440, 512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, 0,
0, 0, 0, "4.4BSD ", "FAT12 " },
{ 1200, 512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, 0,
0, 0, 0, "4.4BSD ", "FAT12 " },
{ 720, 512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, 0,
0, 0, 0, "4.4BSD ", "FAT12 " },
{ 360, 512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, 0,
0, 0, 0, "4.4BSD ", "FAT12 " },
{ 0, 0, 0, 0, 0, 0, 0, 0x00, 0, 0, 0, 0,
0, 0, 0, " ", " " }
};
struct fat {
u_int8_t media; /* the media descriptor again */
u_int8_t padded; /* always 0xff */
u_int8_t contents[1]; /* the `1' is a placeholder only */
};
int main __P((int, char *[]));
static void usage __P((void));
static size_t findformat __P((int));
static void setup_boot_sector_from_template __P((union bootsector *,
struct descrip *));
static void
usage()
{
extern char *__progname;
(void) fprintf(stderr,
"Usage: %s [-f <kbytes>] [-L <label>] <device>\n", __progname);
exit(1);
}
/*
* Try to deduce a format appropriate for our disk.
* This is a bit tricky. If the argument is a regular file, we can
* lseek() to its end and get the size reported. If it's a device
* however, lseeking doesn't report us any useful number. Instead,
* we try to seek just to the end of the device and try reading a
* block there. In the case where we've hit exactly the device
* boundary, we get a zero read, and thus have found the size.
* Since our knowledge of distinct formats is limited anyway, this
* is not a big deal at all.
*/
static size_t
findformat(fd)
int fd;
{
struct stat sb;
off_t offs;
if (fstat(fd, &sb) == -1)
err(1, "Cannot fstat disk"); /* Cannot happen */
if (S_ISREG(sb.st_mode)) {
if (lseek(fd, (off_t) 0, SEEK_END) == -1 ||
(offs = lseek(fd, (off_t) 0, SEEK_CUR)) == -1)
/* Hmm, hmm. Hard luck. */
return 0;
return (size_t) (offs / 1024);
} else if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
char b[512];
int rv;
struct descrip *dp;
for (dp = table; dp->kilobytes != 0; dp++) {
offs = dp->kilobytes * 1024;
if (lseek(fd, offs, SEEK_SET) == -1)
/* Uh-oh, lseek() is not supposed to fail. */
return 0;
if ((rv = read(fd, b, 512)) == 0)
break;
/*
* XXX The ENOSPC is for the bogus fd(4) driver
* return value.
*/
if (rv == -1 && errno != EINVAL && errno != ENOSPC)
return 0;
/* else: continue */
}
(void) lseek(fd, (off_t) 0, SEEK_SET);
return dp->kilobytes;
} else
/* Outta luck. */
return 0;
}
static void
setup_boot_sector_from_template(bs, dp)
union bootsector *bs;
struct descrip *dp;
{
struct byte_bpb50 bpb;
assert(sizeof(bs->bs50) == 512);
assert(sizeof(bootcode) == 512);
(void) memcpy(&bs->bs50, bootcode, 512);
putushort(bpb.bpbBytesPerSec, dp->sectsiz);
bpb.bpbSecPerClust = dp->clustsiz;
putushort(bpb.bpbResSectors, dp->ressecs);
bpb.bpbFATs = dp->fatcnt;
putushort(bpb.bpbRootDirEnts, dp->rootsiz);
putushort(bpb.bpbSectors, dp->totsecs);
bpb.bpbMedia = dp->media;
putushort(bpb.bpbFATsecs, dp->fatsize);
putushort(bpb.bpbSecPerTrack, dp->trksecs);
putushort(bpb.bpbHeads, dp->headcnt);
putulong(bpb.bpbHiddenSecs, dp->hidnsec);
putulong(bpb.bpbHugeSectors, dp->ext_totsecs);
bs->bs50.bsDriveNumber = dp->ext_physdrv;
bs->bs50.bsBootSignature = dp->ext_extboot;
/* assign a "serial number" :) */
srandom((unsigned) time((time_t) 0));
putulong(bs->bs50.bsVolumeID, random());
(void) memcpy(bs->bs50.bsVolumeLabel, dp->ext_label,
MIN(sizeof(dp->ext_label), sizeof(bs->bs50.bsVolumeLabel)));
(void) memcpy(bs->bs50.bsFileSysType, dp->ext_fsysid,
MIN(sizeof(dp->ext_fsysid), sizeof(bs->bs50.bsFileSysType)));
(void) memcpy(bs->bs50.bsBPB, &bpb,
MIN(sizeof(bpb), sizeof(bs->bs50.bsBPB)));
}
int
main(argc, argv)
int argc;
char *argv[];
{
union bootsector bs;
struct descrip *dp;
struct fat *fat;
struct direntry *rootdir;
struct tm *tp;
time_t now;
int c, i, fd, format = 0, rootdirsize, fatsz;
const char *label = 0;
while ((c = getopt(argc, argv, "f:L:")) != -1)
switch (c) {
case 'f':
format = atoi(optarg);
break;
case 'L':
label = optarg;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
if ((fd = open(argv[0], O_RDWR | O_EXCL, 0)) == -1)
err(1, "Cannot open `%s'", argv[0]);
/* If no format specified, try to figure it out. */
if (format == 0 && (format = findformat(fd)) == 0)
errx(1, "Cannot determine size, must use -f format");
for (dp = table; dp->kilobytes != 0; dp++)
if (dp->kilobytes == format)
break;
if (dp->kilobytes == 0)
errx(1, "Cannot find format description for %d KB", format);
/* prepare and write the boot sector */
setup_boot_sector_from_template(&bs, dp);
/* if we've got an explicit label, use it */
if (label)
(void) strncpy(bs.bs50.bsVolumeLabel, label, 11);
if (write(fd, &bs, sizeof bs) != sizeof bs)
err(1, "Writing boot sector");
/* now, go on with the FATs */
if ((fat = (struct fat *) malloc(dp->sectsiz * dp->fatsize)) == NULL)
err(1, "Out of memory (FAT table)");
(void) memset(fat, 0, dp->sectsiz * dp->fatsize);
fat->media = dp->media;
fat->padded = 0xff;
fat->contents[0] = 0xff;
if (dp->totsecs > 20740 ||
(dp->totsecs == 0 && dp->ext_totsecs > 20740))
/* 16-bit FAT */
fat->contents[1] = 0xff;
fatsz = dp->sectsiz * dp->fatsize;
for (i = 0; i < dp->fatcnt; i++)
if (write(fd, fat, fatsz) != fatsz)
err(1, "Writing FAT %d", i);
free(fat);
/* finally, build the root dir */
rootdirsize = dp->rootsiz * sizeof(struct direntry);
rootdirsize = roundup(rootdirsize, dp->clustsiz * dp->sectsiz);
if ((rootdir = (struct direntry *) malloc(rootdirsize)) == NULL)
err(1, "Out of memory (root directory)");
(void) memset(rootdir, 0, rootdirsize);
/* set up a volume label inside the root dir :) */
if (label)
(void) strncpy(rootdir->deName, label, 11);
else
(void) memcpy(rootdir->deName, dp->ext_label, 11);
rootdir->deAttributes = ATTR_VOLUME;
now = time((time_t) 0);
tp = localtime(&now);
rootdir->deCTime[0] = tp->tm_sec / 2;
rootdir->deCTime[0] |= (tp->tm_min & 7) << 5;
rootdir->deCTime[1] = ((tp->tm_min >> 3) & 7);
rootdir->deCTime[1] |= tp->tm_hour << 3;
rootdir->deCDate[0] = tp->tm_mday;
rootdir->deCDate[0] |= ((tp->tm_mon + 1) & 7) << 5;
rootdir->deCDate[1] = ((tp->tm_mon + 1) >> 3) & 1;
rootdir->deCDate[1] |= (tp->tm_year - 80) << 1;
if (write(fd, rootdir, rootdirsize) != rootdirsize)
err(1, "Writing root directory");
(void) close(fd);
return 0;
}