1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-13 10:02:38 +00:00

mkdosfs -- a tool to create an MS-DOS file system on a device or file.

Since msdosfs is part of the base system, it's not wise to rely on
something like mtools to provide this functionality.

This utility is the agreed fix for PR # misc/804      fdformat did not ...
This commit is contained in:
Joerg Wunsch 1995-11-05 16:02:04 +00:00
parent f2959bfd1f
commit 828c68cf7a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/JOERG/; revision=12102
6 changed files with 717 additions and 0 deletions

59
usr.sbin/mkdosfs/Makefile Normal file
View File

@ -0,0 +1,59 @@
# $Id$
#
PROG= mkdosfs
CFLAGS+= -Wall
###################################################################
#
# 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,102 @@
;;; 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$
;;;
;;; 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 */

135
usr.sbin/mkdosfs/dosfs.h Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 1995 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.
*/
/*
* MS-DOS (FAT) file system structure definitions.
*
* $Id$
*/
#ifndef DOSFS_H
#define DOSFS_H 1
typedef u_char Long[4];
typedef u_char Short[2];
union bootsector
{
unsigned char raw[512];
struct bsec
{
u_char jump_boot[3]; /* jump code to boot-up partition */
char oem_name[8]; /* OEM company name & version */
Short sectsiz; /* bytes per sector */
u_char clustsiz; /* sectors per cluster */
Short ressecs; /* reserved sectors [before 1st FAT] */
u_char fatcnt; /* # of FAT's */
Short rootsiz; /* number of root dir entries */
Short totsecs; /* total # of sectors */
u_char media; /* media descriptor */
Short fatsize; /* # of sectors per FAT */
Short trksecs; /* sectors per track (cylinder) */
Short headcnt; /* # of r/w heads */
Short hidnsec; /* hidden sectors */
union
{
/* case totsecs != 0: */
/* This is a partition of MS-DOS 3.3 format (< 32 MB) */
u_char bootprogram[480];
/* case totsecs == 0: */
/* partition of MS-DOS 4.0+ format, or > 32 MB */
struct
{
Short unused;
Long totsecs; /* total # of sectors, as a 32-bit */
Short physdrv; /* physical drive # [0x80...] */
u_char extboot; /* extended boot signature??? */
Long serial; /* volume serial number */
char label[11]; /* same as volume label in root dir */
char fsysid[8]; /* some like `FAT16' */
u_char bootprogram[448];
} extended;
} variable_part;
u_char signature[2]; /* always {0x55, 0xaa} */
} bsec;
};
struct fat
{
u_char media; /* the media descriptor again */
u_char padded; /* alway 0xff */
u_char contents[1]; /* the `1' is a placeholder only */
};
/* DOS file attributes */
#define FA_RONLY 1 /* read/only */
#define FA_HIDDEN 2 /* hidden */
#define FA_SYSTEM 4 /* system */
#define FA_VOLLABEL 8 /* this is the volume label */
#define FA_SUBDIR 0x10 /* sub-directory */
#define FA_ARCH 0x20 /* archive - file hasn't been backed up */
struct dosftime
{
u_char time[2]; /* [0] & 0x1f - seconds div 2
* ([1] & 7) * 8 + ([0] >> 5) - minutes
* [1] >> 3 - hours
*/
u_char date[2]; /* [0] & 0x1f - day
* ([1] & 1) * 8 + ([0] >> 5) - month
* [1] >> 1 - year - 1980
*/
};
#define dosft_hour(dft) ((dft).time[1] >> 3)
#define dosft_minute(dft) (((dft).time[1] & 7) * 8 + ((dft).time[0] >> 5))
#define dosft_second(dft) (((dft).time[0] & 0x1f) * 2)
#define dosft_year(dft) (((dft).date[1] >> 1) + 1980)
#define dosft_month(dft) (((dft).date[1] & 1) * 8 + ((dft).date[0] >> 5))
#define dosft_day(dft) ((dft).date[0] & 0x1f)
struct direntry
{
char name[8]; /* file name portion */
char ext[3]; /* file extension */
u_char attr; /* file attribute as above */
char reserved[10];
struct dosftime fdate; /* time created/last modified */
Short startclstr; /* starting cluster number */
Long filesiz; /* file size in bytes */
};
/* handle endiannes: */
#define s_to_little_s(dst, src) dst[0]=(src)&0xff; dst[1]=((src)&0xff00)>>8
#define l_to_little_l(dst, src) \
dst[0]=(src)&0xff; dst[1]=((src)&0xff00)>>8; \
dst[2]=((src)&0xff0000)>>16; dst[3]=((src)&0xff000000)>>24
#endif /* DOSFS_H */

128
usr.sbin/mkdosfs/mkdosfs.1 Normal file
View File

@ -0,0 +1,128 @@
.\"
.\" Copyright (c) 1995 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$
.\"
.Dd November 5, 1995
.Os
.Dt MKDOSFS 1
.Sh NAME
.Nm mkdosfs
.Nd create an MS-DOS (FAT) file system
.Sh SYNOPSIS
.Nm mkdosfs
.Bq Fl f Ar capacity
.Bq Fl L Ar vollabel
.Ar device
.Sh DESCRIPTION
.Nm Mkdosfs
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.
.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 mkdosfs
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 mkdosfs
and should better be handled by the (nonexistent)
.Xr dosfsck 1
utility.
.Sh HISTORY
.Nm Mkdosfs
appeared in
.Em FreeBSD 2.2 .
.Sh AUTHOR
The program has been contributed by
.if n Joerg Wunsch,
.if t J\(:org Wunsch,
Dresden.

239
usr.sbin/mkdosfs/mkdosfs.c Normal file
View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 1995 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$
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <memory.h>
#include <err.h>
#include <fcntl.h>
#include "bootcode.h"
#include "dosfs.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[] =
{
/*
* kilobytes
* sec cls res fat rot tot med fsz spt hds hid
* tot phs ebt label fsysid
*/
{ 720,
512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, 0,
0, 0, 0, "4.4BSD ", "FAT12 "},
{1440,
512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 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 "},
{1200,
512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, 0,
0, 0, 0, "4.4BSD ", "FAT12 "},
};
void
usage(void)
{
fprintf(stderr, "usage: ");
errx(2, "[-f kbytes] [-L label] device");
}
void
setup_boot_sector_from_template(union bootsector *bs, struct descrip *dp)
{
memcpy((void *)bs->raw, (void *)bootcode, 512);
/* historical part of BPB */
s_to_little_s(bs->bsec.sectsiz, dp->sectsiz);
bs->bsec.clustsiz = dp->clustsiz;
s_to_little_s(bs->bsec.ressecs, dp->ressecs);
bs->bsec.fatcnt = dp->fatcnt;
s_to_little_s(bs->bsec.rootsiz, dp->rootsiz);
s_to_little_s(bs->bsec.totsecs, dp->totsecs);
bs->bsec.media = dp->media;
s_to_little_s(bs->bsec.fatsize, dp->fatsize);
s_to_little_s(bs->bsec.trksecs, dp->trksecs);
s_to_little_s(bs->bsec.headcnt, dp->headcnt);
s_to_little_s(bs->bsec.hidnsec, dp->hidnsec);
/* MSDOS 4 extensions */
l_to_little_l(bs->bsec.variable_part.extended.totsecs, dp->ext_totsecs);
s_to_little_s(bs->bsec.variable_part.extended.physdrv, dp->ext_physdrv);
bs->bsec.variable_part.extended.extboot = dp->ext_extboot;
/* assign a "serial number" :) */
srandom((unsigned)time((time_t)0));
l_to_little_l(bs->bsec.variable_part.extended.serial, random());
memcpy((void *)bs->bsec.variable_part.extended.label,
(void *)dp->ext_label, 11);
memcpy((void *)bs->bsec.variable_part.extended.fsysid,
(void *)dp->ext_fsysid, 8);
}
#define roundup(dst, limit) dst = (((dst) | ((limit) - 1)) & ~(limit)) + 1
int
main(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;
const char *label = 0;
while((c = getopt(argc, argv, "f:L:")) != EOF)
switch(c)
{
case 'f':
format = atoi(optarg);
break;
case 'L':
label = optarg;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if(argc != 1)
usage();
for(i = 0, dp = table; i < sizeof table / sizeof(struct descrip); i++, dp++)
if(dp->kilobytes == format)
break;
if(i == sizeof table / sizeof(struct descrip))
errx(1, "cannot find format description for %d KB", format);
if((fd = open(argv[0], O_RDWR|O_EXCL, 0)) == -1)
err(1, "open(%s)", argv[0]);
/* prepare and write the boot sector */
setup_boot_sector_from_template(&bs, dp);
/* if we've got an explicit label, use it */
if(label)
strncpy(bs.bsec.variable_part.extended.label, label, 11);
if(write(fd, (char *)bs.raw, sizeof bs) != sizeof bs)
err(1, "boot sector write()");
/* now, go on with the FATs */
if((fat = (struct fat *)malloc(dp->sectsiz * dp->fatsize)) == 0)
abort();
memset((void *)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;
for(i = 0; i < dp->fatcnt; i++)
if(write(fd, (char *)fat, dp->sectsiz * dp->fatsize)
!= dp->sectsiz * dp->fatsize)
err(1, "FAT write()");
free((void *)fat);
/* finally, build the root dir */
rootdirsize = dp->rootsiz * sizeof(struct direntry);
roundup(rootdirsize, dp->clustsiz * dp->sectsiz);
if((rootdir = (struct direntry *)malloc(rootdirsize)) == 0)
abort();
memset((void *)fat, 0, rootdirsize);
/* set up a volume label inside the root dir :) */
if(label)
strncpy(rootdir[0].name, label, 11);
else
memcpy(rootdir[0].name, dp->ext_label, 11);
rootdir[0].attr = FA_VOLLABEL;
now = time((time_t)0);
tp = localtime(&now);
rootdir[0].fdate.time[0] = tp->tm_sec / 2;
rootdir[0].fdate.time[0] |= (tp->tm_min & 7) << 5;
rootdir[0].fdate.time[1] = ((tp->tm_min >> 3) & 7);
rootdir[0].fdate.time[1] |= tp->tm_hour << 3;
rootdir[0].fdate.date[0] = tp->tm_mday;
rootdir[0].fdate.date[0] |= ((tp->tm_mon + 1) & 7) << 5;
rootdir[0].fdate.date[1] = ((tp->tm_mon + 1) >> 3) & 1;
rootdir[0].fdate.date[1] |= (tp->tm_year - 80) << 1;
if(write(fd, (char *)rootdir, rootdirsize) != rootdirsize)
err(1, "root dir write()");
(void)close(fd);
return 0;
}