fdutils-5.5-20060227/0000755000175000017500000000000010446366017013202 5ustar anibalanibalfdutils-5.5-20060227/doc/0000755000175000017500000000000010446366017013747 5ustar anibalanibalfdutils-5.5-20060227/doc/css/0000755000175000017500000000000010211702713014522 5ustar anibalanibalfdutils-5.5-20060227/doc/css/fdutils.css0000444000175000017500000000465110211702710016707 0ustar anibalanibalbody { text-align: center; } .titelchen { color: #660000; font-weight: bold; } .datum { color: #99cc33; font-weight: bold; } .globaltitle { font-weight: bold; color: #660000; font-size: 64px; text-align: center; } #frame { margin-right: auto; margin-left: auto; margin-top: auto; padding: 0px; text-align: left; } #leftcolumn { float: left; clear: both; } #navbar { background: #dddd99; font-size: 12px; margin-right: 30px; padding: 5px 10px 1px 1px; } #penguin { vertical-align: top; padding: 5px; font-size: 12px; text-align: left; } #contentright { clear: right; font-family: "Trebuchet MS", verdana, Arial, Helvetica, sans-serif; font-size: 12px; color: #003366; padding: 0px 0px 0px 5px; margin-left: 240px; } #logobar { font-family: "Courier New",Courier,Monaco,monospace; font-size: 12px; color: #003366; margin-right: 70px; } p,pre { text-align: left; } table { font-family: "Trebuchet MS", verdana, Arial, Helvetica, sans-serif; font-size: 12px; color: #003366; } a { font-family: "Courier New",Courier,Monaco,monospace; font-size: 12px; font-weight: 600; } a:link { color: #660033; text-decoration: none; } a:visited { color: #660033; text-decoration: none; } a:hover { color: #ffffff; text-decoration: none; background-color: #990000; } a.picture:hover { background-color: #ffffff; } a:active { color: #0000EE; text-decoration: none; background-color: #FFFF99; } #contentright p { font-size: 12px; } #contentright h1 { font-size: 24px; color: #660033; padding: 0px; margin-bottom: 20px; text-align: right; } #contentright h2 { font-size: 18px; color: #003300; padding: 0px; margin-bottom: 10px; } #contentright h3 { font-size: 14px; color: #003300; padding: 0px; margin-bottom: 10px; } pre { border-color: black; border-width: thin; border-style: solid; display: table-cell; text-align: left; padding: 5px; padding-bottom: 0px; background: #fff8f0 } .blueboard { border-color: black; border-width: thin; border-style: solid; display: table-cell; text-align: center; padding: 5px; padding-top: 0px; padding-bottom: 0px; background: #c0e0ff } .whiteboard { border-color: black; border-width: thin; border-style: solid; display: table-cell; text-align: center; padding: 5px; padding-bottom: 0px; background: #ffffff } .code { color: #ff4040; font-weight: bold; } p { text-align: justify; } fdutils-5.5-20060227/doc/cmdname0000444000175000017500000000115707464324643015305 0ustar anibalanibaldiskd - disk daemon; wait for disk to be inserted diskseek, diskseekd - disk seek daemon; simulates Messy Dos' drive cleaning effect fd - floppy disk device fdmount - Floppy disk mount utility fdrawcmd - send raw commands to the floppy disk controller floppycontrol - floppy driver configuration utility floppymeter - measure raw capacity and exact rotation speed of floppy drive getfdprm - print the current format information MAKEFLOPPIES - Creates the default floppy device nodes. setfdprm - sets user-provided floppy disk parameters superformat - format floppies xdfcopy - Program to copy and format Xdf disks in Linux fdutils-5.5-20060227/doc/fd.40000444000175000017500000001757207560752216014442 0ustar anibalanibal'\" t .\"{{{}}} .\"{{{ Notes .\" Copyright (c) 1993 Michael Haardt (michael@moria.de) .\" and 1994,1995, 1997 Alain Knaff (alain@linux.lu) .\" .\" This is free documentation; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License as .\" published by the Free Software Foundation; either version 2 of .\" the License, or (at your option) any later version. .\" .\" The GNU General Public License's references to "object code" .\" and "executables" are to be interpreted as the output of any .\" document formatting or typesetting system, including .\" intermediate and printed output. .\" .\" This manual is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public .\" License along with this manual; if not, write to the Free .\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, .\" USA. .\"}}} .\"{{{ Title .TH FD 4 "Jul 3, 1999" "Linux" "Special files" .\"}}} .\"{{{ Name .SH NAME fd \- floppy disk device .\"}}} .\"{{{ Configuration .SH CONFIGURATION Floppy drives are block devices with major number 2. Typically they are owned by root.floppy and have either mode 0660 (access checking via group membership) or mode 0666 (everybody has access). For the following devices, \fIn\fP is the drive number. It is 0 for the first drive, 1 for the second etc. To get a minor number for a specific drive connected to the first controller, add \fIn\fP to the minor base number. If it is connected to the second controller, add \fIn\fP+128 to the minor base number. \fBWarning: If you use formats with more tracks than supported by your drive, you may damage it mechanically.\fP Trying once if more tracks than the usual 40/80 are supported should not damage it, but no warranty is given for that. Don't create device entries for those formats to prevent their usage if you are not sure. .PP .\"{{{ drive independent Drive independent device files which automatically detect the media format and capacity: .PP .TS l l. Name Base minor # _ \fBfd\fP\fIn\fP 0 .TE .\"}}} .PP .\"{{{ 5.25 DD 5.25 inch double density device files: .PP .TS lw(1i) l l l l l. Name Capac. Cyl. Sect. Heads Base minor # _ \fBfd\fP\fIn\fP\fBd360\fP 360K 40 9 2 4 .TE .\"}}} .PP .\"{{{ 5.25 HD 5.25 inch high density device files: .PP .TS lw(1i) l l l l l. Name Capac. Cyl. Sect. Heads Base minor # _ \fBfd\fP\fIn\fP\fBh360\fP 360K 40 9 2 20 \fBfd\fP\fIn\fP\fBh410\fP 410K 41 10 2 48 \fBfd\fP\fIn\fP\fBh420\fP 420K 42 10 2 64 \fBfd\fP\fIn\fP\fBh720\fP 720K 80 9 2 24 \fBfd\fP\fIn\fP\fBh880\fP 880K 80 11 2 80 \fBfd\fP\fIn\fP\fBh1200\fP 1200K 80 15 2 8 \fBfd\fP\fIn\fP\fBh1440\fP 1440K 80 18 2 40 \fBfd\fP\fIn\fP\fBh1476\fP 1476K 82 18 2 56 \fBfd\fP\fIn\fP\fBh1494\fP 1494K 83 18 2 72 \fBfd\fP\fIn\fP\fBh1600\fP 1600K 80 20 2 92 .TE .\"}}} .PP .\"{{{ 3.5 DD 3.5 inch double density device files: .PP .TS lw(1i) l l l l l. Name Capac. Cyl. Sect. Heads Base minor # _ \fBfd\fP\fIn\fP\fBu360\fP 360K 80 9 1 12 \fBfd\fP\fIn\fP\fBu720\fP 720K 80 9 2 16 \fBfd\fP\fIn\fP\fBu800\fP 800K 80 10 2 120 \fBfd\fP\fIn\fP\fBu1040\fP 1040K 80 13 2 84 \fBfd\fP\fIn\fP\fBu1120\fP 1120K 80 14 2 88 .TE .\"}}} .PP .\"{{{ 3.5 HD 3.5 inch high density device files: .PP .TS lw(1i) l l l l l. Name Capac. Cyl. Sect. Heads Base minor # _ \fBfd\fP\fIn\fP\fBu360\fP 360K 40 9 2 12 \fBfd\fP\fIn\fP\fBu720\fP 720K 80 9 2 16 \fBfd\fP\fIn\fP\fBu820\fP 820K 82 10 2 52 \fBfd\fP\fIn\fP\fBu830\fP 830K 83 10 2 68 \fBfd\fP\fIn\fP\fBu1440\fP 1440K 80 18 2 28 \fBfd\fP\fIn\fP\fBu1600\fP 1600K 80 20 2 124 \fBfd\fP\fIn\fP\fBu1680\fP 1680K 80 21 2 44 \fBfd\fP\fIn\fP\fBu1722\fP 1722K 82 21 2 60 \fBfd\fP\fIn\fP\fBu1743\fP 1743K 83 21 2 76 \fBfd\fP\fIn\fP\fBu1760\fP 1760K 80 22 2 96 \fBfd\fP\fIn\fP\fBu1840\fP 1840K 80 23 2 116 \fBfd\fP\fIn\fP\fBu1920\fP 1920K 80 24 2 100 .TE .\"}}} .PP .\"{{{ 3.5 ED 3.5 inch extra density device files: .PP .TS lw(1i) l l l l l. Name Capac. Cyl. Sect. Heads Base minor # _ \fBfd\fP\fIn\fP\fBu2880\fP 2880K 80 36 2 32 \fBfd\fP\fIn\fP\fBu3200\fP 3200K 80 40 2 104 \fBfd\fP\fIn\fP\fBu3520\fP 3520K 80 44 2 108 \fBfd\fP\fIn\fP\fBu3840\fP 3840K 80 48 2 112 .TE .\"}}} .\"}}} .\"{{{ Description .SH DESCRIPTION \fBfd\fP special files access the floppy disk drives in raw mode. The following .IR ioctl (2) calls are supported by \fBfd\fP devices: .\"{{{ FDCLRPRM .IP \fBFDCLRPRM\fP clears the media information of a drive (geometry of disk in drive). .\"}}} .\"{{{ FDCLRPRM .IP \fBFDSETPRM\fP sets the media information of a drive. The media information will be lost when the media is changed. .\"}}} .IP \fBFDDEFPRM\fP sets the media information of a drive (geometry of disk in drive). The media information will not be lost when the media is changed. This will disable autodetection. In order to re-enable autodetection, you have to issue an \fBFDCLRPRM\fP . .\"}}} .\"{{{ FDGETDRVTYP .IP \fBFDGETDRVTYP\fP returns the type of a drive (name parameter). For formats which work in several drive types, \fBFDGETDRVTYP\fP returns a name which is appropriate for the oldest drive type which supports this format. .\"}}} .\"{{{ FDFLUSH .IP \fBFDFLUSH\fP invalidates the buffer cache for the given drive. .\"}}} .\"{{{ FDSETMAXERRS .IP \fBFDSETMAXERRS\fP sets the error thresholds for reporting errors, aborting the operation, recalibrating, resetting, and reading sector by sector. .\"}}} .\"{{{ FDGETMAXERRS .IP \fBFDSETMAXERRS\fP gets the current error thresholds. .\"}}} .\"{{{ FDGETDRVTYP .IP \fBFDGETDRVTYP\fP gets the internal name of the drive. .\"}}} .\"{{{ FDWERRORCLR .IP \fBFDWERRORCLR\fP clears the write error statistics. .\"}}} .\"{{{ FDWERRORGET .IP \fBFDWERRORGET\fP reads the write error statistics. These include the total number of write errors, the location and disk of the first write error, and the location and disk of the last write error. Disks are identified by a generation number which is incremented at (almost) each disk change. .\"}}} .\"{{{ FDTWADDLE .IP \fBFDTWADDLE\fP Switch the drive motor off for a few microseconds. This might be needed in order to access a disk whose sectors are too close together. .\"}}} .\"{{{ FDSETDRVPRM .IP \fBFDSETDRVPRM\fP sets various drive parameters. .\"}}} .\"{{{ FDGETDRVPRM .IP \fBFDGETDRVPRM\fP reads these parameters back. .\"}}} .\"{{{ FDGETDRVSTAT .IP \fBFDGETDRVSTAT\fP gets the cached drive state (disk changed, write protected et al.) .\"}}} .\"{{{ FDPOLLDRVSTAT .IP \fBFDPOLLDRVSTAT\fP polls the drive and return its state. .\"}}} .\"{{{ FDGETFDCSTAT .IP \fBFDGETFDCSTAT\fP gets the floppy controller state. .\"}}} .\"{{{ FDRESET .IP \fBFDRESET\fP resets the floppy controller under certain conditions. .\"}}} .\"{{{ FDRAWCMD .IP \fBFDRAWCMD\fP sends a raw command to the floppy controller. .\"}}} .PP For more precise information, consult also the and include files, as well as the manual page for floppycontrol. .\"}}} .\"{{{ Notes .SH NOTES The various formats allow to read and write many types of disks. However, if a floppy is formatted with a too small inter sector gap, performance may drop, up to needing a few seconds to access an entire track. To prevent this, use interleaved formats. It is not possible to read floppies which are formatted using GCR (group code recording), which is used by Apple II and Macintosh computers (800k disks). Reading floppies which are hard sectored (one hole per sector, with the index hole being a little skewed) is not supported. This used to be common with older 8 inch floppies. .\"}}} .\"{{{ Files .SH FILES /dev/fd* .\"}}} .\"{{{ Authors .SH AUTHORS Alain Knaff (Alain@linux.lu), David Niemi (niemidc@tux.org), Bill Broadhurst (bbroad@netcom.com). .\"}}} .\"{{{ See also .SH "SEE ALSO" .BR floppycontrol (1), .BR mknod (1), .BR chown (1), .BR getfdprm (1), .BR superformat (1), .BR mount (8), .BR setfdprm (1) .\"}}} fdutils-5.5-20060227/doc/fdutils.texi0000444000175000017500000001140510211706462016303 0ustar anibalanibal\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename fdutils.info @settitle Fdutils @c UPDATE THIS DATE WHENEVER YOU MAKE CHANGES! @c For double-sided printing, uncomment: @c @setchapternewpage odd @setchapternewpage off @c %**end of header @c MANtitle fdutils 1 "1Jul1999" fdutils @c MANskip @set EDITION 5.5 @set VERSION 5.5 @set UPDATED Mar 2005 @iftex @finalout @end iftex @ifinfo @format START-INFO-DIR-ENTRY * Fdutils: (fdutils). Fdutils: Linux' floppy utilities END-INFO-DIR-ENTRY @end format @end ifinfo @ifinfo Fdutils Copyright (C) 1993-2000 Alain Knaff Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. @end ifinfo @titlepage @title Fdutils @subtitle Linux floppy utilities @subtitle Edition @value{EDITION}, for Fdutils version @value{VERSION} @subtitle @value{UPDATED} @author by Alain Knaff @page @vskip 0pt plus 1filll Copyright @copyright{} 1993, 1994, 1995, 1996 Alain Knaff. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. @end titlepage @ifinfo @node Top, Location, (dir), (dir) @end ifinfo @c MANend-skip @unnumbered General Introduction Fdutils is a collection of utililties for configuring and using the Linux floppy driver. With fdutils, you can: @enumerate @item Format disks with a higher capacity than usual (up to 1992KB on a 3 1/2 HD disk). @item Reconfigure the autodetection sequence to automatically detect some of these extended formats. @item Access various internal driver structures and drive configuration using the floppycontrol program. @end enumerate This manual describes these utilities, and also the floppy driver itself. @menu * Location:: Where to get fdutils and its documentation * Basic usage:: How to get started * Device numbers:: * Media description:: How can a floppy disk and a format be described to fdutils? * Drive descriptions:: How can a drive and its characteristics be described to fdutils? * Extended formats:: How to store more data on your floppy disks * Autodetection:: How the floppy driver distinguishes among the different kinds of disks * Boottime configuration:: Lilo boot options understood by the floppy driver * Floppy ioctls:: The ioctl's understood by the floppy driver * Commands:: The available fdutils commands * Compile-time configuration:: How to use GNU autoconf to customize fdutils * Acronyms:: A brief listing of acronyms used in this documentation * Interesting formats:: A brief list of legacy and other formats * Command Index:: Command Index * Concept Index:: Concept Index @end menu @include location.texi @include tips.texi @include formatlist.texi @include mediaprm.texi @include driveprm.texi @include moredata.texi @include autodetect.texi @include lilo.texi @include ioctl.texi @c MANskip @include commands.texi @c MANend-skip @include configure.texi @include acronyms.texi @include format2.texi @c MANskip @node Command Index, Concept Index, Interesting formats, Top @unnumbered Command Index @printindex pg @node Concept Index, , Command Index, Top @unnumbered Concept index @printindex cp @contents @c MANend-skip @bye fdutils-5.5-20060227/doc/configure.texi0000444000175000017500000000267207464324643016635 0ustar anibalanibal@node Compile-time configuration, Acronyms, Commands, Top @chapter Compile-time configuration via GNU autoconf @cindex configure options @cindex compile-time configuration Before it can be compiled, fdutils must be configured using the GNU autoconf script @code{./configure}. In most circumstances, running @code{./configure} without any parameters is enough. However, you may customize fdutils using various options to @code{./configure}. The following options are supported: @table @code @item --prefix @var{directory} Prefix used for any directories used by fdutils. By default, this is @file{/usr/local}. Fdutils is installed in @file{$prefix/lib}, looks for its system wide configuration file in @file{$prefix/etc}. Man pages are installed in @file{$prefix/man}, info pages in @file{$prefix/info} etc. @item --sysconfdir @var{directory} Directory containing the system-wide configuration files such as @file{mediaprm} and @file{driveprm}. By default, this is derived from @code{prefix} (see above). N.B. For backward compatibility reasons, the old-style floppy parameter file @file{fdprm} is always in @file{/etc}, regardless of the setting for @code{sysconfdir} @item --enable-fdmount-floppy-only Allows usage of the @code{fdmount} program only to members of the group @code{floppy} @end table In addition to the above-listed options, the other standard GNU autoconf options apply. Type @code{./configure --help} to get a complete list of these. fdutils-5.5-20060227/doc/texi-linearize.c0000444000175000017500000000171507560760747017061 0ustar anibalanibal#include #include #include FILE *my_open(char *directory, char *file) { char path[8192]; FILE *r; strcpy(path, directory); strcat(path,"/"); strcat(path, file); r= fopen(path, "r"); if(r == NULL) { fprintf(stderr,"Could not open %s\n", path); perror("open"); exit(1); } return r; } int main(int argc, char **argv) { FILE *stack[256]; int sp; char line[4096]; char *directory; sp = 0; if(argc < 3) { fprintf(stderr,"Usage: %s directory root texi file\n", argv[0]); exit(1); } directory = argv[1]; stack[sp++] = my_open(directory, argv[2]); while(sp) { if(fgets(line, 4095, stack[sp-1]) ) { line[strlen(line)-1]='\0'; if(!strncmp(line, "@input", 6)) { stack[sp++] = my_open(directory, line+7); continue; } if(!strncmp(line, "@include", 8)) { stack[sp++] = my_open(directory, line+9); continue; } puts(line); } else sp--; } exit(0); } fdutils-5.5-20060227/doc/diskd.10000644000175000017500000000650710211703706015125 0ustar anibalanibal.TH diskd 1 "03Mar05" fdutils-5.5 .SH Name diskd - disk daemon; wait for disk to be inserted '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p diskd" .PP The diskd command has the following syntax: .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWdiskd [\fR\&\f(CW-d \fIdrive\fR\&\f(CW] [\fR\&\f(CW-i \fIinterval\fR\&\f(CW] [\fR\&\f(CW-e \fIcommand\fR\&\f(CW] .fi .in -0.3i .ft R .lp \&\fR .PP Diskd waits for a disk to be inserted into a given \fIdrive\fR, and then either executes the \fIcommand\fR or exits. This program can be used to automatically mount a disk as soon as it is inserted. .PP .SH Warning .PP This program works by switching the motor on for a very short interval, and then seeking to track -1. This might damage hardware in the long run. Amigas, which also use these techniques, are known for having problems with their disk drives no longer spinning up properly after a few month of usage. .PP .SH Options .TP \&\fR\&\f(CW-d\ \fIdrive\fR\&\f(CW\fR\ Selects the drive to observe for disk insertion. By default, drive 0 (\fR\&\f(CW/dev/fd0\fR) is observed. .TP \&\fR\&\f(CW-i\ \fIinterval\fR\&\f(CW\fR\ Selects the polling interval. The interval is given in tenths of seconds. Default is 10 (one second). .TP \&\fR\&\f(CW-e\ \fIcommand\fR\&\f(CW\fR\ Gives the command to be executed when a disk is inserted. If no command is given the program simply exits. Typically, the command mounts the disk. It can be a shell scripts which probes for several filesystems and disk geometries until it succeeds. .PP .SH Bugs .IP .TP * \ \ Automatic unmounting cannot yet be handled. It is indeed not enough to scan for disk removal, because when the disk is removed, it is already too late: There might be some buffers needing flushing. However, the \&\fR\&\f(CWfdmountd\fR program allows automatic unmounting by using the \&\fR\&\f(CWSYNC\fR mount options, which switches off write buffering (see section fdmount). .TP * \ \ The drive motor is running all the time, and on some computers, the drive led flickers at each time the drive is polled. .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/acronyms.texi0000444000175000017500000001275407560751735016514 0ustar anibalanibal@node Acronyms, Interesting formats, Compile-time configuration, Top @appendix Acronyms @table @emph @item SD (Single density) Single density disks use a data transfer rate of 125 kb/s and are no longer in use today, because of their low capacity. @item DD (Double density) Double density disks normally hold 360KB (5 1/4) or 720KB (3 1/2) of data per disk. Double density disks have only a hole on one side (for write protection). Double density uses a data transfer rate of 250 kb/s or 300 kb/s depending on the drive type: 5 1/4 high density drives use 300 kb/s when writing to a double density diskm 250 kb/s is used in all other circumstances. The reason why double density disks in high density drives need a higher data transfer rate is because these drives rotate faster (360 rpm instead of 300 rpm). @item HD (High density) High density disks normally hold 1200KB (5 1/4) or 1440KB (3 1/2) of data per disk. High density 3 1/2 disks are marked as such by the presence of a second square hole, just opposed to the write protect hole. 3 1/2 high density disks are the most commonly used type of disks today. @item QD (Quad density) Quad density is a hybrid between double and high density. It only exists for 5 1/4 disks, and holds 720KB of data. It can be obtained by formatting DD disks in a HD drive. QD uses double density for the density along the tracks (data transfer rate), and high density for the density perpendicular to the tracks (spacing between tracks, and thus number of tracks). This came to existence because these two aspects are limited by two different factors: the density along the track is limited by the quality of the media, whereas the density perpendicular to the tracks is mainly limited by the drive mechanism (this density, expressed in bits per inch comes nowhere near the limits of the media, even with HD). Thus quad density is an easy way to double the capacity of an ordinary double density disk, just by formatting it in a HD drive. @item ED (Extra density) Extra density refers to a disk density that can normally hold 2880KB of data per disk. Extra density disks only exist as 3 1/2 disks. ED disks are marked with a second squared hole opposed to the square hole, which is a little bit closer to the middle of the edge than that of HD disks. This format never really took off, because it only was released when storage media with a much higher capacity, such as CD-Roms, tapes and Zip disks became popular. ED uses a data transfer rate of 250 kb/s. @item DS (Double sided) Self explanatory. @item SS (Single sided) Self explanatory @item MSS (Mixed size sectors) Mixed sector size formats are formats which use sectors of several different sizes on a single track. @xref{Mixed size sectors}, for details. @item 2M (2 Megabytes) 2M is a high capacity format developped by Ciriaco de Celis. The basic principle is the same as MSS: mix sectors of several sizes on a same track, in order to minimize both slack space and header overhead. 2M is different from MSS in that it uses a normal 18 sector format on its first track. @xref{2M}, for details. @item rpm (Rotations per minute) All 3 1/2 drives and 5 1/4 DD drives run at 300 rotations per minute, whereas 5 1/4 HD drives run at 360 rotations per minute. @item rps (Rotations per second) See above. @item tpi (tracks per inch) Expresses how close cylinders are to each other. Usually, 5 1/4 double density disks have 48 tpi, whereas 5 1/4 high density and quad density disks have 96 tpi. 3 1/2 disks use 135.5 tpi. @item XDF (eXtended Density Format) XDF is a disk format used for the OS/2 distribution disks. Its operating systems are similar to 2M and MSS disk, but it is faster due to a more creative arrangement of sectors. @xref{XDF}, for details. @item XXDF (eXtended XDF) XXDF is an Linux enhancement for XDF. It can store 1992 KB of data on an ED disk instead of just 1840 available with the regular XDF format. @xref{XXDF}, for details. @item MFM (Multi Frequency Modulation) MFM is a low level encoding of disk data. It is used for DD, HD and ED disks, i.e. virtually all disks that are available today. The PC hardware can only read MFM and FM disks. The doc at: @example http://www.moria.de/~michael/floppy/floppy.ps @end example contains more detailed information about FM and MFM encoding. @item FM (Frequency modulation) FM is a low level encoding of disk data. It was used for SD disks, and is now considered to be obsolete. The doc at: @example http://www.moria.de/~michael/floppy/floppy.ps @end example contains more detailed information about FM and MFM encoding. @item kb (kilobit) 1000 bits @item kb/s (kilobit per second) We express the raw data throughput to and from the disk in this unit, which is also used in the documentation of the floppy disk controller. @item B Byte. A byte is 8 bits, and is the smallest individually addressable unit of data. @item KB (K-Byte) 1024 bytes. Sometimes also noted K. @item KB/s (K-Byte) We express the usable data throughput to and from the disk in KB/s. Roughly, 1 KB/s = 8 kb/s. However, the usable data throughput is always lower than the raw throughput due to header overhead, interleaving and seek overhead. @item MB (Megabyte) Initially, 1 megabyte was 1024*1024 bytes (i.e. 1048576 bytes). However, when talking of floppy disk capacity, we understand it as 1000KB, that is 1000*1024 bytes, i.e. 1024000 bytes. @item MB/s (million bytes per second) We express (high) raw data throughput to and from the disk in kb/s, which is also used in the documentation of the floppy disk controller. @end table fdutils-5.5-20060227/doc/floppy_formats0000444000175000017500000001605307560752107016743 0ustar anibalanibalFloppy format descriptions -------------------------- Notes: Extra Tracks: Many other variations upon these formats are possible. In particular, many nominally 40-track or 80-track drives are capable of more tracks, usually 41 and 83 respectively. Not all drives can seek to these unofficial extra tracks, and even on drives which can these extra tracks tend to be less reliable. However, most of the formats listed below could be increased in capacity by using extra tracks. Extra Sectors: The official formats used by MS-DOS and other operating systems are generally very conservative, and more sectors can nearly always be fit onto each track by reducing the size of the gap between tracks and/or the size of the leftover space at the end of the disk. If the gap sizes are too small, it is necessary to use a 2:1 interleave to achieve acceptable performance. Larger sectors: By using larger sectors, quite a bit of space is saved as the per-sector overhead in gaps and headers, permitting more data to fit on a disk than could possibly be achieved with normal 512-byte sectors. However, MS-DOS and other operating systems cannot normally read these formats. Furthermore, when any portion of one of these larger sectors is read, the entire sector must be read. When any portion of such a sector is written to, the entire sector must be read, and then written back with just the necessary portion modified. Both of these circumstances can entail worse performance for small reads and (especially) small writes. "2m" Formats: "2m" formats have a "standard" density on the first side of the first track, and a higher density on the rest of the disk. And are intended only for MS-DOS file systems. The MS-DOS boot sector indicates the number of sectors and tracks on the disk, and by this method 2m and mtools can determine the geometry of the *rest* of the disk. To cover up for the missing sectors on the first track, 2m and mtools pretend that there is a duplicate FAT in the missing sectors, which it simulates by using the first (real) FAT. Linux is also capable of using non-2m formats with mixed sector sizes (without using a reduced density on the first track. This is necessary for using non-MS-DOS formats, such as ext2fs, tar, Minix, or cpio. This can also be done for MS-DOS formats, but 2m can only read disks with the "standard" format on the first side of the first track. "Xdf" formats: Just like "2m" formats, Xdf formats use mixed sector sizes. However, for Xdf disks, the logical order of the sectors on a given track, and their physical order is not the same. When reading a track, sectors reads alternate between both sides, instead of first one complete side and then the other. This technique allows to do much faster accesses: 550 milliseconds per track instead of the 800 microseconds (or more) needed for 2m. If you have any questions, please mail me at Alain@knaff.lu 80/90/160/180 KB 5.25": Original IBM PC, CP/M, Apple II, TRS-80, etc. Single density, FM (not MFM), 40-track. Some systems also used "hard" sectoring, with an index hole for each sector. These are probably readable on standard FDCs if anyone cares to go to the effort. 160KB/180KB formats were double-sided. 320 KB 5.25": CP/M, Zenith Z-100, some forms of MS-DOS. 8-sector DD 40-track. 400 KB 5.25": AT&T 7300/3B1: cpio format, 10 sectors, DS, 40 tracks. PC: MS-DOS, 10 sectors, DS, 40 tracks; formatted by various utilities; readable by some versions of MS-DOS. <720KB 3.5" formats: - Some dedicated word-processing systems use lower than normal capacity floppies (some may be 40-track either via "stretching" or by having odd drives; others may be single-sided or use fewer sectors per track, or use "single density" or FM). IMHO these are not worth supporting in the kernel per se, but providing info on them for use via setfdprm is appreciated. - Atari ST 360 KB floppies: these are 9 sector 250KBps 80-track single-sided, using a slightly incompatible MS-DOS-like FAT. Very common distribution format for Atari ST software. - Mac 400 KB: single-sided 80-tracks, Mac MFS or HFS file system, Group Code Recording, zone bit recording, variable RPMs from 300 to 600 in 5 zones, and auto-eject mechanism. Almost theoretically impossible to read on "normal" drives without some form of hardware assistance. 720 KB 3.5": - PC: 9 sectors, DS, 80-track; very common. - Atari ST: same as Atari ST 360 KB except double-sided. 720 KB 5.25": - "Quad Density": 9 sectors, DS, 80-track; name is rather misleading, as it is double density 80 track. 800 KB: - PC: 10 sectors, DS, 80 tracks; readable by MS-DOS; formatted by many PC utilities; "almost standard". - Atari ST "Twister": 10 sectors, DS, 80-track; slightly incompatible MS-DOS-like FAT; sector skewing (originated by David Small). - Mac 800 KB: same as Mac 400KB except double-sided. 880 KB: - PC: 11 sectors, DS, 80 tracks, interleaved(?). Formatted by various PD utilities such as fdformat. - Amiga: uses "single-sector" tracks the size of 11 sectors; DS; 80 tracks. Written by a custom chip rather than a standard FDC; it is very difficult to read using a standard FDC, though writing or formatting might be theoretically possible. 880 KB-960 KB: Atari ST: 11/12 sectors, DS, 80-track, interleaved(?); not very reliable, formatted by various PD utilities. 960 KB: 2m and Linux; 12 sectors interleaved(?), DS, 250Kbps?, 80-track, 1K sectors(?). 1001 KB: "Japanese" format: 300Kbps, 77 tracks, HD drives/disks. 1040 KB: 2m and Linux only; 13 sectors, DS, 300Kbps, 80-track. 1120 KB: 2m and Linux only; 14 sectors interleaved, DS, 300Kbps, 80-track. Can only be formatted under Linux; even under Linux difficult to format on ED drives. 1200 KB 5.25" HD: "AT": 360 rpm 500Kbps 80-track 15-sector MS-DOS. 1360 KB 5.25" HD: Highest "fdformat" noninterleaved 5.25" format. 360 rpm 500Kbps 17-sector MS-DOS. 1440 KB 5.25" HD: Interleaved 18-sector 360 rpm 500Kbps; highest "fdformat" 5.25" format. 18-sector MS-DOS. 2m and Linux only: noninterleaved 1024-byte sector 18-sector-equivalent 360 rpm 500Kbps; 18-sector MS-DOS. A good substitute for 1.44MB 3.5" floppies. 1600 KB 5.25" HD: 2m and Linux only: interleaved? 500Kbps 80-track; 1 8KB sector, 1 2KB sector? 1760 KB 3.5" HD: 2m and Linux only: 11 1KB sectors; 500Kbps, noninterleaved? 1840 KB 3.5" HD: 2m and Linux only: 23-sector equivalent; 500Kbps, noninterleaved. 1920 KB 3.5" HD: 2m and Linux only: 3 4KB sectors; 500Kbps, interleaved? 2m and Linux only: 1 8KB sector, 1 4KB sector; 500Kbps, interleaved? 2880 KB 3.5" ED: "Extra Density" or "Extra High Density". 1Mbps, 36-sector, DS, 80- track. 3200 KB 3.5" ED: Non-interleaved, 80 track, 40-sector 1Mbps. Highest capacity that MS-DOS can read directly(?) 3520 KB 3.5" ED: 2m and Linux only: 1 16KB sector, 1 4KB sector, 1 2KB sector? Non-interleaved, 80 track 1Mbps. Highest capacity that 2m can format. 3840 KB 3.5" ED: 2m and Linux only: 1 16KB sector, 1 8KB sector (or is it 3 8KB sectors?). Non-interleaved, 80 track 1Mbps. Formatted only by Linux, but readable and writeable by 2m. fdutils-5.5-20060227/doc/README0000444000175000017500000004033307560751637014641 0ustar anibalanibal This package contains utilities to configure and debug the floppy driver, and utilities to format floppy disks. ----------------------------------------------------------------------------- WARNING ======= Although most drives are able to use 83 tracks, some may not. If your drive is making strange noises while accessing these tracks, don't use formats which use more than 80 tracks (13-19). (You may still gain something by the increased number of sectors) ----------------------------------------------------------------------------- The fdutils allows you to access some of the extended features of the linux floppy driver. These include: 1. Formatting disks with a higher capacity than usual (up to 1992k on a 3 1/2 HD disk). 2. Reconfiguration of the autodetection sequence to automatically detect some of these extended formats. 3. Limitation by the superuser of the highest allowable number of tracks. 4. Access to various internal driver structures, and drive configuration using the floppycontrol program. Floppy ioctls: ============== All these ioctl's may be issued using the floppycontrol program. (See also floppycontrols man page) 1. FDSETPRM sets the geometry (number of tracks, heads and sectors, etc) of a drive. 2. FDDEFPRM sets the geometry in a permanent way (not cleared after a disk change) 3. FDGETPRM read a previously set drive geometry (or an autodetected geometry) back. 4. FDCLRPRM makes the driver forget the geometry for a given drive (to trigger autodetection) 5. FDFLUSH forgets the contents of the floppy buffers. CAUTION: This doesn't write dirty buffers to the disk. Use fsync first. 6. FDGETDRVTYP displays the type of a drive (name parameter). This is used by MAKEFLOPPIES. For the naming convention, see the description of the MAKEFLOPPIES script. For formats which work in several drive types, FDGETDRVTYP return a name which is appropriate for the oldes drive type which supports this format. 7. FDSETDRVPRM sets various drive parameters. 8. FDGETDRVPRM reads these parameters back. 9. FDGETDRVSTAT gets the cached drive state (disk changed, write protected et al.) 10. FDPOLLDRVSTAT polls the drive and return its state. 11. FDGETFDCSTAT gets the floppy controller state. 12. FDRESET resets the floppy controller under certain conditions. 13. FDRAWCMD sends a raw command to the floppy controller. 14. FDWERRORCLR clear the write error stats. 15. FDWERRORGET gets the write error stats. 16. FDSETMAXERRS sets the error thresholds (when to display error messages on the console, and when to abort operations). The maxerror structure is part of the drive parameters, but this ioctl is needed in addition to FDSETDRVPRM because FDSETDRVPRM is only accessible to the superuser whereas FDSETMAXERRS is accessible to whoever has write access to the floppy device. 17. FDMSGON/FDMSGOFF switch informational messages on/off. This flag is part of the drive parameters as well, but FDMSGON/FDMSGOFF don't need superuser status. There are other ioctls as well, but they are considered obsolete and their use is discouraged. The extended formats ==================== Some formats use more than 80 tracks. It is not possible for the kernel to autodetect the number of tracks in a reasonable time, so you have to use a sufficiently recent version of mtools o set the number of tracks according to the boot sector of the disk. Mtools 2.5 and up are ok. This doesn't obviously work with disks containing something else than a MSDOS filesystem. The minor device number for the floppy devices is calculated as follows: minor_device = format_nr * 4 + 128 * fdc_nr + unit_nr (fdc_nr identifies the floppy disk controller, and unit_nr identifies which drive on the floppy disk controller to be used) The major device number is 2. The format_nr is the number of the entry in the table in floppy.c. Valid numbers and formats are: format_nr Format --------- ------ 0 autodetect 1 360kB, 5.25" DD drive 2 1200kB, 5.25" HD drive 3 360kB, 3.5" DD drive 4 720kB, 3.5" DD drive 5 360kB, 5.25" DD disk in HD drive 6 720kB, 5.25" DD disk in HD drive 7 1440kB, 3.5" HD drive 8 2880kB, 3.5" ED drive 9 2880kB, 3.5" CompaQ ED drive (???) 10 1440kB, 5.25" HD drive 11 1680kB, 3.5" HD drive 12 410kB, 5.25" DD disk in HD drive 13 820kB, 3.5" DD drive 14 1476kB, 5.25" HD drive 15 1722kB, 3.5" HD drive 16 420kB, 5.25" DD disk in HD drive 17 830kB, 3.5" DD drive 18 1494kB, 5.25" HD drive 19 1743kB, 3.5" HD drive 20 880kB, 5.25" DD drive 21 1040kB, 3.5" DD drive 22 1120kB, 3.5" DD drive 23 1600kB, 5.25" HD drive 24 1760kB, 3.5" HD drive 25 1920kB, 3.5" HD drive 26 3200kB, 3.5" ED drive 27 3520kB, 3.5" ED drive 28 3840kB, 3.5" ED drive 29 1840kB, 3.5" HD drive 30 800kB, 3.5" DD drive 31 1600kB, 3.5" HD drive This table lists first the format_nr (0-31) used to compute the minor number, then the capacity of the format (360kb - 3200kb), and then the type of the drive in which this format is used. The formats 0..8 are the standard PC formats, 9 is apparently needed for certain weird CompaQ computers. The remaining formats are extended capacity formats. Some of them have been taken from Heiko Schroeder's fdpatches (after correcting some minor bugs). Others have been added by David Niemi and me (Alain Knaff). Formats 30 and 31 are non-interleaved formats with normal sized sectors, and have the highest capacity that can be achieved without resorting to interleaving or bigger sectors. Formats 20 to 29 use bigger sectors than usual, and thus are probably not readable with most DOS utilities (fdformat, vgacopy etc. Get 2m instead :-) ) BEWARE OF FORMATS 13-19 IF YOUR DRIVE ONLY SUPPORTS 80 TRACKS. You can redefine these formats using the setfdprm program (Written by Werner Almesberger). To use the new formats, you have to make new /dev/fd* entries, using the MAKEFLOPPIES shell script. You may also make the devices manually: (This is needed if you redefine your default formats using setfdprm) Example: Make a device entry for a 1.74MB floppy in drive 0: The format number is 19, drive 0, floppy disk controller 0 so the minor device number is 128*0+4*19+0=76. The command line to make the new device entry is: mknod /dev/fd0H1743 b 2 76 ^ ^ ^ ^ | | | Minor device number | | Major device number (always 2!) | Blockdevice A name that you choose for the format. I recommend the names I used in floppy.c, but you can choose any name you want. Other formats: ============== Linux is able to read almost any MFM disks. These include many CP/M disks and also Commodore 1581 disks. Please get Michael Haardt's documentation on floppy drives for a detailed description of those formats. This can be ftp'ed from http://www.moria.de/~michael/floppy/floppy.ps Commodore 1581 disks are not yet described in this documentation. Use 'setfdprm /dev/fd0 1600 10 2 80 2 0x2A 0x02 0xDF 0x2E' to use these. If you want to use these disks often, redefine one of the "default" formats to be Commodore 1581, and then put it into the autodetection list for the drive. The following example describes how to redefine format number 31 (minor device number 124) to be Commodore 1581: mknod /dev/fd0cbm1581 b 2 124 setfdprm /dev/fd0cmb1581 1600 10 2 80 2 0x2A 0x02 0xDF 0x2E floppycontrol --autodetect /dev/fd0 31,7,8,4,25,28,22,21 The two latter commands have to be issued after each reboot, so I suggest you put them into your /etc/rc files if you use many Commodore 1581 disks. Using more than 80 tracks: ========================== Although most drives support more than 80 tracks some may not, and repeatedly trying to read beyond track 80 might be damaging to them. In order to know wether your drive supports more than eighty tracks, first set the number of allowed tracks to 82. (using floppycontrol --tracks 82 -d ) Then format a disks with a 82 track format (for example /dev/fd0H1722), and copy a file on it large enough to fill the disk it completely. (Many small files will do too. The disk is full enough if the free space is less than a track, in this case 18k) Then eject and reinsert the disk, and compare the file on the disk with the original. If they are still the same, your drive supports 82 tracks. (If yes, you might want to try also with 83 tracks: /dev/fd0H1743)) (This single experience should not damage the drive.) If you do have a drive which supports more than 80 tracks, you have to enable the additional tracks after each boot, for instance by calling floppycontrol --tracks 82 from your /etc/rc.local in order to allow programs to use these tracks. (Alternatively, you could also change it in the default_drive_params structure) If your drive doesn't support more than 80 tracks, please remove the entries for formats 13-19 from your /dev directory after running MAKEFLOPPIES. N.B. I have yet to see a 3.5" drive which doesn't support 82 tracks. If you have such a beast, please mail me. Configuring the floppy driver via lilo: ======================================= The floppy driver is configured using the 'floppy=' option in lilo. This option can be typed at the boot prompt, or entered in the lilo configuration file. Example: If your kernel is called linux-72, type the following line at the lilo boot prompt (if you have a thinkpad): linux-72 floppy=thinkpad You may also enter the following line in /etc/lilo.conf, in the description of linux-72: append = "floppy=thinkpad" Several floppy related options may be given, example: linux-72 floppy=daring floppy=two_fdc append = "floppy=daring floppy=two_fdc" If you give options both in the lilo config file and on the boot prompt, the option strings of both places are concatenated, the boot prompt options coming last. That's why there are also options to restore the default behaviour. The floppy related options include: floppy=daring Tells the floppy driver that you have a well behaved floppy controller. This allows more efficient and smoother operation, but may fail on certain controllers. floppy=0,daring Tells the floppy driver that your floppy controller should be used with caution. floppy=one_fdc Tells the floppy driver that you have only floppy controller (default) floppy=two_fdc floppy=
,two_fdc Tells the floppy driver that you have two floppy controllers. The second floppy controller is assumed to be at
. If
is not given, 0x370 is assumed. two_fdc is implied if you use the cmos option with a drive of id 4 to 7. floppy=thinkpad Tells the floppy driver that you have a Thinkpad. Thinkpads use an inverted convention for the disk change line. floppy=0,thinkpad Tells the floppy driver that you don't have a Thinkpad. floppy=,,cmos Sets the cmos type of to . Additionnaly, this drive is allowed in the bitmask. This is useful if you have more than two floppy drives (only two can be described in the physical cmos), or if your BIOS uses non-standard CMOS types. The CMOS types are: 0 - unknown or not installed 1 - 5 1/4 DD 2 - 5 1/4 HD 3 - 3 1/2 DD 4 - 3 1/2 HD 5 - 3 1/2 ED 6 - 3 1/2 ED (Note: there are two valid types for ED drives. This is because 5 was initially chosen to represent floppy *tapes*, and 6 for ED drives. AMI ignored this, and used 5 for ED drives. That's why the floppy driver handles both) Setting the CMOS to 0 for the first two drives (default) makes the floppy driver read the physical cmos for those drives. floppy=unexpected_interrupts Print a warning message when an unexpected interrupt is received (default behaviour) floppy=no_unexpected_interrupts floppy=L40SX Don't print a message when an unexpected interrupt is received. This is needed on IBM L40SX laptops in certain video modes. (There seems to be an interaction between video and floppy. The unexpected interrupts only affect performance, and can safely be ignored.) (There are other options as well, but they are considered obsolete) Included utilities: =================== 1. floppycontrol. This program sets the various error tresholds (error reporting, operation abortion, and read track), prints out drive drive types, and flushes buffers. There is a -h help option. This program provides examples on how to use the new ioctl's. To compile this program just type make in the util directory. See also the included manpage. (in the utils directory) 2. MAKEFLOPPIES. This shell script creates the new floppy block device files. It uses the floppycontrol program to translate the minor device numbers into meaningful names. It also uses these names to decide wether to create a given block device file or not, depending on the type of the physical drive (for instance, for a 3 1/2 drive, the formats corresponding to a 5 1/4 drive are not created). If you have more than two floppy drives, the kernel cannot find out the types of these additional drives, and you need to specify them with the environmental variables FD2 and FD3. The following types are available: H1440 ( HD 3''1/2), h1200 (HD 5''1/4), D720 (DD 3''1/2) and d360 (DD 5''1/4). Sample command line: FD2=1.44M FD3=1.2M MAKEFLOPPIES The names of the device are a letter describing the _drive_ types, followed by a letter describing the size of the _format_. The letters are E = 3.5" ED drive H = 3.5" HD drive D = 3.5" DD drive h = 5.25" HD drive d = 5.25" DD drive Example: h360 is a device for accessing a 360k disk in a 5.25" HD drive. This convention is the same as used by Slackware and the MAKEDEV script, except for the ED drives (which are named H2880 by MAKEDEV, and don't yet exist in Slackware) IMPORTANT: The MAKEFLOPPIES script needs the floppycontrol program on the search PATH. 3. Setfdprm. This program is used to set the media parameters for a drive. See manpage (in the utils directory) 4. Superformat. This program is used to format floppy disks. The old fdformat doesn't work for disks with bigger sectors. WARNING: DO READ THIS MANPAGE CAREFULLY. IMPROPER USAGE MAY LEAD TO DATA LOSS. 5. Others: see the manpages Reading these disks under dos: ============================== *formats with normal sector sizes: (10..19) There are zillions of utilities which are able to read these: fdformat, vgacopy, ... With dos6, you don't even need those, just put the following line in your config.sys: drivparm=/d:0 /f:7 /h:2 /s:21 /t:82 ^ ^ \______________/ | | | drive number | max geometry | drive type, consult the dos help for details *formats with bigger sectors: There is only one utility which can do this: 2m20 (by Ciriaco Garcia) You can get this program from nic.switch.ch:/mirror/msdos/diskutil/2m20.zip (for other adresses, see archie) This program uses a normal format for the first track and first head (18 sectors), and enhanced formats for the other tracks (up to 24*512 bytes per track !) See the manpage of superformat (option --2m) to know how to format disks readable by this program. This man page is in the utils directory. WARNING: DO READ THIS MANPAGE CAREFULLY. IMPROPER USAGE MAY LEAD TO DATA LOSS. DO ONLY PUT MSDOS FILESYSTEMS ON 2M DISKS. Other Doc: ========== There are man pages for mtools (in mtools/) and the utilities (in utils/) included. There's also a FAQ list. It is regularily updated on http://fdutils.linux.lu/FAQ.html . You can find alpha versions of fdutils on http://fdutils.linux.lu/ . (They are named fduddmm.taz, where dd stands for the day and mm for the month. I'll only leave these for a limited time, and then move them into an old directory, or remove them.) fdutils-5.5-20060227/doc/floppymeter.texi0000444000175000017500000001006007464324643017210 0ustar anibalanibal@node floppymeter, getfdprm, floppycontrol, Commands @section floppymeter @pindex floppymeter @cindex rotation speed @cindex raw capacity @example @code{floppymeter} [@code{-f}] [@code{-w} @var{warmup-delay}] [@code{-W} @var{window}] [@code{-c} @var{cycles}] [@code{-h}] @var{drive} @end example The @code{floppymeter} program measures characteristic parameters of a floppy drive and floppy controller, such as the rotation speed of the drive, the data transfer rate of the controller, and the resulting raw capacity of a disk track. To use this program, insert a disposable floppy in the drive, and type @code{floppymeter --}@var{density}, where density describes the density of the disk used for the test. (Should be one of @code{dd, hd} or @code{ed}). @strong{CAUTION: the data on the disk will be erased}. This program should be used to verify whether the drive and controller are out of tolerance if you experience problems with some high capacity formats. It only needs to be run once per drive: although a disk is needed to perform the measurements, the measured data only depend on the drive and the controller, and not on the disk. To measure the raw capacity of the disk track, the floppymeter program formats the first track of the drive in a special way that allows it to read the raw data (gaps and headers) of the disk. @strong{Thus, all data previously stored on that disk is lost}. The rotation speed is measured by timing the return time of a @code{readid} command. In order to gain more precision, the command is issued many times in a row. During this phase, the number of rotations til the start of the test, the average time per rotation til the start, and a sliding average of the times of the last 30 rotations is printed, and updated continously. The data transfer rate is deduced from the two parameters above. At the end of the program, all parameters (raw capacity, duration of one rotation, and data transfer rate) are printed again, as well as their relative deviation to the standard value. Finally, it suggests a capacity deviation description line, which can be directly pasted into the drive definition file (@xref{Drive descriptions}.). Usually, the data transfer rate should not deviate more than 150 ppm from the expected value, and the rotation speed of the drive should not deviate more than 3000 ppm from the expected value. If these deviations are bigger, you may get problems with certain high capacity formats. If the raw capacity of the drive is too small, some high capacity formats may become unformattable on this drive/controller combo. If on the other hand, the raw capacity of the drive is too big, you may get problems when writing to a disk formatted by this drive on another drive with a smaller raw capacity. In order to avoid this, increase superformats gap parameter (@code{-G}). @table @code @item -h Prints a short help @item --dd Tells the program that we use a Double Density disk. @item --hd Tells the program that we use a High Density disk. @item --ed Tells the program that we use an Extra Density disk. @item -f Runs the measurement non interactively. With this option, the program doesn't ask for confirmation, and doesn't display the continously updated values during the rotation speed measurement. @item -W @var{Window} This value describes how many rotations are used for the computation of the sliding average. Default is 30. @item -c @var{cycles} Describes the number of rotations clocked during the rotations speed determination test. Default is 1000. @end table @subsection Bugs This program is quite new, and may have bugs. Here are a few suggested tests to check its sanity: @itemize @bullet @item The deviation of the data transfer rate solely depends on the controller. It should not be different between two drives connected to the same controller. However, the drive rotation speed may be different for different drives. @item All data transfer rates (for double, high and extra density) are derived from a same master frequency. Thus the @emph{deviation} of the data transfer rate should be independant of the density used. @end itemize fdutils-5.5-20060227/doc/xdfcopy.texi0000444000175000017500000000574207464324643016331 0ustar anibalanibal@node xdfcopy, , superformat, Commands @section xdfcopy @pindex xdfcopy @cindex XDF (formatting and copying disks) @cindex formatting XDF disks @example @code{xdfcopy} [@code{-}@var{format-id}] [@code{-d}] [@code{-n}] [@code{-h} @var{head-skew}] [@code{-t} @var{cylinder-skew}] [@code{-T} @var{end-cylinder}] [@var{source}] @var{target} @end example @code{Xdfcopy} is a utility to copy and format XDF disks. XDF (eXtended Density Format) is a format used by OS/2 which can hold 1840KB of data (on a 3 1/2 high density disk). Its advantage over 2m formats is that it is faster: 38KB/s. Because of this fast speed, I extended the XDF standard to higher capacities (1992KB) with a transfer rate of 45KB/s. I called the new formats XXDF. This program works best with kernels newer than 2.0.0. If both source and target are given, xdfcopy copies the disk image from file to floppy disk or vice-versa. When copying to a floppy disk, the disk is first formatted, unless the @code{-n} option is given. If no source is given, the target is only formatted. In this case, the target must be a floppy drive. @subsection Options @subsubsection Selecting a format Formats are selected by the format_id. The following formats are understood: @table @code @item 0 Formats a 5 1/4 XDF disk (1520 KB, 45.6 KB/s). @item 1 Formats a 3 1/2 high density XDF disk (1840 KB, 38.3 KB/s). @item 2 Formats a 3 1/2 extra density XDF disk (3680 KB, 102 KB/s) @item 3 Formats a 3 1/2 high density XXDF disk (1920 KB, 45 KB/s) @item 4 Formats a 3 1/2 extra density XXDF disk (3840 KB, 90 KB/s) @end table @subsection Misc options @table @code @item -D @var{dosdrive} Describes the DOS drive letter for mformat. If this option is given, an MS-DOS filesystem is automatically installed on the disk after the low-level format is complete. In order for this to work, the drive has to be configured to accept the 23x2x80 geometry in your /etc/mtools or your ~/.mtoolsrc file. Moreover, this only works with a version of mtools that is more recent than 3.0. Example of a working mtoolsrc line: @example A /dev/fd0 0 0 0 0 @end example Examples of a non-working mtoolsrc line: @example A /dev/fd0 12 80 2 18 @end example @item -n Don't format the disk before copying the disk image to the disk. @end table @subsection Options for power users @table @code @item -t @var{cylinder skew} Uses a different track skew than the default (14). For more details on skews, @pxref{superformat}. In this version of xdfcopy, the @code{-t} parameter is ignored. @item -h @var{head skew} Uses a different head skew than the default (0) In this version, this parameter is ignored @item -d Debugging. For each read or write operation, the time it took to complete the operation is printed (in milliseconds). This can be used to optimize the skews. @item -T @var{end-cylinders} Tells how many cylinders to format. With the XXDF formats, it is actually possible to format up to 83 cylinders, yielding a format of up to 1992KB on a 3 1/2 high density disk. @end table fdutils-5.5-20060227/doc/makefloppies.10000644000175000017500000000650610211703706016505 0ustar anibalanibal.TH makefloppies 1 "03Mar05" fdutils-5.5 .SH Name MAKEFLOPPIES - Creates the default floppy device nodes. '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWMAKEFLOPPIES [\fR\&\f(CW-tlvng] [\fIdrives\fR\&\f(CW] .fi .in -0.3i .ft R .lp \&\fR .PP The \fR\&\f(CWMAKEFLOPPIES\fR shell script creates the new floppy block device node. It uses the floppycontrol program to translate the minor device numbers into meaningful names. It also uses these names to decide whether to create a given block device file or not, depending on the type of the physical drive (for instance, for a 3 1/2 drive, the formats corresponding to a 5 1/4 drive are not created). .PP If you have more than two floppy drives, you need to tell the kernel the CMOS types of those additional drives using the \&\fR\&\f(CWfloppy=\fR\fIdrive\fR\fR\&\f(CW,\fR\fItype\fR\fR\&\f(CW,cmos\fR lilo option. .PP If the \fIdrives \fR parameter is given, only the device nodes for the listed drives are made. By default, all only the two first drives are tried. .PP \&\fR\&\f(CWMAKEFLOPPIES\fR does not work if you redefine your default formats. .PP \&\fBCaution\fR: \&\fR\&\f(CWMAKEFLOPPIES\fR removes already existing floppy device nodes. .PP .SH Options .IP .TP \&\fR\&\f(CW-t\fR\ Use the old naming convention for 3 1/2 devices (e.g. \fR\&\f(CW\(iffd0H720\(is\fR instead of \fR\&\f(CW\(iffd0u720\(is\fR). .TP \&\fR\&\f(CW-m\fR\ Base the name for the created devices on the type of the media (e.g. \fR\&\f(CW\(iffd0h720\(is\fR instead of \fR\&\f(CW\(iffd0u720\(is\fR). .TP \&\fR\&\f(CW-l\fR\ Local. Creates device nodes in the local directory, not /dev .TP \&\fR\&\f(CW-v\fR\ Verbose .TP \&\fR\&\f(CW-n\fR\ Dry run. (just report what would be done, do not do anything) .TP \&\fR\&\f(CW-g\fR\ Group. Allow read/write access to floppy devices only for group \&\fR\&\f(CW\(iffloppy\(is\fR .PP .SH Bugs The Makefloppies script does not work on redefined "default" formats, If you redefine default formats, you need to create the needed device nodes manually. .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/diskseekd.10000644000175000017500000000632610211703706015774 0ustar anibalanibal.TH diskseekd 1 "03Mar05" fdutils-5.5 .SH Name diskseek, diskseekd - disk seek daemon; simulates Messy Dos' drive cleaning effect '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p diskseekd" .iX "c dust (shaking it off from a drive)" .iX "c shaking off dust from a drive" .PP Several people have noticed that Linux has a bad tendency of killing floppy drives. These failures remained completely mysterious, until somebody noticed that they were due to huge layers of dust accumulating in the floppy drives. This cannot happen under Messy Dos, because this excuse for an operating system is so unstable that it crashes roughly every 20 minutes (actually less if you are running Windows). When rebooting, the BIOS seeks the drive, and by doing this, it shakes the dust out of the drive mechanism. \fR\&\f(CWdiskseekd\fR simulates this effect by seeking the drive periodically. If it is called as \fR\&\f(CWdiskseek\fR, the drive is seeked only once. .PP .SH Options .PP The syntax for \fR\&\f(CWdiskseekd\fR is as follows: .nf .ft 3 .in +0.3i \&\fR\&\f(CWdiskseekd [\fR\&\f(CW-d \fIdrive\fR\&\f(CW] [\fR\&\f(CW-i \fIinterval\fR\&\f(CW] [\fR\&\f(CW-p \fIpidfile\fR\&\f(CW] .fi .in -0.3i .ft R .lp \&\fR .TP \&\fR\&\f(CW-d\ \fIdrive\fR\&\f(CW\fR\ Selects the drive to seek. By default, drive 0 (\fR\&\f(CW\(if/dev/fd0\(is\fR) is seeked. .TP \&\fR\&\f(CW-i\ \fIinterval\fR\&\f(CW\fR\ Selects the cleaning interval, in seconds. If the interval is 0, a single seek is done. This is useful when calling diskseek from a crontab. The default is 1000 seconds (about 16 minutes) for \&\fR\&\f(CWdiskseekd\fR and 0 for \fR\&\f(CWdiskseek\fR. .TP \&\fR\&\f(CW-p\ \fIpidfile\fR\&\f(CW\fR\ Stores the process id of the diskseekd daemon into \fIpidfile\fR instead of the default \fR\&\f(CW\(if/var/run/diskseekd.pid\(is\fR. .PP .SH Bugs .TP 1.\ Other aspects of Messy Dos' flakiness are not simulated. .TP 2.\ This section lacks a few smileys. .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/floppycontrol.10000644000175000017500000006047510211703706016745 0ustar anibalanibal.TH floppycontrol 1 "03Mar05" fdutils-5.5 .SH Name floppycontrol - floppy driver configuration utility '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p floppycontrol" .iX "c configuration of floppy driver" .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWfloppycontrol [\fR\&\f(CW-p] [\fR\&\f(CW--pollstate] [\fR\&\f(CW--printfdstate] [\fR\&\f(CW-a \fIoperation-abort-threshold\fR\&\f(CW] [\fR\&\f(CW-c \fIread-track-threshold\fR\&\f(CW] [\fR\&\f(CW-r \fIrecalibrate-threshold\fR\&\f(CW] [\fR\&\f(CW-R \fIreset-threshold\fR\&\f(CW] [\fR\&\f(CW-e \fIreporting-threshold\fR\&\f(CW] [\fR\&\f(CW-f] [\fR\&\f(CW-x] [\fR\&\f(CW-d \fIdrive\fR\&\f(CW][\fR\&\f(CW-F] [\fR\&\f(CW-T] [\fR\&\f(CW-reset \fIcondition\fR\&\f(CW] [\fR\&\f(CW--debug] [\fR\&\f(CW--nodebug] [\fR\&\f(CW--messages] [\fR\&\f(CW--nomessages] [\fR\&\f(CW--broken_dcl] [\fR\&\f(CW--working_dcl] [\fR\&\f(CW--inverted_dcl] [\fR\&\f(CW--no_inverted_dcl] [\fR\&\f(CW--silent_dcl_clear] [\fR\&\f(CW--noisy_dcl_clear] [\fR\&\f(CW-c\fIcmos-type\fR\&\f(CW] [\fR\&\f(CW-hlt \fIhlt\fR\&\f(CW] [\fR\&\f(CW-hut \fIhut\fR\&\f(CW] [\fR\&\f(CW-srt \fIsrt\fR\&\f(CW] [\fR\&\f(CW-o \fIspindown\fR\&\f(CW] [\fR\&\f(CW-u \fIspinup\fR\&\f(CW] [\fR\&\f(CW-s \fIselect-delay\fR\&\f(CW] [\fR\&\f(CW-rps \fIrotations-per-second\fR\&\f(CW] [\fR\&\f(CW-O \fIspindown-offset\fR\&\f(CW] [\fR\&\f(CW-track \fImax-tracks\fR\&\f(CW] [\fR\&\f(CW-timeout \fIseconds\fR\&\f(CW] [\fR\&\f(CW-C \fIcheck-interval\fR\&\f(CW] [\fR\&\f(CW-n \fInative-format\fR\&\f(CW] [\fR\&\f(CW-autodetect \fIautodetection-sequence\fR\&\f(CW] [\fR\&\f(CW-P] [\fR\&\f(CW--clrwerror] [\fR\&\f(CW--printwerror] [\fR\&\f(CW-h] .fi .in -0.3i .ft R .lp \&\fR .PP The \fR\&\f(CWfloppycontrol\fR program is used to configure the floppy driver. .PP .SH General\ Options .IP .TP \&\fR\&\f(CW-h\fR\ .TQ \&\fR\&\f(CW--help\fR Print a help screen. .TP \&\fR\&\f(CW-d\ \fIdrive\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--drive\ \fI\ drive\fR\&\f(CW\fR Selects the drive to configure. The default is drive 0 (\fR\&\f(CW\(if/dev/fd0\(is\fR). .PP .SH One\ time\ actions .iX "c ejecting a disk" .iX "c flushing floppy cache" .iX "c resetting controller" .PP The following \fR\&\f(CWfloppycontrol\fR options don't set a configuration parameter, but perform a one-time action. They are available to anybody who has write access to the drive .TP \&\fR\&\f(CW-f\ \ \fR\ .TQ \&\fR\&\f(CW--flush\fR Flushes (throws away) the dirty data buffers associated with this drive. .TP \&\fR\&\f(CW-x\ \ \fR\ .TQ \&\fR\&\f(CW--eject\fR Ejects the disk out of the drive (Sparc). The dirty buffers are first committed to disk before ejecting it. Fails if the disk is mounted. .TP \&\fR\&\f(CW--reset\ \fI\ condition\fR\&\f(CW\fR\ Resets the FDC under \&\fIcondition\fR . Condition may be one of the following: .RS .TP \&\fR\&\f(CW0\fR\ resets the FDC only if a reset is needed anyways, .TP \&\fR\&\f(CW1\fR\ resets the FDC also if a raw command has been performed since the last reset, and .TP \&\fR\&\f(CW2\ \fR\ resets the FDC unconditionally. .RE .IP This command may be needed after some failed raw commands (see section fdrawcmd). .IP .TP \&\fR\&\f(CW-F\fR\ .TQ \&\fR\&\f(CW--formatend\fR Issues an end format ioctl. This might be needed after exiting a \&\fR\&\f(CWfdformat\fR in an unclean way. \fR\&\f(CWsuperformat\fR is not subject to this. .PP .SH Printing\ current\ settings .iX "c printing current settings" .iX "c determining drive type" .iX "c detecting a disk change" .IP .TP \&\fR\&\f(CW-T\fR\ .TQ \&\fR\&\f(CW--type\fR Print out the drive name of a floppy device. This is used by the \&\fR\&\f(CWMAKEFLOPPIES\fR script. The drive name is a letter (describing the drive type) followed by the capacity of the format in bytes. The letter is E for 3.5 ED drives, H for 3.5 HD drives, D for 3.5 DD drives, h for 5.25 HD drives and d for 5.25 DD drives. The drive type letter corresponds to the oldest drive type supporting the format of this device node (not necessarily the type of the drive refered by this node.) For the generic format nodes (/dev/fd0 et al.) the name of "native format" of the drive is printed, and for the default formats, if a generic format has been redefined, its name becomes \fR\&\f(CW(null)\fR. .TP \&\fR\&\f(CW-p\fR\ .TQ \&\fR\&\f(CW--print\fR Prints out the configuration of the drive. The names of the various fields are the same as the names of the option to set them, see below. .TP \&\fR\&\f(CW-P\fR\ .TQ \&\fR\&\f(CW--printstate\fR Prints out the cached internal state of the driver. The first line lists various attributes about the disk: .RS .TP \&\fR\&\f(CWdrive\ present\fR\ .TQ \&\fR\&\f(CWdisk\ present\fR .TQ \&\fR\&\f(CWdisk\ writable\fR These are only updated when the drive is accessed. .TP \&\fR\&\f(CWspinup\fR\ is the time when the motor became switched on for the last time. .TP \&\fR\&\f(CWselect\fR\ is the time when the drive became selected for the last time .TP \&\fR\&\f(CWfirst_read\fR\ is the time when the first read request after the last spin up completed. .TP \&\fR\&\f(CWprobed_fmt\fR\ is the the index of the autodetected format in the autodetection sequence for this drive. .TP \&\fR\&\f(CWcylinder\fR\ is the cylinder where the drive head currently sits. If this number is negative, it has the following meaning: .RS .TP * \ \ -1 means that the driver doesn't know, but the controller does (a seek command must be issued). .TP * \ \ -2 means that the controller doesn't know either, but is sure that it not beyond the 80th track. The drive needs a recalibration. .TP * \ \ -3 means that the head may be beyond the 80th track. The drive needs two successive recalibrations, because at each recalibration, the controller only issues 80 move head commands per recalibration. .RE .TP \&\fR\&\f(CWmaxblock\fR\ is the highest block number that has been read. .TP \&\fR\&\f(CWmaxcylinder\fR\ is a boolean which is set when a sector that is not on cylinder 0/head 0 has been read. These are used for smart invalidation of the buffer cache on geometry change. The buffer cache of the drive is only invalidated on geometry change when this change actually implies that a block that has already been read changes position. This optimization is useful for mtools which changes the geometry after reading the boot sector. .TP \&\fR\&\f(CWgeneration\fR\ is roughly the number of disk changes noticed since boot. Disk changes are noticed if the disk is actually changed, or if a flush command is issued and for both cases if any I/O to/from the disk occurs. (i.e. if you insert several disks, but don't do any I/O to them, the generation number stays the same.) .TP \&\fR\&\f(CWrefs\fR\ is number of open file descriptors for this drive. It is always at least one, because floppycontrol's file descriptor is counted too. .TP \&\fR\&\f(CWdevice\fR\ is format type (as derived from the minor device number) which is currently being used. .TP \&\fR\&\f(CWlast_checked\fR\ is date (in jiffies) when the drive was last checked for a disk change, and a disk was actually in the drive. .RE .IP .TP \&\fR\&\f(CW--pollstate\fR\ Polls the drive and then prints out the internal state of the driver.(\fR\&\f(CW--Printstate\fR only prints out the cached information without actually polling the drive for a disk change.) .TP \&\fR\&\f(CW--printfdcstate\fR\ Prints out the state of the controller where the target drive is attached to. .RS .TP \&\fR\&\f(CWspec1\fR\ .TQ \&\fR\&\f(CWspec2\fR are the current values of those registers. .TP \&\fR\&\f(CWrate\fR\ is current data transfer rate .TP \&\fR\&\f(CWrawcmd\fR\ is true if a raw command has been executed since the last reset. If this is the case, a reset will be triggered when a drive on the same FDC is next opened. .TP \&\fR\&\f(CWdor\fR\ is the value of the digital output register. The 4 high bits are a bit mask describing which drives are spinning, the 2 low bits describe the selected drive, bit 2 is used to reset the FDC, and bit 3 describes whether this FDC has hold of the interrupt and the DMA. If you have two FDCs, bit 3 is only set on one of them. .TP \&\fR\&\f(CWversion\fR\ is the version of the FDC. See \fR\&\f(CW\(iflinux/include/linux/fdreg.h\(is\fR for a listing of the FDC version numbers. .TP \&\fR\&\f(CWreset\fR\ is true if a reset needs to be issued to the FDC before processing the next request. .TP \&\fR\&\f(CWneed_configure\fR\ is true if this FDC needs configuration by the \fR\&\f(CWFD_CONFIGURE\fR command. .TP \&\fR\&\f(CWhas_fifo\fR\ is set if the FDC understands the \fR\&\f(CWFD_CONFIGURE\fR command. .TP \&\fR\&\f(CWperp_mode\fR\ describes the perpendicular mode of this FDC. 0 is non-perpendicular mode, 2 is HD perpendicular mode, 3 is ED perpendicular mode, and 1 is unknown. .TP \&\fR\&\f(CWaddress\fR\ is the address of the first I/O port of the FDC. Normally, this is 0x3f0 for the first FDC and 0x370 for the second. .RE .PP .SH Drive\ type\ configuration\ and\ autodetection .iX "c CMOS type" .iX "c drive type" .iX "c swapping drives" .PP The following options handle the different available drive types, such as double density vs. high density vs. extra density drives, and 5 1/4 drives vs 3 1/2 drives. Usually the drive type is stored in a non-volatile memory, called CMOS, under the form of an integer ranging from 1 to 6. .PP Different drive types are able to handle and autodetect different formats (different autodetection lists). They also have different "native format name". The native format is the "usual" format with the highest capacity supported by the drive. (For example 720KB on a double density 3 1/2 drive, and 1.2MB on a high density 5 1/4 drive.) .PP These settings are only changeable by the super user. .TP \&\fR\&\f(CW-c\ \fIcmos-type\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--cmos\ \fI\ cmos-type\fR\&\f(CW\fR Set the virtual CMOS type of the floppy drive. This is useful if .RS .TP * \ \ the physical CMOS type is wrong (this may happen with BIOSes which use a non-standard mapping), .TP * \ \ you have more than two drives (the physical CMOS may only describe up to two drives). .TP * \ \ you have a BIOS that allows swapping drives A: and B: for DOS. .RE Right now, this CMOS parameter is not used by the kernel, except for feeding it back to other applications (for instance \fR\&\f(CWsuperformat\fR, \&\fR\&\f(CWfloppymeter\fR or \fR\&\f(CWMAKEFLOPPIES\fR). It is also possible to supply a virtual CMOS type with the \fR\&\f(CWcmos\fR boot option (see section Boottime configuration). If possible, I recommend you use the boot option, rather than \fR\&\f(CWfloppycontrol\fR, because the boot option also sets any parameters derived from the CMOS type, such as the autodetection list and the native format, whereas \fR\&\f(CWfloppycontrol\fR does not. .TP \&\fR\&\f(CW-A\ \ \fIautodetect-seq\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--autodetect\ \fI\ autodetect-seq\fR\&\f(CW\fR Set the autodetection sequence (see section Autodetection) The autodetection sequence is a comma-separated list of at most eight format descriptors. Each format descriptor is a format number optionally followed by the letter \fR\&\f(CWt\fR. For drive 0, the format number is the minor device number divided by 4. The autodetection sequence is used by the driver to find out the format of a newly inserted disk. The formats are tried one after the other, and the first matching format is retained. To test the format, the driver tries to read the first sector on the first track on the first head when \fR\&\f(CWt\fR is not given, or the whole first track when \fR\&\f(CWt\fR is given. Thus, autodetection cannot detect the number of tracks. However, this information is contained in the boot sector, which is now accessible. The boot sector can then be used by mtools to configure the correct number of tracks. .IP Example: .nf .ft 3 .in +0.3i 7,4,24t,25 .fi .in -0.3i .ft R .lp \&\fRmeans to try out the formats whose minor device numbers are 28 (1.44M), 16 (720KB), 96 (1.76MB), and 100 (1.92MB), in this order. For the 1.76MB format, try to read the whole track at once. .IP Reading the whole track at once allows you to distinguish between two formats which differ only in the number of sectors. (The format with the most sectors must be tried first.) If you use mtools, you do not need this feature, as mtools can figure out the number of sectors without any help from the floppy driver, by looking at the boot sector. .IP Reading the whole track at once may also speed up the first read by 200 milliseconds. However, if, on the other hand, you try to read a disk which has less sectors than the format, you lose some time. .IP I suggest that you put the most often used format in the first place (barring other constraints), as each format that is tried out takes 400 milliseconds. .TP \&\fR\&\f(CW-n\ \fInative-format\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--native_format\ \fI\ native-format\fR\&\f(CW\fR Set the native format of this drive. The native format of a drive is the highest standard format available for this drive. (Example: For a 5 1/4 HD drive it is the usual 1200K format.) This is format is used to make up the format name for the generic device (which is the name of the native format). This drive name is read back from the kernel by the \&\fR\&\f(CWMAKEFLOPPIES\fR script which uses it to decide which device nodes to create. .PP .SH Configuration\ of\ the\ disk\ change\ line .iX "c disk change line" .iX "c Thinkpad" .iX "c disk change detection" .iX "c disk absent during operation (false alert)" .TP \&\fR\&\f(CW--broken_dcl\fR\ Assumes that the disk change line of the drive is broken. If this is set, disk changes are assumed to happen whenever the device node is first opened. The physical disk change line is ignored. .IP This option should be used if disk changes are either not detected at all, or if disk changes are detected when the disk was actually not changed. If this option fixes the problem, I'd recommend that you try to trace the root cause of the problem. Indeed, this options results in reduced performance due to spurious cache flushes. .IP The following hardware problems may lead to a bad disk change line: .RS .TP * \ \ If the floppy cable is not inserted straight, or if it is kinked, the disk change line is likely to suffer, as it is on the edge of the cable. Gently press on both connectors of the cable (drive and controller) to insure that all wires make contact. Visually inspect the cable, and if it shows obvious traces of damage, get a new one. .TP * \ \ On some drives, the locations disk change line may be chosen by jumper. Make sure that your floppy controller and your drive agree on which line is the disk change line. .TP * \ \ Some older drives (mostly double density 5 1/4 drives) don't have a disk change line. In this case, you have no choice other than to leave the \&\fR\&\f(CWbroken_dcl\fR option on. .RE .TP \&\fR\&\f(CW--working_dcl\fR\ Assumes that the disk change line works all right. Switching from broken to working may lead to unexpected results after the first disk change. .TP \&\fR\&\f(CW--inverted_dcl\fR\ Assumes that this disk drive uses an inverted disk change line. Apparently this is the case for IBM thinkpads. .TP \&\fR\&\f(CW--no_inverted_dcl\fR\ Assumes that this drive follows the standard convention for the disk change line. .TP \&\fR\&\f(CW--noisy_dcl_clear\fR\ Switches off silent disk change line clearing for this drive. .PP .SH Timing\ Parameters .iX "c strange noises during seek" .PP This section describes how to configure drive timings. To set these parameters, you need superuser privileges. All times are in "jiffy" units (10 milliseconds), unless otherwise specified. .TP \&\fR\&\f(CW--hlt\ \fI\ hlt\fR\&\f(CW\fR\ Set the head load time (in microseconds) for this floppy drive. The head load time describes how long the floppy controller waits after seeking or changing heads before allowing access to a track. .TP \&\fR\&\f(CW--hut\ \fI\ hut\fR\&\f(CW\fR\ Set the head unload time (in microseconds) for this floppy drive. The head unload time describes how long the floppy controller waits after an access before directing its attention to the other head, or before seeking. .TP \&\fR\&\f(CW--srt\ \fI\ srt\fR\&\f(CW\fR\ Set the step rate (in microseconds) for this floppy drive. The step rate describes how long the drive head stays on one cylinder when seeking. Setting this value to low (too fast seeks) may make seeks fail, because the motor doesn't follow fast enough. .TP \&\fR\&\f(CW-u\ \fIspinup-time\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--spinup\ \fI\ spinup-time\fR\&\f(CW\fR Set the spinup time of the floppy drive. In order to do read or write to the floppy disk, it must spin. It takes a certain time for the motor to reach enough speed to read or write. This parameter describes this time. The floppy driver doesn't try to access the drive before the spinup time has elapsed. With modern controllers, you may set this time to zero, as the controller itself enforces the right delay. .TP \&\fR\&\f(CW-o\ \fIspindown-time\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--spindown\ \fI\ spindown-time\fR\&\f(CW\fR Set the spindown time of this floppy drive. The motor is not stopped immediately after the operation completes, because there might be more operations following. The spindown time is the time the driver waits before switching off the motor. .TP \&\fR\&\f(CW-O\ \fIspindown-offset\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--spindown_offset\ \fI\ spindown-offset\fR\&\f(CW\fR Set the spindown offset of this floppy drive. This parameter is used to set the position in which the disk stops. This is useful to minimize the next access time. (If the first sector is just near the head at the very moment at which the disk has reached enough speed, you win 200 milliseconds against the most unfavorable situation). .IP This is done by clocking the time where the first I/O request completes, and using this time to calculate the current position of the disk. .TP \&\fR\&\f(CW-s\ \fIselect-delay\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--select_delay\ \fI\ select-delay\fR\&\f(CW\fR Set the \fIselect delay\fR of this floppy drive. This is the delay that the driver waits after selecting the drive and issuing the first command to it. For modern controllers/drives, you may set this to zero. .TP \&\fR\&\f(CW-C\ \fIcheck-interval\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--checkfreq\ \fI\ check-interval\fR\&\f(CW\fR Set the maximal disk change check interval. The disk change line is checked whenever a read or write to the device is issued, and it has not been checked for more than \fIinterval\fR jiffies. .PP .SH Debugging\ messages .PP This subsection describes how to switch the available debugging messages on and off. .IP .TP \&\fR\&\f(CW--debug\fR\ Switch debugging output on. The debugging information includes timing information. This option might be useful to fine-tune the timing options for your local setups. (But for most normal purposes, the default values are good enough.) .TP \&\fR\&\f(CW--nodebug\fR\ Switch debugging output off. .TP \&\fR\&\f(CW--messages\fR\ Print informational messages after autodetection, geometry parameter clearing and dma over/underruns. .TP \&\fR\&\f(CW--nomessages\fR\ Don't print informational messages after these events. .PP .SH Error\ Handling\ Options .PP The following options configure the behavior of the floppy driver in case of read/write errors. They may be used by any user who has write privileges for the drive. Whenever the floppy driver encounters an error, a retry counter is incremented. If the value of this counter gets bigger than the thresholds described below, the corresponding actions are performed at the next retry. The counter is reset when the read or write finally terminates, whether successfully or not. .TP \&\fR\&\f(CW-a\ \fIoperation-abort-trshld\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--abort\ \fI\ operation-abort-trshld\fR\&\f(CW\fR Tell the floppy driver to stop trying to read/write a sector after \&\fIoperation-abort-trshld\fR retries, and signal the I/O error to the user. .TP \&\fR\&\f(CW-t\ \fIread-track-trshld\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--readtrack\ \fI\ read-track-trshld\fR\&\f(CW\fR Tell the floppy driver to switch from track-reading mode to sector-at-a-time-mode after \&\fIread-track-trshld\fR retries. .TP \&\fR\&\f(CW-r\ \fIrecalibrate-trshld\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--recalibrate\ \fI\ recalibrate-trshld\fR\&\f(CW\fR Tell the floppy driver to recalibrate the drive after \&\fIrecalibrate-trshld\fR retries. .TP \&\fR\&\f(CW-R\ \fIreset-treshold\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--reset\ \fI\ reset-threshold\fR\&\f(CW\fR Tell the floppy driver to reset the controller after \&\fIreset-threshold\fR retries. After a controller reset, the floppy driver also recalibrates all drives connected to that controller. .IP .TP \&\fR\&\f(CW-e\ \fIerror-report-trshld\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--reporting\ \fI\ error-report-trshld\fR\&\f(CW\fR Tell the floppy driver to start printing error messages to the console after \fIerror-report-trshld\fR retries. .PP .SH Write\ error\ reporting .PP Due to the buffer cache, write errors cannot always be reported to the writing user program as soon as the write system call returns. Indeed, the actual writing may take place much later. If a write error is encountered, the floppy driver stores information about it in its per drive write error structure. This write error structure stays until explicitly cleared. It can for example be queried by a backup program which wants to make sure that the data has been written successfully. .IP .TP \&\fR\&\f(CW--clrwerror\fR\ Clears the write error structure. .TP \&\fR\&\f(CW--printwerror\fR\ Prints the contents of the write error structure: .RS .TP \&\fR\&\f(CWwrite_errors\fR\ is a count of how many write errors have occurred since the structure was last cleared. .TP \&\fR\&\f(CWbadness\fR\ is the maximal number of retries that were needed to complete an operation (reads, writes and formats). .TP \&\fR\&\f(CWfirst_error_sector\fR\ is where the first (chronologically) write error occurred. .TP \&\fR\&\f(CWfirst_error_generation\fR\ is the disk change generation in which did the first write error occurred. The disk change generation is a number which is incremented at each disk change. .TP \&\fR\&\f(CWlast_error_sector\fR\ and .TP \&\fR\&\f(CWlast_error_generation\fR\ are similar. .RE .PP .SH Other\ drive\ configuration\ options .PP This subsection lists per drive configuration options, which don't fit in any other category. They are available only to the superuser: .IP .TP \&\fR\&\f(CW--tracks\ \fI\ max-tracks\fR\&\f(CW\fR\ Set the maximal numbers of physical tracks that this drive may handle. If you have a drive which is only able to handle 80 tracks (making strange noises when you try to format or read a disk with more than 80 tracks), use this option to prevent unprivileged users of damaging your drive by repeatedly reading disks with more than 80 tracks. .IP If you trust your users and your disks, you don't need this. With most drives you don't need to worry anyways. See section More cylinders, for details. .TP \&\fR\&\f(CW-i\ \fIsector-interleave\fR\&\f(CW\ \fR\ .TQ \&\fR\&\f(CW--interleave\ \fIsector-interleave\fR\&\f(CW\fR Set the number of sectors beyond which sector interleaving will be used. This option will only be used by the \fR\&\f(CWFDFMTTRK\fR ioctl. The \&\fR\&\f(CWfdformat\fR command, which is now considered obsolete, uses \&\fR\&\f(CWFDFMTTRK\fR ioctl, but \fR\&\f(CWsuperformat\fR does not. .IP .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/superformat.10000644000175000017500000003153110211703706016371 0ustar anibalanibal.TH superformat 1 "03Mar05" fdutils-5.5 .SH Name superformat - format floppies '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p superformat" .iX "c formatting disks (non XDF)" .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWsuperformat [\fR\&\f(CW-D \fIdos-drive\fR\&\f(CW] [\fR\&\f(CW-v \fIverbosity-level\fR\&\f(CW] [\fR\&\f(CW-b \fIbegin-track\fR\&\f(CW] [\fR\&\f(CW-e \fIend-track\fR\&\f(CW] [\fR\&\f(CW--superverify] [\fR\&\f(CW--dosverify] [\fR\&\f(CW--noverify] [\fR\&\f(CW--verify_later] [\fR\&\f(CW--zero-based] [\fR\&\f(CW-G \fIformat-gap\fR\&\f(CW] [\fR\&\f(CW-F \fIfinal-gap\fR\&\f(CW] [\fR\&\f(CW-i \fIinterleave\fR\&\f(CW] [\fR\&\f(CW-c \fIchunksize\fR\&\f(CW] [\fR\&\f(CW-g \fIgap\fR\&\f(CW] [\fR\&\f(CW--absolute-skew \fIabsolute-skew\fR\&\f(CW] [\fR\&\f(CW--head-skew \fIhead-skew\fR\&\f(CW] [\fR\&\f(CW--track-skew \fItrack-skew\fR\&\f(CW] [\fR\&\f(CW--biggest-last] \fIdrive\fR\&\f(CW [\fImedia-description\fR\&\f(CW] .fi .in -0.3i .ft R .lp \&\fR .PP \&\fR\&\f(CWsuperformat\fR is used to format disks with a capacity of up to 1992K HD or 3984K ED. See section Extended formats, for a detailed description of these formats. See section Media description, for a detailed description of the syntax for the media description. If no media description is given, superformat formats a disk in the highest available density for that drive, using standard parameters (i.e. no extra capacity formats). .PP When the disk is formatted, \fR\&\f(CWsuperformat\fR automatically invokes \&\fR\&\f(CWmformat\fR in order to put an MS-DOS filesystem on it. You may ignore this filesystem, if you don't need it. .PP Supeformat allows to format 2m formats. Be aware, however, that these \&\fR\&\f(CW2m\fR formats were specifically designed to hold an MS-DOS filesystem, and that they take advantage of the fact that the MS-DOS filesystem uses redundant sectors on the first track (the FAT, which is represented twice). The second copy of the FAT is \fInot\fR represented on the disk. .PP High capacity formats are sensitive to the exact rotation speed of the drive and the resulting difference in raw capacity. That's why \&\fR\&\f(CWsuperformat\fR performs a measurement of the disks raw capacity before proceeding with the formatting. This measurement is rather time consuming, and can be avoided by storing the relative deviation of the drive capacity into the drive definition file file. See section Drive descriptions, for more details on this file. The line to be inserted into the drive definition file is printed by superformat after performing its measurement. However, this line depends on the drive and the controller. Do not copy it to other computers. Remove it before installing another drive or upgrade your floppy controller. Swap the drive numbers if you swap the drives in your computer. .PP .SH Common\ Options Many options have a long and a short form. .TP \&\fR\&\f(CW-h\fR\ .TQ \&\fR\&\f(CW--help\fR Print the help. .TP \&\fR\&\f(CW-D\ \fIdrive\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--dosdrive\ \fIdos-drive\fR\&\f(CW\fR Selects DOS drive letter for \fR\&\f(CWmformat\fR (for example \fR\&\f(CWa:\fR or \&\fR\&\f(CWb:\fR). The colon may be omitted. The default is derived from the minor device number. If the drive letter cannot be guessed, and is not given on the command line, \fR\&\f(CWmformat\fR is skipped. .TP \&\fR\&\f(CW-v\ \fIverbosity-level\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--verbosity\ \fIverbosity-level\fR\&\f(CW\fR Sets the verbosity level. 1 prints a dot for each formatted track. 2 prints a changing sign for each formatted track (- for formatting the first head, = for formatting the second head, x for verifying the first head, and + for verifying the second head). 3 prints a complete line listing head and track. 6 and 9 print debugging information. .TP \&\fR\&\f(CW--superverify\fR\ Verifies the disk by first reading the track, than writing a pattern of U's, and then reading it again. This is useful as some errors only show up after the disk has once been written. However, this is also slower. .TP \&\fR\&\f(CW-B\fR\ .TQ \&\fR\&\f(CW--dosverify\fR Verifies the disk using the \fR\&\f(CWmbadblocks\fR program. \&\fR\&\f(CWmbadblocks\fR marks the bad sectors as bad in the FAT. The advantage of this is that disks which are only partially bad can still be used for MS-DOS filesystems. .TP \&\fR\&\f(CW-V\fR\ .TQ \&\fR\&\f(CW--verify_later\fR Verifies the whole disk at the end of the formatting process instead of at each track. Verifying the disk at each track has the advantage of detecting errors early on. .TP \&\fR\&\f(CW-f\fR\ .TQ \&\fR\&\f(CW--noverify\fR Skips the verification altogether. .PP .SH Advanced\ Options Usually, superformat uses sensible default values for these options, which you normally don't need to override. They are intended for expert users. Most of them should only be needed in cases where the hardware or superformat itself has bugs. .IP .TP \&\fR\&\f(CW-b\ \fIbegin-track\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--begin_track\ \ \fIbegin-track\fR\&\f(CW\fR Describes the track where to begin formatting. This is useful if the previous formatting failed halfway through. The default is 0. .TP \&\fR\&\f(CW-e\ \fIend-track\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--end_track\ \fIend-track\fR\&\f(CW\fR Describes where to stop formatting. \fIend_track\fR is the last track to be formatted plus one. This is mainly useful for testing purposes. By default, this is the same as the total number of tracks. When the formatting stops, the final skew is displayed (to be used as absolute skew when you'll continue). .TP \&\fR\&\f(CW-S\ \fIsizecode\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--sizecode\ \fIsizecode\fR\&\f(CW\fR Set the sector size to be used. The sector size is 128 * (2 ^ \&\fIsizecode\fR). Sector sizes below 512 bytes are not supported, thus sizecode must be at least 2. By default 512 is assumed, unless you ask for more sectors than would fit with 512 bytes. .TP \&\fR\&\f(CW--stretch\ \fIstretch\fR\&\f(CW\fR\ Set the stretch factor. The stretch factor describes how many physical tracks to skip to get to the next logical track (2 ^ \fIstretch\fR). On double density 5 1/4 disks, the tracks are further apart from each other. .TP \&\fR\&\f(CW-G\ \fIfmt-gap\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--format_gap\ \fIfmt-gap\fR\&\f(CW\fR Set the formatting gap. The formatting gap tells how far the sectors are away from each other. By default, this is chosen so as to evenly distribute the sectors along the track. .TP \&\fR\&\f(CW-F\ \fIfinal-gap\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--final_gap\ \fIfinal-gap\fR\&\f(CW\fR Set the formatting gap to be used after the last sector. .TP \&\fR\&\f(CW-i\ \fIinterleave\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--interleave\ \fIinterleave\fR\&\f(CW\fR Set the sector interleave factor. .TP \&\fR\&\f(CW-c\ \fIchunksize\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--chunksize\ \fIchunksize\fR\&\f(CW\fR Set the size of the chunks. The chunks are small auxiliary sectors used during formatting. They are used to handle heterogeneous sector sizes (i.e. not all sectors have the same size) and negative formatting gaps. .TP \&\fR\&\f(CW--biggest-last\fR\ For MSS formats, make sure that the biggest sector is last on the track. This makes the format more reliable on drives which are out of spec. .TP \&\fR\&\f(CW--zero-based\fR\ Formats the disk with sector numbers starting at 0, rather than 1. Certain CP/M boxes or Music synthesizers use this format. Those disks can currently not be read/written to by the standard Linux read/write API; you have to use fdrawcmd to access them. As disk verifying is done by this API, verifying is automatically switched off when formatting zero-based. .PP .SH Sector\ skewing\ options .PP In order to maximize the user data transfer rate, the sectors are arranged in such a way that sector 1 of the new track/head comes under the head at the very moment when the drive is ready to read from that track, after having read the previous track. Thus the first sector of the second track is not necessarily near the first sector of the first track. The skew value describes for each track how far sector number 1 is away from the index mark. This skew value changes for each head and track. The amount of this change depends on how fast the disk spins, and on how much time is needed to change the head or the track. .TP \&\fR\&\f(CW--absolute_skew\ \fIabsolute-skew\fR\&\f(CW\fR\ .IP Set the absolute skew. This skew value is used for the first formatted track. It is expressed in raw bytes. .TP \&\fR\&\f(CW--head_skew\ \fIhead-skew\fR\&\f(CW\fR\ .IP Set the head skew. This is the skew added for passing from head 0 to head 1. It is expressed in raw bytes. .TP \&\fR\&\f(CW--track_skew\ \fItrack-skew\fR\&\f(CW\fR\ .IP Set the track skew. This is the skew added for seeking to the next track. It is expressed in raw bytes. .PP Example: (absolute skew=3, head skew=1, track skew=2) .PP .nf .ft 3 .in +0.3i track 0 head 0: 4,5,6,1,2,3 (skew=3) track 0 head 1: 3,4,5,6,1,2 (skew=4) \&\& track 1 head 0: 1,2,3,4,5,6 (skew=0) track 1 head 1: 6,1,2,3,4,5 (skew=1) \&\& track 2 head 0: 4,5,6,1,2,3 (skew=3) track 2 head 1: 3,4,5,6,1,2 (skew=4) .fi .in -0.3i .ft R .lp \&\fR .PP N.B. For simplicitie's sake, this example expresses skews in units of sectors. In reality, superformat expects the skews to be expressed in raw bytes. .PP .SH Examples In all the examples of this section, we assume that drive 0 is a 3 1/2 and drive 1 a 5 1/4. .PP The following example shows how to format a 1440K disk in drive 0: .nf .ft 3 .in +0.3i superformat /dev/fd0 hd .fi .in -0.3i .ft R .lp \&\fR .PP The following example shows how to format a 1200K disk in drive 1: .nf .ft 3 .in +0.3i superformat /dev/fd1 hd .fi .in -0.3i .ft R .lp \&\fR .PP The following example shows how to format a 1440K disk in drive 1: .nf .ft 3 .in +0.3i superformat /dev/fd1 hd sect=18 .fi .in -0.3i .ft R .lp \&\fR .PP The following example shows how to format a 720K disk in drive 0: .nf .ft 3 .in +0.3i superformat /dev/fd0 dd .fi .in -0.3i .ft R .lp \&\fR .PP The following example shows how to format a 1743K disk in drive 0 (83 cylinders times 21 sectors): .nf .ft 3 .in +0.3i superformat /dev/fd0 sect=21 cyl=83 .fi .in -0.3i .ft R .lp \&\fR .PP The following example shows how to format a 1992K disk in drive 0 (83 cylinders times 2 heads times 12 KB per track) .nf .ft 3 .in +0.3i superformat /dev/fd0 tracksize=12KB cyl=83 mss .fi .in -0.3i .ft R .lp \&\fR .PP The following example shows how to format a 1840K disk in drive 0. It will have 5 2048-byte sectors, one 1024-byte sector, and one 512-byte sector per track: .nf .ft 3 .in +0.3i superformat /dev/fd0 tracksize=23b mss 2m ssize=2KB .fi .in -0.3i .ft R .lp \&\fR .PP All these formats can be autodetected by mtools, using the floppy driver's default settings. .PP .SH Troubleshooting .TP \&\fR\&\f(CWFDC\ busy,\ sleeping\ for\ a\ second\fR\ When another program accesses a disk drive on the same controller as the one being formatted, \fR\&\f(CWsuperformat\fR has to wait until the other access is finished. If this happens, check whether any other program accesses a drive (or whether a drive is mounted), kill that program (or unmount the drive), and the format should proceed normally. .TP \&\fR\&\f(CWI/O\ errors\ during\ verification\fR\ Your drive may be too far out of tolerance, and you may thus need to supply a margin parameter. Run \fR\&\f(CWfloppymeter\fR (see section floppymeter) to find out an appropriate value for this parameter, and add the suggested \fR\&\f(CWmargin\fR parameter to the command line .PP .SH Bugs Opening up new window while \fR\&\f(CWsuperformat\fR is running produces overrun errors. These errors are benign, as the failed operation is automatically retried until it succeeds. .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/makefloppies.texi0000444000175000017500000000332107464324643017323 0ustar anibalanibal@node makefloppies, setfdprm, getfdprm, Commands @section makefloppies @example @code{MAKEFLOPPIES} [@code{-tlvng}] [@var{drives}] @end example The @code{MAKEFLOPPIES} shell script creates the new floppy block device node. It uses the floppycontrol program to translate the minor device numbers into meaningful names. It also uses these names to decide whether to create a given block device file or not, depending on the type of the physical drive (for instance, for a 3 1/2 drive, the formats corresponding to a 5 1/4 drive are not created). If you have more than two floppy drives, you need to tell the kernel the CMOS types of those additional drives using the @code{floppy=}@var{drive}@code{,}@var{type}@code{,cmos} lilo option. If the @var{drives } parameter is given, only the device nodes for the listed drives are made. By default, all only the two first drives are tried. @code{MAKEFLOPPIES} does not work if you redefine your default formats. @strong{Caution}: @code{MAKEFLOPPIES} removes already existing floppy device nodes. @subsection Options @table @code @item -t Use the old naming convention for 3 1/2 devices (e.g. @file{fd0H720} instead of @file{fd0u720}). @item -m Base the name for the created devices on the type of the media (e.g. @file{fd0h720} instead of @file{fd0u720}). @item -l Local. Creates device nodes in the local directory, not /dev @item -v Verbose @item -n Dry run. (just report what would be done, do not do anything) @item -g Group. Allow read/write access to floppy devices only for group @samp{floppy} @end table @subsection Bugs The Makefloppies script does not work on redefined "default" formats, If you redefine default formats, you need to create the needed device nodes manually. fdutils-5.5-20060227/doc/fdmount.10000644000175000017500000002706110211703706015501 0ustar anibalanibal.TH fdmount 1 "03Mar05" fdutils-5.5 .SH Name fdmount - Floppy disk mount utility '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p fdmount" .iX "p fdmountd" .iX "p fdlist" .iX "p fdumount" .iX "c automounting" .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWfdmount [\fR\&\f(CW-l] [\fR\&\f(CW--list] [\fR\&\f(CW-d] [\fR\&\f(CW--daemon] [\fR\&\f(CW--detach] [\fR\&\f(CW-i \fIinterval\fR\&\f(CW] [\fR\&\f(CW--interval \fIinterval\fR\&\f(CW] [\fR\&\f(CW-o \fImount-options\fR\&\f(CW] [\fR\&\f(CW-r] [\fR\&\f(CW-readonly] [\fR\&\f(CW-s] [\fR\&\f(CW--sync] [\fR\&\f(CW--nosync] [\fR\&\f(CW--nodev] [\fR\&\f(CW--nosuid] [\fR\&\f(CW--noexec] [\fR\&\f(CW-f] [\fR\&\f(CW--force] [\fR\&\f(CW-h] [\fR\&\f(CW--help] [\fIdrivename\fR\&\f(CW] [\fImountpoint\fR\&\f(CW] \&\& \&\fR\&\f(CWfdumount [\fR\&\f(CW-f] [\fR\&\f(CW--force] [\fIdrivename\fR\&\f(CW] \&\& \&\fR\&\f(CWfdlist \&\& \&\fR\&\f(CWfdmountd [\fR\&\f(CW-i \fIinterval\fR\&\f(CW] [\fR\&\f(CW--interval \fIinterval\fR\&\f(CW] [\fR\&\f(CW-r] [\fR\&\f(CW-readonly] [\fR\&\f(CW-s] [\fR\&\f(CW--sync] [\fR\&\f(CW--nosync] [\fR\&\f(CW--nodev] [\fR\&\f(CW--nosuid] [\fR\&\f(CW--noexec] [\fR\&\f(CW--help] [\fIdrivename\fR\&\f(CW] [\fImountpoint\fR\&\f(CW]] \&\& .fi .in -0.3i .ft R .lp \&\fR .PP The \fR\&\f(CWfdmount\fR program mounts a floppy disk in the specified drive. It tries to figure out the exact format and filesystem type of the disk from data in the disk's boot sector or super block and the auto-detected track layout. .PP Currently, fdmount supports the filesystems \fR\&\f(CWminix\fR, \fR\&\f(CWext\fR, \&\fR\&\f(CWext2\fR, \fR\&\f(CWxia\fR, and \fR\&\f(CWmsdos\fR, and includes special support for disks formatted by the \fR\&\f(CW2M\fR utility for MS-DOS. .PP It also checks whether the disk is write protected, in which case it is mounted read-only. .PP The symbolic \fIdrivename\fR is (currently) one of \fR\&\f(CW\(iffd[0-7]\(is\fR, corresponding to the special device files \fR\&\f(CW\(if/dev/fd[0-7]\(is\fR. If \&\fIdrivename\fR is not specified, \fR\&\f(CW\(iffd0\(is\fR is assumed. .PP The disk is mounted on the directory \fImountpoint\fR, if specified, or on \fR\&\f(CW\(if/fd[0-7]\(is\fR. In either case, the mount point must be an existing, writable directory. .PP \&\fBDue to a bug in the floppy driver (?), the polling interval (-i flag) must be longer than the spindown offset. Thus you need to do (for example) floppycontrol --spindown 99 before starting fdmountd in daemon mode\fR .PP .SH Options .IP .TP \&\fR\&\f(CW-l\ \fI--list\fR\&\f(CW\fR\ List all known drives with their symbolic name, type, and mount status. .TP \&\fR\&\f(CW-d\ \fI--daemon\fR\&\f(CW\fR\ Run in daemon mode (see below). .TP \&\fR\&\f(CW--detach\fR\ Runs daemon in background, and detaches it from its tty. Messages produced after the fork are logged to syslog. .TP \&\fR\&\f(CW-p\ \fIfile\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--pidfile\ \fIfile\fR\&\f(CW\fR .IP Dumps the process id of the daemon to \&\fIfile\fR. This makes killing the daemon easier: \&\fR\&\f(CWkill -9 `cat \fIfile\fR\&\f(CW`\fR .TP \&\fR\&\f(CW-i\ \fIinterval\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--interval\ \fIinterval\fR\&\f(CW\fR Set the polling interval for daemon mode. The unit for \fIinterval\fR is 0.1 seconds, the default value is 10 (i.e. 1 second). .TP \&\fR\&\f(CW-o\ \fIoptions\fR\&\f(CW\fR\ .TQ \&\fR\&\f(CW--options\ \fIoptions\fR\&\f(CW\fR Sets filesystem-specific options. So far, these are only available for DOS and Ext2 disks. The following DOS options are supported: \&\fR\&\f(CWcheck\fR, \fR\&\f(CWconv\fR, \fR\&\f(CWdotsOK\fR, \fR\&\f(CWdebug\fR, \fR\&\f(CWfat\fR, \&\fR\&\f(CWquiet\fR, \fR\&\f(CWblocksize\fR. The following Ext2 options are supported: \fR\&\f(CWcheck\fR, \fR\&\f(CWerrors\fR, \fR\&\f(CWgrpid\fR, \fR\&\f(CWbsdgroups\fR, \&\fR\&\f(CWnogrpid\fR, \fR\&\f(CWsysvgroups\fR, \fR\&\f(CWbsddf\fR, \fR\&\f(CWminixdf\fR, \&\fR\&\f(CWresgid\fR, \fR\&\f(CWdebug\fR, \fR\&\f(CWnocheck\fR. When running as a daemon, options not applying to the disk that is inserted (because of its filesystem type) are not passed to mount. .TP \&\fR\&\f(CW-r\ \fI--readonly\fR\&\f(CW\fR\ Mount the disk read-only. This is automatically assumed if the disk is write protected. .TP \&\fR\&\f(CW-s\ \fI--sync\fR\&\f(CW\fR\ Mount with the \fR\&\f(CWSYNC\fR option. .TP \&\fR\&\f(CW--nosync\fR\ Mounts without the \fR\&\f(CWSYNC\fR option, even when running as daemon. .TP \&\fR\&\f(CW--nodev\fR\ Mount with the \fR\&\f(CWNODEV\fR option. Ignored for \fR\&\f(CWmsdos\fR filesystems, otherwise always set for non-root users. .TP \&\fR\&\f(CW--nosuid\fR\ Mount with the \fR\&\f(CWNOSUID\fR option. Ignored for \fR\&\f(CWmsdos\fR filesystems, otherwise always set for non-root users. .TP \&\fR\&\f(CW--noexec\fR\ Mount with the \fR\&\f(CWNOEXEC\fR option. .TP \&\fR\&\f(CW-f\ \fI--force\fR\&\f(CW\fR\ Attempt a mount or unmount operation even \fR\&\f(CW\(if/etc/mtab\(is\fR says that the drive is already mounted, or not mounted, respectively. This option is useful if \fR\&\f(CW\(if/etc/mtab\(is\fR got out of sync with the actual state for some reason. .TP \&\fR\&\f(CW-h\ \fI--help\fR\&\f(CW\fR\ Show short parameter description .PP .SH Security .PP When mounting on the default mount point, the mount points' owner is set to the current user, and the access flags according to the user's umask. For a specified mountpoint, owner and permissions are left unchanged. Default mount points are called \fR\&\f(CW/fd0\fR, \fR\&\f(CW/fd1\fR, \&\&... , \fR\&\f(CW/fd7\fR. .PP The user running fdmount must have read access to the floppy device for read only mounts, and read/write access for read/write mounts. .PP Fdmount can be run suid root, allowing users to mount floppy disks. The following restrictions are placed upon non-root users: .TP * \ \ If a mountpoint is specified explicitly, it must be owned by the user. .TP * \ \ A user may only unmount a disk if the mount point is owned by the user, or if it the disk has been mounted by the same user. .TP * \ \ Non-msdos disks are automatically mounted with the \fR\&\f(CWnodev\fR and \&\fR\&\f(CWnosuid\fR flags set. .PP However, \fBdo not rely on fdmount being secure at the moment\fR. .PP .SH Daemon\ mode .PP In daemon mode, the specified drive is periodically checked and if a disk is inserted, it is automatically mounted. .PP When the disk is removed, it is automatically unmounted. However, it is recommended to unmount the disk manually \fIbefore\fR removing it. In order to limit corruption, disks are mounted with the SYNC option when running in daemon mode, unless the \fR\&\f(CW--nosync\fR flag is given. .PP Note that this mode has some potential drawbacks: .TP * \ \ Some floppy drives have to move the drive head physically in order to reset the disk change signal. It is strongly recommended not to use daemon mode with these drives. See section floppycontrol, for details. .TP * \ \ If a disk does not contain a filesystem (e.g. a tar archive), the mount attempt may slow down initial access. .TP * \ \ As fdmount cannot identify the user trying to use the disk drive, there is no way to protect privacy. Disks are always mounted with public access permissions set. .PP .SH Diagnostics .IP .TP \&\fR\&\f(CWerror\ opening\ device\ \fIname\fR\&\f(CW\fR\ .TP \&\fR\&\f(CWerror\ reading\ boot/super\ block\fR\ fdmount failed to read the first 1K of the disk. The disk might be damaged, unformatted, or it may have a format wich is unsupported by the FDC or the Linux kernel. .TP \&\fR\&\f(CWunknown\ filesystem\ type\fR\ No magic number of any of the supported filesystems (see above) could be identified. .TP \&\fR\&\f(CWsorry,\ can\(fmt\ figure\ out\ format\ (\fIfs\fR\&\f(CW\ filesystem)\fR\ The size of the filesystem on the disk is incompatible with the track layout detected by the kernel and an integer number of tracks. This may occur if the filesystem uses only part of the disk, or the track layout was detected incorrectly by the kernel. .TP \&\fR\&\f(CWfailed\ to\ mount\ \fIfs>\ >$outfile echo .TH\ $command\ 1\ \"$date\" $package >$outfile echo .SH Name >>$outfile grep -i $command cmdname >>$outfile #echo ".SH Description" >>$outfile # -e "1,/^@node $command/d" \ # -e "/^@node [^,]*, [^,]*, $command, Commands$/,/^@bye/d" \ # -e "/^@node [^,]*, [^,]*, Commands/,/^@bye/d" \ cat man-warning.texi $texifile | sed \ -e 's/^@section/@chapter/' \ -e 's/^@subs/@s/' \ -e 's/^@chapter.*$/@chapter Description/' \ -e 's/^@section/@chapter/' \ -e 's/^@subs/@s/' \ -e 's/^@c xMANoptions/@chapter Options/' \ -e "s/^@c MAN/@MAN/" | texi2roff -ma | sed -f strip-pp.sed >>$outfile echo ".SH See Also" >>$outfile echo "Fdutils' texinfo doc" >>$outfile } extract diskd extract diskseekd extract fdmount extract fdrawcmd extract floppycontrol extract floppymeter extract getfdprm extract makefloppies extract setfdprm extract superformat extract xdfcopy fdutils-5.5-20060227/doc/setfdprm.10000644000175000017500000000657210211703706015655 0ustar anibalanibal.TH setfdprm 1 "03Mar05" fdutils-5.5 .SH Name setfdprm - sets user-provided floppy disk parameters '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p setfdprm" .iX "c setting the geometry information" .iX "c geometry information (setting)" .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWsetfdprm [\fR\&\f(CW-p] \fIdevice\fR\&\f(CW \fImedia-description\fR\&\f(CW \&\& \&\fR\&\f(CWsetfdprm [\fR\&\f(CW-c | \fR\&\f(CW-y | \fR\&\f(CW-n] \fIdevice\fR\&\f(CW \&\& .fi .in -0.3i .ft R .lp \&\fR .PP \&\fR\&\f(CWsetfdprm\fR is a utility that can be used to load disk parameters into the auto-detecting floppy devices and "fixed parameter" floppy devices, to clear old parameter sets and to disable or enable diagnostic messages. These parameters are derived from a media-description, see section Media description for more details. .PP Without any options, \fR\&\f(CWsetfdprm\fR loads the \fIdevice\fR (for example \&\fR\&\f(CW\(if/dev/fd0\(is\fR or \fR\&\f(CW\(if/dev/fd1\(is\fR) with a new parameter set with the \&\fIname\fR entry found in \fR\&\f(CW\(if/etc/fdprm\(is\fR (usually named 360/360, etc.). For autodetecting floppy devices, these parameters stay in effect until the media is changed. For "fixed parameter" devices, they stay in effect until they are changed again. .PP \&\fR\&\f(CWSetfdprm\fR can also be used by the superuser to redefine the default formats. .PP .SH Options .IP .TP \&\fR\&\f(CW-p\ \fIdevice\ name\fR\&\f(CW\fR\ Permanently loads a new parameter set for the specified auto-configuring floppy device for the configuration with \fIname\fR in \&\fR\&\f(CW\(if/etc/fdprm\(is\fR. Alternatively, the parameters can be given directly from the command line. .TP \&\fR\&\f(CW-c\ \fIdevice\fR\&\f(CW\fR\ Clears the parameter set of the specified auto-configuring floppy device. .TP \&\fR\&\f(CW-y\ \fIdevice\fR\&\f(CW\fR\ Enables format detection messages for the specified auto-configuring floppy device. .TP \&\fR\&\f(CW-n\ \fIdevice\fR\&\f(CW\fR\ Disables format detection messages for the specified auto-configuring floppy device. .PP .SH Bugs This documentation is grossly incomplete. .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/xdfcopy.10000644000175000017500000001127110211703706015475 0ustar anibalanibal.TH xdfcopy 1 "03Mar05" fdutils-5.5 .SH Name xdfcopy - Program to copy and format Xdf disks in Linux '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p xdfcopy" .iX "c XDF (formatting and copying disks)" .iX "c formatting XDF disks" .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWxdfcopy [\fR\&\f(CW-\fIformat-id\fR\&\f(CW] [\fR\&\f(CW-d] [\fR\&\f(CW-n] [\fR\&\f(CW-h \fIhead-skew\fR\&\f(CW] [\fR\&\f(CW-t \fIcylinder-skew\fR\&\f(CW] [\fR\&\f(CW-T \&\fIend-cylinder\fR\&\f(CW] [\fIsource\fR\&\f(CW] \fItarget\fR\&\f(CW .fi .in -0.3i .ft R .lp \&\fR .PP \&\fR\&\f(CWXdfcopy\fR is a utility to copy and format XDF disks. XDF (eXtended Density Format) is a format used by OS/2 which can hold 1840KB of data (on a 3 1/2 high density disk). Its advantage over 2m formats is that it is faster: 38KB/s. Because of this fast speed, I extended the XDF standard to higher capacities (1992KB) with a transfer rate of 45KB/s. I called the new formats XXDF. .PP This program works best with kernels newer than 2.0.0. .PP If both source and target are given, xdfcopy copies the disk image from file to floppy disk or vice-versa. When copying to a floppy disk, the disk is first formatted, unless the \fR\&\f(CW-n\fR option is given. .PP If no source is given, the target is only formatted. In this case, the target must be a floppy drive. .PP .SH Options .PP .SS Selecting\ a\ format .PP Formats are selected by the format_id. The following formats are understood: .IP .TP \&\fR\&\f(CW0\fR\ Formats a 5 1/4 XDF disk (1520 KB, 45.6 KB/s). .TP \&\fR\&\f(CW1\fR\ Formats a 3 1/2 high density XDF disk (1840 KB, 38.3 KB/s). .TP \&\fR\&\f(CW2\fR\ Formats a 3 1/2 extra density XDF disk (3680 KB, 102 KB/s) .TP \&\fR\&\f(CW3\fR\ Formats a 3 1/2 high density XXDF disk (1920 KB, 45 KB/s) .TP \&\fR\&\f(CW4\fR\ Formats a 3 1/2 extra density XXDF disk (3840 KB, 90 KB/s) .PP .SH Misc\ options .TP \&\fR\&\f(CW-D\ \fIdosdrive\fR\&\f(CW\fR\ Describes the DOS drive letter for mformat. If this option is given, an MS-DOS filesystem is automatically installed on the disk after the low-level format is complete. In order for this to work, the drive has to be configured to accept the 23x2x80 geometry in your /etc/mtools or your ~/.mtoolsrc file. Moreover, this only works with a version of mtools that is more recent than 3.0. .IP Example of a working mtoolsrc line: .nf .ft 3 .in +0.3i A /dev/fd0 0 0 0 0 .fi .in -0.3i .ft R .lp \&\fR .IP Examples of a non-working mtoolsrc line: .nf .ft 3 .in +0.3i A /dev/fd0 12 80 2 18 .fi .in -0.3i .ft R .lp \&\fR .TP \&\fR\&\f(CW-n\fR\ Don't format the disk before copying the disk image to the disk. .PP .SH Options\ for\ power\ users .IP .TP \&\fR\&\f(CW-t\ \fIcylinder\ skew\fR\&\f(CW\fR\ Uses a different track skew than the default (14). For more details on skews, see section superformat. In this version of xdfcopy, the \fR\&\f(CW-t\fR parameter is ignored. .TP \&\fR\&\f(CW-h\ \fIhead\ skew\fR\&\f(CW\fR\ Uses a different head skew than the default (0) In this version, this parameter is ignored .TP \&\fR\&\f(CW-d\fR\ Debugging. For each read or write operation, the time it took to complete the operation is printed (in milliseconds). This can be used to optimize the skews. .TP \&\fR\&\f(CW-T\ \fIend-cylinders\fR\&\f(CW\fR\ Tells how many cylinders to format. With the XXDF formats, it is actually possible to format up to 83 cylinders, yielding a format of up to 1992KB on a 3 1/2 high density disk. .IP .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/driveprm.texi0000444000175000017500000001246210211706523016463 0ustar anibalanibal@node Drive descriptions, Extended formats, Media description, Top @chapter Drive descriptions Unlike earlyer version, fdutils-5.0 separates drive descriptions and media description. For more details on this separation, @pxref{Introduction (Mediaprm)}. Drive descriptions are used to describe the hardware characteristics of a drive, such as their maximal density, their rotation speed, their form factor, etc. @menu * Syntax of a drive description :: What to put into a drive description * Drive definition file :: Where drive definitions are stored @end menu @node Syntax of a drive description, Drive definition file, Drive descriptions, Drive descriptions @section Syntax A drive description is a series of @emph{variable=value} and @emph{selector} clauses. @menu * Density :: The maximal available density on the drive * Form factor :: Whether this drive is a 3 1/2", 5 1/4" or 8" drive * Cmos code :: Sums up both density and form factor * Other parameters :: Rotation speed and tracks per inch @end menu @node Density, Form factor, Syntax of a drive description, Syntax of a drive description @subsection Density The density of a drive is the highest media density that it supports. Density is one of @code{sd}, @code{dd}, @code{qd}, @code{hd} or @code{ed}. Usually, you do not need to specify this parameter, as it can be derived from the drives CMOS code. @node Form factor, Cmos code, Density, Syntax of a drive description @subsection Form factor The form factor of a drive describes the physical dimensions of the media it accepts. It is one of @code{3.5}, @code{5.25} or @code{8}. Usually, you do not need to specify this parameter, as it can be derived from the drives CMOS code. @node Cmos code, Other parameters, Form factor, Syntax of a drive description @subsection Cmos code The PC Bios already knows on its own about the most common drive types. These are named by an integer from 1 to 6, according to the following table. @example 0 no drive installed 1 5.25 DD 2 5.25 HD 3 3.5 DD 4 3.5 HD 5 3.5 ED 6 3.5 ED @end example As you see 3.5 ED drives have two possible codes. Some BIOSes use 5, others use 6. The reason for this is that initially 5 was intended for floppy tape drives, and only 6 was for 3.5 ED drives. However, some BIOS manufacturers didn't know about this convention, and used 5 for the then "new" 3.5 ED drives. Usually, you do not need to specify this parameter, as it can be read from the physical CMOS of your PC. This parameter may be useful if your BIOS does not store the drive's CMOS code at the expected place, or if you have more than two drives. @node Other parameters, , Cmos code, Syntax of a drive description @subsection Other parameters @table @code @item deviation=@var{deviation} Tells how much more/less raw capacity the drive has than the standard. Due to slightly different rotation speeds @footnote{drives do not always rotate at exactly 5 or 6 rotations per second, but some may be slightly faster or slightly slower than spec} and to slightly different data transfer rates, the raw capacity per track can vary slightly. For normal formats, these small deviations from the prescribed raw capacity is not harmful, as these have plenty of safety margins built in. However, the new extra capacity formats are affected by this, as they try to squeeze every available raw byte out of the disk. Deviation is expressed in ppm. Positive values mean a higher raw capacity than normal, and negative values mean a lower raw capacity than normal. The deviation can be measured using the @code{floppymeter} program. @item rpm=@var{rotation_speed} Prescribed rotation speed of the drive, expressed in rotations per minute. This is 360 for 5 1/4 HD drives, and 300 for all other commonly available drive types. Usually, you do not need to specify this parameter, as it can be derived from the drive's CMOS code. It is useful however for single density drives or other drives not commonly found on a PC. Usually, you do not to specify this parameter, as it can be derived from the drive's form factor and maximal density. @item tpi=@var{cylinder_density} This parameter is only meaningful for 5 1/4 drives. It expresses whether the drive is able to use 80 tracks (@code{tpi=96}) or only 40 (@code{tpi=48}). Usually, you do not to specify this parameter, as it can be derived from the drive's maximal density: quad density and high density drives are 96 tpi, whereas double density drives are 48 tpi. @end table @node Drive definition file, , Syntax of a drive description, Drive descriptions @section The drive definition file in @file{/usr/local/etc/fddriveprm} @file{/usr/local/etc/fddriveprm} @footnote{The actual location of this file depends on the value of the @code{sysconfdir} compile time configuration variable (@pxref{Compile-time configuration} for details)} contains a dictionary of commonly used media descriptions. Each description is identified by a name, which can then be used by setfdprm or superformat to refer to it, instead of an explicit description. Each definition starts with @code{"drive}@emph{number}@code{":}, followed by the actual description. Definitions may be spread over several lines, for better readability. The file may contain comments, which start with # and stop at the end of the line. fdutils-5.5-20060227/doc/lilo.texi0000444000175000017500000001660207464324643015611 0ustar anibalanibal@node Boottime configuration, Floppy ioctls, Autodetection, Top @chapter Configuring the floppy driver via lilo or insmod The floppy driver is configured using the @code{floppy=} options in lilo. These options can be typed at the boot prompt, or entered in the lilo configuration file. Example: If your kernel is called @code{linux-2.0}, type the following line at the lilo boot prompt (if you have a thinkpad): @example linux-2.0 floppy=thinkpad @end example You may also enter the following line in @file{/etc/lilo.conf}, in the description of @code{linux-2.0}: @example append = "floppy=thinkpad" @end example Several floppy related options may be given, example: @example linux-2.0 floppy=daring floppy=two_fdc append = "floppy=daring floppy=two_fdc" @end example If you give options both in the lilo config file and on the boot prompt, the option strings of both places are concatenated, the boot prompt options coming last. That's why there are also options to restore the default behaviour. If you use the floppy driver as a module, use the following syntax: @code{insmod floppy 'floppy="@var{options}"'}. (This line may be unreadable in the info version of this document. If so, please refer to the printed version). Example: @example insmod floppy 'floppy="daring two_fdc"' @end example Note that in this case @code{floppy=} should only be typed out once, and not once for each option. You need at least modules-1.3.57 for this method. However, the older environment variable based syntax is still available: @table @asis @item Bourne (sh, bash, ksh, zsh) syntax: @code{floppy="daring two_fdc" insmod floppy} @item C-shell (csh, tcsh) syntax: @code{setenv floppy "daring two_fdc" ; insmod floppy} @end table Some versions of insmod are buggy in one way or another. If you have any problems (options not being passed correctly, segfaults during insmod), first check whether there is a more recent version. If there isn't, use the old method using environment variables. Problems with @code{insmod} happen mostly for options involving both a number and a string, such as @code{floppy=0,4,cmos}. Options only involving strings, such as @code{floppy=daring} are not affected. The floppy related options include: @table @code @item floppy=daring Tells the floppy driver that you have a well behaved floppy controller. This allows more efficient and smoother operation, but may fail on certain controllers. @item floppy=0,daring Tells the floppy driver that your floppy controller should be used with caution. @item floppy=one_fdc Tells the floppy driver that you have only floppy controller (default) @item floppy=two_fdc @item floppy=@var{address},two_fdc Tells the floppy driver that you have two floppy controllers. The second floppy controller is assumed to be at @var{address}. If @var{address} is not given, 0x370 is assumed. two_fdc is implied if you use the cmos option with a drive of id 4 to 7. @item floppy=thinkpad Tells the floppy driver that you have a Thinkpad. Thinkpads use an inverted convention for the disk change line. @item floppy=0,thinkpad Tells the floppy driver that you don't have a Thinkpad. @item floppy=omnibook @itemx floppy=nodma Tells the floppy driver not to use Dma for data transfers. This is needed for instance on some HP Omnibooks, which don't have a workable DMA channel for the floppy driver. This option is also useful if you frequently get "Unable to allocate DMA memory" messages. Indeed, dma memory needs to be continuous in physical memory, and is thus harder to find, whereas non-dma buffers may be allocated in virtual memory. However, I advise against this if you have an FDC without a FIFO (8272A or 82072). 82072A and later are OK. You also need at least a 486 to use nodma. If you use nodma mode, I suggest you also set the FIFO threshold to 10 or lower, in order to limit the number of data transfer interrupts. @item floppy=dma Tells the floppy driver that a workable DMA channel is available (the default). @item floppy=nofifo Disables the FIFO entirely. This is needed if you get "Bus master arbitration error" messages from your ethernet card (or from other devices) while accessing the floppy. @item floppy=fifo Enables the FIFO (default) @item floppy=@var{threshold},fifo_depth Sets the FIFO threshold. This is mostly relevant in DMA mode. If this is higher, the floppy driver tolerates more interrupt latency, but it triggers more interrupts (i.e. it imposes more load on the rest of the system). If this is lower, the interrupt latency should be lower too (faster processor). The benefit of a lower threshold is less interrupts. To tune the fifo threshold, switch on over/underrun messages using @code{floppycontrol --messages}. Then access a floppy disk. If you get a huge amount of @code{Over/Underrun - retrying} messages, then the fifo threshold is too low. Try with a higher value, until you only get an occasional Over/Underrun. It is a good idea to compile the floppy driver as a module when doing this tuning. Indeed, it allows to try different fifo values without rebooting the machine for each test. Note that you need to do @code{floppycontrol --messages} every time you re-insert the module. Usually, tuning the fifo threshold should not be needed, as the default (0xa) is reasonable. @item floppy=@var{drive},@var{type},cmos Sets the cmos type of @var{drive} to @var{type}. Additionnaly, this drive is allowed in the bitmask. This is useful if you have more than two floppy drives (only two can be described in the physical cmos), or if your BIOS uses non-standard CMOS types. The CMOS types are: @table @code @item 0 unknown or not installed @item 1 5 1/4 DD @item 2 5 1/4 HD @item 3 3 1/2 DD @item 4 3 1/2 HD @item 5 3 1/2 ED @item 6 3 1/2 ED @end table Note that there are two valid types for ED drives. This is because 5 was initially chosen to represent floppy tapes, and 6 for ED drives. AMI ignored this, and used 5 for ED drives. That's why the floppy driver handles both) Setting the CMOS to 0 for the first two drives (default) makes the floppy driver read the physical cmos for those drives. @item floppy=unexpected_interrupts Print a warning message when an unexpected interrupt is received (default behaviour) @item floppy=no_unexpected_interrupts @itemx floppy=L40SX Don't print a message when an unexpected interrupt is received. This is needed on IBM L40SX laptops in certain video modes. (There seems to be an interaction between video and floppy. The unexpected interrupts only affect performance, and can safely be ignored.) @item floppy=broken_dcl Don't use the disk change line, but assume that the disk was changed whenever the device node is reopened. Needed on some boxes where the disk change line is broken or unsupported. This should be regarded as a stopgap measure, indeed it makes floppy operation less efficient due to unneeded cache flushings, and slightly more unreliable. Please verify your cable, connection and jumper settings if you have any DCL problems. However, some older drives, and also some Laptops are known not to have a DCL. @item floppy=debug Print debugging messages @item floppy=messages Print informational messages for some operations (disk change notifications, warnings about over and underruns, and about autodetection) @item floppy=silent_dcl_clear Uses a less noisy way to clear the disk change line (which doesn't involve seeks). Implied by daring. (There are other options as well, but they are considered obsolete, and thus they are not documented here) @end table fdutils-5.5-20060227/doc/Makefile.in0000444000175000017500000000724407567106003016016 0ustar anibalanibalMAKEINFO = makeinfo TEXI2DVI = texi2dvi TEXI2HTML = texi2html top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ infodir = @infodir@ mandir = @mandir@ infodir = @infodir@ sysconfdir = @sysconfdir@ mandir1 = $(mandir)/man1 mandir4 = $(mandir)/man4 mandir8 = $(mandir)/man8 MANPAGES1 = diskd.1 fdrawcmd.1 getfdprm.1 superformat.1 diskseekd.1 \ floppycontrol.1 makefloppies.1 xdfcopy.1 fdmount.1 \ floppymeter.1 setfdprm.1 MANPAGES4 = fd.4 MANPERM = 644 UID = root GID = root INSTALL = @INSTALL@ INSTALL_DATA= @INSTALL_DATA@ INSTALL_INFO= @INSTALL_INFO@ CC = @CC@ CPPFLAGS = @CPPFLAGS@ CFLAGS = @CFLAGS@ all: info dvi TEXISRC = \ acronyms.texi fdrawcmd.texi ioctl.texi superformat.texi \ autodetect.texi fdutils.texi lilo.texi tips.texi \ commands.texi floppycontrol.texi location.texi utilities.texi \ diskd.texi floppymeter.texi makefloppies.texi xdfcopy.texi \ diskseekd.texi formatlist.texi moredata.texi \ fdmount.texi getfdprm.texi setfdprm.texi html: Fdutils.html dvi: Fdutils.dvi info: fdutils.info %.info: $(TEXISRC) $(MAKEINFO) -I @srcdir@ @srcdir@/fdutils.texi %.dvi: Fdutils.texi $(TEXI2DVI) Fdutils.texi clean: rm -f fdutils.aux fdutils.cp fdutils.cps fdutils.dvi fdutils.fn rm -f fdutils.log fdutils.pg fdutils.ps fdutils.toc fdutils.tp rm -f fdutils.ky fdutils.vr fdutils.info fdutils.pgs rm -f Fdutils.aux Fdutils.cp Fdutils.cps Fdutils.dvi Fdutils.fn rm -f Fdutils.log Fdutils.pg Fdutils.pgs Fdutils.toc Fdutils.tp rm -f Fdutils.ky Fdutils.vr Fdutils.pgs rm -f fdutils.info* %.html: Fdutils.texi $(TEXI2HTML) $< Fdutils.texi: $(TEXISRC) texi-linearize ./texi-linearize $(srcdir) fdutils.texi > $@ # Don't cd, to avoid breaking install-sh references. install-info: info $(top_srcdir)/mkinstalldirs $(infodir) if test -f fdutils.info; then \ for i in fdutils.info*; do \ $(INSTALL_DATA) $$i $(infodir)/$$i; \ done; \ else \ for i in $(srcdir)/fdutils.info*; do \ $(INSTALL_DATA) $$i $(infodir)/`echo $$i | sed 's|^$(srcdir)/||'`; \ done; \ fi; \ if [ -n "$(INSTALL_INFO)" ] ; then \ if [ -f $(infodir)/dir.info ] ; then \ $(INSTALL_INFO) $(infodir)/fdutils.info $(infodir)/dir.info; \ fi; \ if [ -f $(infodir)/dir ] ; then \ $(INSTALL_INFO) $(infodir)/fdutils.info $(infodir)/dir; \ fi; \ fi install-man: $(top_srcdir)/mkinstalldirs $(mandir1) $(top_srcdir)/mkinstalldirs $(mandir4) $(top_srcdir)/mkinstalldirs $(mandir8) for i in $(MANPAGES1); do \ install -c -m $(MANPERM) -o $(UID) -g $(GID) \ $(srcdir)/$$i $(mandir1)/$$i; \ done for i in $(MANPAGES4); do \ install -c -m $(MANPERM) -o $(UID) -g $(GID) \ $(srcdir)/$$i $(mandir4)/$$i; \ done # for i in $(MANPAGES8); do \ # install -c -m $(MANPERM) -o $(UID) -g $(GID) \ # $(srcdir)/$$i $(mandir8)/$$i; \ # done ( cd $(mandir1); \ ln -sf fdmount.1 $(mandir1)/fdumount.1; \ ln -sf fdmount.1 $(mandir1)/fdlist.1; \ ln -sf fdmount.1 $(mandir1)/fdmountd.1; \ ln -sf xdfcopy.1 $(mandir1)/xdfformat.1 \ ) install-zman: for i in $(MANPAGES1); do \ gzip < $(srcdir)/$$i >_; \ install -c -m $(MANPERM) -o $(UID) -g $(GID) \ _ $(mandir1)/$$i.gz; \ done for i in $(MANPAGES4); do \ gzip < $(srcdir)/$$i >_; \ install -c -m $(MANPERM) -o $(UID) -g $(GID) \ _ $(mandir4)/$$i.gz; \ done for i in $(MANPAGES8); do \ gzip < $(srcdir)/$$i >_; \ install -c -m $(MANPERM) -o $(UID) -g $(GID) \ _ $(mandir8)/$$i.gz; \ done rm _ install: install-man install-info fdutils-5.5-20060227/doc/mediaprm.texi0000444000175000017500000001737110211706670016440 0ustar anibalanibal@node Media description, Drive descriptions, Device numbers, Top @chapter Media description @menu * Introduction (Mediaprm) :: Benefits of the new representation * Syntax :: What a media description looks like * Media definition file :: Refer to media by a symbolic name @end menu @node Introduction (Mediaprm), Syntax, Media description, Media description @section Introduction Fdutils-5.0 introduces a new uniform format description, which is supported both by setfdprm and superformat. The new format description is easyer to handle, because it allows to set the different parameters of a format description in a symbolic and position independant way, using a series of @emph{variable=value} clauses. Moreover, it automatically fills in sensible default values for unspecified parameters. Thus you only need to describe those aspects of the format that are important to you, and let the system handle the others. Moreover, the new description separates those aspects that were specific to the drive (like for instance its rotation speed) from those that are specific to the media (spacial density, number of sectors, etc.). The same description can be used both by setfdprm and superformat: @example setfdprm /dev/fd0 hd sect=21 cyl=83 superformat /dev/fd0 hd sect=21 cyl=83 @end example The first line above configures a 21 sector/83 cylinder format for drive 0, and the second line formats a disk using this same format. @node Syntax, Media definition file, Introduction (Mediaprm), Media description @section Syntax A media description is a series of @emph{variable=value} and @emph{selector} clauses. @emph{Value} is a number followed by an optional unit. The unit is either @code{KB} (1024 bytes) or @code{b} (blocks of 512 bytes), or none (bytes). @menu * Selecting the density :: * Selecting the number of cylinders heads and sectors :: * Selecting non-standard sector sizes :: * Legacy formats :: * Expert options :: @end menu @node Selecting the density, Selecting the number of cylinders heads and sectors, Syntax, Syntax @subsection Selecting the density To select a density just insert its two letter code into the format description. Selecting a density also selects its default number of sectors, heads and cylinders. However, these latter parameters can be overridden. @table @code @item hd High density (1440KB for 3 1/2 and 1200KB for 5 1/4). The most commonly used format today. @item dd Double density (720KB for 3 1/2 and 360KB for 5 1/4) @item ed Extra density (2880KB for 3 1/2) @item qd Quad density (720KB for 5 1/4). @item sd Single density (no nominal size). Used mostly for CP/M. Only for experienced users. @end table If no density is given, the maximal density supported by the drive is used. However, in order to keep the drive description and the media description independent, I strongly suggest that you @strong{always} indicate the density anyways. @node Selecting the number of cylinders heads and sectors, Selecting non-standard sector sizes, Selecting the density, Syntax @subsection Selecting the number of cylinders, heads and sectors This subsection describes how to select custom formats with a non-standard number of heads, cylinders or sectors. However, note that just describing the number of sectors, heads and cylinders is not enough: you also need to indicate which density your custom format is based on (cf. previous section). @table @code @item sect=@emph{nb_of_sectors} This describes the number of sectors. @item head=@emph{nb_of_heads} This describes the number of heads to be used. @item cyl=@emph{nb_of_cylinders} This described the number of cylinders to be used. @end table @node Selecting non-standard sector sizes, Legacy formats, Selecting the number of cylinders heads and sectors, Syntax @subsection Selecting non-standard sector sizes In order to achieve a higher capacity, you may want to use a bigger sector size. @table @code @item ssize=@emph{sector_size} Choses a bigger sector size. The sector size is expressed in bytes. Only powers of two between 128 and 32768 are acceptable @item sect=@emph{nb_of_sectors} Describes the number of sectors. For example @code{hd sect=11 ssize=1024} describes a format where one track (1 side) is made up of 11 sectors of 1024 bytes each (thus 11KB per track, and 22KB per cylinder). @item tracksize=@emph{size_of_one_track} Describes the size of one track. For example, @code{hd tracksize=11KB ssize=1KB} describes a format where one track contains 11KB of data (tracksize) stored in sectors of 1KB each. This option exists mainly to describe MSS (mixed sector size) formats. For example, @code{hd tracksize=12KB mss} describes a format where one track which contains 12 KB of data. The sectors size are chosen by the system in a way to take up the least raw space: 8KB + 4KB. @item mss This option says that the format is an MSS format. @item 2m This option says that the format is a so-called 2M format. These formats are intended for easy readability on DOS boxes. Their first track has the usual 18 sectors, whereas the other tracks have bigger sector, and in some cases mixed sector sizes. @end table @node Legacy formats, Expert options, Selecting non-standard sector sizes, Syntax @subsection Legacy formats The @code{swapsides} format allows to descibe disks whose sides are swapped, such as CBM1581 disks. @node Expert options,, Legacy formats, Syntax @subsection Expert options The following options are not needed in most common situations, as they are implied by the @emph{density} selector. They may be needed to read some legacy (CP/M) formats. @table @code @item tpi=48 For 5 1/4 disks only. This says that the format uses double-spaced cylinders (implied by double density). @item tpi=96 For 5 1/4 disks only. This says that the format uses single-spaced cylinders (implied by quad and high density). @item fm=0 Uses MFM encoding (implied by double, quad, high and extra density) @item fm=1 Uses FM encoding (implied by single density) @item dtr=@emph{dtr-code} Sets the data transfer rate. The following table lists the dtr codes for various transfer rates: @example dtr-code rate for FM rate for MFM ============================================= 0 250kb/s 500kb/s 1 150kb/s 300kb/s 2 125kb/s 250kb/s 3 500kb/s 1000kb/s @end example @item perp=0 Do not use "perpendicular mode" sector headers (this setting is implied by single, double, quad and high density). @item perp=1 Use "perpendicular" sector headers (this setting is implied by extra-density) @item gap=@emph{value} Sets the size of the read/write gap. I don't know the purpose of this parameter (which is passed @emph{as-is} to the floppy controller): any value seems to work with any format... @item fmt_gap=@emph{value} Sets the size of the formatting gap. This is only used by the now obsolete @code{fdformat} program, and not by superformat. @end table @node Media definition file, ,Syntax, Media description @section The media description dictionary in /etc/fdmediaprm @file{/usr/local/etc/fdmediaprm} @footnote{The actual location of this file depends on the value of the @code{sysconfdir} compile time configuration variable (@pxref{Compile-time configuration} for details)} contains a dictionary of commonly used media descriptions. Each description is identified by a name, which can then be used by setfdprm or superformat to refer to it, instead of an explicit description. Each definition starts with @code{"}@emph{name}@code{":}, followed by the actual description. Definitions may be spread over several lines, for better readability. The file may contain comments, which start with # and stop at the end of the line. fdutils-5.5-20060227/doc/setfdprm.texi0000444000175000017500000000340007464324643016466 0ustar anibalanibal@node setfdprm, superformat, makefloppies, Commands @section setfdprm @pindex setfdprm @cindex setting the geometry information @cindex geometry information (setting) @example @code{setfdprm} [@code{-p}] @var{device} @var{media-description} @code{setfdprm} [@code{-c} | @code{-y} | @code{-n}] @var{device} @end example @code{setfdprm} is a utility that can be used to load disk parameters into the auto-detecting floppy devices and "fixed parameter" floppy devices, to clear old parameter sets and to disable or enable diagnostic messages. These parameters are derived from a media-description, @pxref{Media description} for more details. Without any options, @code{setfdprm} loads the @var{device} (for example @file{/dev/fd0} or @file{/dev/fd1}) with a new parameter set with the @var{name} entry found in @file{/etc/fdprm} (usually named 360/360, etc.). For autodetecting floppy devices, these parameters stay in effect until the media is changed. For "fixed parameter" devices, they stay in effect until they are changed again. @code{Setfdprm} can also be used by the superuser to redefine the default formats. @subsection Options @table @code @item -p @var{device name} Permanently loads a new parameter set for the specified auto-configuring floppy device for the configuration with @var{name} in @file{/etc/fdprm}. Alternatively, the parameters can be given directly from the command line. @item -c @var{device} Clears the parameter set of the specified auto-configuring floppy device. @item -y @var{device} Enables format detection messages for the specified auto-configuring floppy device. @item -n @var{device} Disables format detection messages for the specified auto-configuring floppy device. @end table @subsection Bugs This documentation is grossly incomplete. fdutils-5.5-20060227/doc/commands.texi0000444000175000017500000000237407464324643016454 0ustar anibalanibal@node Commands, Compile-time configuration, Floppy ioctls, Top @chapter Command list @cindex Command list @cindex List of available commands This section describes the available fdutils commands, and the command line parameters that each of them accepts. @menu * diskd:: detect a disk change and execute a command * diskseekd:: seeks the drive from time to time to shake of the dust * fdmount:: automatically mounts and unmounts floppy disks * fdrawcmd:: send raw commands to the floppy disk controller * floppycontrol:: configure the floppy driver * floppymeter:: measures characteristic parameters of a floppy drive * getfdprm:: print current geometry parameters * makefloppies:: makes the floppy device entries * superformat:: formats high capacity disks * setfdprm:: changes the current and permanent geometry parameters * xdfcopy:: copies and formats XDF disks @end menu @include diskd.texi @include diskseekd.texi @include fdmount.texi @include fdrawcmd.texi @include floppycontrol.texi @include floppymeter.texi @include getfdprm.texi @include makefloppies.texi @include setfdprm.texi @include superformat.texi @include xdfcopy.texi fdutils-5.5-20060227/doc/fdmount.texi0000444000175000017500000002156407464324643016331 0ustar anibalanibal@node fdmount, fdrawcmd, diskseekd, Commands @section fdmount @pindex fdmount @pindex fdmountd @pindex fdlist @pindex fdumount @cindex automounting @example @code{fdmount} [@code{-l}] [@code{--list}] [@code{-d}] [@code{--daemon}] [@code{--detach}] [@code{-i} @var{interval}] [@code{--interval} @var{interval}] [@code{-o} @var{mount-options}] [@code{-r}] [@code{-readonly}] [@code{-s}] [@code{--sync}] [@code{--nosync}] [@code{--nodev}] [@code{--nosuid}] [@code{--noexec}] [@code{-f}] [@code{--force}] [@code{-h}] [@code{--help}] [@var{drivename}] [@var{mountpoint}] @code{fdumount} [@code{-f}] [@code{--force}] [@var{drivename}] @code{fdlist} @code{fdmountd} [@code{-i} @var{interval}] [@code{--interval} @var{interval}] [@code{-r}] [@code{-readonly}] [@code{-s}] [@code{--sync}] [@code{--nosync}] [@code{--nodev}] [@code{--nosuid}] [@code{--noexec}] [@code{--help}] [@var{drivename}] [@var{mountpoint}]] @end example The @code{fdmount} program mounts a floppy disk in the specified drive. It tries to figure out the exact format and filesystem type of the disk from data in the disk's boot sector or super block and the auto-detected track layout. Currently, fdmount supports the filesystems @code{minix}, @code{ext}, @code{ext2}, @code{xia}, and @code{msdos}, and includes special support for disks formatted by the @code{2M} utility for MS-DOS. It also checks whether the disk is write protected, in which case it is mounted read-only. The symbolic @var{drivename} is (currently) one of @file{fd[0-7]}, corresponding to the special device files @file{/dev/fd[0-7]}. If @var{drivename} is not specified, @file{fd0} is assumed. The disk is mounted on the directory @var{mountpoint}, if specified, or on @file{/fd[0-7]}. In either case, the mount point must be an existing, writable directory. @strong{Due to a bug in the floppy driver (?), the polling interval (-i flag) must be longer than the spindown offset. Thus you need to do (for example) floppycontrol --spindown 99 before starting fdmountd in daemon mode} @subsection Options @table @code @item -l @var{--list} List all known drives with their symbolic name, type, and mount status. @item -d @var{--daemon} Run in daemon mode (see below). @item --detach Runs daemon in background, and detaches it from its tty. Messages produced after the fork are logged to syslog. @item -p @var{file} @itemx --pidfile @var{file} Dumps the process id of the daemon to @var{file}. This makes killing the daemon easier: @code{kill -9 `cat @var{file}`} @item -i @var{interval} @itemx --interval @var{interval} Set the polling interval for daemon mode. The unit for @var{interval} is 0.1 seconds, the default value is 10 (i.e. 1 second). @item -o @var{options} @itemx --options @var{options} Sets filesystem-specific options. So far, these are only available for DOS and Ext2 disks. The following DOS options are supported: @code{check}, @code{conv}, @code{dotsOK}, @code{debug}, @code{fat}, @code{quiet}, @code{blocksize}. The following Ext2 options are supported: @code{check}, @code{errors}, @code{grpid}, @code{bsdgroups}, @code{nogrpid}, @code{sysvgroups}, @code{bsddf}, @code{minixdf}, @code{resgid}, @code{debug}, @code{nocheck}. When running as a daemon, options not applying to the disk that is inserted (because of its filesystem type) are not passed to mount. @item -r @var{--readonly} Mount the disk read-only. This is automatically assumed if the disk is write protected. @item -s @var{--sync} Mount with the @code{SYNC} option. @item --nosync Mounts without the @code{SYNC} option, even when running as daemon. @item --nodev Mount with the @code{NODEV} option. Ignored for @code{msdos} filesystems, otherwise always set for non-root users. @item --nosuid Mount with the @code{NOSUID} option. Ignored for @code{msdos} filesystems, otherwise always set for non-root users. @item --noexec Mount with the @code{NOEXEC} option. @item -f @var{--force} Attempt a mount or unmount operation even @file{/etc/mtab} says that the drive is already mounted, or not mounted, respectively. This option is useful if @file{/etc/mtab} got out of sync with the actual state for some reason. @item -h @var{--help} Show short parameter description @end table @subsection Security When mounting on the default mount point, the mount points' owner is set to the current user, and the access flags according to the user's umask. For a specified mountpoint, owner and permissions are left unchanged. Default mount points are called @code{/fd0}, @code{/fd1}, @dots{} , @code{/fd7}. The user running fdmount must have read access to the floppy device for read only mounts, and read/write access for read/write mounts. Fdmount can be run suid root, allowing users to mount floppy disks. The following restrictions are placed upon non-root users: @itemize @bullet @item If a mountpoint is specified explicitly, it must be owned by the user. @item A user may only unmount a disk if the mount point is owned by the user, or if it the disk has been mounted by the same user. @item Non-msdos disks are automatically mounted with the @code{nodev} and @code{nosuid} flags set. @end itemize However, @strong{do not rely on fdmount being secure at the moment}. @subsection Daemon mode In daemon mode, the specified drive is periodically checked and if a disk is inserted, it is automatically mounted. When the disk is removed, it is automatically unmounted. However, it is recommended to unmount the disk manually @emph{before} removing it. In order to limit corruption, disks are mounted with the SYNC option when running in daemon mode, unless the @code{--nosync} flag is given. Note that this mode has some potential drawbacks: @itemize @bullet @item Some floppy drives have to move the drive head physically in order to reset the disk change signal. It is strongly recommended not to use daemon mode with these drives. @xref{floppycontrol}, for details. @item If a disk does not contain a filesystem (e.g. a tar archive), the mount attempt may slow down initial access. @item As fdmount cannot identify the user trying to use the disk drive, there is no way to protect privacy. Disks are always mounted with public access permissions set. @end itemize @subsection Diagnostics @table @code @item error opening device @var{name} @item error reading boot/super block fdmount failed to read the first 1K of the disk. The disk might be damaged, unformatted, or it may have a format wich is unsupported by the FDC or the Linux kernel. @item unknown filesystem type No magic number of any of the supported filesystems (see above) could be identified. @item sorry, can't figure out format (@var{fs} filesystem) The size of the filesystem on the disk is incompatible with the track layout detected by the kernel and an integer number of tracks. This may occur if the filesystem uses only part of the disk, or the track layout was detected incorrectly by the kernel. @item failed to mount @var{fs> Frequently asked question about the Linux floppy driver
Join the Big Noise! Pay fair prices to coffee growers
No Software Patents!

Fdutils

Frequently asked question about the Linux floppy driver

Most of the floppy utilities mentioned in this FAQ can be found in the fdutils package. For others, consult the lsm or archie. Alpha releases of fdutils are named fdutils-version-YearMonthDay..diff.gz

How do I access floppy drives in Linux?

Either use mtools or mount the disk. Mtools can be found here.

It is a collection of utilities to access DOS disks. These utilities behave mostly like their DOS counterparts, i.e. mdir is like dir, mcopy is like copy, etc. Specifics are in the manpages.

To mount a disk on /mnt, use the following command lines:

 mount -t msdos /dev/fd0 /mnt
The directory /mnt must already exist:
 mkdir /mnt

How should I report bugs?

If you have a question or a bug report about the floppy driver, mail me at alain @ linux.lu . If you post to the news, use preferably one of the groups comp.os.linux.help (for questions) or comp.os.linux.hardware (for bug reports). As the volume in these groups is rather high, be sure to include the word "floppy" (or "FLOPPY") in the subject line.

  • In case of a kernel panic, or OOPS, please note the EIP, and the values on the stack (some of these are the calling functions). Then look up those values in your zSystem.map (or System.map)
  • In case of a lock-up (operation never completes), try to figure out what operations are needed to reproduce it. (If you don't succeed in reproducing it, please mention the floppy operations you remember.)
  • If you can't access a disk, include the output of
     floppycontrol -pP --printfdcstate
    into your bug report.
  • If something weird happens during boot (lock-up, no floppy drives accessible, trouble with unrelated hardware), include a listing of the messages at boot. (You can obtain this with dmesg. If the boot doesn't complete only note the most important messages down [few lines before the crash, and floppy related lines]).
  • In case of I/O errors, first switch the error reporting threshold to 0. If that doesn't yield any more error messages, switch on full debugging with floppycontrol --debug and floppycontrol --reporting 0. Note that floppycontrol --debug generates a huge output. Thus, try first with --reporting. Please note also that both commands are drive specific, and that the default drive is /dev/fd0. So, if you experience a problem on /dev/fd1, use floppycontrol --debug -d/dev/fd1. Then include the kernel messages as well as the application messages with your bug report. If you're using X windows, you won't see the kernel messages appear in your xterm window. Use dmesg to get them. dmesg includes all messages since boot (or as many as fit in the buffer, if there are too many messages). Use dmesg also before executing the command, in order to find out which messages were generated by the command, and which ones were generated by earlyer commands. Alternatively, you may get the user-printk module which allows you to insert "comments" into the stream of console messages.
  • Be aware that after a crash, no user program runs, not even syslog. If you direct your kernel messages only to syslog, you may see nothing at all in the log file after rebooting. Thus, I recommend directing the messages also to the console, and noting them down. If there are more than a few lines, note only the last few lines, and the addresses of EIP and the stack trace, if applicable. Obviously, this only applies when investigating bugs which lead to a crash. If no crash happens (like for instance read errors), syslog is actually an useful and beneficial feature, as it is able to keep far more messages than fit into dmesg's buffer.
  • If you have other patches in the kernel, report them (especially ftape). If it is easy enough to undo these other patches, please try whether the problem happens without them.
  • Be sure to include complete command lines of the floppy commands which led to the problem, as well as a history of the disk changes.
  • Is the problem repeatable?
  • If you notice that the problem is very time dependent, try to find out if there is any correlation between the occurrence of the problem, and the state of the drive LED.
  • If the problem is that the drive becomes inaccessible, but everything else just works fine, try to find out the following:
    • Are all floppy drives inaccessible?
    • Does the drive LED stay on?
    • Does the drive make any noises?
    • Do all floppy related commands fail, or only those that try to actually read or write to the drive. In particular, what does floppycontrol -P do?
  • Give some description of your computer! Is it a Laptop? A particularly slow computer (386 SX)? PCI based?
  • If you can't supply all these items, go ahead anyways, I want just to make sure you aren't forgetting anything.

I can't fdformat the new formats.

Fdformat is considered obsolete. Use superformat instead.

Mtools says "12 bit FAT on a: sure?" when trying to access an ED disk (or a similar message) when formatting a disk

Some ED (extra density) disks use 16 bit FATS. The FAT type (12 or 16 bit) is described in the configuration file (/etc/mtools or ~/.mtoolsrc). It is the first number. Example:
A /dev/fd0 12 0 0 0
           ^^ 12 bit FAT

12means12 bit FAT
16means16 bit FAT
0means"use whatever is appropriate"
-12means12 bit FAT, even if it looks fishy
-16means16 bit FAT, even if it looks fishy

CAUTION: If you have an /etc/mtools file AND an ~/.mtoolsrc file, the ~/.mtoolsrc file overrides /etc/mtools. The home directory used for ~/.mtoolsrc is $HOME, if that is undefined, it is derived from $LOGNAME, and if that's undefined too, it is derived from getlogin, and finally from getuid.

There are also compiled-in defaults, which are used if neither /etc/mtools, nor ~/.mtoolsrc are found.

Mtools says "fat_read: Wrong FAT encoding 12 16?" (or similar) when accessing a disk formatted with the old mtools.

mtools does some sanity checks on the size of the FAT. Unfortunately, these are too strict for certain disks formatted with the old mtools, and for hard disk partitions formatted by DOS 6, and probably for other conditions as well. Define the environment variable MTOOLS_FAT_COMPATIBILITY to override this check.

(to do this, type

 setenv MTOOLS_FAT_COMPATIBILITY 1
in csh or tcsh, and
 export MTOOLS_FAT_COMPATIBILITY=1
in sh/bash/zsh/...)

How should I describe the new 2m formats in /etc/mtools?

Support for both disk drives a: and b: for all formats (except Xdf) is already built into the new version of mtools (3.9.10). Definitions for new drive letters no longer override these default definitions.

Just for the record, here are definitions to mimic the standard behavior:

 drive a: file="/dev/fd0"
 drive b: file="/dev/fd1"

How should I describe the Xdf formats in /etc/mtools?

The following /etc/mtools lines allow to access all disks, including Xdf:

drive a: file="/dev/fd0" use_xdf=1 drive b: file="/dev/fd1" use_xdf=1
However, the use_xdf flag slightly slows down initial access to non Xdf disks.

Which minor device number should I use for 2m formats?

2m formats don't have a minor number associated with them, they can only be accessed using the "generic " devices (i.e. /dev/fd0, /dev/fd1).

I have an IBM Thinkpad :-(

Don't panic. Add the line 'floppy=thinkpad' to your lilo boot parameters. This can be entered at the lilo prompt after the name of the kernel image. It can also be specified in the lilo.conf file, by adding the following line:
 append = "floppy=thinkpad"
With some IBM thinkpads, it's also possible to make their floppy drive work by toggling the "FLOPPY" option in CMOS from "auto" to "on". However, apparently this CMOS option is not available on all models.

On some models, both options may be required, on others, none are required.

More info about IBM Tinkpads on Linux can be found here.

What are the minor device numbers for the floppy device nodes?

The major device number for the floppy drives is 2. The minor device number is calculated using the following formula:
    minor_device = format_nr * 4 + 128 * fdc_nr + unit_nr
(fdc_nr identifies the floppy disk controller, and unit_nr identifies which drive on the floppy disk controller to be used) format_nr identifies the (see the README file in fdutils for more details). If format_nr is 0, the device is an autodetection device. Use the MAKEFLOPPIES script included in the fdutils package to automatically create the needed devices.

What are the recommended names for the floppy device nodes?

Floppy drives are named fd drive_nr type max_capacity.

Drive_nr identifies the drive. It ranges from 0 to 3 for drives connected to the first controller, and from 4 to 7 for drives connected to the second controller.

Type is the type of the drive or media. The exact meaning of this (drive or media) is still being discussed. Traditionally, this letter described the type of the drive (density, 5 1/4 or 3 1/2). Lower case letters described 5 1/4 drives, and upper case letters describe 3 1/2 drives. h or H meant high density drives, d or D meant double density drives.

Initially this letter described the type of the drive and not the type of the media in the drive. For instance, a meant for accessing 720k double density disks in a high density drive was called h720k and not d720k. The reason for this is that for 5 1/4 drives the parameters for accessing a disk do not only depend on the of the disk, but also on the drive type. The of the disk is already implied by the capacity, and so the type letter is used to describe the type of the drive.

However, this dependency on the drive type only exists for 5 1/4 drives. For 3 1/2 drives, this is not needed, and as 3 1/2 drives are more frequent, people started forgetting about this, and understood that the letter described the media . When support for extra density drives was added to the kernel, people still used the name H1440 for accessing high density disks using their extra density drive. By the way, several distribution use this scheme.

In order to calm down the confusion, we propose to make the type letter again describe the type of the drive. However, all 3 1/2 drives are now described by a unique type letter: "u". This means universal (one letter fits all 3 1/2 formats). Moreover the u resembles the Greek letter mu, as in microfloppy.

So the recommended name for a device node allowing to read 1440K disks in a 3 1/2 drive (no matter its density) is called u1440. Note that this is now lowercase.

However, this new convention is still subject to discussion.

Capacity is the capacity of the media in K bytes. Fortunately, this leads to no ambiguity.

Example:

A device node allowing to use 720K 5 1/4 floppies in a high density drive connected as first unit to the second controller is called /dev/fd4h720 Right now, MAKEFLOPPIES supports all three conventions (media, drive, and "u"), you may chose amongst them using command line switches.

14. My drive doesn't detect disk changes / When I type mdir a:, I get the directory listing of the previous disk. This means that there is a problem with the disk change line. This problem may have several reasons:

a. The disk change line is near the edge of the cable, and is the first line to suffer if the cable is not inserted straight. Press gently on the connectors of your floppy disk cable, in order to ensure that all wires make contact.

b. Because the disk change line is near the edge of the cable, it is also the first line to suffer if the cable is damaged. If necessary, buy a new cable, they cost less than five dollars.

c. On some drives, the disk change line may be chosen by jumper. Make sure that your floppy controller board and your drive agree which line is the disk change line. The usual location is line 34.

d. Some older drives don't support the disk change line at all. In this case, you have to configure the floppy driver to work around the problem. Use 'floppycontrol --broken_dcl' to do this. Now the floppy driver assumes that the disk is changed whenever the device node is closed and then re-opened. This is less efficient, as it results in many useless cache flushes, so use it only if you really need it. This command has to be issued after each reboot, so I suggest you put it into your /etc/rc files.

I get "No such device or address" errors for various floppy related commands.

This message can mean one of several things:

  1. No floppy driver is compiled into the kernel, and no floppy module is inserted. Kerneld may fail to automatically insert the floppy module when you upgraded your kernel without upgrading the module and moving it to a place where kerneld finds it.
  2. The drive doesn't exist (mistyped drive name?)
  3. No disk is in the drive.
  4. A problem with the disk change line: The disk change line is not only used to detect disk changes, but also to tell whether there is a disk in the drive at all.) See question 13 for fixes for disk change line problem.
  5. The floppy geometry is unknown for the getfdprm or fdformat programs. If you a disk, rather use superformat.

I have a HP Omnibook 6000 :(

These laptops are supplied with a floppy-drive & fdc combo which doesn't support DMA :( Just add floppy=nodma to your Lilo command line. More info about the Omnibook and linux can be found here.

I can't get my floppy drive going, is there another method to install?

You may also install via hard disk and initrd. You need a big enough hard disk to do this (and it takes a little bit more time than the usual method). The following method presumes that it is possible to access the disk using DOS.

  1. Leave a small DOS partition (with enough spare space to hold the tar files from a few install disks). The bigger that partition is, the less come and goes from DOS are needed later. However, the bigger it is, the less space is available for Linux itself.
  2. On a desktop computer, using Linux, make a filesystem on a smallish spare partition (for instance on your swap partition). This filesystem should contain the files usually found on the install root disks. Add a '/linuxrc' file which contains the following lines:
    
    #!/bin/sh
    . etc/rc
    /bin/sh
    
  3. On the desktop computer, unmount the filesystem, and dd it to a file. Compress the file, and copy it to a floppy disk.
  4. Copy it to the Laptops hard disks.
  5. Copy the tar files from the first few install disks to the laptops hard disk.
  6. Use loadlin to boot Linux on the laptop (use the umsdos fs as root).
  7. Start installation (tell the install program to look for the tar files on your hard disk).
  8. If the first few files are installed, move back to DOS to erase the tar files which you already unpacked, and copy the next ones.
  9. reboot Linux.
  10. repeat until all is installed.
  11. After installation, it is wise to leave that DOS partition, in case you need to bring more files later.
Steps 5 to 10 may be skipped if your laptop has a CD-ROM drive :-)

Is it possible to use two floppy disk controllers under Linux?

YES. To use both controllers, boot the kernel with the lilo parameter 'floppy=two_fdc'. This parameter can be given on the lilo prompt, just after the name of the kernel. It can also be specified in the /etc/lilo.conf file by adding the following line:
 append = "floppy=two_fdc"

It is assumed that your second controller lives at 0x370. If it uses another I/O base-address, change this address in the floppy.c. The drives on the second controller use the minor device numbers 128-131 for the generic device, and 132-255 for the fixed geometry device. The following formula gives the minor number:

	minor = fdc * 128 + geometry * 4 + unit 
See the README file in fdutils for more details.

Is it possible to boot off these special disks?

Yes. Make sure you have a version of lilo more recent than v18, and put the following line into your /etc/lilo.defines before compiling it:
 -DXL_SECS=44
This enables Lilo to boot from disks with up to 44 sectors (i.e. more than you'll ever see :-) ) It allows to boot from ED disks and from disks with more sectors than usual (up to 21 on a HD disk, 42 on an ED disk). However, 2m and Xdf disks cannot be booted using this method.

I get "Unable to allocate DMA memory" messages when trying to use the floppy.

This happens whenever the memory is too scarce to allocate the floppy driver's DMA buffer. It is possible to use the floppy driver without DMA, and in that case, the floppy driver uses vmalloc'ed memory, which is more readily available. In order to disable DMA, use the floppy=nodma boot flag. If you use the floppy driver as a module, set the environment variable 'floppy' to 'dma'.

I have a Micron Millenia Transport.

Apparently, these laptops are supplied with a floppy controller which doesn't support the fifo.

Switch off the FIFO by adding floppy=nofifo to your Lilo command line.


Last modified: Thu Mar 3 23:29:19 CET 2005 fdutils-5.5-20060227/doc/format2.texi0000444000175000017500000001345307560752216016223 0ustar anibalanibal@node Interesting formats, Command Index, Acronyms, Top @appendix Interesting formats This table lists a few interesting formats. Some of them are not included in the table of predefined formats due to lack of space. You may use these by setting the geometry of the variable geometry device using @code{setfdprm}. Most of the entries in the following table do not describe a single format, but rather a family of formats which share a common characteristic. For this reason, no precise parameters are included. @table @strong @item 80/90/160/180 KB 5.25" Original IBM PC, CP/M, Apple II, TRS-80, etc. Single density, FM (not MFM), 40-track. Some systems also used "hard" sectoring, with an index hole for each sector. These are probably readable on standard FDCs if anyone cares to go to the effort. 160KB/180KB formats were double-sided. @item 320 KB 5.25" CP/M, Zenith Z-100, some forms of MS-DOS. 8-sector DD 40-track. @item 400 KB 5.25" AT&T 7300/3B1: cpio format, 10 sectors, DS, 40 tracks. PC: MS-DOS, 10 sectors, DS, 40 tracks; formatted by various utilities; readable by some versions of MS-DOS. @item <720KB 3.5" formats @itemize @bullet @item Some dedicated word-processing systems use lower than normal capacity floppies (some may be 40-track either via "stretching" or by having odd drives; others may be single-sided or use fewer sectors per track, or use "single density" or FM). @item Atari ST 360 KB floppies: these are 9 sector 250kb/s 80-track single-sided, using a slightly incompatible MS-DOS-like FAT. Very common distribution format for Atari ST software. @item Mac 400 KB: single-sided 80-tracks, Mac MFS or HFS file system, Group Code Recording, zone bit recording, variable RPMs from 300 to 600 in 5 zones, and auto-eject mechanism. Impossible to read on normal PC drives without some form of hardware assistance. @end itemize @item 720 KB 3.5" @itemize @bullet @item PC: 9 sectors, DS, 80-track; very common. @item Atari ST: same as Atari ST 360 KB except double-sided. @end itemize @item 720 KB 5.25" "Quad Density": 9 sectors, DS, 80-track; name is rather misleading, as it is double density 80 track. @item 800 KB @itemize @bullet @item PC: 10 sectors, DS, 80 tracks; readable by MS-DOS; formatted by many PC utilities; "almost standard". @item Atari ST "Twister": 10 sectors, DS, 80-track; slightly incompatible MS-DOS-like FAT; sector skewing (originated by David Small). @item Mac 800 KB: same as Mac 400KB except double-sided. @end itemize @item 880 KB @itemize @bullet @item PC: 11 sectors, DS, 80 tracks, interleaved(?). Formatted by various PD utilities such as fdformat. @item Amiga: uses "single-sector" tracks the size of 11 sectors; DS; 80 tracks. Written by a custom chip rather than a standard FDC; it is very difficult to access these using a standard FDC, though it might be possible in theory, using some trickery. @end itemize @item 880 KB - 960 KB Atari ST: 11/12 sectors, DS, 80-track, interleaved(?); not very reliable, formatted by various PD utilities. @item 960 KB 2m and Linux; 6 sectors interleaved(?), DS, 250kb/s?, 80-track, 1K sectors(?). @item 1001 KB "Japanese" format: 300kb/s, 77 tracks, HD drives/disks. @item 1040 KB 2m and Linux only; 13 sectors, DS, 300kb/s, 80-track. @item 1120 KB 2m and Linux only; 14 sectors interleaved, DS, 300kb/s, 80-track. Can only be formatted on Linux; even on Linux, it is difficult to format these on an ED drive. @item 1200 KB 5.25" HD "AT": 360 rpm 500kb/s 80-track 15-sector MS-DOS. @item 1360 KB 5.25" HD Highest "fdformat" noninterleaved 5.25" format. 360 rpm 500kb/s 17-sector MS-DOS. @item 1440 KB 5.25" HD Interleaved 18-sector 360 rpm 500kb/s; highest "fdformat" 5.25" format. 18-sector MS-DOS. 2m and Linux only: noninterleaved 1024-byte sector 18-sector-equivalent 360 rpm 500kb/s; 18-sector MS-DOS. A good substitute for 1.44MB 3.5" floppies. @item 1600 KB 5.25" HD 2m and Linux only: interleaved? 500kb/s 80-track; 1 8KB sector, 1 2KB sector? @item 1760 KB 3.5" HD 2m and Linux only: 11 1KB sectors; 500kb/s, noninterleaved? @item 1840 KB 3.5" HD 2m and Linux only: 23-sector equivalent; 500kb/s, noninterleaved. @item 1920 KB 3.5" HD 2m and Linux only: 3 4KB sectors; 500kb/s, interleaved? 2m and Linux only: 1 8KB sector, 1 4KB sector; 500kb/s, interleaved? @item 2880 KB 3.5" ED "Extra Density" or "Extra High Density". 1 Mb/s, 36-sector, DS, 80- track. @item 3200 KB 3.5" ED Non-interleaved, 80 track, 40-sector 1 Mb/s. Highest capacity that MS-DOS can read directly(?) @item 3520 KB 3.5" ED 2m and Linux only: 1 16KB sector, 1 4KB sector, 1 2KB sector? Non-interleaved, 80 track 1 Mb/s. Highest capacity that 2m can format. @item 3840 KB 3.5" ED 2m and Linux only: 1 16KB sector, 1 8KB sector (or is it 3 8KB sectors?). Non-interleaved, 80 track 1 Mb/s. Formatted only by Linux, but readable and writeable by 2m. @end table Linux is able to read almost any MFM disk. These include many CP/M disks and also Commodore 1581 disks. Please get Michael Haardt's documentation on floppy drives for a detailed description of those formats. This can be ftp'ed from the following location: @example http://www.moria.de/~michael/floppy/ @end example Commodore 1581 disks are not yet described in this documentation. Use @code{setfdprm /dev/fd0 DD DS sect=10 cyl=80 swapsides}. If you want to use these disks often, redefine one of the "default" formats to be Commodore 1581, and then put it into the autodetection list for the drive. The following example describes how to redefine format number 31 (minor device number 124) to be Commodore 1581: @example mknod /dev/fd0cbm1581 b 2 124 setfdprm /dev/fd0cbm1581 DD DS sect=10 cyl=80 swapsides floppycontrol --autodetect /dev/fd0 31,7,8,4,25,28,22,21 @end example The two latter commands have to be issued after each reboot, so I suggest you put them into your @file{/etc/rc} files if you use many Commodore 1581 disks. fdutils-5.5-20060227/doc/autodetect.texi0000444000175000017500000001040010020206725016757 0ustar anibalanibal@node Autodetection, Boottime configuration, Extended formats, Top @chapter How autodetection works @cindex autodetection @cindex format @cindex recognize a disk The principle of autodetection is rather simple. When a floppy disk is first accessed, and its geometry is not yet known, the floppy driver tries out a list of up to 8 geometries (format descriptions) until one is found that matches (i.e. that makes it possible to read the first sector or track). This list of geometries is called the @emph{autodetection list}. There is one autodetection list per drive type (as indicated in the cmos). The autodetection list doesn't contain the geometry descriptions themselves, but rather references to entries in the @emph{geometry list} (@pxref{geometry list}). Each list may contain up to 8 such references. Each reference can be tagged with a @code{t} flag. If this tag is set, the floppy driver tries to read the whole track when trying out that description; if it is not set, it only tries to read the boot sector. Reading the whole track is useful to distinguish among geometries which differ only in the amount of sectors per track. In order to do this, put the geometry with the most sectors first in the list, and set its @code{t} tag. Use the @code{t} tag only in this case, as it makes autodetection slower. Autodetection cannot distinguish between geometries that only differ in the number of heads or in the number of tracks. Autodetection is meant to supply only a first approximation of the actual format of the disk. It supplies enough information to enable a program such as @code{mtools} to read the boot sector, which contains the exact information. @code{Mtools} then uses the information contained in the boot sector to set the exact geometry. The autodetection list is set using the following command: @example floppycontrol --autodetect @var{list} @end example @section Example The following example restores the default autodetection sequence for a 3 1/2 ED drive: @example floppycontrol --autodetect 7,8,4,25,28,22,31,21 @end example The following example changes this sequence, so as to add the 1680KB format (number 11). As only 8 formats are allowed in the autodetection list, we have to dump one entry (we chose the last, which is numbered 21). The 1680KB format is identical with the default 1440KB format except for the number of sectors. Thus we must read the whole track in order to distinguish it from the 18 sector format (@code{t} flag). Furthermore, the the 1680KB sector format should be detected first, as an 21 sector disk would also matches the standard format with its 18 sectors. @example floppycontrol --autodetect 11t,7,8,4,25,28,22,31 @end example The following example attempts to autodetect CBM 1581 disks along with the more usual formats. CBM 1581 disks are not among the predefined formats. Thus we first have to pick one of the predefined formats and change it so it fits our needs. We may for example pick one of the rarely used 5 1/4 formats, such as h880, which bears number 20). We first make a device node bearing the requested number (so that we have a filename to pass to setfdprm), then we chmod it so it becomes accessible to mortal users, finally we configure the geometry of the new node, and enter it into the autodetection list. We place it at the 4th position, just behind the usual ED, HD and DD formats, and before the more exotic extended formats. Indeed, formats which are nearer to the head of the list are autodetected faster, and hence more commonly used formats should be put nearer to the beginning @footnote{except of course if several formats only differ in the number of sectors per track, in which case the formats with the most sectors should come first}. @example mknod /dev/fd0cbm1581 b 2 80 chmod 666 /dev/fd0cbm1581 setfdprm /dev/fd0cbm1581 DD DS sect=10 cyl=80 ssize=512 fmt_gap=35 gap=12 swapsides floppycontrol --autodetect 7,8,4,20,25,28,22,31 @end example Some formats use more than 80 tracks. It is not possible for the kernel to autodetect the number of tracks in a reasonable time, so you have to use a sufficiently recent version of mtools to set the number of tracks according to the boot sector of the disk. Mtools 3.0 and up are ok. This doesn't obviously work with disks containing something else than a MS-DOS filesystem. fdutils-5.5-20060227/doc/fdrawcmd.10000644000175000017500000002662310211703706015617 0ustar anibalanibal.TH fdrawcmd 1 "03Mar05" fdutils-5.5 .SH Name fdrawcmd - send raw commands to the floppy disk controller '\" t .de TQ .br .ns .TP \\$1 .. .tr \(is' .tr \(if` .tr \(pd" .SH Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. .TP * \ \ To generate a printable copy from the texinfo doc, run the following commands: .nf .ft 3 .in +0.3i ./configure; make dvi; dvips fdutils.dvi .fi .in -0.3i .ft R .lp \&\fR .TP * \ \ To generate a html copy, run: .nf .ft 3 .in +0.3i ./configure; make html .fi .in -0.3i .ft R .lp \&\fRA premade html can be found at: \&\fR\&\f(CW\(ifhttp://www.tux.org/pub/knaff/fdutils\(is\fR .TP * \ \ To generate an info copy (browsable using emacs' info mode), run: .nf .ft 3 .in +0.3i ./configure; make info .fi .in -0.3i .ft R .lp \&\fR .PP The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. .SH Description .iX "p fdrawcmd" .iX "c raw command" .iX "c low level interaction with floppy driver" .iX "c direct interaction with floppy driver" .PP .nf .ft 3 .in +0.3i \&\fR\&\f(CWfdrawcmd [\fR\&\f(CWdrive=\fIdrive\fR\&\f(CW] [\fR\&\f(CWrate=\fIrate\fR\&\f(CW] [\fR\&\f(CWlength=\fIlength\fR\&\f(CW] [\fR\&\f(CWrepeat=\fIrepeat\fR\&\f(CW] [\fR\&\f(CWcylinder=\fIphysical-cyl\fR\&\f(CW] \fIcommand\fR\&\f(CW [\fIparamters\fR\&\f(CW \&...] [\fImode\fR\&\f(CW] .fi .in -0.3i .ft R .lp \&\fR .PP \&\fR\&\f(CWfdrawcmd\fR is used to send raw commands to the floppy disk controller, after having selected a given drive. You must have write permission to the selected drive. .PP When writing to a disk, data is read from stdin; when reading, data is printed to stdout. Diagnostic messages, return values from the controller, and the value of the disk change line after the command are printed to stderr. .PP .SH Options .PP All numbers may be given in octal (0211), decimal (137), or hexadecimal (0x89). .IP .TP \&\fR\&\f(CWdrive=\fIdrive\fR\&\f(CW\fR\ Selects the drive. The default is drive 0 (\fR\&\f(CW\(if/dev/fd0\(is\fR). .TP \&\fR\&\f(CWrate=\fIrate\fR\&\f(CW\fR\ Selects the data transfer rate. Use 0 for high density disks, 1 for double density 5 1/4 disks (or 2 Mbps tapes, if the appropriate rate table is selected), and 2 for double density 3 1/2 disks. .TP \&\fR\&\f(CWlength=\fIlength\fR\&\f(CW\fR\ Describes the length of the transferred data for commands reading from and writing to the disk. The default is to continue until end of file. .TP \&\fR\&\f(CWrepeat=\fIcount\fR\&\f(CW\fR\ Repeat the command \fIcount\fR times. This only works correctly for commands which don't do any data transfer. .TP \&\fR\&\f(CWcylinder=\fIcount\fR\&\f(CW\fR\ Seek to the given cylinder before executing the command .TP \&\fR\&\f(CW\fIcommand\fR\&\f(CW\fR\ The name of the command to send. \fIcommand\fR may be a spelled out name (like \fR\&\f(CWread\fR or \fR\&\f(CWwrite\fR), or a number representing the commands floppy disk controller opcode. A named command has already a mode associated with it, whereas for a number the mode parameter should be described using the \fR\&\f(CWmode\fR option. .IP .TP \&\fR\&\f(CW\fIparameters\fR\&\f(CW\fR\ The parameters for the command (optional, not all commands need parameters). .TP \&\fR\&\f(CW\fImode\fR\&\f(CW\fR\ Various flags or'ed together describing the properties of the command. .PP .SH Commands .PP The description of the various floppy commands given in this manpage is very sketchy. For more details get the 82078 spec sheet which can be found at: .nf .ft 3 .in +0.3i http://www-techdoc.intel.com/docs/periph/fd_contr/datasheets/ .fi .in -0.3i .ft R .lp \&\fR .PP Look for the chapter \fR\&\f(CWCOMMAND SET/DESCRIPTIONS\fR. Older FDCs only support a subset of the commands described therein, but the syntax for the commands that do exist is the same. .PP .SS Commands\ available\ on\ all\ FDCs .IP .TP \&\fR\&\f(CWread\ \fIdrvsel\ cyl\ head\ sect\ szcod\ spt\ rw-gap\ szcod2\fR\&\f(CW\fR\ Reads \fIlength\fR bytes of data from the disk. \fIdrvsel\fR is the drive selector. Bit 0 and 1 describe the drive, and bit 2 describes the head. The remaining parameters give the cylinder, head (yes, again), sector, size of the sector (128 * 2 ^ \fIszcod\fR), sectors per track (\fR\&\f(CWspt\fR, this is used to switch to the second head when the first side has been read), and size of the read-write gap. \fIszcod2\fR should be 0xff. \fR\&\f(CWread\fR returns \fIST0 ST1 ST2\fR and \fIcyl head sect szcod\fR of the next sector to be read; see \&\fR\&\f(CW\(if/usr/include/linux/fdreg.h\(is\fR . .IP N.B. Certain newer floppy disk controllers are buggy, and do not correctly recognize the end of transfer when operating in virtual DMA mode. For these, you need to set \fR\&\f(CWspt\fR to the id of the last sector to be read (for example, if you intend to read sectors 2, 3, 4, set \fR\&\f(CWspt\fR to 4, even if the disk has more sectors), and set the \&\fR\&\f(CWno-mt\fR flag. .TP \&\fR\&\f(CWwrite\ \fIdrvsel\ cyl\ head\ sect\ szcod\ spt\ rw-gap\ szcod2\fR\&\f(CW\fR\ Analogous to \&\fR\&\f(CWread\fR. .TP \&\fR\&\f(CWsense\ \fIdrvsel\fR\&\f(CW\fR\ Returns the third status byte (\fIST3\fR) .TP \&\fR\&\f(CWrecalibrate\ \fIdrvsel\fR\&\f(CW\fR\ Recalibrates the drive and returns \fIST0 ST1\fR. .TP \&\fR\&\f(CWseek\ \fIdrvsel\ cyl\fR\&\f(CW\fR\ Moves the head to \fIcyl\fR and returns \fIST0 ST1\fR. .TP \&\fR\&\f(CWspecify\ \fIdrvsel\ spec1\ spec2\fR\&\f(CW\fR\ Specify various parameters to the drive. .TP \&\fR\&\f(CWformat\ \fIdrvsel\ szcod\ sect-per-track\ fmt-gap\ fmt-fill\fR\&\f(CW\fR\ Formats the cylinder. The new sectors are filled with \fIfmt-fill\fR. The header information comes from the input, which is made up of \&\fIcyl head sect szcod\fR quadruples. The \fIszcod\fR parameter from the command line is used to describe the actual size of the sectors, and the \fIszcod\fR from the input is used to write into the header. However, the first write to these sectors will use the header information, and might overwrite the following sectors if the \&\fIszcod\fR parameter from the command line was too small. .TP \&\fR\&\f(CWreadid\ \fIdrvsel\fR\&\f(CW\fR\ reads the first sector header that comes and returns \&\fIST0 ST1 ST2 \fR and \&\fIcyl head sect szcod \fR of the encountered header. .PP .SS Commands\ available\ on\ 82072\ and\ later .TP \&\fR\&\f(CWdumpregs\fR\ Prints the contents of the FDCs registers, if supported. .PP .SS Commands\ available\ on\ 82072A\ and\ later .TP \&\fR\&\f(CWconfigure\ \fIconf1\ conf2\ conf3\fR\&\f(CW\fR\ Configures FIFO operation. .PP .SS Commands\ available\ on\ 82077\ and\ later .TP \&\fR\&\f(CWversion\fR\ Echoes 0x90 if the FDC is more recent than 82072A, and 0x80 otherwise .TP \&\fR\&\f(CWperpendicular\ \fIrate\fR\&\f(CW\fR\ Sets the perpendicular mode. Use 0 for normal, 2 for 500kb/s perpendicular, and 3 for 1 Mb/s perpendicular. .TP \&\fR\&\f(CWseek-out\ \fIdrvsel\ n\fR\&\f(CW\fR\ does a relative seek of \&\fIn\fR cylinders towards cylinder 0. .TP \&\fR\&\f(CWseek-in\ \ \fIdrvsel\ n\fR\&\f(CW\fR\ does a relative seek of \fIn\fR cylinders away from cylinder 0. .PP .SS Commands\ available\ on\ 82077AA\ and\ later .TP \&\fR\&\f(CWlock\fR\ Locks the FIFO configuration, so that it survives a FDC software reset. .TP \&\fR\&\f(CWunlock\fR\ Unlock the FIFO configuration .PP .SS Commands\ available\ on\ 82078 .TP \&\fR\&\f(CWpartid\fR\ echoes a byte describing the type of the FDC in the 3 high bits, and the stepping in the three low bits. .TP \&\fR\&\f(CWpowerdown\ \fIpowerconf\fR\&\f(CW\fR\ configures automatic power down of the FDC. The old configuration is echoed .TP \&\fR\&\f(CWoption\ \fIiso\fR\&\f(CW\fR\ enables/disables ISO formats. Odd values of \&\fIiso\fR enable these formats, whereas even values disable them. ISO formats don't have index headers, and thus allow to fit slightly more data on a disk. .TP \&\fR\&\f(CWsave\fR\ prints out 16 internal registers of the FDC. .TP \&\fR\&\f(CWrestore\ \fIr1\ r2\ r3\ ...\ r16\fR\&\f(CW\fR\ restores the 16 internal registers of the FDC. .TP \&\fR\&\f(CWformat_n_write\ \fIdrvsel\ szcod\ sect-per-track\ fmt-gap\ fmt-fill\fR\&\f(CW\fR\ formats the cylinder and writes initial data to it. The input data is made up of a sequence of headers (4 bytes) and data: \&\fIheader1 data1 header2 data2 ... headern datan\fR .TP \&\fR\&\f(CWdrivespec\ \fIdspec1\ dspec2\ ...\ specn\ terminator\fR\&\f(CW\fR\ chooses rate tables for various drives. Each dspec byte describes one drive. Bits 0 and 1 say which drive is described. Bits 2 and 3 describe the rate table. Only tables 0 and 2 are interesting. Both tables only differ in the meaning og rate 1. For table 0 (the default) rate 0 is 300 kb/s (used for 5 1/4 DD disks), whereas for table 1 it is 2 Mbps (used for fast floppy tape drives). Bit 4 is the precompensation table select bit. It should be set to 0. Bit 5-7 should be zero as well. The \&\fIterminator\fR byte ends the \fR\&\f(CWdrivespec\fR command. It is either 0xc0 or 0x80. If it is 0xc0, no result phase follows; if it is 0x80, the current data rate table configuration for the four drives is echoed. .PP .SH Modes The mode option is only needed when you describe the command as a numerical value. Some mode names are also valid command names. They are considered as command name if the command name has not yet been given, and as mode name otherwise. .PP If you give a command name followed by explicit modes, both the implicit flags of the command name, and the explicit modes are or'ed together. .PP If on the other hand you give a command name preceded by explicit modes, only the explicit modes are or'ed together. .TP \&\fR\&\f(CWread\fR\ Read data from disk using DMA. .TP \&\fR\&\f(CWwrite\fR\ Write data to the disk. .TP \&\fR\&\f(CWintr\fR\ Wait for an interrupt. .TP \&\fR\&\f(CWspin\fR\ wait for the disk to spin up .TP \&\fR\&\f(CWdisk\fR\ Aborts the operation if no disk is in the drive. This only works if you also chose a physical cylinder to seek to. .TP \&\fR\&\f(CWno-motor\fR\ Don't switch on the drive motor while issuing the command .TP \&\fR\&\f(CWno-motor-after\fR\ Switch off the motor immediately after the command returns. .TP \&\fR\&\f(CWfm\fR\ Uses the FM version of the \fR\&\f(CWread\fR, \fR\&\f(CWreadid\fR, \fR\&\f(CWwrite\fR and \&\fR\&\f(CWformat\fR commands. .TP \&\fR\&\f(CWno-mt\fR\ Do not use MT (multitrack) mode for the \fR\&\f(CWread\fR, \fR\&\f(CWreadid\fR and \&\fR\&\f(CWwrite\fR commands. This is needed on certain broken FDC's which don't recognize end of transfer when running in \fR\&\f(CWnodma\fR mode. In order to use these safely, set \fR\&\f(CWno-mt\fR, and chose the id of the last sector to be read as \fR\&\f(CWsect-per-track\fR. .PP \&\fR\&\f(CWfdrawcmd\fR opens the device node with the \fR\&\f(CWNDELAY\fR flag. This means that the driver should not try to autodetect the disk type (it might not be formatted), and that it should not reset the FDC. If a reset was needed, the command simply fails. If that happens, execute \&\fR\&\f(CWfloppycontrol --resetnow 0\fR , and try again. .PP .SH See Also Fdutils' texinfo doc fdutils-5.5-20060227/doc/location.texi0000444000175000017500000000342510210705565016446 0ustar anibalanibal@node Location, Basic usage, Top, Top @chapter Where to get fdutils and its documentation @cindex bugs @cindex ALPHA patches @cindex patches @cindex diffs @cindex mailing list Fdutils can be found at the following places (+ mirrors): @example ftp://www.tux.org/pub/knaff/fdutils/fdutils-5.5.tar.gz ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.5.tar.gz ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.5.tar.gz @end example The FAQ included in this package is also available separetely at: @example http://alain.knaff.linux.lu/floppy/FAQ.html http://www.tux.org/pub/knaff/floppy/FAQ.html @end example The FAQ at fdutils.linux.lu and www.tux.org is usually more up to date than versions found elsewhere. Thus, if you don't find an answer in the copy of the FAQ you have, please check this one for more recent info. Before reporting a bug, make sure that it has not yet been fixed in the Alpha patches which can be found at: @example http://fdutils.linux.lu ftp://www.tux.org/pub/knaff/fdutils @end example These patches are named @code{fdutils-}@var{version}@code{-}@var{ddmm}@code{.taz}, where version stands for the base version, @var{dd} for the day and @var{mm} for the month. Due to a lack of space, I usually leave only the most recent patch. There is an fdutils mailing list at fdutils @@ www.tux.org . Please send all bug reports to this list. You may subscribe to the list by sending a message with 'subscribe fdutils @@ www.tux.org' in its body to majordomo @@ www.tux.org . (N.B. Please remove the spaces around the "@@" both times. I left them there in order to fool spambots.) Announcements of new fdutils versions will also be sent to the list, in addition to the linux announce newsgroups. The mailing list is archived at http://www.tux.org/hypermail/fdutils/latest fdutils-5.5-20060227/doc/diskd.texi0000444000175000017500000000350507704057263015744 0ustar anibalanibal@node diskd, diskseekd, Commands, Commands @section diskd @pindex diskd The diskd command has the following syntax: @example @code{diskd} [@code{-d} @var{drive}] [@code{-i} @var{interval}] [@code{-e} @var{command}] @end example Diskd waits for a disk to be inserted into a given @var{drive}, and then either executes the @var{command} or exits. This program can be used to automatically mount a disk as soon as it is inserted. @subsection Warning This program works by switching the motor on for a very short interval, and then seeking to track -1. This might damage hardware in the long run. Amigas, which also use these techniques, are known for having problems with their disk drives no longer spinning up properly after a few month of usage. @subsection Options @table @code @item -d @var{drive} Selects the drive to observe for disk insertion. By default, drive 0 (@code{/dev/fd0}) is observed. @item -i @var{interval} Selects the polling interval. The interval is given in tenths of seconds. Default is 10 (one second). @item -e @var{command} Gives the command to be executed when a disk is inserted. If no command is given the program simply exits. Typically, the command mounts the disk. It can be a shell scripts which probes for several filesystems and disk geometries until it succeeds. @end table @subsection Bugs @itemize @bullet @item Automatic unmounting cannot yet be handled. It is indeed not enough to scan for disk removal, because when the disk is removed, it is already too late: There might be some buffers needing flushing. However, the @code{fdmountd} program allows automatic unmounting by using the @code{SYNC} mount options, which switches off write buffering (@pxref{fdmount}). @item The drive motor is running all the time, and on some computers, the drive led flickers at each time the drive is polled. @end itemize fdutils-5.5-20060227/doc/superformat.texi0000444000175000017500000002622407560752217017221 0ustar anibalanibal@node superformat, xdfcopy, setfdprm, Commands @section superformat @pindex superformat @cindex formatting disks (non XDF) @example @code{superformat} [@code{-D} @var{dos-drive}] [@code{-v} @var{verbosity-level}] [@code{-b} @var{begin-track}] [@code{-e} @var{end-track}] [@code{--superverify}] [@code{--dosverify}] [@code{--noverify}] [@code{--verify_later}] [@code{--zero-based}] [@code{-G} @var{format-gap}] [@code{-F} @var{final-gap}] [@code{-i} @var{interleave}] [@code{-c} @var{chunksize}] [@code{-g} @var{gap}] [@code{--absolute-skew} @var{absolute-skew}] [@code{--head-skew} @var{head-skew}] [@code{--track-skew} @var{track-skew}] [@code{--biggest-last}] @var{drive} [@var{media-description}] @end example @code{superformat} is used to format disks with a capacity of up to 1992K HD or 3984K ED. @xref{Extended formats}, for a detailed description of these formats. @xref{Media description}, for a detailed description of the syntax for the media description. If no media description is given, superformat formats a disk in the highest available density for that drive, using standard parameters (i.e. no extra capacity formats). When the disk is formatted, @code{superformat} automatically invokes @code{mformat} in order to put an MS-DOS filesystem on it. You may ignore this filesystem, if you don't need it. Supeformat allows to format 2m formats. Be aware, however, that these @code{2m} formats were specifically designed to hold an MS-DOS filesystem, and that they take advantage of the fact that the MS-DOS filesystem uses redundant sectors on the first track (the FAT, which is represented twice). The second copy of the FAT is @emph{not} represented on the disk. High capacity formats are sensitive to the exact rotation speed of the drive and the resulting difference in raw capacity. That's why @code{superformat} performs a measurement of the disks raw capacity before proceeding with the formatting. This measurement is rather time consuming, and can be avoided by storing the relative deviation of the drive capacity into the drive definition file file. @xref{Drive descriptions}, for more details on this file. The line to be inserted into the drive definition file is printed by superformat after performing its measurement. However, this line depends on the drive and the controller. Do not copy it to other computers. Remove it before installing another drive or upgrade your floppy controller. Swap the drive numbers if you swap the drives in your computer. @menu * Common options:: The most frequently used options * Advanced options:: For experts * Sector skewing options:: Optimizing throughput by creatively arranging the sectors * Examples:: Some example command lines * Troubleshooting:: Most common failure modes * Superformat bugs:: Nobody is perfect @end menu @node Common options, Advanced options, superformat, superformat @subsection Common Options Many options have a long and a short form. @table @code @item -h @itemx --help Print the help. @item -D @var{drive} @itemx --dosdrive @var{dos-drive} Selects DOS drive letter for @code{mformat} (for example @code{a:} or @code{b:}). The colon may be omitted. The default is derived from the minor device number. If the drive letter cannot be guessed, and is not given on the command line, @code{mformat} is skipped. @item -v @var{verbosity-level} @itemx --verbosity @var{verbosity-level} Sets the verbosity level. 1 prints a dot for each formatted track. 2 prints a changing sign for each formatted track (- for formatting the first head, = for formatting the second head, x for verifying the first head, and + for verifying the second head). 3 prints a complete line listing head and track. 6 and 9 print debugging information. @item --superverify Verifies the disk by first reading the track, than writing a pattern of U's, and then reading it again. This is useful as some errors only show up after the disk has once been written. However, this is also slower. @item -B @itemx --dosverify Verifies the disk using the @code{mbadblocks} program. @code{mbadblocks} marks the bad sectors as bad in the FAT. The advantage of this is that disks which are only partially bad can still be used for MS-DOS filesystems. @item -V @itemx --verify_later Verifies the whole disk at the end of the formatting process instead of at each track. Verifying the disk at each track has the advantage of detecting errors early on. @item -f @itemx --noverify Skips the verification altogether. @end table @node Advanced options, Sector skewing options, Common options, superformat @subsection Advanced Options Usually, superformat uses sensible default values for these options, which you normally don't need to override. They are intended for expert users. Most of them should only be needed in cases where the hardware or superformat itself has bugs. @table @code @item -b @var{begin-track} @itemx --begin_track @var{begin-track} Describes the track where to begin formatting. This is useful if the previous formatting failed halfway through. The default is 0. @item -e @var{end-track} @itemx --end_track @var{end-track} Describes where to stop formatting. @var{end_track} is the last track to be formatted plus one. This is mainly useful for testing purposes. By default, this is the same as the total number of tracks. When the formatting stops, the final skew is displayed (to be used as absolute skew when you'll continue). @item -S @var{sizecode} @itemx --sizecode @var{sizecode} Set the sector size to be used. The sector size is 128 * (2 ^ @var{sizecode}). Sector sizes below 512 bytes are not supported, thus sizecode must be at least 2. By default 512 is assumed, unless you ask for more sectors than would fit with 512 bytes. @item --stretch @var{stretch} Set the stretch factor. The stretch factor describes how many physical tracks to skip to get to the next logical track (2 ^ @var{stretch}). On double density 5 1/4 disks, the tracks are further apart from each other. @item -G @var{fmt-gap} @itemx --format_gap @var{fmt-gap} Set the formatting gap. The formatting gap tells how far the sectors are away from each other. By default, this is chosen so as to evenly distribute the sectors along the track. @item -F @var{final-gap} @itemx --final_gap @var{final-gap} Set the formatting gap to be used after the last sector. @item -i @var{interleave} @itemx --interleave @var{interleave} Set the sector interleave factor. @item -c @var{chunksize} @itemx --chunksize @var{chunksize} Set the size of the chunks. The chunks are small auxiliary sectors used during formatting. They are used to handle heterogeneous sector sizes (i.e. not all sectors have the same size) and negative formatting gaps. @item --biggest-last For MSS formats, make sure that the biggest sector is last on the track. This makes the format more reliable on drives which are out of spec. @item --zero-based Formats the disk with sector numbers starting at 0, rather than 1. Certain CP/M boxes or Music synthesizers use this format. Those disks can currently not be read/written to by the standard Linux read/write API; you have to use fdrawcmd to access them. As disk verifying is done by this API, verifying is automatically switched off when formatting zero-based. @end table @node Sector skewing options, Examples, Advanced options, superformat @subsection Sector skewing options In order to maximize the user data transfer rate, the sectors are arranged in such a way that sector 1 of the new track/head comes under the head at the very moment when the drive is ready to read from that track, after having read the previous track. Thus the first sector of the second track is not necessarily near the first sector of the first track. The skew value describes for each track how far sector number 1 is away from the index mark. This skew value changes for each head and track. The amount of this change depends on how fast the disk spins, and on how much time is needed to change the head or the track. @table @code @item --absolute_skew @var{absolute-skew} Set the absolute skew. This skew value is used for the first formatted track. It is expressed in raw bytes. @item --head_skew @var{head-skew} Set the head skew. This is the skew added for passing from head 0 to head 1. It is expressed in raw bytes. @item --track_skew @var{track-skew} Set the track skew. This is the skew added for seeking to the next track. It is expressed in raw bytes. @end table Example: (absolute skew=3, head skew=1, track skew=2) @example track 0 head 0: 4,5,6,1,2,3 (skew=3) track 0 head 1: 3,4,5,6,1,2 (skew=4) track 1 head 0: 1,2,3,4,5,6 (skew=0) track 1 head 1: 6,1,2,3,4,5 (skew=1) track 2 head 0: 4,5,6,1,2,3 (skew=3) track 2 head 1: 3,4,5,6,1,2 (skew=4) @end example N.B. For simplicitie's sake, this example expresses skews in units of sectors. In reality, superformat expects the skews to be expressed in raw bytes. @node Examples, Troubleshooting, Sector skewing options, superformat @subsection Examples In all the examples of this section, we assume that drive 0 is a 3 1/2 and drive 1 a 5 1/4. The following example shows how to format a 1440K disk in drive 0: @example superformat /dev/fd0 hd @end example The following example shows how to format a 1200K disk in drive 1: @example superformat /dev/fd1 hd @end example The following example shows how to format a 1440K disk in drive 1: @example superformat /dev/fd1 hd sect=18 @end example The following example shows how to format a 720K disk in drive 0: @example superformat /dev/fd0 dd @end example The following example shows how to format a 1743K disk in drive 0 (83 cylinders times 21 sectors): @example superformat /dev/fd0 sect=21 cyl=83 @end example The following example shows how to format a 1992K disk in drive 0 (83 cylinders times 2 heads times 12 KB per track) @example superformat /dev/fd0 tracksize=12KB cyl=83 mss @end example The following example shows how to format a 1840K disk in drive 0. It will have 5 2048-byte sectors, one 1024-byte sector, and one 512-byte sector per track: @example superformat /dev/fd0 tracksize=23b mss 2m ssize=2KB @end example All these formats can be autodetected by mtools, using the floppy driver's default settings. @node Troubleshooting, Superformat bugs, Examples, superformat @subsection Troubleshooting @table @code @item FDC busy, sleeping for a second When another program accesses a disk drive on the same controller as the one being formatted, @code{superformat} has to wait until the other access is finished. If this happens, check whether any other program accesses a drive (or whether a drive is mounted), kill that program (or unmount the drive), and the format should proceed normally. @item I/O errors during verification Your drive may be too far out of tolerance, and you may thus need to supply a margin parameter. Run @code{floppymeter} (@pxref{floppymeter}) to find out an appropriate value for this parameter, and add the suggested @code{margin} parameter to the command line @end table @node Superformat bugs, , Troubleshooting, superformat @subsection Bugs Opening up new window while @code{superformat} is running produces overrun errors. These errors are benign, as the failed operation is automatically retried until it succeeds. fdutils-5.5-20060227/doc/man-warning.texi0000444000175000017500000000227607560760540017067 0ustar anibalanibal@c for man page version only @unnumbered Note This manpage has been automatically generated from fdutils's texinfo documentation. However, this process is only approximative, and some items, such as crossreferences, footnotes and indices are lost in this translation process. Indeed, these items have no appropriate representation in the manpage format. Moreover, only the items specific to each command have been translated, and the general information about fdutils has been dropped in the manpage version. Thus I strongly advise you to use the original texinfo doc. @itemize @bullet @item To generate a printable copy from the texinfo doc, run the following commands: @example ./configure; make dvi; dvips fdutils.dvi @end example @item To generate a html copy, run: @example ./configure; make html @end example A premade html can be found at: @file{http://www.tux.org/pub/knaff/fdutils} @item To generate an info copy (browsable using emacs' info mode), run: @example ./configure; make info @end example @end itemize The texinfo doc looks most pretty when printed or as html. Indeed, in the info version certain examples are difficult to read due to the quoting conventions used in info. fdutils-5.5-20060227/doc/cleanup0000555000175000017500000000051207560761135015323 0ustar anibalanibal#!/bin/sh rm -f fdutils.aux fdutils.cp fdutils.cps fdutils.dvi fdutils.fn fdutils.ky rm -f fdutils.log fdutils.pg fdutils.ps fdutils.toc fdutils.tp fdutils.vr rm -f fdutils.info* rm -f Fdutils.aux Fdutils.cp Fdutils.cps Fdutils.dvi Fdutils.fn Fdutils.ky rm -f Fdutils.log Fdutils.pg Fdutils.pgs Fdutils.toc Fdutils.tp Fdutils.vr fdutils-5.5-20060227/src/0000755000175000017500000000000010446366017013771 5ustar anibalanibalfdutils-5.5-20060227/src/diskd.c0000444000175000017500000000451710203640432015223 0ustar anibalanibal#include #include #include #include #include #include #include #include #include #include #include #include #include #include "enh_options.h" int eioctl(int fd, int command,void * param, char *emsg) { int r; if ((r=ioctl(fd,command,param))<0 ) { perror(emsg); exit(1); } return r; } static char procFd[80]; int doPoll(int fd, struct floppy_drive_params *dpr, struct floppy_drive_struct *state) { if(! (dpr->flags & FD_SILENT_DCL_CLEAR)) { /* Work around a bug in floppy driver when silent dcl is not set */ struct floppy_raw_cmd raw_cmd; int fd2; fd2=open(procFd, 3 | O_NDELAY); if(fd2 != -1) close(fd2); /* Perform "dummy" rawcmd to flush out newchange */ raw_cmd.flags = FD_RAW_NEED_DISK; raw_cmd.cmd_count = 0; raw_cmd.track = 0; ioctl(fd, FDRAWCMD, &raw_cmd, "rawcmd"); } eioctl(fd, FDPOLLDRVSTAT, state, "reset"); return state->flags; } int main(int argc, char **argv) { int mask=0; int fd=-2; char *command=0; int interval=10; int ch; struct timeval timval; struct floppy_drive_struct state; struct floppy_drive_params dpr; struct enh_options optable[] = { { 'd', "drive", 1, EO_TYPE_FILE_OR_FD, 3, 0, (void *) &fd, "drive to be polled"}, { 'e', "exec", 1, EO_TYPE_STRING, 0, 0, (void *) &command, "shell command to be executed after disk insertion" }, { 'i', "interval", 1, EO_TYPE_LONG, 0, 0, (void *) &interval, "set polling interval (in tenth of seconds)" }, { '\0', 0 } }; while((ch=getopt_enh(argc, argv, optable, 0, &mask, "drive") ) != EOF ){ if ( ch== '?' ){ fprintf(stderr,"exiting\n"); exit(1); } printf("unhandled option %d\n", ch); exit(1); } if ( fd == -2 ) fd = open("/dev/fd0", 3 | O_NDELAY); if ( fd < 0 ){ perror("can't open floppy drive"); exit(1); } eioctl(fd,FDGETDRVPRM,(void *) &dpr, "Get drive parameters"); sprintf(procFd, "/proc/self/fd/%d", fd); doPoll(fd, &dpr, &state); while (state.flags & (FD_VERIFY|FD_DISK_NEWCHANGE)) { timval.tv_sec = interval / 10; timval.tv_usec = (interval % 10) * 100000; select(0, 0, 0, 0, &timval); doPoll(fd, &dpr, &state); } close(fd); if ( command) system(command); exit(0); } fdutils-5.5-20060227/src/measure.c0000444000175000017500000001071307560752353015603 0ustar anibalanibal#include #include #include #include #include #include #include #include #include #include #include #include #include #include "enh_options.h" #include "fdutils.h" static struct { unsigned char value; int offset; } byte_tab[16]= { { 0x03, 0 }, { 0x7c, 0 }, { 0x81, 0 }, { 0x3e, 0 }, { 0xc0, 0 }, { 0x1f, 0 }, { 0x60, 0 }, { 0x8f, 1 }, { 0x30, 1 }, { 0xc7, 1 }, { 0x18, 1 }, { 0xe3, 1 }, { 0x0c, 1 }, { 0xf1, 1 }, { 0x06, 1 }, { 0xf8, 1 } }; static int read_track(int fd, int dn, int rate, int cylinder) { struct floppy_raw_cmd raw_cmd; int tmp; unsigned char ref; unsigned char buffer[32*1024]; unsigned char c; int ptr; int i; raw_cmd.cmd_count = 9; raw_cmd.cmd[0] = FD_READ & ~0x80; /* format command */ raw_cmd.cmd[1] = dn /* drive */; raw_cmd.cmd[2] = 0; /* cylinder */ raw_cmd.cmd[3] = 0; /* head */ raw_cmd.cmd[4] = 1; /* sector */ raw_cmd.cmd[5] = 8; /* sizecode */ raw_cmd.cmd[6] = 1; /* sect per track */ raw_cmd.cmd[7] = 0x1b; /* gap */ raw_cmd.cmd[8] = 0xff; /* sizecode2 */ raw_cmd.data = buffer; raw_cmd.length = 32 * 1024; raw_cmd.flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK | FD_RAW_READ; raw_cmd.rate = rate; raw_cmd.track = cylinder; tmp = ioctl(fd, FDRAWCMD, & raw_cmd); if ( tmp < 0 ){ perror("read"); exit(1); } if((raw_cmd.reply[1] & ~0x20) | (raw_cmd.reply[2] & ~0x20) | raw_cmd.reply[3]) { int i; fprintf(stderr, "\nFatal error while measuring raw capacity\n"); for(i=0; i < raw_cmd.reply_count; i++) { fprintf(stderr, "%d: %02x\n", i, raw_cmd.reply[i]); } exit(1); } ptr = 514; /* we look first for the place where the 0x4e's are going to stop */ ref = buffer[ptr]; while(buffer[ptr] == ref) ptr += 256; ptr -= 240; while(buffer[ptr] == ref) ptr += 16; ptr -= 15; while(buffer[ptr] == ref) ptr ++; /* we have now found the first byte after wrap-around */ /* jump immediately to the supposed beginning */ ptr += 210; c = buffer[ptr]; while(buffer[ptr] == c) ptr--; for(i=0; i<16; i++) { if(byte_tab[i].value == c) { ptr -= byte_tab[i].offset; return ptr * 16 + i; } } return ptr * 16; } static void m_format_track(int fd, int dn, int rate, int cylinder) { struct floppy_raw_cmd raw_cmd; int tmp; format_map_t format_map[1] = { { 0, 0, 1, 8 } }; raw_cmd.cmd_count = 6; raw_cmd.cmd[0] = FD_FORMAT; /* format command */ raw_cmd.cmd[1] = dn /* drive */; raw_cmd.cmd[2] = 2; /* sizecode used for formatting */ raw_cmd.cmd[3] = 1; /* sectors per track */ raw_cmd.cmd[4] = 255; /* gap. unimportant anyways */ raw_cmd.cmd[5] = 3; raw_cmd.data = format_map; raw_cmd.length = sizeof(format_map); raw_cmd.flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK | FD_RAW_WRITE; raw_cmd.rate = rate; raw_cmd.track = cylinder; tmp = ioctl(fd, FDRAWCMD, & raw_cmd); if ( tmp < 0 ){ perror("format"); exit(1); } if((raw_cmd.reply[1] & ~0x20) | (raw_cmd.reply[2] & ~0x20)) { int i; if ( raw_cmd.reply[1] & ST1_WP ){ fprintf(stderr,"The disk is write protected\n"); exit(1); } fprintf(stderr, "\nFatal error while measuring raw capacity\n"); for(i=0; i < raw_cmd.reply_count; i++) { fprintf(stderr, "%d: %02x\n", i, raw_cmd.reply[i]); } exit(1); } } void readid(int fd, int dn, int rate, int cylinder) { struct floppy_raw_cmd raw_cmd; int tmp; raw_cmd.cmd_count = 2; raw_cmd.cmd[0] = FD_READID; /* format command */ raw_cmd.cmd[1] = dn /* drive */; raw_cmd.flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK; raw_cmd.rate = rate; raw_cmd.track = cylinder; tmp = ioctl( fd, FDRAWCMD, & raw_cmd ); if ( tmp < 0 ){ perror("readid"); exit(1); } } int measure_raw_capacity(int fd, int dn, int rate, int cylinder, int warmup, int verbosity) { int cap, min, ctr; if(warmup) /* first formatting, so that we have sth to read during the * warmup cycles */ m_format_track(fd, dn, rate, cylinder); m_format_track(fd, dn, rate, cylinder); min = cap = read_track(fd, dn, rate, cylinder); ctr = 0; while(ctr < 10) { m_format_track(fd, dn, rate, cylinder); cap = read_track(fd, dn, rate, cylinder); if(cap < min) { min = cap; ctr = 0; } else ctr++; if(verbosity) fprintf(stderr,"warmup cycle: %3d %6d %6d\r", ctr, cap, min); } if(verbosity) fprintf(stderr," \r"); return min; } fdutils-5.5-20060227/src/enh_options.c0000444000175000017500000002563307464324643016476 0ustar anibalanibal#include #include #include #include #include #include #include #include "enh_options.h" static struct option *my_longopts; static char **my_xopts; static char *my_shortopts; static int length; void print_usage(char *progname, struct enh_options *eo, char *userparams) { int i; fprintf(stderr,"Usage: %s ", progname); for (i=0; itype & EO_TYPE_LIST ) iterations = eo->arg; else iterations = 1; for( i=0; i < iterations; i++ ){ if ( !nextname ) break; name = nextname+1; if ( eo->type & EO_TYPE_LIST ) nextname = strchr(name, ',' ); else nextname = 0; switch(eo->type & EO_DTYPE){ case EO_TYPE_NONE: return 0; case EO_TYPE_STRING: if ( nextname ) *nextname='\0'; *((char **) eo->address) = name; if ( nextname) *nextname=','; continue; } if (eo->has_arg){ if(!*name ) /* last field is empty */ break; if ( name == nextname ) /* field to be skipped */ continue; } switch(eo->type & EO_DTYPE){ case EO_TYPE_FLOAT: if( sscanf(name, "%f", &f ) != 1 ){ fprintf(stderr,"%s is not a float\n", name); return -1; } ((float *) eo->address)[i] = f; continue; case EO_TYPE_DOUBLE: if ( sscanf(name, "%lf", &d) != 1 ){ fprintf(stderr,"%s is not a double\n", name); return -1; } ((double *) eo->address)[i]=d; continue; case EO_TYPE_CHAR: *((char *) eo->address ) = name[0]; continue; case EO_TYPE_BITMASK_BYTE: if ( eo->arg >= 0 ) ((char *) eo->address)[i] |= eo->arg & 0xff; else ((char *) eo->address)[i] &= eo->arg; return 0; case EO_TYPE_BITMASK_SHORT: if ( eo->arg >= 0 ) ((short *) eo->address)[i] |= eo->arg & 0xff; else ((short *) eo->address)[i] &= eo->arg; return 0; case EO_TYPE_BITMASK_LONG: if ( eo->arg >= 0 ) ((long *) eo->address)[i] |= eo->arg & 0x7fff; else ((long *) eo->address)[i] &= eo->arg; return 0; } if ( ! eo->has_arg ) number = eo->arg; else number = strtoul(name, &end, 0 ); switch( eo->type & EO_DTYPE){ case EO_TYPE_FILE_OR_FD: if ((!*end || end == nextname) && number >= 0){ ((int *) eo->address)[i] = number; continue; } /* fall through */ case EO_TYPE_FILE: if (nextname) *nextname='\0'; if ( eo->type & EO_TYPE_LIST ) flags = O_RDONLY; else flags = eo->arg; number = open(name, flags, 0644 ); if (nextname) *nextname=','; if ( number < 0 ){ perror(name); } ((int *) eo->address)[i] = number; continue; } if (eo->has_arg && end != nextname && *end){ fprintf(stderr,"%s is not a number\n", name); return -1; } switch(eo->type & EO_DTYPE){ case EO_TYPE_BYTE: ((char *) eo->address)[i] = number; continue; case EO_TYPE_SHORT: ((short *) eo->address)[i] = number; continue; case EO_TYPE_LONG: ((long *) eo->address)[i] = number; continue; default: fprintf(stderr, "Bad option type in parse_option for %s\n", eo->longo); exit(1); } } if ( eo->type & EO_TYPE_LIST ) eo->arg = i; return 0; } static int get_wordlength(struct enh_options *eo) { int wordlength=0; int i, wl; for( i=0; i wordlength ) wordlength = wl; } return wordlength; } static void print_option(struct enh_options *eo, int wordlength) { int i, iterations; long number; if ( eo->type & EO_TYPE_LIST ) iterations = eo->arg; else iterations = 1; if ( eo->has_arg ){ printf("%s=", eo->longo); for(i=strlen(eo->longo); itype & EO_DTYPE ){ case EO_TYPE_BITMASK_BYTE: if ( eo->arg >= 0 && ((char *) eo->address)[i] & eo->arg) printf("%s\n", eo->longo); return; case EO_TYPE_BITMASK_SHORT: if ( eo->arg >= 0 && ((short *) eo->address)[i] & eo->arg) printf("%s\n", eo->longo); return; case EO_TYPE_BITMASK_LONG: if ( eo->arg >= 0 && ((long *) eo->address)[i] & eo->arg) printf("%s\n", eo->longo); return; } switch( eo->type & EO_DTYPE ){ case EO_TYPE_FLOAT: printf("%f", ((float *) eo->address)[i] ); continue; case EO_TYPE_DOUBLE: printf("%f", ((double *) eo->address)[i] ); continue; case EO_TYPE_STRING: printf("%s", ((char **) eo->address)[i] ); continue; case EO_TYPE_FILE: case EO_TYPE_FILE_OR_FD: number = ((int *) eo->address)[i]; if ( number < 0 ) printf(""); else printf("%%%ld", number); continue; } switch( eo->type & EO_DTYPE ){ case EO_TYPE_BYTE: number = ((char *) eo->address)[i] ; break; case EO_TYPE_SHORT: number = ((short *) eo->address)[i] ; break; case EO_TYPE_LONG: number = ((long *) eo->address)[i] ; break; case EO_TYPE_CHAR: number = ((char *) eo->address)[i] ; break; default: printf("??\n"); return; } if ( eo->has_arg ){ if ( (eo->type & EO_DTYPE ) == EO_TYPE_CHAR ) printf("%c", (char) number); else printf("%ld", number); } else { if ( eo->arg == number ) printf("%s", eo->longo ); else return; } } printf("\n"); } int parse_delayed_options(struct enh_options *eo, int mask) { int i; int ret=0; for(i=0; i #ifdef HAVE_SYS_SYSMACROS_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "enh_options.h" #include #include int eioctl(int fd, int command,void * param, char *emsg) { int r; if ((r=ioctl(fd,command,param))<0 ) { perror(emsg); exit(1); } return r; } #ifndef PIDFILE #define PIDFILE NULL #endif void dummy(int dummy) {} int main(int argc, char **argv) { int mask=0; int fd=-2; int interval=1000; int ch; struct timeval timval; struct floppy_raw_cmd raw_cmd; struct stat buf; int drive; char *drive_name="/dev/fd0"; char *pidfilename=PIDFILE; char *tmp_s; FILE *pidfile; int pid; struct enh_options optable[] = { { 'd', "drive", 1, EO_TYPE_STRING, 0, 0, (void *) &drive_name, "drive to be seeked"}, { 'i', "interval", 1, EO_TYPE_LONG, 0, 0, (void *) &interval, "set polling interval (in tenth of seconds)" }, { 'p', "pidfile", 1, EO_TYPE_STRING, 0, 0, (void *) &pidfilename, "stores the daemon process id into named file"}, { '\0', 0 } }; tmp_s = strrchr(argv[0],'/'); if(!tmp_s) tmp_s = argv[0]; else tmp_s++; if ( !strcmp(tmp_s, "diskseek" )) interval = 0; while((ch=getopt_enh(argc, argv, optable, 0, &mask, "drive") ) != EOF ){ if ( ch== '?' ){ fprintf(stderr,"exiting\n"); exit(1); } printf("unhandled option %d\n", ch); exit(1); } if(interval){ switch((pid = fork())){ case 0: /* child */ break; case -1: /* error */ perror("fork"); exit(1); default: /* parent */ if(!pidfilename) pidfilename = getenv("DISKSEEKDPIDFILE"); if(pidfilename){ pidfile = fopen(pidfilename, "w"); fprintf(pidfile, "%d\n", pid); fclose(pidfile); } exit(0); } } while(1){ signal(SIGHUP, dummy); /* open the device */ fd=open(drive_name, O_ACCMODE | O_EXCL); if (fd < 0 ){ fprintf(stderr,"%s\n", drive_name); perror("open"); exit(1); } if (fstat (fd, &buf) < 0) { perror("fstat"); exit(1); } if (major(buf.st_rdev) != FLOPPY_MAJOR) { fprintf(stderr,"Not a floppy drive\n"); exit(1); } drive = minor( buf.st_rdev ); drive = (drive & 3) + ((drive & 0x80) >> 5); /* reset the fdc, if needed */ eioctl(fd, FDRESET, FD_RESET_IF_NEEDED, "reset"); /* then recalibrate the disk */ raw_cmd.flags = FD_RAW_INTR; raw_cmd.cmd_count = 2; raw_cmd.cmd[0] = FD_RECALIBRATE; raw_cmd.cmd[1] = drive; eioctl(fd, FDRAWCMD, (void *)&raw_cmd, "recalibrate"); raw_cmd.flags = FD_RAW_INTR; raw_cmd.cmd_count = 3; raw_cmd.cmd[0] = FD_SEEK; raw_cmd.cmd[1] = drive & 3; raw_cmd.cmd[2] = 80; eioctl(fd, FDRAWCMD, (void *)&raw_cmd, "blind seek"); /* then recalibrate the disk */ raw_cmd.flags = FD_RAW_INTR; raw_cmd.cmd_count = 2; raw_cmd.cmd[0] = FD_RECALIBRATE; raw_cmd.cmd[1] = drive; eioctl(fd, FDRAWCMD, (void *)&raw_cmd, "recalibrate"); close(fd); if(!interval) exit(0); timval.tv_sec = interval; timval.tv_usec = 0; if (select(0, 0, 0, 0, &timval) < 0 && errno != EINTR){ perror("select"); exit(1); } } return 0; } fdutils-5.5-20060227/src/floppycontrol.c0000444000175000017500000003156207560752353017061 0ustar anibalanibal/* * floppycontrol.c * * This program illustrates the new FDGETEMSTRESH, FDSETMAXERRS, FDGETMAXERRS, * FDGETDRVTYP ioctl added by A. Knaff */ #include #include #include #include #include #include #include #include #include "enh_options.h" #ifndef FD_DISK_CHANGED #define FD_DISK_CHANGED 0 #endif int eioctl(int fd, int command,void * param, char *emsg) { int r; if ((r=ioctl(fd,command,param))<0 ) { perror(emsg); exit(1); } return r; } char *autodetect; int reset_now; struct floppy_drive_struct drivstat; struct floppy_fdc_state fdcstat; #ifdef FDWERRORGET struct floppy_write_errors sta; #endif struct floppy_fdc_state fdcstat; struct floppy_drive_params dpr; #define max_error (dpr.max_errors) int fd; #define PRINT 0x1 #define SET_ERR 0x2 #define SET_EMSG 0x4 #define DO_FLUSH 0x8 #define DO_FMT_END 0x10 #define DO_DRVTYP 0x20 #define DO_EJECT 0x40 #define SET_DPR 0x80 #define PRINTSTATE 0x100 #define SET_AUTODETECT 0x200 #define POLLSTATE 0x400 #define SET_RESET 0x800 #define PRINTFDCSTATE 0x1000 #ifdef FDWERRORGET #define CLRWERROR 0x2000 #define PRINTWERROR 0x4000 #endif #ifndef FD_DEBUG #define FD_DEBUG 2 #endif struct enh_options optable[] = { { 'p', "print", 0, EO_TYPE_NONE, 0, PRINT, 0, "print the current error thresholds and the drive type"}, { 'a', "abort", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_ERR, (void *) &max_error.abort, "set operation abortion threshold (if there are more errors than this threshold, the driver gives up to read/write the requested sector and reports an I/O error to the user program" }, { 't', "readtrack", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_ERR, (void *) &max_error.read_track, "set read track threshold (if there are less errors than this threshold, an entire track is read at once)" }, { 'r', "recalibrate", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_ERR, (void *) &max_error.recal, "set recalibration threshold (if there are more errors than this threshold, the driver recalibrates the drive, i.e. moves the head to track 0 and back, to make sure it really knows where the head is)" }, { 'R', "reset", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_ERR, (void *) &max_error.reset, "set reset threshold (if there are more errors than this threshold, the driver resets the floppy disk controller)" }, { 'e', "reporting", 1, EO_TYPE_SHORT | EO_TYPE_DELAYED, 0, SET_ERR, (void *) &max_error.reporting, "set error reporting threshold (if there are more errors than this threshold, error messages are printed to the console)" }, { 'f', "flush", 0, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, DO_FLUSH, 0, "flush the floppy buffers" }, #ifdef FDEJECT { 'x', "eject", 0, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, DO_EJECT, 0, "eject the floppy disk" }, #endif { 'd', "drive", 1, EO_TYPE_FILE_OR_FD, 3, 0, (void *) &fd, "specify the target drive (default is /dev/fd0)" }, { 'F', "formatend", 1, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, DO_FMT_END, 0, "emits an FDFMTEND ioctl. This is needed when, after interrupting a formatting program, the drive light stays on" }, { 'T', "type", 0, EO_TYPE_NONE, 0, DO_DRVTYP, 0, "prints the drive type" }, {'\0', "debug", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, FD_DEBUG, SET_DPR, (void *) &dpr.flags, "switch debugging on" }, {'\0', "nodebug", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, ~FD_DEBUG, SET_DPR, (void *) &dpr.flags, "switch debugging off" }, {'\0', "message", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, FTD_MSG, SET_DPR, (void *) &dpr.flags, "switch autodetection and overrun messages on" }, {'\0', "nomessage", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, ~FTD_MSG,SET_DPR, (void *) &dpr.flags, "switch autodetection and overrun messages off" }, #ifdef FD_SILENT_DCL_CLEAR {'\0', "silent_dcl_clear", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, FD_SILENT_DCL_CLEAR, SET_DPR, (void *) &dpr.flags, "switches on silent disk change status clear" }, {'\0', "noisy_dcl_clear", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, ~FD_SILENT_DCL_CLEAR,SET_DPR, (void *) &dpr.flags, "switches off silent disk change status clear" }, #endif { 'c', "cmos", 1, EO_TYPE_BYTE | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.cmos, "set cmos type" }, { '\0', "hlt", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.hlt, "set hlt" }, { '\0', "hut", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.hut, "set hut" }, { '\0', "srt", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.srt, "set srt" }, { 'o', "spindown", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.spindown, "set spindown time" }, { 'u', "spinup", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.spinup, "set spinup time" }, { 's', "select_delay", 1, EO_TYPE_BYTE | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.select_delay, "set drive select delay" }, {'\0', "rps", 1, EO_TYPE_BYTE | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.rps, "sets rotations per second" }, { 'O', "spindown_offset", 1, EO_TYPE_BYTE | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.spindown_offset, "set spindown offset (decides in which position the disk stops)" }, {'\0', "cylinders", 1, EO_TYPE_BYTE | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.tracks, "set maximal number of cylinders" }, {'\0', "tracks", 1, EO_TYPE_BYTE | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.tracks, "obsolete (same as --cylinders)" }, {'\0', "timeout", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.timeout, "set interrupt timeout" }, { 'i', "interleave", 1, EO_TYPE_BYTE | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.interleave_sect, "set interleave" }, {'A', "autodetect", 1, EO_TYPE_STRING, 0, SET_AUTODETECT, (void *) &autodetect, "set autodetection sequence (comma separated list of format indexes. The format index is the minor device number divided by four)" }, { 'C', "checkfreq", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.checkfreq, "set maximal disk change check interval" }, { 'n', "native_format", 1, EO_TYPE_LONG | EO_TYPE_DELAYED, 0, SET_DPR, (void *) &dpr.native_format, "set the native format of this drive" }, {'\0', "resetnow", 1, EO_TYPE_LONG, 0, SET_RESET, (void *) &reset_now, "issue a reset command", }, { 'P', "printstate", 0, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, PRINTSTATE, 0, "print internal per drive driver status"}, { '\0', "printfdcstate", 0, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, PRINTFDCSTATE, 0, "print internal per fdc driver status"}, { '\0', "pollstate", 0, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, POLLSTATE, 0, "polls internal driver status and prints it"}, #ifdef FDWERRORGET { '\0', "clrwerror", 0, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, CLRWERROR, 0, "clears write error structure"}, { '\0', "printwerror", 0, EO_TYPE_NONE | EO_TYPE_DELAYED, 0, PRINTWERROR, 0, "prints write error structure"}, #endif #ifdef FD_BROKEN_DCL {'\0', "broken_dcl", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED,FD_BROKEN_DCL, SET_DPR, (void *) &dpr.flags, "work around broken disk change line" }, {'\0', "working_dcl", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED,~FD_BROKEN_DCL, SET_DPR, (void *) &dpr.flags, "assume a working disk change line" }, #endif #ifdef FD_INVERTED_DCL {'\0', "inverted_dcl", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, FD_INVERTED_DCL, SET_DPR, (void *) &dpr.flags, "assume an inverted disk change line" }, {'\0', "no_inverted_dcl", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED, ~FD_INVERTED_DCL, SET_DPR, (void *) &dpr.flags, "assume a non-inverted disk change line" }, #endif {'\0', "messages", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED,FTD_MSG, SET_DPR, (void *) &dpr.flags, "print informational messages" }, {'\0', "no_messages", 0, EO_TYPE_BITMASK_BYTE | EO_TYPE_DELAYED,~FTD_MSG, SET_DPR, (void *) &dpr.flags, "don't print informational messages" }, { '\0', 0 } }; int main( int argc, char **argv) { int ch; int mask=0; char drivtyp[17]; char *cont; int i; fd = -2; while((ch=getopt_enh(argc, argv, optable, 0, &mask, "drive") ) != EOF ){ if ( ch== '?' ){ fprintf(stderr,"exiting\n"); exit(1); } printf("unhandled option %d\n", ch); exit(1); } if ( fd == -1 ) exit(0); if ( fd < 0 ){ if ( optind < argc ) fd = open(argv[optind], 3 | O_NDELAY); else fd = open("/dev/fd0", 3 | O_NDELAY); if ( fd < 0 ){ perror("can't open floppy drive"); print_usage(argv[0],optable,""); exit(1); } } if (mask & DO_FMT_END ) eioctl(fd,FDFMTEND,0,"format end"); if (mask & DO_FLUSH) eioctl(fd,FDFLUSH,0,"flush buffers"); #ifdef FDEJECT if (mask & DO_EJECT) { fsync(fd); eioctl(fd,FDEJECT,0,"eject floppy"); } #endif if (mask & (DO_DRVTYP ) ) eioctl(fd,FDGETDRVTYP,(void *) drivtyp, "Get drive type"); if ( mask & (PRINT | SET_DPR | SET_AUTODETECT ) ) eioctl(fd,FDGETDRVPRM,(void *) &dpr, "Get drive parameters"); else if ( mask & SET_ERR ) eioctl(fd,FDGETMAXERRS,(void *) &max_error, "Get max errors"); if (mask & PRINT ){ print_current_settings(optable, SET_ERR|SET_EMSG|SET_DPR); printf("autodetect seq.= "); for ( i=0; i<8; i++){ if ( dpr.autodetect[i] == 0 ) break; if ( i ) putchar(','); printf("%1d", dpr.autodetect[i]); if ( dpr.read_track & ( 1 << i ) ) putchar('t'); } printf("\nflags: "); if(dpr.flags & 2 ) printf("debug "); if(dpr.flags & FTD_MSG ) printf("messages "); #ifdef FD_BROKEN_DCL if(dpr.flags & FD_BROKEN_DCL ) printf("broken_dcl"); #endif #ifdef FD_SILENT_DCL_CLEAR if(dpr.flags & FD_SILENT_DCL_CLEAR) printf("silent_dcl_clear"); #endif #ifdef FD_INVERTED_DCL if(dpr.flags & FD_INVERTED_DCL ) printf("inverted_dcl"); #endif printf("\n"); } if (mask & DO_DRVTYP ) printf("%s\n", drivtyp); parse_delayed_options(optable, mask & (SET_ERR| SET_EMSG| SET_DPR)); if ( mask & SET_AUTODETECT ){ cont = autodetect; for ( i=0; i<8; i++){ if ( *cont == '\0' ) break; if ( *cont == ',' ){ cont++; continue; } dpr.autodetect[i] = strtoul( cont, &cont, 0 ); if ( *cont == 't' ){ cont++; dpr.read_track |= 1 << i; } else dpr.read_track &= ~(1 << i); while ( *cont != ',' && *cont != '\0' ) cont++; if ( *cont == ',' ) cont++; } if ( i < 8 ) dpr.autodetect[i] = 0; } if (mask & SET_RESET) eioctl(fd, FDRESET, (void *)reset_now, "reset"); if (mask & (PRINTSTATE | POLLSTATE) ){ if ( mask & POLLSTATE ) eioctl( fd, FDPOLLDRVSTAT, &drivstat,"get drive state"); else eioctl( fd, FDGETDRVSTAT , &drivstat,"get drive state"); #ifndef FD_DCL_SEEN # define FD_DCL_SEEN 0x40 #endif printf("%s %s %s %s %s %s\n", drivstat.flags & FD_VERIFY ? "verify" : "", drivstat.flags & FD_DISK_NEWCHANGE ? "newchange" : "", drivstat.flags & FD_NEED_TWADDLE ? "need_twaddle" : "", drivstat.flags & FD_DISK_CHANGED ? "disk_changed" : "", drivstat.flags & FD_DISK_WRITABLE ?"disk_writable" : "", drivstat.flags & FD_DCL_SEEN ?"dcl_seen" : ""); printf("spinup= %ld\n", drivstat.spinup_date); printf("select= %ld\n", drivstat.select_date); printf("first_read= %ld\n", drivstat.first_read_date); printf("probed_fmt= %d\n", drivstat.probed_format); printf("cylinder= %d\n", drivstat.track); printf("maxblock= %d\n", drivstat.maxblock); printf("maxcylinder= %d\n", drivstat.maxtrack); printf("generation= %d\n", drivstat.generation); printf("keep data= %d\n", drivstat.keep_data); printf("refs= %d\n", drivstat.fd_ref); printf("device= %d\n", drivstat.fd_device); printf("last_checked= %ld\n", drivstat.last_checked); } if ( mask & PRINTFDCSTATE ){ eioctl( fd, FDGETFDCSTAT , &fdcstat,"get fdc state"); printf("spec1=%x\n", fdcstat.spec1); printf("spec2=%x\n", fdcstat.spec2); printf("rate=%x\n", fdcstat.dtr); printf("rawcmd=%x\n", fdcstat.rawcmd); printf("dor=%x\n", fdcstat.dor); printf("version=%x\n", fdcstat.version); printf("reset=%x\n", fdcstat.reset); printf("need_configure=%x\n", fdcstat.need_configure); printf("has_fifo=%x\n", fdcstat.has_fifo); printf("perp_mode=%x\n", fdcstat.perp_mode); printf("address=%x\n", (unsigned int) fdcstat.address); } #ifdef FDWERRORGET if (mask & PRINTWERROR){ eioctl( fd, FDWERRORGET , &sta,"get write error state"); printf("write_errors %u badness %u\n", sta.write_errors, sta.badness); printf("first_error_sector %lu first_error_generation %d\n", sta.first_error_sector, sta.first_error_generation); printf("last_error_sector %lu last_error_generation %d\n", sta.last_error_sector, sta.last_error_generation); } if (mask & CLRWERROR) eioctl( fd, FDWERRORCLR , 0,"clear write error state"); #endif if (mask & ( SET_DPR | SET_AUTODETECT )) eioctl(fd,FDSETDRVPRM, (void *) &dpr, "Set drive parameters"); else if (mask & SET_ERR ) eioctl(fd,FDSETMAXERRS, (void *) &max_error, "Set max errors"); exit(0); } fdutils-5.5-20060227/src/superformat.c0000444000175000017500000007251010446366017016507 0ustar anibalanibal/* Done: Added calc_skews to figure out skews for all tracks at once. This has the happy side effect of making 24-sector formats work on my 8272a system whereas it didn't before (perhaps due to the time required to calculate skews *during* formatting?) Added a few interesting verbosity levels verify_now changed to verify_later; verify_now is default Combined format_track_1 and format_track_2; once calc_skews was created, they took the same parameters and were always called in succession Add support for 300 Kbps 3.5" DD disks (13-14 sector equivalent) like 2m 940707 DCN Fixed BYTE vs. CHAR handling of no_verify and verify_later Allowed use of 13/14 sector non-2m disks 940710 AK Fixed support for 300Kbps 3.5" DD disks without 2m 20021102 AK: switched verify_later to be default on. Newer kernels (2.4.x) cannot refrain from reading ahead, even if BLKRA is set to 0, and this will cause failure when verifying during formatting, because read-ahead will attempt to access tracks that are not _yet_ formatted Todo: - Allow reversing cylinder order, or perhaps have option to try as many cylinders as happen to work (as in 2m). Currently, if too many cylinders are attempted it won't fail until the very end */ #include #ifdef HAVE_SYS_SYSMACROS_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "enh_options.h" #include "mediaprm.h" #include "fdutils.h" #include "oldfdprm.h" #include "superformat.h" int fm_mode=0; struct defaults { char density; struct { int sect; int rate; } fmt[6]; } drive_defaults[] = { { DENS_UNKNOWN, { {0, 0}, {0, 0} }}, { DENS_DD, { {0, 0}, { 0, 0}, {9, 2}, { 0, 0}, {0, 0}, {0, 0} } }, { DENS_HD, { {0, 0}, { 0, 0}, {9, 1}, { 0, 0}, {15, 0}, {0, 0} } }, { DENS_DD, { {0, 0}, { 0, 0}, {9, 2}, { 0, 0}, {0, 0}, {0, 0} } }, { DENS_HD, { {0, 0}, { 0, 0}, {9, 2}, { 0, 0}, {18, 0}, {0, 0} } }, { DENS_ED, { {0, 0}, { 0, 0}, {9, 2}, { 0, 0}, {18, 0}, {36, 0x43} } }, { DENS_ED, { {0, 0}, { 0, 0}, {9, 2}, { 0, 0}, {18, 0}, {36, 0x43} } } }; int header_size=62; int index_size=146; char floppy_buffer[24 * 512]; int verbosity = 3; static char noverify = 0; static char noformat = 0; static char dosverify = 0; static char verify_later = 0; short stretch; int cylinders, heads, sectors; int begin_cylinder, end_cylinder; int head_skew=1024, cylinder_skew=1536, absolute_skew=0; int use_2m=0; int lskews[MAX_TRACKS][MAX_HEADS] = {{0}}; int findex[MAX_TRACKS][MAX_HEADS] = {{0}}; int mask= 0; char *error_msg[22]={ "Missing Data Address Mark", "Bad cylinder", "Scan not satisfied", "Scan equal hit", "Wrong cylinder", "CRC error in data field", "Control Mark = deleted", 0, "Missing Address Mark", "Write Protect", "No Data - unreadable", 0, "Overrun", "CRC error in data or address", 0, "End Of Cylinder", 0, 0, 0, "Not ready", "Equipment check error", "Seek end" }; int send_cmd(int fd,struct floppy_raw_cmd *raw_cmd, char *message) { int i; int code; int retries; struct floppy_raw_cmd tmp; retries=0; tmp = *raw_cmd; repeat: *raw_cmd = tmp; if ( ioctl( fd, FDRAWCMD, raw_cmd) < 0 ){ if ( errno == EBUSY ){ fprintf(stderr,"FDC busy, sleeping for a second\n"); sleep(1); goto repeat; } perror(message); #if 0 printf("the final skew is %d\n", skew ); #endif exit(1); } if ( raw_cmd->reply_count ){ switch( raw_cmd->reply[0] & 0xc0 ){ case 0x40: /* ignore EOC */ if((raw_cmd->reply[0] & ~0x4)== 0x40 && (raw_cmd->reply[1] == 0x80) && (raw_cmd->reply[2] == 0)) { /* OK, we merely reached the end of * our cylinder */ break; } if((raw_cmd->reply[0] & ~0x4)== 0x40 && raw_cmd->reply[1] == 0x10 && raw_cmd->reply[2] == 0x00) { fprintf(stderr,"Overrun, pausing for a second\n"); sleep(1); goto repeat; } fprintf(stderr,"error during command execution\n"); if ( raw_cmd->reply[1] & ST1_WP ){ fprintf(stderr,"The disk is write protected\n"); exit(1); } fprintf(stderr," "); for (i=0; i< raw_cmd->cmd_count; i++) fprintf(stderr,"%2.2x ", (int)raw_cmd->cmd[i] ); printf("\n"); for (i=0; i< raw_cmd->reply_count; i++) fprintf(stderr,"%2.2x ", (int)raw_cmd->reply[i] ); fprintf(stderr,"\n"); code = (raw_cmd->reply[0] <<16) + (raw_cmd->reply[1] << 8) + raw_cmd->reply[2]; for(i=0; i<22; i++){ if ( (code & ( 1 << i )) && error_msg[i]) fprintf(stderr,"%s\n", error_msg[i]); } printf("cylinder=%d head=%d sector=%d size=%d\n", raw_cmd->reply[3], raw_cmd->reply[4], raw_cmd->reply[5], raw_cmd->reply[6]); return -1; break; case 0x80: fprintf(stderr,"invalid command given\n"); exit(1); case 0xc0: fprintf(stderr,"abnormal termination caused by polling\n"); exit(1); case 0: /* OK */ break; } } return 0; } int floppy_read(struct params *fd, void *data, int cylinder, int head, int sectors) { int n,m; if (lseek(fd->fd, (cylinder * heads + head) * sectors * 512, SEEK_SET) < 0) { perror("lseek"); return -1; } m = sectors * 512; while(m>0) { /* read until we have read everything we should */ n=read(fd->fd, data, m); if ( n < 0 ) { perror("read"); return -1; } if(n== 0) { fprintf(stderr, "Error, %d bytes remaining\n", m); return -1; } m -= n; } return 0; } int floppy_write(struct params *fd, void *data, int cylinder, int head, int sectors) { int n,m; if (lseek(fd->fd, (cylinder * heads + head) * sectors * 512, SEEK_SET) < 0) { perror("lseek"); return -1; } m = sectors * 512; while(m>0) { /* write until we have write everything we should */ n=write(fd->fd, data, m); if ( n < 0 ) { perror("write"); return -1; } if(n== 0) { fprintf(stderr, "Error, %d bytes remaining\n", m); return -1; } m -= n; } return 0; } int floppy_verify(int superverify, struct params *fd, void *data, int cylinder, int head, int sectors) { if(floppy_read(fd, data, cylinder, head, sectors)) return -1; if(superverify) { /* write, and then read again */ memset(data, sectors * 512, 0x55); if(floppy_write(fd, data, cylinder, head, sectors)) return -1; ioctl(fd->fd, FDFLUSH); if(floppy_read(fd, data, cylinder, head, sectors)) return -1; } return 0; } static int rw_track(struct params *fd, int cylinder, int head, int mode); /* format_track. Does the formatting proper */ int format_track(struct params *fd, int cylinder, int head, int do_skew) { format_map_t *data; struct floppy_raw_cmd raw_cmd; int offset; int i; int nssect; int skew; data = (format_map_t *) floppy_buffer; /* place "fill" sectors */ for (i=0; inssect*2+1; ++i){ data[i].sector = 128+i; data[i].size = /*fd->sizecode*/7; data[i].cylinder = cylinder; data[i].head = head; } if(do_skew) { fd += findex[cylinder][head]; skew = fd->min + lskews[cylinder][head] * fd->chunksize; assert(skew >= fd->min); assert(skew <= fd->max); } else skew = 0; /* place data sectors */ nssect = 0; for (i=0; idsect; ++i){ offset = fd->sequence[i].offset + lskews[cylinder][head]; offset = offset % fd->nssect; data[offset].sector = fd->sequence[i].sect - fd->zeroBased; data[offset].size = fd->sequence[i].size; data[offset].cylinder = cylinder; data[offset].head = head; if ( offset >= nssect ) nssect = offset+1; } if ( (nssect-1) * fd->chunksize > fd->raw_capacity - header_size - index_size){ printf("Sector too far out %d*%d > %d-%d-%d!\n", nssect , fd->chunksize, fd->raw_capacity , header_size, index_size); exit(1); } /* debugging */ if (verbosity == 9){ printf("chunksize=%d\n", fd->chunksize); printf("sectors=%d\n", nssect); for (i=0; idrive & 3)) ^ (fd->swapSides ? 4 : 0); raw_cmd.cmd[2] = fd->sizecode; raw_cmd.cmd[3] = nssect; raw_cmd.cmd[4] = fd->fmt_gap; raw_cmd.cmd[5] = 0; raw_cmd.flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK; raw_cmd.track = cylinder << stretch; raw_cmd.rate = fd->rate & 0x43; /* first pass */ if (verbosity >= 6) printf("formatting...\n"); if(send_cmd(fd->fd, & raw_cmd, "format")) return -1; memset(floppy_buffer, 0, sizeof(floppy_buffer)); if ( !fd->need_init && fd->sizecode) return 0; if (verbosity >= 6) printf("initializing...\n"); return rw_track(fd, cylinder, head, 1); } /* format_track. Does the formatting proper */ static int rw_track(struct params *fd, int cylinder, int head, int mode) { int i; int cur_sector; int retries; struct floppy_raw_cmd raw_cmd; cur_sector = 1 - fd->zeroBased; for (i=MAX_SIZECODE-1; i>=0; --i) { if ( fd->last_sect[i] <= cur_sector + fd->zeroBased) continue; retries=0; retry: /* second pass */ raw_cmd.data = floppy_buffer; raw_cmd.cmd_count = 9; raw_cmd.cmd[0] = (mode ? FD_WRITE : FD_READ) & ~fm_mode & ~0x80; raw_cmd.cmd[1] = (head << 2 | ( fd->drive & 3)) ^ (fd->swapSides ? 4 : 0); raw_cmd.cmd[2] = cylinder; raw_cmd.cmd[3] = head; raw_cmd.cmd[4] = cur_sector; raw_cmd.cmd[5] = i; raw_cmd.cmd[6] = fd->last_sect[i] - 1 - fd->zeroBased; raw_cmd.cmd[7] = fd->gap; if ( i ) raw_cmd.cmd[8] = 0xff; else raw_cmd.cmd[8] = 0xff; raw_cmd.flags = (mode ? FD_RAW_WRITE : FD_RAW_READ) | FD_RAW_INTR | FD_RAW_SPIN | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK; raw_cmd.track = cylinder << stretch; raw_cmd.rate = fd->rate & 0x43; raw_cmd.length = (fd->last_sect[i] - fd->zeroBased - cur_sector) * 128 << i; /* debugging */ if (verbosity == 9) printf("%s %ld sectors of size %d starting at %d\n", mode ? "writing" : "reading", raw_cmd.length / 512, i, cur_sector); if(send_cmd(fd->fd, & raw_cmd, mode ? "format" : "verify")){ if ( !retries && mode && (raw_cmd.reply[1] & ST1_ND) ){ cur_sector = raw_cmd.reply[5]; retries++; goto retry; } return -1; } cur_sector = fd->last_sect[i]; } return 0; } void print_formatting(int cylinder, int head) { switch(verbosity) { case 0: break; case 1: if (!head) { printf("."); fflush(stdout); } break; case 2: if (head) printf("\b="); else printf("-"); fflush(stdout); break; case 3: case 4: printf("\rFormatting cylinder %2d, head %d ", cylinder, head); fflush(stdout); break; default: printf("formatting cylinder %d, head %d\n", cylinder, head); break; } } void print_verifying(int cylinder, int head) { if (verbosity >= 5) { printf("verifying cylinder %d head %d\n", cylinder, head); } else if (verbosity >= 3) { printf("\r Verifying cylinder %2d, head %d ", cylinder, head); fflush(stdout); } else if (verbosity == 2) { if (!verify_later && !dosverify) { if (head) printf("\b+"); else printf("\bx"); } else { if (head) printf("\b+"); else printf("x"); } fflush(stdout); } } void old_parameters() { } #define DRIVE_DEFAULTS (drive_defaults[drivedesc.type.cmos]) int main(int argc, char **argv) { int nseqs; /* number of sequences used */ char env_buffer[10]; struct floppy_struct parameters; struct params fd[MAX_SECTORS], fd0; int ch,i; short density = DENS_UNKNOWN; char drivename[10]; int have_geom = 0; int margin=50; int deviation=-3100; int warmup = 40; /* number of warmup rotations for measurement */ int cylinder, head, interleave; int gap; int final_gap; int chunksize; int sizecode=2; int error; int biggest_last = 0; int superverify=0; char command_buffer[80]; char twom_buffer[6]; char *progname=argv[0]; short retries; short zeroBased=0; short swapSides=0; int n,rsize; char *verify_buffer = NULL; char dosdrive; drivedesc_t drivedesc; struct floppy_struct geometry; int max_chunksize = 128*128+62+256; struct enh_options optable[] = { { 'D', "dosdrive", 1, EO_TYPE_CHAR, 0, SET_DOSDRIVE, (void *) &dosdrive, "set the dos drive" }, { 'v', "verbosity", 1, EO_TYPE_LONG, 0, 0, (void *) &verbosity, "set verbosity level" }, { 'f', "noverify", 0, EO_TYPE_BYTE, 1, 0, (void *) &noverify, "skip verification" }, { '\0', "print-drive-deviation", 0, EO_TYPE_BYTE, 1, 0, (void *) &noformat, "print deviation, do not format " }, { 'B', "dosverify", 0, EO_TYPE_BYTE, 1, 0, (void *) &dosverify, "verify disk using mbadblocks" }, { 'V', "verify_later", 1, EO_TYPE_BYTE, 1, 0, (void *) &verify_later, "verify floppy after all formatting is done" }, { 'b', "begin_cylinder", 1, EO_TYPE_LONG, 0, 0, (void *) &begin_cylinder, "set cylinder where to begin formatting" }, { 'e', "end_cylinder", 1, EO_TYPE_LONG, 0, SET_ENDTRACK, (void *) &end_cylinder, "set cylinder where to end formatting" }, { 'G', "fmt_gap", 1, EO_TYPE_LONG, 0, SET_FMTGAP, (void *) &gap, "set the formatting gap" }, { 'F', "final_gap", 1, EO_TYPE_LONG, 0, SET_FINALGAP, (void *) &final_gap, "set the final gap" }, { 'i', "interleave", 1, EO_TYPE_LONG, 0, SET_INTERLEAVE, (void *) &interleave, "set the interleave factor" }, { 'c', "chunksize", 1, EO_TYPE_LONG, 0, SET_CHUNKSIZE, (void *) &chunksize, "set the size of the \"chunks\" (small auxiliary sectors used for formatting). This size must be in the interval [191,830]" }, { '\0', "max-chunksize", 1, EO_TYPE_LONG, 0, 0, (void *) &max_chunksize, "set a maximal size for the \"chunks\" (small auxiliary sectors used for formatting)." }, { 'g', "gap", 1, EO_TYPE_LONG, 0, 0, (void *) &fd[0].gap, "set the r/w gap" }, {'\0', "absolute_skew", 1, EO_TYPE_LONG, 0, 0, (void *) &absolute_skew, "set the skew used at the beginning of formatting" }, {'\0', "head_skew", 1, EO_TYPE_LONG, 0, 0, (void *) &head_skew, "set the skew to be added when passing to the second head" }, {'\0', "cylinder_skew", 1, EO_TYPE_LONG, 0, 0, (void *) &cylinder_skew, "set the skew to be added when passing to another cylinder" }, {'\0', "aligned_skew", 0, EO_TYPE_BITMASK_LONG, ALSKEW, 0, (void *) &fd[0].flags, "select sector aligned skewing" }, {'w', "warmup", 1, EO_TYPE_LONG, 0, 0, (void *) &warmup, "number of warmup rotations for before measurement of raw drive capacity"}, { 'd', "drive", 1, EO_TYPE_STRING, O_RDWR, 0, (void *) &fd[0].name, "set the target drive (obsolete. Specify drive without -d instead)" }, {'\0', "deviation", 1, EO_TYPE_LONG, 0, SET_DEVIATION, (void *) &deviation, "selects the deviation (in ppm) from the standard rotation speed (obsolete. Use " DRIVEPRMFILE " instead"}, {'m', "margin", 1, EO_TYPE_LONG, 0, SET_MARGIN, (void *) &margin, "selects the margin to be left at the end of the physical cylinder (obsolete. Use " DRIVEPRMFILE " instead)" }, { 's', "sectors", 1, EO_TYPE_LONG, 0, SET_SECTORS, (void *) §ors, "set number of sectors (obsolete. Use a media description instead)" }, { 'H', "heads", 1, EO_TYPE_LONG, 0, SET_HEADS, (void *) &heads, "set the number of heads (obsolete. Use a media description instead)" }, { 't', "cylinders", 1, EO_TYPE_LONG, 0, SET_CYLINDERS, (void *) &cylinders, "set the number of cylinders (obsolete. Use a media description instead)" }, {'\0', "stretch", 1, EO_TYPE_LONG, 0, SET_STRETCH, (void *) &stretch, "set the stretch factor (how spaced the cylinders are from each other) (obsolete. Use a media description instead)" }, { 'r', "rate", 1, EO_TYPE_LONG, 0, SET_RATE, (void *) &fd[0].rate, "set the data transfer rate (obsolete. Use a media description instead)" }, { '2', "2m", 0, EO_TYPE_LONG, 255, SET_2M, (void *) &use_2m, "format disk readable by the DOS 2m shareware program (obsolete. Use a media description instead)" }, { '1', "no2m", 0, EO_TYPE_LONG, 0, SET_2M, (void *) &use_2m, "don't use 2m formatting (obsolete. Use a media description instead)" }, { '\0', "fm", 0, EO_TYPE_SHORT, 0x40, 0, (void *) &fm_mode, "chose fm mode (obsolete. Use a media description instead)" }, { '\0', "dd", 0, EO_TYPE_SHORT, DENS_DD, 0, (void *) &density, "chose low density (obsolete. Use a media description instead)" }, { '\0', "hd", 0, EO_TYPE_SHORT, DENS_HD, 0, (void *) &density, "chose high density (obsolete. Use a media description instead)" }, { '\0', "ed", 0, EO_TYPE_SHORT, DENS_ED, 0, (void *) &density, "chose extra density (obsolete. Use a media description instead)" }, { 'S', "sizecode", 1, EO_TYPE_LONG, 0, SET_SIZECODE, (void *) &sizecode, "set the size code of the data sectors. The size code describes the size of the sector, according to the formula size=128<= MAX_SIZECODE) { fprintf(stderr,"Bad sizecode %d\n", sizecode); print_usage(progname,optable, ""); exit(1); } if ( gap < 0 ){ fprintf(stderr,"Fmt gap too small: %d\n", gap); print_usage(progname,optable, ""); exit(1); } if (sectors <= 0 || cylinders <= 0 || heads <= 0) { fprintf(stderr,"bad geometry s=%d h=%d t=%d\n", sectors, heads, cylinders); print_usage(progname,optable, ""); exit(1); } argc -= optind; argv += optind; if(argc) { fd[0].name = argv[0]; argc--; argv++; } if (! fd[0].name){ fprintf(stderr,"Which drive?\n"); print_usage(progname,optable, ""); exit(1); } while(1) { fd[0].fd = open(fd[0].name, O_RDWR | O_NDELAY | O_EXCL); /* we open the disk wronly/rdwr in order to check write * protect */ if (fd[0].fd < 0) { perror("open"); exit(1); } if(parse_driveprm(fd[0].fd, &drivedesc)) exit(1); fd[0].drive = drivedesc.drivenum; fd[0].drvprm = drivedesc.drvprm; if(minor(drivedesc.buf.st_rdev) & 0x7c) { if(fd[0].name == drivename) { fprintf(stderr, "%s has bad minor/major numbers\n", fd[0].name); exit(1); } /* this is not a generic format device. Close it, * and open the proper device instead */ if(argc == 0) ioctl(fd[0].fd, FDGETPRM, &geometry); have_geom = 1; close(fd[0].fd); snprintf(drivename,9,"/dev/fd%d", fd[0].drive); fd[0].name = drivename; continue; } break; } if(have_geom || !parse_mediaprm(argc, argv, &drivedesc, &geometry) || !parse_fdprm(argc-2, argv+2, &geometry)) { if(argc > 0) have_geom = 1; } else { fprintf(stderr,"Syntax error in format description\n"); exit(1); } if(have_geom) { if(mask & (SET_SECTORS | SET_CYLINDERS | SET_HEADS | SET_SIZECODE | SET_2M | SET_RATE)) { fprintf(stderr, "Cannot mix old style and new style geometry spec\n"); exit(1); } sectors = geometry.sect; cylinders = geometry.track; heads = geometry.head; fd[0].rate = geometry.rate & 0x43; sizecode = (((geometry.rate & 0x38) >> 3) + 2) % 8; use_2m = (geometry.rate >> 2) & 1; switch(fd[0].rate) { case 0x43: density = DENS_ED; break; case 0x2: case 0x1: density = DENS_DD; break; case 0: density = DENS_HD; break; } stretch = geometry.stretch & 1; if(geometry.stretch & FD_ZEROBASED) { zeroBased = 1; } if(geometry.stretch & FD_SWAPSIDES) { swapSides = 1; } mask |= SET_SECTORS | SET_CYLINDERS | SET_SIZECODE | SET_2M | SET_RATE; } else { /* density */ if ( (mask & SET_SECTORS ) && density == DENS_UNKNOWN){ if ( sectors < 15 ) density = DENS_DD; else if ( sectors < 25 ) density = DENS_HD; else density = DENS_ED; } if (density == DENS_UNKNOWN) { density = DRIVE_DEFAULTS.density; if ( mask & SET_RATE ){ for (i=0; i< density; ++i) { if(fd[0].rate == DRIVE_DEFAULTS.fmt[i].rate) density=i; } } } else { if (DRIVE_DEFAULTS.fmt[density].sect == 0) { fprintf(stderr, "Density %d not supported drive type %d\n", density, drivedesc.type.cmos); exit(1); } } /* rate */ if (! ( mask & SET_RATE)) fd[0].rate = DRIVE_DEFAULTS.fmt[density].rate; /* number of sectors */ if (! (mask & SET_SECTORS)) sectors =DRIVE_DEFAULTS.fmt[density].sect; if (! (mask & SET_CYLINDERS)) { if (fd[0].drvprm.tracks >= 80) cylinders = 80; else cylinders = 40; } if ( ! ( mask & SET_STRETCH )){ if ( cylinders + cylinders < fd[0].drvprm.tracks) stretch = 1; else stretch = 0; } } fd[0].zeroBased = zeroBased; fd[0].swapSides = swapSides; if (cylinders > fd[0].drvprm.tracks) { fprintf(stderr,"too many cylinder for this drive\n"); print_usage(progname,optable,""); exit(1); } if (! (mask & SET_ENDTRACK ) || end_cylinder > cylinders) end_cylinder = cylinders; if(begin_cylinder >= end_cylinder) { fprintf(stderr,"begin cylinder >= end cylinder\n"); exit(1); } fd0 = fd[0]; repeat: /* capacity */ if (!have_geom && sectors >= 12 && fd[0].rate == 2) fd[0].rate = 1; switch(fd[0].rate & 0x3) { case 0: fd[0].raw_capacity = 500 * 1000 / 8 / fd[0].drvprm.rps; break; case 1: fd[0].raw_capacity = 300 * 1000 / 8 / fd[0].drvprm.rps; break; case 2: fd[0].raw_capacity = 250 * 1000 / 8 / fd[0].drvprm.rps; break; case 3: fd[0].raw_capacity = 1000 * 1000 / 8 / fd[0].drvprm.rps; break; } if (fd[0].rate & 0x40) header_size = 81; else header_size = 62; if(! (mask & (SET_DEVIATION | SET_MARGIN)) && (drivedesc.mask & (1 << FE__DEVIATION))) { deviation = drivedesc.type.deviation; mask |= SET_DEVIATION; } if(mask & SET_DEVIATION) { mask &= ~SET_MARGIN; fd[0].raw_capacity += fd[0].raw_capacity * deviation / 1000000; } else if (mask & SET_MARGIN) { fd[0].raw_capacity -= margin; } else { int old_capacity = fd[0].raw_capacity; /* printf("old capacity=%d\n", old_capacity);*/ if(verbosity) { fprintf(stderr,"Measuring drive %d's raw capacity\n", fd[0].drive); } /* neither a deviation nor a margin have been given */ fd[0].raw_capacity = measure_raw_capacity(fd[0].fd, fd[0].drive, fd[0].rate, begin_cylinder, warmup, verbosity) / 16; if(verbosity) { fprintf(stderr, "In order to avoid this time consuming " "measurement in the future,\n" "add the following line to " DRIVEPRMFILE ":\n"); fprintf(stdout, "drive%d: deviation=%d\n", fd[0].drive, (fd[0].raw_capacity-old_capacity)*1000000/ old_capacity); fprintf(stderr, "CAUTION: The line is drive and controller " "specific, so it should be\n" "removed before installing a new " "drive %d or floppy controller.\n\n", fd[0].drive); } } if(noformat) return 0; /* FIXME. Why is this needed? */ fd[0].raw_capacity -= 30; fd0.raw_capacity = fd[0].raw_capacity ; if (verbosity == 9) printf("rate=%d density=%d sectors=%d capacity=%d\n", fd[0].rate, density, sectors, fd[0].raw_capacity); fd->chunksize = chunksize; fd->max_chunksize = max_chunksize; fd->preset_interleave = interleave; nseqs = compute_all_sequences(fd, sectors * 512, sizecode, gap, mask, biggest_last); /* print all the stuff out */ if (verbosity == 9) { for (i=0; i 2 && !(mask & SET_2M)) { use_2m = 1; if (fd[0].rate == 2) { fd[0].rate = 1; goto repeat; } } if (use_2m) { fd0.dsect = DRIVE_DEFAULTS.fmt[density].sect; compute_track0_sequence(&fd0); if (verbosity == 9){ for (i=0; i< fd0.dsect; i++) printf("s=%2d S=%2d o=%2d\n", fd0.sequence[i].sect, fd0.sequence[i].size, fd0.sequence[i].offset); printf("fd[0].sizecode=%d\n", fd0.sizecode); printf("fd[0].fmt_gap=%d\n", fd0.fmt_gap); printf("fd[0].dsect=%d\n", fd0.dsect); printf("fd[0].nssect=%d\n", fd0.nssect); } } parameters.sect = sectors; parameters.head = heads; parameters.track = cylinders; parameters.size = cylinders * heads * sectors; parameters.stretch = stretch #ifdef FD_ZEROBASED | (zeroBased ? 4 : 0) #endif | (swapSides ? 2 : 0); parameters.gap = fd[0].gap; if ( !use_2m) fd0.rate = fd[0].rate; parameters.rate = ( fd0.rate & ~(FD_SIZECODEMASK | FD_2M) ) | (((sizecode + 6 ) % 8 ) << 3) | (use_2m ? FD_2M : 0) ; parameters.spec1 = 0xcf; if(fd[0].fmt_gap < 1 ) parameters.fmt_gap = 1; else if (fd[0].fmt_gap > 255 ) parameters.fmt_gap = 0; else parameters.fmt_gap = fd[0].fmt_gap; if(ioctl(fd[0].fd, FDSETPRM, ¶meters) < 0) { perror("set geometry"); exit(1); } calc_skews(&fd0, fd, nseqs); if (!verify_later && !dosverify) { ioctl(fd[0].fd, FDFLUSH ); verify_buffer = malloc( 512 * sectors * heads); if (! verify_buffer) { printf("out of memory error\n"); exit(1); } } retries=0; /*ioctl(fd[0].fd, FDRESET, FD_RESET_IF_RAWCMD);*/ for (cylinder=begin_cylinder; cylinder= 2) exit(1); #if 0 if(seek_floppy( fd, cylinder << stretch)) exit(1); #endif for (head=0; headfd, FDRESET, FD_RESET_ALWAYS); continue; } retries = 0; ++cylinder; } ioctl(fd[0].fd, FDFLUSH ); close(fd[0].fd); if (! (mask & SET_DOSDRIVE ) && fd[0].drive < 2 && !zeroBased) dosdrive = fd[0].drive+'a'; if (dosdrive) { if (verbosity >= 5) printf("calling mformat\n"); if (use_2m) snprintf(twom_buffer, 5, "-2 %2d", fd0.dsect); else twom_buffer[0]='\0'; snprintf(command_buffer, 79, "mformat -s%d -t%d -h%d -S%d -M512 %s %c:", sectors, /*use_2m ? sectors : sectors >> (sizecode - 2), */ cylinders, heads, sizecode, twom_buffer, dosdrive); if (verbosity >= 3) { printf("\n%s\n", command_buffer); } snprintf(env_buffer, 9, "%d", (int)fd0.rate&3); setenv("MTOOLS_RATE_0", env_buffer,1); snprintf(env_buffer, 9, "%d", (int)fd->rate&3); setenv("MTOOLS_RATE_ANY", env_buffer,1); if(system(command_buffer)){ fprintf(stderr,"\nwarning: mformat error\n"); /*exit(1);*/ /* Do not fail, if mformat happens to not be * installed. The user might have wanted to make * an ext2 disk for instance */ dosverify = 0; } } else { if(!zeroBased) fprintf(stderr, "\nwarning: mformat not called because DOS drive unknown\n"); /*exit(1);*/ dosverify = 0; } if (!noverify && verify_later) { fd[0].fd = open ( fd[0].name, O_RDONLY); if ( fd[0].fd < 0 ) { perror("open for verify"); exit(1); } if (verbosity >= 7) printf("verifying\n"); else if (verbosity == 2) { printf("\r"); fflush(stdout); } verify_buffer = malloc( 512 * sectors * heads); if (! verify_buffer) { printf("out of memory error\n"); exit(1); } lseek(fd[0].fd, 512 * begin_cylinder * heads, SEEK_SET ); for (cylinder=begin_cylinder; cylinder= 3) { printf("\n%s\n", command_buffer); } if(system(command_buffer)){ fprintf(stderr,"mbadblocks error\n"); exit(1); } } printf("\n"); return 0; } fdutils-5.5-20060227/src/superformat.h0000444000175000017500000000446007560752355016522 0ustar anibalanibal#ifndef SUPERFORMAT_H #define SUPERFORMAT_H #include "driveprm.h" #define SET_SOFTGAP 0x1 #define SET_ENDTRACK 0x2 #define SET_CHUNKSIZE 0x4 #define SET_SECTORS 0x8 #define SET_INTERLEAVE 0x10 #define SET_FMTGAP 0x20 #define SET_RATE 0x40 #define SET_SIZECODE 0x80 #define SET_CYLINDERS 0x100 #define SET_STRETCH 0x200 #define SET_FINALGAP 0x400 #define SET_DOSDRIVE 0x800 #define SET_2M 0x1000 #define SET_VERBOSITY 0x2000 #define SET_MARGIN 0x4000 #define SET_DEVIATION 0x8000 #define SET_HEADS 0x10000 #define MAX_SIZECODE 8 #define DO_DEBUG 1 #define ALSKEW 4 #define MAX_TRACKS 85 #define MAX_HEADS 2 extern int fm_mode; extern int cylinder_skew; extern int head_skew; extern int absolute_skew; extern int begin_cylinder; extern int end_cylinder; extern int heads; extern int sectors; extern int use_2m; extern int lskews[MAX_TRACKS][MAX_HEADS]; extern int findex[MAX_TRACKS][MAX_HEADS]; #define MAX_SECTORS 50 /* int skew; */ struct fparm { unsigned char cylinder,head,sect,size; }; struct fparm2 { unsigned char sect, size, offset; }; struct params { char *name; /* the name of the drive */ int fd; /* the open file descriptor */ int drive; /* the drive number */ int sizecode; int preset_interleave; int actual_interleave; int rate; int gap; unsigned int fmt_gap; int use_2mf; struct fparm2 *sequence; int last_sect[MAX_SIZECODE]; int nssect; /* number of small sectors */ int dsect; /* number of data sectors */ int need_init; /* does this cylinder need initialization ? */ int raw_capacity; /* raw capacity of one track inbytes */ struct floppy_drive_params drvprm; int chunksize; /* used for re-aligning skew */ int max_chunksize; int flags; int min; /* minimal offset that this geometry can handle */ int max; /* maximal offset */ int length; /* length of the track */ int rotations; /* how many time do we have to go over 0 to read * the track */ int zeroBased; /* 1 if sector numbering starts at zero */ int swapSides; /* if logical side 0 is on physical 1 and vice-versa */ }; int compute_all_sequences(struct params *fd, int tracksize, int sizecode, int gap, int mask, int biggest_last); void compute_track0_sequence(struct params *fd); int calc_skews(struct params *fd0, struct params *fd, int n); extern int verbosity; int header_size; int index_size; #endif fdutils-5.5-20060227/src/skews.c0000444000175000017500000000426007560761005015270 0ustar anibalanibal#include #include #include #include "fdutils.h" #include "superformat.h" /* computes the position at the end of this track */ static inline int calc_end_offset(struct params *f, int cur_pos, int *lskew) { int sector_skew, byte_skew; if(cur_pos < f->min) { /* the current skew is smaller than the extend that this * sequence can handle. Wait until its beginning */ *lskew = 0; return f->min + f->length; } sector_skew = (cur_pos - f->min + f->chunksize - 1) / f->chunksize; byte_skew = f->min + sector_skew * f->chunksize; if(byte_skew >= f->max) { /* the current skew is larger than the extend that this * sequence can handle. Wait until its next beginning */ *lskew = 0; return f->min + f->length + f->raw_capacity; } *lskew = sector_skew; return byte_skew + f->length; } static inline void pick_best(struct params *f, int n, int *min, /* skew in bytes */ int *lskew, /* skew in sectors */ int *min_index) { int i,new, t_lskew; int cur_pos = *min; for(i = 0 ; i < n; i++) { new = calc_end_offset(f+i, cur_pos, &t_lskew); if(i == 0 || new < *min) { *min = new; *lskew = t_lskew; *min_index = i; } } } /* calc_skews. Fill skew table for use in formatting */ int calc_skews(struct params *fd0, struct params *fd, int n) { int cylinder, head; struct params *f = NULL; int cur_skew, next_cylinder_skew; int ind, rots; /* Amount to advance skew considering head skew already added in */ next_cylinder_skew = cylinder_skew - head_skew; cur_skew = absolute_skew; rots = 0; for (cylinder=begin_cylinder; cylinder <= end_cylinder; ++cylinder) { for (head=0; head < heads; ++head) { if (!head && !cylinder && use_2m) f = fd0; else f = fd; cur_skew = cur_skew % f->raw_capacity; pick_best(f, n, &cur_skew, &lskews[cylinder][head], &findex[cylinder][head]); rots += cur_skew / f->raw_capacity; ind = findex[cylinder][head]; if(lskews[cylinder][head] * fd[ind].chunksize > fd->raw_capacity){ fprintf(stderr,"Skew too big\n"); abort(); } cur_skew += head_skew; } cur_skew += next_cylinder_skew; } return 0; } /* End calc_skews */ fdutils-5.5-20060227/src/driveprm.lex0000444000175000017500000000157707464324643016350 0ustar anibalanibal%{ #include #include #include "parse.h" #include "driveprmP.h" #include "driveprm.h" static int lineno; static int col; %} %option noyywrap vid [A-Za-z_][A-Za-z0-9_]* number (0x[a-zA-Z0-9]+|-?[0-9]+)(KB|s)? %% \n { col = 0; lineno++;} [ \t] col++; #.*\n { col = 0; lineno++;} drive[0-7]: { col += yyleng; if(*found) return 0; _zero_all(ids, size, mask); yytext[yyleng-1]='\0'; if(yytext[5] - '0' == drivenum) *found = 1; } 3.5 | 5.25 | 8 | ss | SS | ds | DS | sd | SD | dd | DD | qd | QD | hd | HD | ed | ED | {vid}={number} { col += yyleng; _set_int(yytext, ids, size, mask); } [^\t \n][^\t =\n]* { fprintf(stderr, "Syntax error in " DRIVEPRMFILE " at line %d col %d: %s unexpected\n", lineno + 1, col + 1, yytext_ptr); return 1; } %% fdutils-5.5-20060227/src/fdmount.c0000444000175000017500000007143110211705414015601 0ustar anibalanibal#include "../config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LINUX_EXT_FS_H #include #endif #include #ifdef HAVE_LINUX_XIA_FS_H #include #endif #include #include #include #define USE_2M #include "msdos_fs.h" /* if set to 1, fdmount will chown the mount point to the user who did the mount, and set permissions according to his umask. */ #define SETOWNER 1 /* if set to 1, the mount point for fdmount must be owned by the user unless it is the default. Leave this on if you are concerned about security. */ #define CHKOWNER_MOUNT 1 /* if set to 1, the mount point for fdumount must be owned by the user _even if_ it is the default. Should be used only with SETOWNER. */ #define CHKOWNER_UMOUNT 1 /* by default, drive names are fd0..7, device names /dev/fd0../dev/fd7, and default mountpoints /fd0../fd7 */ #define NAME_PATTERN "fd%d" #define DEFAULT_DIR_PATTERN "/fd%d" #define DEVICE_PATTERN "/dev/fd%d" #define DEBUG 0 /***********************************************************************/ #define UNKNOWN -1 #define INRANGE(x,lo,hi) ((unsigned)((x)-(lo))<=(hi)) typedef unsigned short word; typedef unsigned char byte; typedef struct floppy_struct format; typedef struct mnt_node { struct mnt_node *next; struct mntent ms; } mnt_node; typedef struct { int sect; int tracks; int heads; int totsect; int _2m; int sectsizec; } fmt_descr; int locked=0; char curdev[100] = ""; char *progname = NULL; int opt_silent=0; int use_syslog = 0; int opt_detach = 0; int ruid=-1; int rgid=-1; int _umask=077; enum { T_NULL, T_MINIX, T_DOS, T_VFAT, T_EXT2, T_EXT, T_XIA }; char *fsnames[7] = {"???","minix", "msdos", "vfat", "ext2","ext","xia"}; void die(const char *text,...) { char buff[140]; va_list p; va_start(p,text); vsnprintf(buff,139,text,p); va_end(p); if(use_syslog) syslog(LOG_ERR, "%s: %s\n",curdev,buff); else fprintf(stderr,"%s (%s): %s\n",progname,curdev,buff); exit(1); } void msg(char *text,...) { char buff[140]; va_list p; va_start(p,text); vsnprintf(buff,139,text,p); va_end(p); if(!opt_silent) { if(use_syslog) syslog(LOG_INFO, "%s: %s\n",curdev,buff); else fprintf(stderr,"%s (%s): %s\n",progname,curdev,buff); } } void errmsg(char *text,...) { char buff[140]; va_list p; va_start(p,text); vsnprintf(buff,139,text,p); va_end(p); if(use_syslog) syslog(LOG_ERR, "%s: %s\n",curdev,buff); else fprintf(stderr,"%s (%s): %s\n",progname,curdev,buff); } #if 0 void print_format(format *F) { static int rates[4] = { 500,300,250,1000 }; printf("%d sectors\n" "%d sectors per track\n" "%d heads\n" "%d tracks\n" "double stepping: %s\n" "gap1: %d, gap2: %d, rate: %d Kbps, cod: %s, perp: %d\n" "sectsize: %d, 2M: %s, steprate: %d, hut: %d\n" "format name: %s\n", F->size, F->sect, F->head, F->track, (F->stretch==UNKNOWN)?"?":(F->stretch?"yes":"no"), F->gap, F->fmt_gap, rates[F->rate&0x03], (F->rate&0x80)?"FM":"MFM", F->rate & FD_PERP, 128<<((((F->rate&0x38)>>3)+2)%8), (F->rate&FD_2M)?"yes":"no",F->spec1>>4, F->spec1%0x0F, F->name?"":F->name); } #else #define print_format(f) #endif void *xmalloc(int size) { void *p = malloc(size); if (!p) die("out of memory"); return p; } /* Make a canonical pathname from PATH. Returns a freshly malloced string. It is up the *caller* to ensure that the PATH is sensible. i.e. canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.'' is not a legal pathname for ``/dev/fd0.'' */ /* shamelessly copied from mount */ char * canonicalize (const char *path) { char *canonical = xmalloc (PATH_MAX + 1); char *p = canonical; if (path == NULL) return NULL; #if 0 if (!strcmp (path, "none")) { strncpy (canonical, path, sizeof(canonical)-1); canonical[sizeof(canonical)-1] = '\0'; return canonical; } if (strchr (path, ':') != NULL) { strncpy(canonical, path, sizeof(canonical)-1); canonical[sizeof(canonical)-1] = '\0'; return canonical; } #endif if (*path == '/') { /* We've already got an absolute path in PATH, but we need at least one char in canonical[] on entry to the loop below. */ *p = *path++; } else { getcwd (canonical, PATH_MAX); p = canonical + strlen (canonical) - 1; if (*p != '/') *++p = '/'; } /* There is at least one character in canonical[], and the last char in canonical[], *p, is '/'. */ while ((*path != '\0') && (p < canonical + PATH_MAX)) if (*p != '/') { *++p = *path++; } else { if (path[0] == '/') { path++; /* eliminate duplicate slashes (``//'') */ } else if ((path[0] == '.') && ((path[1] == '\0') || (path[1] == '/'))) { path++; /* eliminate ``/.'' */ } else if ((path[0] == '.') && (path[1] == '.') && ((path[2] == '\0') || (path[2] == '/'))) { while ((p > canonical) && (*--p != '/')) /* ascend on ``/../'' */ ; path += 2; } else { *++p = *path++; /* not a special case, just copy char */ } } if (p >= (canonical + PATH_MAX)) die ("path too long"); if (*p == '/') --p; /* eliminate trailing slash */ *++p = '\0'; return canonical; } /**********************************************************************/ mnt_node *mounted_list = NULL, *mounted_list_end = NULL; int mtab_changed; const char *mtab_filename = "/etc/mtab"; const char *lock_filename = "/etc/mtab~"; mnt_node *get_mounted(const char *devname) { mnt_node *mnt; for(mnt=mounted_list;mnt;mnt=mnt->next) if (strcmp(mnt->ms.mnt_fsname,devname)==0) return mnt; return NULL; } void _dup(char **s) { *s = *s?strdup(*s):NULL; } void _free(char *s) { if (s) free(s); } void free_mtab_node(mnt_node *ent) { _free(ent->ms.mnt_fsname); _free(ent->ms.mnt_dir); _free(ent->ms.mnt_type); _free(ent->ms.mnt_opts); free(ent); } void add_mtab(const struct mntent *ent) { mnt_node *mm; mm=xmalloc(sizeof(mnt_node)); if (!mounted_list) mounted_list=mounted_list_end=mm; else mounted_list_end->next=mm; mounted_list_end=mm; memcpy(&mm->ms,ent,sizeof(struct mntent)); _dup(&mm->ms.mnt_fsname); _dup(&mm->ms.mnt_dir); _dup(&mm->ms.mnt_type); _dup(&mm->ms.mnt_opts); mm->next=NULL; mtab_changed=1; } /* remove all mtab entries with special entry 'devname'. */ void remove_mtab(const char *devname) { mnt_node *mm,*prev,*nxt; mm=mounted_list; prev=NULL; while(mm) { nxt=mm->next; if (strcmp(mm->ms.mnt_fsname,devname)==0) { if (!prev) mounted_list=mm->next; else prev->next=mm->next; free_mtab_node(mm); } else { prev=mm; } mm=nxt; } mounted_list_end=prev; mtab_changed=1; } /* read table of mounted drives from /etc/mtab and put it in mounted_list. */ void read_mtab() { FILE *mtab; struct mntent *ent; mounted_list=mounted_list_end=NULL; mtab=setmntent(mtab_filename,"r"); while((ent=getmntent(mtab))) add_mtab(ent); endmntent(mtab); mtab_changed=0; } void save_mtab() { FILE *mtab; mnt_node *mnt,*next; mtab=setmntent(mtab_filename,"w"); for(mnt=mounted_list;mnt;mnt=next) { addmntent(mtab,&mnt->ms); next=mnt->next; free_mtab_node(mnt); } mounted_list=mounted_list_end=NULL; endmntent(mtab); mtab_changed=0; } inline void lock_mtab() { int fd; if((fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0744)) < 0) { die("Cannot create lock file %s: %s",lock_filename,strerror(errno)); } close(fd); locked=1; } inline void unlock_mtab() { unlink(lock_filename); locked=0; } void lock_read_mtab() { lock_mtab(); read_mtab(); mtab_changed=0; } void save_unlock_mtab() { if (mtab_changed) save_mtab(); unlock_mtab(); } /*********************************************************************/ int probe_drive(char *devname) { char drive_name[17]; int e,fd,type; drive_name[16]=0; fd=open(devname,O_RDONLY | O_NDELAY); if (fd<=0) return 0; e=ioctl(fd,FDGETDRVTYP,(void*)drive_name); if (e) { errmsg("ioctl(FDGETDRVTYP) failed on %s: %s",devname,strerror(errno)); close(fd); return 0; } close(fd); if (strchr("EDHQdhq",drive_name[0])) { type=atoi(drive_name+1); if (type==360 || type==720 || type==1200 || type==1440 || type==2880) { return type; } } errmsg("unknown drive type '%s' for %s",drive_name,devname); return 0; } /* identify the type of file system from the given boot sector/ super block and read out the available format parameters into *fmt. super = first 2K of the disk. return the type if identified filesystem (T_DOS,T_MINIX,...) or 0 for error. */ int id_fstype(byte *super, fmt_descr *fmt) { #define minix ((struct minix_super_block*)(super+1024)) #define dos ((struct msdos_boot_sector*)super) #define ext2 ((struct ext2_super_block*)(super+1024)) #define ext ((struct ext_super_block*)(super+1024)) #define xia ((struct xiafs_super_block*)(super+1024)) memset(fmt,0,sizeof(*fmt)); /* we look for Unix-type filesystems first because mkfs doesn't overwrite the first 1K of the disk, so a DOS filesystem might be detected even though the data area is overwritten. */ /* look for Minix filesystem */ if (minix->s_magic==MINIX_SUPER_MAGIC || minix->s_magic==MINIX_SUPER_MAGIC2) { fmt->totsect=minix->s_nzones * (2<s_log_zone_size); return T_MINIX; } /* look for ext2 filesystem */ if (ext2->s_magic==EXT2_SUPER_MAGIC #ifdef EXT2_PRE_02B_MAGIC || ext2->s_magic==EXT2_PRE_02B_MAGIC #endif ) { fmt->totsect=ext2->s_blocks_count * (2<s_log_block_size); return T_EXT2; } #ifdef EXT_SUPER_MAGIC /* look for ext filesystem */ if (ext->s_magic==EXT_SUPER_MAGIC) { fmt->totsect=ext->s_nzones * (2<s_log_zone_size); return T_EXT; } #endif #ifdef _XIAFS_SUPER_MAGIC /* look for xia filesystem */ if (xia->s_magic==_XIAFS_SUPER_MAGIC) { fmt->totsect=xia->s_nzones * xia->s_zone_size/512; return T_XIA; } #endif /* add more format types here ... */ /* look for MS-DOG filesystem this is more a looking for hints than checking a well-defined identification (which doesn't exist), and I don't expect it to be 100% reliable. */ if (dos->bootid==0xAA55 || /* check boot sector id */ (*(byte*)(super+512)>=0xF0 && /* check media descriptor */ *(word*)(super+513)==0xFFFF) || strncmp(dos->fat_type,"FAT",3)==0) /* check FAT id string */ { int sect,heads,tracks,totsect,s_cyl; totsect=dos->sectors; if (totsect==0) totsect=dos->total_sect; sect=dos->secs_track; heads=dos->heads; s_cyl=sect*heads; /* sanity checks */ if (!INRANGE(heads,1,2) || !INRANGE(sect,3,60) || !INRANGE(totsect,100,10000) || totsect % s_cyl != 0) { /* try media descriptor (very old DOS disks) */ switch(super[512]) { case 0xfe: /* 160k */ tracks=40; sect=8; heads=1; break; case 0xfc: /* 180k */ tracks=40; sect=9; heads=1; break; case 0xff: /* 320k */ tracks=40; sect=8; heads=2; break; case 0xfd: /* 360k */ tracks=40; sect=9; heads=2; break; case 0xf9: /* 1.2M */ tracks=80; sect=15; heads=2; break; default: goto no_dos; } totsect=tracks*sect*heads; } else { tracks=totsect/s_cyl; } fmt->sect = sect; fmt->tracks = tracks; fmt->heads = heads; fmt->totsect = totsect; fmt->_2m=0; fmt->sectsizec=2; /* 512 bytes */ /* check for 2M format */ if (strncmp(dos->banner,"2M",2)==0) { int inftm=dos->InfTm; if (INRANGE(inftm,76,510)) { fmt->sectsizec=super[inftm]; if (!INRANGE(fmt->sectsizec,0,7)) fmt->sectsizec=2; } fmt->_2m=1; } else { fmt->sectsizec=2; } return T_DOS; } no_dos: return 0; /* disk format not identified. */ } int chk_mountpoint(char *dir,int is_default) { int must_own; struct stat st; if (stat(dir,&st)!=0) { errmsg("Can't access %s: %s\n",dir,strerror(errno)); return 0; } if (!S_ISDIR(st.st_mode)) { errmsg("%s is not a directory\n",dir); return 0; } if (!is_default && access(dir,W_OK)!=0) { errmsg("No write permission to %s\n",dir); return 0; } #if CHKOWNER_MOUNT /* user specified mount points must be owned by the user unless the user is root */ must_own=(ruid!=0) && !is_default; if (must_own && st.st_uid!=ruid) { errmsg("Not owner of %s\n",dir); return 0; } #endif return 1; } /* open the given device (which ought to be a floppy disk), figure out the format, and mount it. All message output here should be done via msg() and errmsg(). */ #define DO_IOCTL(fd,code,parm) \ { \ if (ioctl(fd,code,parm)!=0) { \ errmsg("ioctl(code) failed: %s",strerror(errno)); \ goto err_close; \ } \ } #define ADD_OPT(format,parameter) \ snprintf(options+strlen(options), MAX_OPT - strlen(options)-1, \ "," format, parameter) #define MAX_OPT 1024 char dos_options[MAX_OPT]; char ext2_options[MAX_OPT]; int do_mount(char *devname,char *_mountpoint, int flags,int force,int is_default,int drivetype) { int fd,e,fstype; format F; char *fsname; fmt_descr fmt; struct mntent ms; struct floppy_drive_struct drivstat; char options[80+MAX_OPT]; char super[2048]; char *mountpoint; strncpy(curdev,devname, sizeof(curdev)); curdev[sizeof(curdev)-1]='\0'; if (access(devname,R_OK)!=0) die("no access to %s",devname); if (!(flags&MS_RDONLY) && access(devname,W_OK)!=0) die("no write access to %s",devname); lock_read_mtab(); if(get_mounted(devname)) { if (!force) { errmsg("already mounted"); goto err_unlock; } else { msg("already in /etc/mtab, trying to mount anyway!"); } } mountpoint=canonicalize(_mountpoint); if (!chk_mountpoint(mountpoint,is_default)) goto err_unlock; /* all right, it's ok to mount. Now try to figure out the details. */ fd=open(devname,O_RDONLY); if (fd<0) { errmsg("error opening device: %s",strerror(errno)); goto err_unlock; } errno=0; lseek(fd,0,SEEK_SET); read(fd,super,sizeof(super)); if (errno) { errmsg("error reading boot/super block: %s",strerror(errno)); goto err_close; } /* check if disk is write protected note: we don't need to poll (FDPOLLDRVSTAT) here because the previous super block read updated the state. */ DO_IOCTL(fd,FDGETDRVSTAT, &drivstat); if (!(drivstat.flags & FD_DISK_WRITABLE)) flags|=MS_RDONLY; /* get the auto-detected floppy parameters */ DO_IOCTL(fd,FDGETPRM,&F); #if DEBUG printf("autodetected format:\n\n"); print_format(&F); #endif fstype=id_fstype(super,&fmt); if (fstype==0) { errmsg("unknown filesystem type"); goto err_close; } fsname=fsnames[fstype]; if (fstype==T_DOS) { F.sect = fmt.sect; F.track = fmt.tracks; F.head = fmt.heads; F.size = fmt.totsect; F.rate &= ~FD_2M; if (fmt._2m) { F.rate &= ~0x38; F.rate |= (((fmt.sectsizec+6)%8)<<3) | FD_2M; } } else { /* hope that the track layout was detected correctly and figure out the number of tracks from the fs size. */ int s_cyl = F.sect*F.head; int tr; if (!s_cyl) goto err_close; tr=fmt.totsect/s_cyl; if (fmt.totsect%s_cyl==0 && INRANGE(tr,30,83)) { /* was detected OK! */ F.track=tr; F.size=fmt.totsect; } else { errmsg("sorry, can't figure out format (%s filesystem)", fsname); goto err_close; } } F.stretch = (drivetype!=360 && F.track<43); #if DEBUG printf("setting format:\n\n"); print_format(&F); #endif DO_IOCTL(fd,FDSETPRM,&F); close(fd); /* prepare the /etc/mtab entry and mount the floppy. */ if (fstype==T_DOS) flags &= ~(MS_NOEXEC|MS_NODEV); *options=0; strcat(options,(flags&MS_RDONLY) ? "ro" : "rw"); strcat(options,(flags&MS_NOSUID) ? ",nosuid" : ""); strcat(options,(flags&MS_NODEV) ? ",nodev" : ""); strcat(options,(flags&MS_NOEXEC) ? ",noexec" : ""); strcat(options,(flags&MS_SYNCHRONOUS) ? ",sync" : ""); if(fstype == T_EXT2) { ADD_OPT("resuid=%d", ruid); /* resuid doesn't change the owner of the fs, but rather names the * user who is allowed to fill up the fs more than 100%. * This is just fine for use as a marker */ strcat(options, ext2_options); } if(fstype == T_DOS) strcat(options, dos_options); if(fstype != T_EXT2) { /* Unfortunately, ext2 barfs at options it doesn't understand */ ADD_OPT("uid=%d", ruid); ADD_OPT("gid=%d", rgid); ADD_OPT("umask=%03o", _umask); } e=mount(devname,mountpoint,fsname,flags|MS_MGC_VAL,NULL); if (e && fstype==T_DOS) { fsname=fsnames[T_VFAT]; e=mount(devname,mountpoint,fsname,flags|MS_MGC_VAL,NULL); } if (e) { errmsg("failed to mount %s %dK-disk: %s", fsname,F.size/2,strerror(errno)); goto err_unlock; } #if SETOWNER if(fstype != T_DOS && !(flags&MS_RDONLY)) { e=chown(mountpoint,ruid,rgid); if (e) msg("warning: chown failed"); } if(fstype != T_DOS && !(flags&MS_RDONLY)) { e=chmod(mountpoint,~_umask & 0777); if (e) msg("warning: chmod failed"); } #endif msg("mounted %s %dK-disk (%s) on %s",fsname,F.size/2, (flags&MS_RDONLY) ? "readonly":"read/write", mountpoint); /* add entry to /etc/mtab */ ms.mnt_fsname=devname; ms.mnt_dir=mountpoint; ms.mnt_type=fsname; ms.mnt_opts=options; ms.mnt_freq=0; ms.mnt_passno=0; add_mtab(&ms); save_unlock_mtab(); return 0; err_close: close(fd); err_unlock: save_unlock_mtab(); return -1; } int do_umount(const char *devname,int force) { int e,fuid; mnt_node *mnt; char *mountpoint, *uidstr; struct stat st; lock_read_mtab(); strncpy(curdev,devname, sizeof(curdev)); curdev[sizeof(curdev)-1]='\0'; mnt=get_mounted(devname); if (!mnt) { errmsg("not mounted"); save_unlock_mtab(); return -1; } else { mountpoint=mnt->ms.mnt_dir; #if CHKOWNER_UMOUNT e=stat(mountpoint,&st); if (e) { errmsg("Cannot access %s: %s\n",mountpoint,strerror(errno)); goto err; } uidstr = strstr(mnt->ms.mnt_opts, ",uid="); if(uidstr) fuid = atoi(uidstr+5); else { uidstr = strstr(mnt->ms.mnt_opts, ",resuid="); if(uidstr) fuid = atoi(uidstr+8); fuid = 0; } if (ruid && st.st_uid!=ruid && fuid != ruid) { errmsg("Not owner of mounted directory: UID=%d\n",st.st_uid); goto err; } } #endif e=umount(mountpoint); if (e) { errmsg("failed to unmount: %s\n",strerror(errno)); goto err; } remove_mtab(devname); #if 0 /* have to check whether user's own for this. */ chown(mountpoint,0,0); /* back to root */ chmod(mountpoint,0700); /* no public permissions */ #endif msg("disk unmounted"); save_unlock_mtab(); return 0; err: save_unlock_mtab(); return -1; } void list_drives() { mnt_node *mnt; int i,type; char devname[10]; read_mtab(); /* printf("NAME DEVICE TYPE MOUNTPOINT STATUS\n"); */ printf("NAME TYPE STATUS\n"); for(i=0;i<4;i++) { sprintf(devname,DEVICE_PATTERN,i); type=probe_drive(devname); if (type) { mnt=get_mounted(devname); if (mnt) { printf(" " NAME_PATTERN " %4dK mounted on %s (%s %s)\n", i,type, mnt->ms.mnt_dir, mnt->ms.mnt_type, mnt->ms.mnt_opts); } else { printf(" " NAME_PATTERN " %4dK not mounted\n", i,type); } } } } int daemon_mode(char *devname,char *mountpoint,int mountflags, int interval,int drivetype) { int e,fd,disk_in,prev_disk_in,first; struct floppy_drive_struct state; mnt_node *mnt; strncpy(curdev,devname, sizeof(curdev)); curdev[sizeof(curdev)-1]='\0'; fd=open(devname,O_RDONLY|O_NDELAY); if (fd<0) { errmsg("error opening device: %s",strerror(errno)); return -1; } prev_disk_in=0; first=1; ioctl(fd,FDFLUSH); /* close(fd);*/ while(1) { /* fd=open(devname,O_RDONLY|O_NDELAY); if (fd<0) { errmsg("error opening device: %s",strerror(errno)); return -1; } */ usleep(interval*100000); e=ioctl(fd,FDPOLLDRVSTAT,&state); if (e) { msg("ioctl(FDPOLLDRVSTAT) failed: %s",strerror(errno)); return -1; } printf("flags=%02lx\n", state.flags); disk_in=!(state.flags & (FD_VERIFY | FD_DISK_NEWCHANGE)); if (disk_in && !prev_disk_in && !first) { msg("disk inserted"); ioctl(fd,FDFLUSH); do_mount(devname,mountpoint,mountflags,0,1,drivetype); } if (!disk_in && prev_disk_in) { msg("disk removed"); read_mtab(); mnt=get_mounted(devname); if (mnt) { if (!hasmntopt(&mnt->ms,"sync") && !hasmntopt(&mnt->ms,"ro")) msg("arg!! wasn't mounted sync"); /* should check for dirty buffers here! */ do_umount(devname,0); } } prev_disk_in=disk_in; first=0; /* close(fd);*/ } } void syntax() { fprintf(stderr, "usage: fdmount [options] drive_name [mount_dir]\n" " fdumount [options] drive_name\n" " fdlist\n" " fdmountd [options] drive_name [mount_dir]\n" "\n" " -r --readonly mount read-only\n" " -s --sync synchronize writes\n" " --nodev ignore device flags\n" " --nosuid ignore suid flags\n" " --noexec ignore executable flags\n" " -f --force force mount/unmount\n" " -l --list list known drives\n" " -d --daemon run as daemon\n" " -i --interval n set probing interval for -d [0.1 seconds]\n" " -o --options l sets filesystem specific options\n" " --silent don't print informational messages\n" " --detach run daemon in the background\n" " --nosync don't mount synchronously, even if daemon\n" " -p --pidfile dump the process id of the daemon to a file\n" " -v --vfat use vfat fs, instead of msdos\n" " -h --help this message\n\n"); exit(1); } void dump_pid(char *name, int pid) { FILE *fp; if(!name) return; fp=fopen(name, "w"); if(!fp) { errmsg("Can't write pidfile\n"); return; } fprintf(fp,"%d\n",pid); fclose(fp); } char *allowed_dos_options[]= { "check=r", "check=n", "check=s", "conv=", "dotsOK=", "debug", "fat=", "quiet", "blocksize=", 0 }; char *allowed_ext2_options[]= { "check=normal", "check=strict", "check=none", "errors=", "grpid", "bsdgroups", "nogrpid", "sysvgroups", "bsddf", "minixdf", "resgid=", "debug", "nocheck", 0 }; int add_opt(char **allopts, char *optlist, int *offset, char *new, int l) { for(;*allopts; allopts++) { if(!strncmp(*allopts, new, strlen(*allopts))) { if(l + *offset + 2> MAX_OPT) die("too many options"); optlist[(*offset)++] = ','; strncpy(optlist + *offset, new, l); *offset += l; optlist[(*offset)] = '\0'; return 0; } } return -1; } static void add_opts(char *opts) { char *newopt; int l; int dos_off, ext2_off; dos_off = strlen(dos_options); ext2_off = strlen(ext2_options); while(opts && *opts) { newopt = strchr(opts, ','); if(newopt) { l = newopt - opts; newopt++; } else l = strlen(opts); if((add_opt(allowed_dos_options, dos_options, &dos_off, opts, l) & add_opt(allowed_ext2_options, ext2_options, &ext2_off, opts, l))) { opts[l]='\0'; die("Illegal option %s", opts); } opts = newopt; } } int main(int argc, char **argv) { int pid; int i,e,c,is_default,optidx=0; char *drivename,*mountpoint=NULL,def_mountpoint[40],devname[40]; int drivetype; static int opt_force=0, opt_list=0, opt_daemon=0, opt_interval=10,opt_help=0,opt_umount=0,opt_nosync=0, opt_noexec=0,opt_nodev=0,opt_nosuid=0, opt_vfat=0; int mountflags=0; char *opt_pidfile="/var/run/fdmount.pid"; #ifdef FLOPPY_ONLY gid_t groups[NGROUPS_MAX]; int not_allowed = 1, ngroups; #endif static struct option longopt[] = { { "silent", 0, &opt_silent, 1 }, { "detach", 0, &opt_detach, 1 }, { "readonly", 0, NULL, 'r' }, { "pidfile", 1, NULL, 'p' }, { "noexec", 0, &opt_noexec, MS_NOEXEC }, { "nodev", 0, &opt_nodev, MS_NODEV }, { "nosuid", 0, &opt_nosuid, MS_NOSUID }, { "sync", 0, NULL, 's' }, { "nosync", 0, &opt_nosync, 1 }, { "force", 0, &opt_force, 1 }, { "list", 0, &opt_list, 1 }, { "daemon", 0, NULL, 'd' }, { "options", 0, NULL, 'o' }, { "interval", 1, NULL, 'i' }, { "vfat", 0, &opt_vfat, 'v' }, { "help", 0, &opt_help, 1 }, {0} }; progname = strrchr(argv[0], '/'); if(progname) progname++; else progname = argv[0]; opt_umount=(strcmp(progname,"fdumount")==0); opt_daemon=(strcmp(progname,"fdmountd")==0); opt_list =(strcmp(progname,"fdlist")==0); #ifdef FLOPPY_ONLY if ((ngroups = getgroups (NGROUPS_MAX, groups)) != -1) { int i; struct group *gr; not_allowed = getuid(); for (i = 0; not_allowed && i < ngroups; i++) if ((gr = getgrgid (groups[i]))) not_allowed = strcmp (gr -> gr_name, "floppy"); } if (not_allowed) die("Must be member of group floppy"); #endif if (geteuid()!=0) die("Must run with EUID=root"); ruid = getuid(); rgid = getgid(); _umask = umask(0); umask(_umask); *dos_options = 0; *ext2_options = 0; while(1) { c=getopt_long(argc,argv,"rsfldi:hp:o:v",longopt,&optidx); if (c==-1) break; switch(c) { case 'o': add_opts(optarg); break; case 'r': mountflags |= MS_RDONLY; break; case 's': mountflags |= MS_SYNCHRONOUS; break; case 'l': opt_list=1; break; case 'f': opt_force=1; break; case 'd': mountflags |= MS_SYNCHRONOUS; opt_daemon=1; break; case 'i': opt_interval=atoi(optarg); break; case 'p': opt_pidfile = optarg; break; case 'h': opt_help=1; break; case 'v': opt_vfat=1; break; case 0: break; default: syntax(); } } mountflags |= opt_noexec | opt_nosuid | opt_nodev; if (opt_vfat) { fsnames[T_DOS] = "vfat"; } if(opt_nosync) mountflags &= ~MS_SYNCHRONOUS; if(opt_detach && !opt_daemon) die("Detach option can only be used when running as daemon\n"); if(opt_force && ruid) die("You must be root to use the force option"); drivename=argv[optind++]; if (drivename) mountpoint=argv[optind++]; if (optind10000) opt_interval=10000; /* get drive type */ drivetype=probe_drive(devname); if (!drivetype) { die("drive %s does not exist",drivename); } e=0; if (opt_help) { syntax(); } else if (opt_list) { list_drives(); } else if (opt_daemon) { if (ruid!=0) die("Must be root to run as daemon"); if (opt_detach) { pid = fork(); if (pid == -1) die("Failed to fork"); if (pid) { dump_pid(opt_pidfile, pid); exit(0); /* the father */ } openlog(progname, 0, LOG_DAEMON); use_syslog = 1; setsid(); chdir ("/"); /* no current directory. */ /* Ensure that nothing of our device environment is inherited. */ close (0); close (1); close (2); } else if (opt_pidfile) dump_pid(opt_pidfile, getpid()); daemon_mode(devname,mountpoint,mountflags, opt_interval,drivetype); } else if (opt_umount) { e=do_umount(devname,opt_force); } else { if (ruid!=0) mountflags |= MS_NODEV|MS_NOSUID; e=do_mount(devname,mountpoint,mountflags, opt_force,is_default,drivetype); } return e; } fdutils-5.5-20060227/src/getfdprm.c0000444000175000017500000000312507464324643015751 0ustar anibalanibal #include #include #include #include #include #include #include "driveprm.h" #include "printfdprm.h" struct floppy_struct floppy_type; extern int errno; void usage(char *name) __attribute__((noreturn)); void usage(char *name) { fprintf(stderr,"Usage: %s\n", name); exit(1); } static void myprintf(char *fmt, int value) { printf(fmt, value); putchar(' '); } int main(int argc,char **argv) { int fd; char *name; level_t level; drivedesc_t drivedesc; level = LEV_NONE; if (argc > 1 && *argv[1] == '-') { switch (argv[1][1]) { case 'e': level = LEV_EXPL; break; case 'm': level = LEV_MOST; break; case 'a': level = LEV_ALL; break; case 'o': level = LEV_OLD; break; default: usage(argv[0]); } argc--; argv++; } if ( argc == 1 ) name = "/dev/fd0" ; else name = argv[1]; fd=open(name,3); if ( fd < 0 ) fd=open(name,O_RDONLY); if ( fd < 0 ){ perror("open"); exit(1); } if(ioctl(fd,FDGETPRM,&floppy_type)<0){ perror("get geometry parameters"); exit(1); } if(level == LEV_OLD) { printf("%4d %2d %d %2d %d 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", floppy_type.size, floppy_type.sect, floppy_type.head, floppy_type.track, floppy_type.stretch, floppy_type.gap, floppy_type.rate, floppy_type.spec1, floppy_type.fmt_gap); } else { parse_driveprm(fd, &drivedesc); print_params(&drivedesc, &floppy_type, level, 0, (void(*)(char *,int))myprintf); } close(fd); exit(0); } fdutils-5.5-20060227/src/message0000444000175000017500000000062307464324643015344 0ustar anibalanibalCompiling superformat... WARNING !!!! ============ 2m formats (HD formats whith more than 21 sectors, and ED formats with more than 42 sectors) are only suitable for msdos filesystems. USE FOR OTHER FILESYSTEMS MAY RESULT IN DATA LOSS. READ THE SUPERFORMAT MANPAGE AND THE README FILE CAREFULLY. If you want to use a different filesystem on these disks, use the -1 option. Press enter to continue fdutils-5.5-20060227/src/convert.c0000444000175000017500000000253207464324643015622 0ustar anibalanibal/* setfdprm.c - Sets user-provided floppy disk parameters, re-activates autodetection and switches diagnostic messages. */ #include #include #include #include #include #include #include #include #include #include "oldfdprm.h" #include "printfdprm.h" #define FDPRMFILE "/etc/fdprm" #define MAXLINE 200 static int col = 0; static int cpm=1; level_t level = LEV_NONE; static void print_token(char *fmt, int param) { char buffer[50]; int l; snprintf(buffer, 49, fmt, param); l = strlen(buffer); if(l + col > 70) { printf("\n"); col = 1; } printf(" %s", buffer); col += l+1; } static void _print_params(char *name, char *comment, struct floppy_struct *ft) { printf("\n\"%s\":", name); if(comment) printf(" #%s", comment); else printf("\n"); col = 0; print_params(0, ft, level, cpm, print_token); } static void usage(char *name) { } int main(int argc,char **argv) { struct floppy_struct ft; char *name = argv[0]; if (argc > 1 && *argv[1] == '-') { switch (argv[1][1]) { case 'e': level = LEV_EXPL; break; case 'm': level = LEV_MOST; break; case 'a': level = LEV_ALL; break; default: usage(name); } argc--; argv++; } scan_fdprm(stdin, 0, &ft, _print_params); exit(0); } fdutils-5.5-20060227/src/setfdprm.c0000444000175000017500000000360207464324643015765 0ustar anibalanibal/* setfdprm.c - Sets user-provided floppy disk parameters, re-activates autodetection and switches diagnostic messages. */ #include #include #include #include #include #include #include #include #include #include "enh_options.h" #include "mediaprm.h" #include "driveprm.h" #include "oldfdprm.h" int mcmd = 0; int cmd = FDSETPRM; struct enh_options optable[] = { { 'c', "clear", 0, EO_TYPE_NONE, FDCLRPRM, 0, &cmd, "clear the geometry parameters" }, { 'p', "permanent", 0, EO_TYPE_NONE, FDCLRPRM, 0, &cmd, "set the geometry parameters permanently" }, { 'y', "message-on", 0, EO_TYPE_NONE, FDMSGON, 0, &mcmd, "switch messages on" }, { 'n', "message-off", 0, EO_TYPE_NONE, FDMSGOFF, 0, &mcmd, "switch messages off" }, { '\0', 0 } }; int main(int argc,char **argv) { int cmd,fd,c; char *name; drivedesc_t drivedesc; struct floppy_struct medprm; int have_fmt = 0; char *userparams="drive [geometry]"; int mask; name = argv[0]; if (argc < 3) print_usage(name, optable, userparams); cmd = FDSETPRM; mcmd = 0; while((c=getopt_enh(argc, argv, optable, 0, &mask, userparams)) != EOF){ if(c == '?') { fprintf(stderr,"exiting\n"); exit(1); } printf("unhandled option %d\n", c); exit(1); } argv += optind; argc -= optind; if ((fd = open(argv[0],3)) < 0) { /* 3 == no access at all */ perror(argv[0]); exit(1); } argv++; argc--; parse_driveprm(fd, &drivedesc); if(argc) { if(parse_mediaprm(argc, argv, &drivedesc, &medprm) && parse_fdprm(argc, argv, &medprm)) { print_usage(name, optable, userparams); exit(1); } have_fmt = 1; } if(mcmd && ioctl(fd, cmd) < 0) { perror("message ioctl"); exit(1); } if(have_fmt || cmd == FDCLRPRM) { if(ioctl(fd, cmd, &medprm) < 0) { perror("geometry ioctl"); exit(1); } } exit(0); } fdutils-5.5-20060227/src/xdfcopy.c0000444000175000017500000004300207705711544015611 0ustar anibalanibal/* * Software patents declared unconstitutional, worldwide */ #include #ifdef HAVE_SYS_SYSMACROS_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fdutils.h" #ifdef FD_RAW_MORE char *error_msg[22]={ "Missing Data Address Mark", "Bad cylinder", "Scan not satisfied", "Scan equal hit", "Wrong cylinder", "CRC error in data field", "Control Mark = deleted", 0, "Missing Address Mark", "Write Protect", "No Data - unreadable", 0, "Overrun", "CRC error in data or address", 0, "End Of Cylinder", 0, 0, 0, "Not ready", "Equipment check error", "Seek end" }; enum dir { READ_, WRITE_ } ; static int curcylinder = -1; int interpret_errors(struct floppy_raw_cmd *raw_cmd, int probe_only) { int i,k; int code; k = 0; do { if ( raw_cmd[k].reply_count ){ switch( raw_cmd[k].reply[0] & 0xc0 ){ case 0x40: if((raw_cmd[k].reply[0] & 0x38) == 0 && raw_cmd[k].reply[1] == 0x80 && raw_cmd[k].reply[2] == 0) break; if(probe_only) return -2; curcylinder = -1; fprintf(stderr, "\nerror during command execution\n"); if ( raw_cmd[k].reply[1] & ST1_WP ){ fprintf(stderr, "The disk is write protected\n"); exit(1); } fprintf(stderr," "); for (i=0; i< raw_cmd[k].cmd_count; i++) fprintf(stderr,"%2.2x ", (int)raw_cmd[k].cmd[i] ); printf("\n"); for (i=0; i< raw_cmd[k].reply_count; i++) fprintf(stderr,"%2.2x ", (int)raw_cmd[k].reply[i] ); fprintf(stderr,"\n"); code = (raw_cmd[k].reply[0] <<16) + (raw_cmd[k].reply[1] << 8) + raw_cmd[k].reply[2]; for(i=0; i<22; i++){ if ( (code & ( 1 << i )) && error_msg[i]) fprintf(stderr, "%s\n", error_msg[i]); } sleep(4); return k; case 0x80: curcylinder = -1; fprintf(stderr, "\ninvalid command given\n"); return 1; case 0xc0: curcylinder = -1; fprintf(stderr, "\nabnormal termination caused by polling\n"); return 0; case 0: break; } if (raw_cmd[k].flags & FD_RAW_NEED_SEEK) curcylinder = raw_cmd[k].track; /* OK */ } else { fprintf(stderr,"\nNull reply from FDC\n"); return 1; } k++; } while(raw_cmd[k-1].flags & FD_RAW_MORE); return -1; } int send_cmd(int fd,struct floppy_raw_cmd *raw_cmd, char *message, int probe_only) { int i,j,k; for (j=0; j<4; j++){ if ( raw_cmd->track == curcylinder && !(raw_cmd->flags & FD_RAW_WRITE)) raw_cmd->flags &= ~FD_RAW_NEED_SEEK; if ( ioctl( fd, FDRAWCMD, raw_cmd) < 0 ){ curcylinder = -1; if (errno == EBUSY){ i--; fprintf(stderr, "\nFDC busy, sleeping for a second\n"); sleep(1); continue; } if (errno == EIO){ fprintf(stderr,"\nresetting controller\n"); if(ioctl(fd, FDRESET, 2) < 0){ perror("reset"); exit(1); } continue; } perror(message); exit(1); } k = interpret_errors(raw_cmd, probe_only); switch(k) { case -2: return 1; case -1: return 0; } raw_cmd += k; } fprintf(stderr,"\nToo many errors, giving up\n"); exit(1); } int readwrite_sectors(int fd, /* file descriptor */ int drive, enum dir direction, int cylinder, int head, int sector, int size, /* address */ char *data, int bytes, struct floppy_raw_cmd *raw_cmd, int rate) { raw_cmd->data = data; raw_cmd->length = bytes; raw_cmd->rate = rate; raw_cmd->flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK | FD_RAW_MORE; raw_cmd->cmd_count = 9; if (direction == READ_) { raw_cmd->cmd[0] = FD_READ & ~0x80; raw_cmd->flags |= FD_RAW_READ; } else { raw_cmd->cmd[0] = FD_WRITE & ~0x80; raw_cmd->flags |= FD_RAW_WRITE; } raw_cmd->cmd[1] = (drive & 3) | (head << 2); raw_cmd->cmd[2] = cylinder; raw_cmd->cmd[3] = head; raw_cmd->cmd[4] = sector; raw_cmd->cmd[5] = size; raw_cmd->cmd[6] = sector + (bytes >> (size + 7)) - 1; raw_cmd->cmd[7] = 0x1b; raw_cmd->cmd[8] = 0xff; raw_cmd->track = cylinder; return 0; } typedef struct sector_map { unsigned int head:1; unsigned int size:7; /* unsigned char sectors; unsigned char phantom;*/ unsigned char position; /* physical position */ } sector_map; struct xdf_struct { unsigned char gap_any; /* formatting gap */ unsigned char sect_per_track_any; unsigned char skew; /* skew */ /* the following info is used for track 0 */ unsigned char gap_0; /* gap used on track 0 */ unsigned char sect_per_track_0; /* the following info is used for track 1 (cyl 0 head 1) */ unsigned char gap_1; /* gap used on track 1 */ unsigned char sect_per_track_1; unsigned char rate; unsigned char period; unsigned char sizecode; unsigned char rootskip; unsigned char FatSize; sector_map map[9]; } xdf_table[] = { { /* 5 1/4 format */ 0x29, 19, 21, 74, 16, 36, 17, 0, 42, 0, 0, 9, { {0,3, 0}, {0,6, 8}, {1,2, 1}, {0,2, 5}, {1,6, 9}, {1,3, 4}, {0,0, 0} } }, { /* 3 1/2 HD */ 0x7a, 23, 20, 77, 19, 77, 19, 0, 40, 0, 0, 11, { {0, 3, 0}, {0, 4, 6}, {1, 6, 15}, {0, 2, 4}, {1, 2, 9}, {0, 6, 13}, {1, 4, 2}, {1, 3, 11}, {0, 0, 0} } }, { /* 3 1/2 ED */ 14, 46, 15, 60, 37, 60, 37, 0x43, 60, 1, 1, 22, { {0,3, 0}, {0,4, 4}, {0,5, 11}, {0,7, 24}, {1,3, 1}, {1,4, 5}, {1,5, 12}, {1,7, 25}, {0,0, 0} } }, /* my own formats */ { /* 3 1/2 HD */ 56, 24, 25, 49, 20, 49, 20, 0, 50, 0, 1, 12, { {0, 5, 0}, {1, 6, 19}, {0, 6, 17}, {1, 5, 2}, {0, 0, 0} } }, { /* 3 1/2 ED */ 81, 48, 36, 43, 39, 43, 39, 0x43, 54, 1, 0, 21, { {0, 6, 0}, {1, 7, 21}, {0, 7, 20}, {1, 6, 1}, {0, 0, 0} } } }; #define NUMBER(x) (sizeof(x)/sizeof(x[0])) #define POS(x) ( (skew + x) % 21 ) static int hs=0; static int ts=14; static int debug=0; void format_track(int fd, int drive, int cylinder, int head, struct xdf_struct *fmt, int FatSize, int RootDirSize) { int i,j; int skew; int max; #define NEXT(x,max) x+=2; if(x>=max)x=1; struct floppy_raw_cmd raw_cmd; sector_map *p; format_map_t format_map[256]; for(i=0; i<256; i++){ format_map[i].sector = i; format_map[i].size = fmt->sizecode; format_map[i].cylinder = cylinder; format_map[i].head = head; } if (cylinder == 0){ j = 0; if(head) { for (i=0; i< fmt->sect_per_track_1; i++) { format_map[j].sector = i+129; format_map[j].size = 2; NEXT(j, fmt->sect_per_track_1); } raw_cmd.cmd[3] = fmt->sect_per_track_1; raw_cmd.cmd[4] = fmt->gap_1; } else { for (i=0; i< 8; i++) { format_map[j].sector = i+1; format_map[j].size = 2; NEXT(j, fmt->sect_per_track_0); } for (i=0; i< fmt->sect_per_track_0 - 8; i++) { format_map[j].sector = i+129; format_map[j].size = 2; NEXT(j, fmt->sect_per_track_0); } raw_cmd.cmd[3] = fmt->sect_per_track_0; raw_cmd.cmd[4] = fmt->gap_0; } raw_cmd.cmd[2] = 2; } else { skew = (cylinder * fmt->skew) % fmt->period; max=0; for(p = fmt->map; p->size; p++) { if(p->head == head) { format_map[p->position+skew].sector = p->size+128; format_map[p->position+skew].size = p->size; if(p->position + skew> max) max = p->position + skew; } } raw_cmd.cmd[2] = fmt->sizecode; raw_cmd.cmd[3] = max+1; raw_cmd.cmd[4] = fmt->gap_any; } raw_cmd.data = format_map; raw_cmd.length = sizeof(format_map[0]) * raw_cmd.cmd[3]; raw_cmd.rate = fmt->rate; raw_cmd.flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK | FD_RAW_WRITE; raw_cmd.cmd[0] = FD_FORMAT; raw_cmd.cmd[1] = (drive & 3 ) | ( head << 2 ); raw_cmd.cmd[5] = 42; raw_cmd.cmd_count = 6; raw_cmd.track = cylinder; send_cmd(fd, &raw_cmd, "format", 0); } enum fs { MAIN_FS, AUX_FS }; void read_sectors(enum fs fs, int sector, char **data, int sectors, int drive, int fd, int cylinder, struct xdf_struct *fmt, int direction, struct floppy_raw_cmd *raw_cmd, int *j) { int limit, head, psector, lsectors; while(sectors) { lsectors = sectors; head = 0; if(fs == MAIN_FS) { limit = fmt->sect_per_track_0 - 8; if(sector < limit) { psector = sector + 129; if(sector + lsectors > limit) lsectors = limit - sector; } else { head = 1; psector = sector - limit + 129; } } else { if(sector >= 8) return; psector = sector + 1; if(lsectors + sector >= 8) lsectors = 8 - sector; } readwrite_sectors(fd, drive, direction, cylinder, head, psector, 2, *data, lsectors << 9, raw_cmd + (*j)++, fmt->rate); *data += lsectors << 9; sector += lsectors; sectors -= lsectors; } } #define WORD(x) ((unsigned char)(x)[0] + (((unsigned char)(x)[1]) << 8)) void readwrite_cylinder(int fd, int drive, enum dir direction, int cylinder, char *data, struct xdf_struct *fmt, int FatSize, int RootDirSize) { struct floppy_raw_cmd raw_cmd[20]; int i,j; struct timeval tv1, tv2; static struct timeval tv3, tv4; sector_map *map; j=i=0; if(cylinder) { map = fmt->map; while(map->size){ readwrite_sectors(fd, drive, direction, cylinder, map->head, map->size + 128, map->size, data, 128 << map->size, raw_cmd + j++, fmt->rate); data += 128 << map->size; map++; i++; } } else { /* the boot sector & the FAT */ read_sectors(MAIN_FS, 0, &data, 1 + FatSize, drive, fd, cylinder, fmt, direction, raw_cmd, &j); /* the index fs */ read_sectors(AUX_FS, 0, &data, 8, drive, fd, cylinder, fmt, direction, raw_cmd, &j); if( direction == READ_) { /* the remaining sectors of the phantom FAT */ read_sectors(MAIN_FS, 9, &data, FatSize - 8, drive, fd, cylinder, fmt, direction, raw_cmd, &j); } else data += (FatSize - 8) * 512; read_sectors(MAIN_FS, 1 + FatSize, & data, RootDirSize, drive, fd, cylinder, fmt, direction, raw_cmd, &j); if (direction == READ_) read_sectors(AUX_FS, 3, &data, 5, drive,fd,cylinder,fmt, direction, raw_cmd, &j); else data += 5 * 512; read_sectors(MAIN_FS, 1 + FatSize + RootDirSize + fmt->rootskip, &data, fmt->sect_per_track_any * 2 - RootDirSize - 2 * FatSize - 6, drive, fd, cylinder, fmt, direction, raw_cmd, &j); } raw_cmd[j-1].flags &= ~ FD_RAW_MORE; if(debug) gettimeofday(&tv1,0); send_cmd(fd, raw_cmd, "read/write", 0); if(debug) { gettimeofday(&tv2,0); printf("\ncylinder %d: %ld %ld %ld\n\n", cylinder, (long) ((tv2.tv_sec-tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec), (long) ((tv2.tv_sec-tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec), (long) ((tv2.tv_sec-tv4.tv_sec) * 1000000 + tv2.tv_usec - tv4.tv_usec)); if(cylinder == 2) tv4 = tv2; tv3 = tv2; } } static int get_type(int fd) { int drive; struct stat statbuf; if (fstat(fd, &statbuf) < 0 ){ perror("stat"); exit(0); } if (!S_ISBLK(statbuf.st_mode) || major(statbuf.st_rdev) != FLOPPY_MAJOR) return -1; drive = minor( statbuf.st_rdev ); return (drive & 3) + ((drive & 0x80) >> 5); } #define TRACKSIZE 512*2*48 static void usage(char *progname) { fprintf(stderr,"Usage:\n"); fprintf(stderr," For copying: %s [-n] \n", progname); fprintf(stderr, " For formatting: %s [-D dosdrive] [-t cylinderskew] [-h headskew] [-01234]\n", progname); exit(1); } static char *readme= "This is an Xdf disk. To read it in Linux, you have to use a version of\r\n" "mtools which is more recent than 3.0, and set the environmental\r\n" "variable MTOOLS_USE_XDF before accessing it.\r\n\r\n" "Bourne shell syntax (sh, ash, bash, ksh, zsh etc):\r\n" " export MTOOLS_USE_XDF=1\r\n\r\n" "C shell syntax (csh and tcsh):\r\n" " setenv MTOOLS_USE_XDF 1\r\n\r\n" "mtools can be gotten from http://www.tux.org/pub/knaff/mtools\r\n" "\032"; int progress; static void clear(void) { if(progress) fprintf(stderr,"\b\b\b"); } int main(int argc, char **argv) { int sfd=0, tfd; int sdrive=0, tdrive; int cylinder, head, ret; int c; int noformat=0; char dosdrive=0; int max_cylinder = 80; char buffer[TRACKSIZE]; char cmdbuffer[80]; char *sourcename, *targetname; struct xdf_struct *fmt; FILE *fp; unsigned int type = 1; int FatSize = 11; int RootDirSize = 14; while ((c = getopt(argc, argv, "T:t:h:dnD:01234")) != EOF) { switch (c) { case 'D': dosdrive = optarg[0]; break; case 't': ts = strtoul(optarg,0,0); break; case 'h': hs = strtoul(optarg,0,0); break; case 'd': debug = 1; break; case 'n': noformat = 1; break; case 'T': max_cylinder = strtoul(optarg,0,0); break; case '0': case '1': case '2': case '3': case '4': type = c - '0'; FatSize = xdf_table[type].FatSize; RootDirSize = 14; break; default: usage(argv[0]); } } if(argc < optind +1 || argc >optind+2) usage(argv[0]); if(argc >= optind + 2) sourcename = argv[optind++]; else sourcename = 0; targetname = argv[optind]; if(!sourcename && noformat) { fprintf(stderr, "Missing sourcename\n"); usage(argv[0]); } if(sourcename) { sfd = open( sourcename, O_RDONLY | O_NDELAY); if ( sfd < 0 ){ perror("Couldn't open source file"); exit(1); } sdrive = get_type(sfd); } tfd = open(targetname, O_WRONLY | O_CREAT | O_TRUNC | O_NDELAY, 0666); if ( tfd < 0 ){ perror("Couldn't open target file"); exit(1); } tdrive = get_type(tfd); if(tdrive < 0 && !sourcename) { fprintf(stderr, "Format target is not a floppy disk\n"); usage(argv[0]); } progress = (tdrive >= 0 || sdrive >= 0) && isatty(2); if(sourcename) { if( sdrive == -1) { ret = read(sfd, buffer, 512); if ( ret < 0 ){ perror("read"); exit(1); } if ( ret < 512 ){ fprintf(stderr,"short read\n"); exit(1); } lseek(sfd, 0, SEEK_SET); } else { struct floppy_raw_cmd raw_cmd; /* the boot sector & the FAT */ readwrite_sectors(sfd, sdrive, READ_, 0, 0, 0x81, 2, buffer, 512, &raw_cmd, 0); raw_cmd.flags &= ~ FD_RAW_MORE; if(type == 2 || send_cmd(sfd, &raw_cmd, "probe HD", 1)) { readwrite_sectors(sfd, sdrive, READ_, 0, 0, 0x81, 2, buffer, 512, &raw_cmd, 0x43); raw_cmd.flags &= ~ FD_RAW_MORE; send_cmd(sfd, &raw_cmd, "probe ED", 0); } } RootDirSize = WORD(buffer+17)/16; FatSize = WORD(buffer+22); for(type=0; type < NUMBER(xdf_table); type++) { if(xdf_table[type].sect_per_track_any == WORD(buffer+24)) break; } if(type == NUMBER(xdf_table)) { fprintf(stderr, "Source is of unknown density, probably not an XDF disk\n"); exit(1); } } fmt = xdf_table + type; for ( cylinder = 0 ; cylinder < max_cylinder ; cylinder++){ if(sourcename) { if ( sdrive == - 1 ){ ret = read(sfd, buffer, fmt->sect_per_track_any*1024); if ( ret < 0 ){ perror("read"); exit(1); } if ( ret < fmt->sect_per_track_any * 1024 ){ fprintf(stderr,"short read\n"); exit(1); } } else { if(progress) { fprintf(stderr,"r%02d", cylinder); fflush(stderr); } readwrite_cylinder(sfd, sdrive, READ_, cylinder, buffer, fmt, FatSize, RootDirSize); clear(); } } else { memset(buffer, 0, fmt->sect_per_track_any * 1024); if(!cylinder) { buffer[17]=0xe0; buffer[18]=0; buffer[22]=FatSize; buffer[23]=0; buffer[24]=fmt->sect_per_track_any; buffer[25]=0; } } if (tdrive == -1){ ret = write(tfd, buffer, fmt->sect_per_track_any * 1024); if ( ret < 0 ){ perror("write"); exit(1); } if ( ret < fmt->sect_per_track_any * 1024 ){ fprintf(stderr,"short write\n"); exit(1); } } else { if(!noformat) { if(progress) { fprintf(stderr,"f%02d", cylinder); fflush(stderr); } for(head = 0; head < 2; head++) format_track(tfd, tdrive, cylinder,head, fmt, FatSize, RootDirSize); clear(); } if(progress) { fprintf(stderr,"w%02d", cylinder); fflush(stderr); } readwrite_cylinder(tfd, tdrive, WRITE_, cylinder, buffer, fmt, FatSize, RootDirSize); clear(); } } close(tfd); close(sfd); if(dosdrive && !sourcename && !noformat) { snprintf(cmdbuffer,79,"mformat -X -s%d -t%d -h2 %c:", fmt->sect_per_track_any, max_cylinder, dosdrive); system(cmdbuffer); setenv("MTOOLS_USE_XDF","0", 1); snprintf(cmdbuffer,79,"mformat -t1 -h1 -s8 %c:", dosdrive); system(cmdbuffer); snprintf(cmdbuffer,79,"mcopy - %c:README", dosdrive); fp = popen(cmdbuffer, "w"); if(fp) { fwrite(readme, strlen(readme), 1, fp); fclose(fp); } } exit(0); } #else void main(void) { fprintf(stderr,"xdfcopy not supported on this system\n"); fprintf(stderr,"Please upgrade your kernel and recompile fdutils\n"); exit(1); } #endif fdutils-5.5-20060227/src/Makefile.in0000444000175000017500000001015707567104732016044 0ustar anibalanibal# Define PIDFILE if you want to have the pid of the diskseekd stored # somewhere on the filesystem. You'll get a (very) little shell # script diskseek.sh that uses this to connect with the daemon # when the disk should be cleaned by hand. In that case it's a replacement # for diskseek. If you don't want to have this feature, don't define it. # top_srcdir=@top_srcdir@ srcdir=@srcdir@ VPATH=@srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ infodir = @infodir@ mandir = @mandir@ infodir = @infodir@ sysconfdir = @sysconfdir@ CC = @CC@ PID = -DPIDFILE=\"@localstatedir@/run/diskseekd.pid\" DEFINES = $(DEFINES) $(PID) -DSYSCONFDIR=\"@sysconfdir@\" DEFS = @DEFS@ -DSYSCONFDIR=\"@sysconfdir@\" CPPFLAGS = -I. -I@srcdir@ @CPPFLAGS@ $(DEFS) CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = -L. -lfdutils @LIBS@ SHLIB = @SHLIB@ MACHDEPLIBS = @MACHDEPLIBS@ LN_S = @LN_S@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ OBJECTS=enh_options.o floppycontrol.o superformat.o SOURCES=enh_options.c floppycontrol.o superformat.c MANPAGES1=diskd.1 diskseekd.1 fdrawcmd.1 floppycontrol.1 getfdprm.1 \ makefloppies.1 superformat.1 xdfcopy.1 fdmount.1 MANPAGES4=fd.4 MANPAGES8=setfdprm.8 PERM=755 SPERM=4750 #we only people in group floppy to run priviledged programs MANPERM = 644 UID = root GID = floppy all: floppycontrol getfdprm setfdprm fdrawcmd \ superformat xdfcopy fdmount diskseekd diskd floppymeter convertfdprm LIBFILES=lex.mediaprm.o lex.driveprm.o mediaprm.o driveprm.o parse.o \ oldfdprm.o enh_options.o measure.o printfdprm.o calc-format.o \ misc.o skews.o lex.%.c: %.lex lex -P$* $< libfdutils.a: libfdutils.a($(LIBFILES)) ranlib libfdutils.a floppycontrol.o getfdprm setfdprm: /usr/include/linux/fd.h diskseekd.o superformat.o fdrawcmd.o: /usr/include/linux/fd.h \ /usr/include/linux/fdreg.h convertfdprm: convert.o libfdutils.a ${CC} $(LDFLAGS) -o $@ $< $(LIBS) floppycontrol: floppycontrol.o libfdutils.a ${CC} $(LDFLAGS) -o $@ $< $(LIBS) diskd: diskd.o libfdutils.a ${CC} $(LDFLAGS) -o $@ $< $(LIBS) diskseekd: diskseekd.o libfdutils.a ${CC} $(LDFLAGS) -o $@ $< $(LIBS) diskseek: diskseekd ln -s diskseekd diskseek superformat: superformat.o libfdutils.a ${CC} $(LDFLAGS) -o $@ $< $(LIBS) floppymeter: floppymeter.o libfdutils.a ${CC} ${LDFLAFS} -o $@ $< $(LIBS) fdrawcmd: fdrawcmd.o ${CC} $(LDFLAGS) -o $@ $< $(LIBS) getfdprm: getfdprm.o libfdutils.a ${CC} $(LDFLAGS) -o $@ $< $(LIBS) setfdprm: setfdprm.c libfdutils.a ${CC} $(LDFLAGS) $(CFLAGS) -o $@ $< $(LIBS) clean: -rm -f *~ *.orig *.o a.out *.a lex.*.c core 2>/dev/null spotless: clean -rm -f floppycontrol superformat getfdprm fdrawcmd diskseekd diskd \ diskseek diskd_old setfdprm xdfcopy fdmount 2>/dev/null install: install-bin install-conf @grep -q '^floppy:' /etc/group \ || echo 'Add a group "floppy" to /etc/group.' install-conf: $(top_srcdir)/mkinstalldirs $(syconfdir) if [ ! -f $(sysconfdir)/mediaprm ] ; then \ cp $(srcdir)/mediaprm $(sysconfdir) ; \ fi install-bin: all $(top_srcdir)/mkinstalldirs $(bindir) $(INSTALL) -c -m $(PERM) -o $(UID) -g $(GID) $(srcdir)/MAKEFLOPPIES $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) diskd $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) diskseekd $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) floppycontrol $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) floppymeter $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) getfdprm $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) setfdprm $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) fdrawcmd $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) superformat $(bindir) $(INSTALL) -c -s -m $(PERM) -o $(UID) -g $(GID) xdfcopy $(bindir) $(INSTALL) -c -s -m $(SPERM) -o $(UID) -g $(GID) fdmount $(bindir) $(INSTALL) -c -s -m $(SPERM) -o $(UID) -g $(GID) fdmount $(bindir)/fdumount ( cd $(bindir); \ ln -sf xdfcopy $(bindir)/xdfformat; \ ln -sf fdmount $(bindir)/fdumount; \ ln -sf fdmount $(bindir)/fdlist; \ ln -sf fdmount $(bindir)/fdmountd ) fdutils-5.5-20060227/src/fdutils.h0000444000175000017500000000156510446366017015621 0ustar anibalanibal#ifndef __FDUTILS_H #define __FDUTILS_H #include /* This file contains common structures understood by several of the * fdutils */ /* format map */ typedef struct format_map { unsigned char cylinder; unsigned char head; unsigned char sector; unsigned char size; } format_map_t; void readid(int fd, int dn, int rate, int cylinder); int measure_raw_capacity(int fd, int dn, int rate, int cylinder, int warmup, int verbosity); #define NewArray(n,type) ((type *)(calloc((n), sizeof(type)))) #define New(type) ((type *)(malloc(sizeof(type)))) #define SafeNewArray(n,type) ((type *)(safe_calloc((n), sizeof(type)))) #define SafeNew(type) ((type *)(safe_malloc(sizeof(type)))) void *safe_malloc(size_t size); void *safe_calloc(size_t nmemb, size_t size); #ifndef FD_SWAPSIDES #define FD_SWAPSIDES 2 #endif #ifndef FD_ZEROBASED #define FD_ZEROBASED 4 #endif #endif fdutils-5.5-20060227/src/driveprmP.h0000644000175000017500000000022010211673101016065 0ustar anibalanibalextern FILE *driveprmin; #define YY_DECL int driveprmlex(int drivenum, struct keyword_l *ids, int size, \ int *mask, int *found) YY_DECL; fdutils-5.5-20060227/src/misc.c0000444000175000017500000000065507464324643015101 0ustar anibalanibal#include #include #include #include "fdutils.h" void *safe_calloc(size_t nmemb, size_t size) { void *ptr; ptr = calloc(nmemb, size); if(!ptr) { fprintf(stderr,"Out of memory error\n"); exit(1); } return ptr; } void *safe_malloc(size_t size) { void *ptr; ptr = malloc(size); if(!ptr) { fprintf(stderr,"Out of memory error\n"); exit(1); } return ptr; } fdutils-5.5-20060227/src/mediaprm.c0000444000175000017500000001437110446366017015737 0ustar anibalanibal#include #include #include #include #include "parse.h" #include "mediaprmP.h" #include "driveprm.h" #include "mediaprm.h" typedef enum { FE_UNKNOWN, FE_SIZE, FE_SECT, FE_VSECT, FE_HEAD, FE_CYL, /* the stretch byte */ FE_TPI, FE_STRETCH, FE_SWAPSIDES, FE_ZEROBASED, FE_GAP, FE_FM, FE_PERP, FE_SSIZE, FE_2M, FE_DTR, FE_SPEC1, /* spec1, obsolete */ FE_FMT_GAP, FE_DENSITY, } field_t; static int SIZE, SECT, VSECT, HEAD, CYL, TPI, STRETCH, SWAPSIDES, ZEROBASED; static int GAP, FM; static int PERP, SSIZE, _2M, DTR, SPEC1, FMT_GAP, DENSITY; static int ssize; #define F_SIZE FE_SIZE,&SIZE #define F_SECT FE_SECT,&SECT #define F_VSECT FE_VSECT,&VSECT #define F_HEAD FE_HEAD,&HEAD #define F_CYL FE_CYL,&CYL #define F_TPI FE_TPI,&TPI #define F_STRETCH FE_STRETCH,&STRETCH #define F_SWAPSIDES FE_SWAPSIDES,&SWAPSIDES #define F_ZEROBASED FE_ZEROBASED,&ZEROBASED #define F_GAP FE_GAP,&GAP #define F_FM FE_FM,&FM #define F_PERP FE_PERP,&PERP #define F_SSIZE FE_SSIZE,&SSIZE #define F_2M FE_2M,&_2M #define F_DTR FE_DTR,&DTR #define F_SPEC1 FE_SPEC1,&SPEC1 #define F_FMT_GAP FE_FMT_GAP,&FMT_GAP #define F_DENSITY FE_DENSITY,&DENSITY static int mask; static keyword_t ids[]= { { "size", F_SIZE, 0 }, { "sect", F_SECT, 0}, { "tracksize", F_VSECT, 0}, { "head", F_HEAD, 0}, { "ss", F_HEAD, 1}, { "ds", F_HEAD, 2}, { "cyl", F_CYL, 0}, { "tpi", F_TPI, 0 }, { "stretch", F_STRETCH, 0 }, { "swapsides", F_SWAPSIDES, 1}, { "zerobased", F_ZEROBASED, 1}, { "zero-based", F_ZEROBASED, 1}, { "gap", F_GAP, 0}, { "fm", F_FM, 1}, { "perp", F_PERP, 0}, { "ssize", F_SSIZE, 0}, { "2m", F_2M, 1}, { "dtr", F_DTR, 0}, { "mss", F_SSIZE, 16384 }, { "sd", F_DENSITY, DENS_SD }, { "dd", F_DENSITY, DENS_DD }, { "qd", F_DENSITY, DENS_QD }, { "hd", F_DENSITY, DENS_HD }, { "ed", F_DENSITY, DENS_ED }, { "spec1", F_SPEC1, 0}, { "fmt_gap", F_FMT_GAP, 0} }; struct { int dtr; /* dtr, as it would be in a 3 1/2 or DD drive */ int fm; /* fm mode */ int perp; /* perp mode */ int tpi; int capacity[4]; /* capacity per track */ } dens_tab[] = { { 0, 0, 0, 0}, /* none */ {2, 1, 0, 48, { 2500, 2500, 2500, 2500} }, /* SD */ {2, 0, 0, 48, { 6250, 6250, 6250, 6250} }, /* DD */ {1, 0, 0, 96, { 6250, 7500, 6250, 0} }, /* QD */ {0, 0, 0, 96, {12500,12500,10416, 0} }, /* HD */ {3, 0, 1, 96, {25000,25000, 0, 0} } /* ED */ }; int gap[4] = { 0x1b, 0x23, 0x2a, 0x1b }; static inline void set_field(field_t slot, int *var, int value) { if( !(mask & (1 << slot))) *var = value; } static void compute_params(drivedesc_t *drvprm, struct floppy_struct *medprm) { int r, capacity, mysize; int header_size, fmt_gap; set_field(F_DENSITY, drvprm->type.max_density); r = dens_tab[DENSITY].dtr; if(r == 2 && drvprm->type.rpm == 360) r = 1; capacity = dens_tab[DENSITY].capacity[drvprm->type.ff]; set_field(F_DTR, r); set_field(F_GAP, gap[DTR]); set_field(F_FM, dens_tab[DENSITY].fm); set_field(F_PERP, dens_tab[DENSITY].perp); set_field(F_HEAD, 2); /* 5 1/4 drives have two different cylinder densities */ if(drvprm->type.ff == FF_525) { if(DENSITY == DENS_DD) /* double density disks are 48 TPI */ set_field(F_TPI, 48); else set_field(F_TPI, 96); if(mask & (1 << FE_CYL)) { /* we know the number of cylinders, try to infer * cylinder density from there */ if(CYL < 50) set_field(F_TPI, 48); if(CYL > 70) set_field(F_TPI, 96); } if(drvprm->type.tpi == 96 && TPI == 48) set_field(F_STRETCH, 1); else set_field(F_STRETCH, 0); /* if, on the other hand, we know TPI, but not the number of * cylinders, infer in the other direction */ if(TPI == 48) set_field(F_CYL, 40); else set_field(F_CYL, 80); } else { set_field(F_STRETCH, 0); set_field(F_CYL, 80); } if(PERP) header_size = 81; else header_size = 62; switch(capacity) { case 25000: set_field(F_SECT, 36); break; case 12500: set_field(F_SECT, 18); break; case 10416: set_field(F_SECT, 15); break; case 6250: set_field(F_SECT, 9); break; default: set_field(F_SECT, capacity / (SSIZE + header_size + 1)); } set_field(F_SSIZE, 512); set_field(F_VSECT, SECT * SSIZE); set_field(F_SIZE, HEAD * CYL * VSECT / 512); if(mask & ( 1 << FE_SSIZE) ) { mysize = 128; for(ssize = 0; ssize < 8 ; ssize++) { if(mysize == SSIZE) break; mysize += mysize; } if(ssize == 8) { fprintf(stderr,"Bad sector size\n"); exit(1); } ssize = (ssize + 6) % 8; } else ssize = 0; if(VSECT && VSECT >= SSIZE) { fmt_gap = (capacity * 199 / 200 / (VSECT / SSIZE)) - SSIZE - header_size; if(fmt_gap < 1) fmt_gap = 1; if(fmt_gap > 0x6c) fmt_gap = 0x6c; set_field(F_FMT_GAP, fmt_gap); } set_field(F_2M,0); medprm->size = SIZE; medprm->sect = VSECT / 512; medprm->head = HEAD; medprm->track = CYL; medprm->stretch = STRETCH | (SWAPSIDES << 1) | (ZEROBASED << 2); medprm->gap = GAP; medprm->rate = (FM<<7) | (PERP<<6) | (ssize<<3) | (_2M<<2) | DTR; medprm->spec1 = SPEC1; medprm->fmt_gap = FMT_GAP; } /* ========================================= * * Routines called by other parts of fdutils * * ========================================= */ static int parse_indirect(int argc, char **argv, drivedesc_t *drvprm, struct floppy_struct *medprm) { int found; if(argc != 1) return 2; /* more than one parameter */ mediaprmin = fopen(MEDIAPRMFILE, "r"); if(!mediaprmin) return 2; /* no file */ zero_all(ids, &mask); found = 0; mediaprmlex(argv[0], ids, sizeof(ids)/sizeof(ids[0]), &mask, &found); fclose(mediaprmin); if(!found) return 1; compute_params(drvprm, medprm); return 0; } static int parse_direct(int argc, char **argv, drivedesc_t *drvprm, struct floppy_struct *medprm) { int i,r; mask = 0; zero_all(ids, &mask); for(i=0; i #include #include #include #include #include #include #include #include #include "oldfdprm.h" #define FDPRMFILE "/etc/fdprm" #define MAXLINE 200 static unsigned long convert(char *arg, int *error) { unsigned long result; char *end; result = strtoul(arg,&end,0); if (!*end) return result; *error = 1; return 0; } static int set_params(char **params, struct floppy_struct *ft) { int error; error = 0; ft->size = convert(params[0],&error); ft->sect = convert(params[1],&error); ft->head = convert(params[2],&error); ft->track = convert(params[3],&error); ft->stretch = convert(params[4],&error); ft->gap = convert(params[5],&error); ft->rate = convert(params[6],&error); ft->spec1 = convert(params[7],&error); ft->fmt_gap = convert(params[8],&error); return error; } int scan_fdprm(FILE *file, char *name, struct floppy_struct *ft, void (*callback)(char *name, char *comment, struct floppy_struct *ft)) { char line[MAXLINE+2],this[MAXLINE+2],param[9][MAXLINE+2]; char *params[9],*start; char *comment; int i, lineno; lineno = 0; while (fgets(line,MAXLINE,file)) { lineno++; for (start = line; *start == ' ' || *start == '\t'; start++); if (!*start || *start == '\n' || *start == '#') { /* comment line, print as is */ if(!name) printf("%s", line); continue; } comment = strchr(start, '#'); if(comment) { *comment='\0'; comment++; } if (sscanf(start,"%s %s %s %s %s %s %s %s %s %s",this,param[0], param[1],param[2],param[3],param[4],param[5],param[6], param[7],param[8]) != 10) { fprintf(stderr,"Syntax error in line %d: '%s'\n", lineno, line); exit(1); } for(i=0;i<9;i++) params[i]=param[i]; if(!name || !strcmp(this,name) ) { i=set_params(params, ft); if(name) return 0; else callback(this, comment, ft); } } return 1; } int parse_fdprm(int argc, char **argv, struct floppy_struct *ft) { FILE *f; int r; switch(argc) { case 1: /* indirect */ if ((f = fopen(FDPRMFILE,"r")) == NULL) return 1; r = scan_fdprm(f, argv[0], ft,0); fclose(f); return r; case 9: return set_params(argv, ft); default: return 1; } } fdutils-5.5-20060227/src/oldfdprm.h0000444000175000017500000000030307464324643015750 0ustar anibalanibalint scan_fdprm(FILE *f, char *name, struct floppy_struct *ft, void (*callback)(char *, char *, struct floppy_struct *)); int parse_fdprm(int argc, char **argv, struct floppy_struct *ft); fdutils-5.5-20060227/src/calc-format.c0000444000175000017500000002702210020207574016314 0ustar anibalanibal#include #include #include #include "superformat.h" #include "fdutils.h" #define GAP_DIVISOR (128*128) #define GAPSIZE(j) (( (128<= 0 && fd->last_sect[j] <= i; j--); return j; } static inline int firstSector(struct params *fd, int i) { if(i>=MAX_SIZECODE-1) return 1; else return fd->last_sect[i+1]; } static inline int lastSector(struct params *fd, int i) { return fd->last_sect[i]; } static inline int nrSectorsForSize(struct params *fd, int i) { return lastSector(fd, i) - firstSector(fd, i); } static inline int isMultisize(struct params *fd) { int i, n; n = 0; for(i = 1; i < MAX_SIZECODE; i++) { if(nrSectorsForSize(fd, i)) n++; } return n > 1; } static int compute_tot_size(struct params *fd, int chunksize, int gap, int tailsize) { int i, nr; fd->nssect = 0; fd->actual_interleave = 1; for(i= 0; i < MAX_SIZECODE; i++){ nr = nrSectorsForSize(fd, i); fd->nssect += chunks_in_sect(fd, i, gap, chunksize) * nr; if(nr && GAPSIZE(i) < 34) fd->actual_interleave = 2; } if (tailsize >= 0) return (fd->nssect - chunks_in_sect(fd, tailsize, gap, chunksize)) * chunksize + SSIZE(tailsize); else return fd->nssect * chunksize; } /* find out how many sectors of each size there are */ static void compute_sizes(struct params *fd, int remaining, /* bytes per track */ int max_sizecode) /* size of biggest sector used */ { int cur_sector; int sizes; /* number of different sizes found along the track */ int i; int nr_sectors; cur_sector = 1; sizes=0; for (i=MAX_SIZECODE-1; i>=0; --i) { if(i > max_sizecode) nr_sectors = 0; else { nr_sectors = remaining >> (i+7); remaining -= nr_sectors << (i+7); } cur_sector += nr_sectors; fd->last_sect[i] = cur_sector; if(nr_sectors) sizes++; } fd->dsect = cur_sector-1; /* number of data sectors */ if(sizes > 1) fd->need_init = 1; if (remaining) { fprintf(stderr,"Internal error: remaining not 0\n"); abort(); } } static int compute_gap(struct params *fd, int track_size) { int gap; gap = (fd->raw_capacity-track_size)*track_size/GAP_DIVISOR-header_size; if (gap > 0x6c * 32) /* kludge to allow to format at least the usual * formats on out of tolerance drives */ gap = 0x6c * 32; if (gap < 0) gap = 0; return gap; } /* * Determine the chunk size for disks which have same sized sectors. * We do this by dividing the sector size through ever increasing * divisors. t_chunksize = ceil( sector_size / divisor ) * We skip divisors yielding unreachable chunk sizes. */ static int compute_chunk_size_for_monosize(struct params *fd, int gap, int tailsize) { int min_chunksize; /* minimal chunk size reached so far */ int t_chunksize; /* tentative chunk size */ int ceiling; /* maximal divisor */ int t_sect_size; /* tentative sector size */ int min_sect_size=0; /* actual sector size */ int sector_size; int chunks_per_sect; int i; sector_size = SSIZE(sizeOfSector(fd,1)); min_chunksize = 0; ceiling = sector_size /( 129 + header_size); for(i= 1; i <= ceiling; i++ ){ t_chunksize = (sector_size - 1)/i + 1; /* unreachable chunk sizes */ if (((t_chunksize-header_size-1) & 511) > 255 && t_chunksize > 768 + header_size) continue; chunks_per_sect = (sector_size - 1)/t_chunksize + 1; t_sect_size = chunks_per_sect * t_chunksize; /* find the smallest sector size */ if (!min_chunksize || t_sect_size < min_sect_size ){ min_sect_size = t_sect_size; min_chunksize = t_chunksize; } if (t_sect_size == sector_size) break; } if(min_chunksize != sector_size) fd->need_init = 1; return min_chunksize; } static int compute_chunk_size_for_multisize(struct params *fd, int gap, int tailsize) { int t_chunksize; int tot_size; int min_chunksize; int i; int min_tot_size = 0; min_chunksize = 0; fd->need_init = 1; for(t_chunksize = fd->max_chunksize; t_chunksize > 128+header_size; t_chunksize--){ for(i=0; i < MAX_SIZECODE; i++ ){ if(t_chunksize<(128<= 6) printf("%d chasing %d\n", t_chunksize, min_chunksize); #endif min_tot_size = tot_size; min_chunksize = t_chunksize; } } return min_chunksize; } static void compute_chunk_size(struct params *fd, int gap, int tailsize) { if (isMultisize(fd)) fd->chunksize = compute_chunk_size_for_multisize(fd, gap, tailsize); else fd->chunksize = compute_chunk_size_for_monosize(fd, gap, tailsize); } /* convert chunksize to sizecode/fmt_gap pair */ static void convert_chunksize(struct params *fd) { int i; for (i=0; i < MAX_SIZECODE; ++i) { if (fd->chunksize < (128 << i) + header_size + 1) { fprintf(stderr,"Bad chunksize %d\n", fd->chunksize); exit(1); } if (fd->chunksize <= (128 << i) + 256 + header_size) { fd->sizecode = i; fd->fmt_gap = fd->chunksize - (128 << i) - header_size; break; } } if (i == MAX_SIZECODE){ fprintf(stderr,"Chunksize %d too big\n", fd->chunksize ); exit(1); } } /* * calculate the ordering of the sectors along the track in such * a way that the last one is sector number */ static void calc_sequence(struct params *fd, int tailsect) { int sec_id, cur_sector, i; fd->sequence = SafeNewArray(fd->dsect,struct fparm2); cur_sector = fd->dsect-1; /* construct the sequence while working backwards. cur_sector * points to the place where the next sector will be placed. * We place it, then move circularily backwards placing more * and more sectors */ sec_id = tailsect; fd->rotations = 0; for(i=0; i < fd->dsect; i++, cur_sector -= fd->actual_interleave, sec_id--) { if (sec_id == 0) sec_id = fd->dsect; if ( cur_sector < 0) { cur_sector += fd->dsect; if(sec_id != fd->dsect) fd->rotations++; } /* slot occupied, look elsewhere */ while(fd->sequence[cur_sector].sect ){ cur_sector--; if ( cur_sector < 0 ) { cur_sector += fd->dsect; if(sec_id != fd->dsect) fd->rotations++; } } /* place the sector */ fd->sequence[cur_sector].sect = sec_id; fd->sequence[cur_sector].size = sizeOfSector(fd, sec_id); } /* handle wrap-around between tailsect and tailsect+1 */ if(tailsect != fd->dsect) { /* always add one rotation, because tailsect+1 cannot be * at the last position, thus is necessarily earlyer */ fd->rotations++; if(fd->actual_interleave == 2 && cur_sector + fd->actual_interleave == 1) /* if we use interleave, and the last sector was * placed at the first last position, add one * extra rotation for tailsect+1 following tailsect * too closely */ fd->rotations++; } } /* given the sequence, calculate the exact placement of the sectors */ static void calc_placement(struct params *fd, int gap) { int cur_sector, i, max_offset; int track_end=0; int final_slack; /* slack space extending from data start of last * sector on the track to fd->raw_capacity mark */ /* now compute the placement in terms of small sectors */ cur_sector = 0; for(i=0; i< fd->dsect; i++){ fd->sequence[i].offset = cur_sector; max_offset = cur_sector; /* offset of the starting sector */ if ( fd->sequence[i].sect == 1 ) fd->min = cur_sector * fd->chunksize; /* offset of the end of the of the highest sector */ if (fd->sequence[i].sect == fd->dsect) track_end = cur_sector * fd->chunksize + header_size + index_size + SSIZE(fd->sequence[i].size); if(i == fd->dsect - 1) break; cur_sector += chunks_in_sect(fd, fd->sequence[i].size, gap, fd->chunksize); } final_slack = fd->raw_capacity - cur_sector * fd->chunksize - header_size - index_size - 1; if(final_slack < 0) { fprintf(stderr, "Internal error, negative final slack %d\n", final_slack); abort(); } fd->max = fd->min + final_slack; fd->length = fd->rotations * fd->raw_capacity + track_end - fd->min; if(fd->length < 0) { fprintf(stderr, "Internal error, negative track length %d %d %d\n", fd->length, track_end, fd->min); abort(); exit(1); } /* this format accepts any offsets ranging from fd->min to fd->max. * After this track, the current offset will be: * fd->track_end + initial_offset - fd->min */ } static int compute_chunks_per_sect(struct params *fd, int tracksize, int sizecode, int *gap, int mask, int tailsize) { int tot_size; if (! (mask & SET_FMTGAP)) *gap = compute_gap(fd, tracksize); while(1) { compute_chunk_size(fd, *gap, tailsize); tot_size=compute_tot_size(fd, fd->chunksize, *gap, tailsize); if(fd->raw_capacity >= tot_size) /* enough space available, ok */ break; if ((mask & SET_FMTGAP) || *gap <= 0) /* does not fit on disk */ return -1; *gap -= (tot_size-fd->raw_capacity) * GAP_DIVISOR / tracksize; if (*gap < 0) *gap = 0; } convert_chunksize(fd); if (mask & SET_INTERLEAVE) fd->actual_interleave = fd->preset_interleave; if(verbosity >= 9) { printf("%d raw bytes per cylinder\n", tot_size ); printf("%d final gap\n", fd->raw_capacity - tot_size ); } return 0; } static void compute_sector_sequence(struct params *fd, int tailsect, int gap) { calc_sequence(fd, tailsect); calc_placement(fd, gap); if (verbosity >= 9) printf("chunksize=%d\n", fd->chunksize); } static void compute_all_sequences_for_size(struct params *fd, int *offset, int tracksize, int sizecode, int gap, int mask, int tailsize) { int base = *offset; int i; /* no sectors of this size */ if(!nrSectorsForSize(fd, tailsize)) return; fd[*offset] = fd[0]; if(compute_chunks_per_sect(fd + *offset, tracksize, sizecode, &gap, /* gap. expressed in 1/256 bytes */ mask, tailsize) < 0) { /* not enough raw space for this arrangement */ return; } for(i = firstSector(fd, tailsize); i < lastSector(fd, tailsize); i++) { fd[*offset] = fd[base]; compute_sector_sequence(fd+*offset, i, gap); (*offset)++; } } int compute_all_sequences(struct params *fd, int tracksize, int sizecode, int gap, int mask, int biggest_last) { int offset, i; compute_sizes(fd, sectors*512,sizecode); offset = 0; for(i=MAX_SIZECODE - 1 ; i >= 0; i--) { compute_all_sequences_for_size(fd, &offset, tracksize, sizecode, gap, mask, i); if(biggest_last && offset) break; } if(! offset){ fprintf(stderr, "Not enough raw space on this disk for this format\n"); exit(1); } return offset; } void compute_track0_sequence(struct params *fd) { int i; int sectors; sectors= fd->nssect = fd->dsect; fd->length = fd->raw_capacity; fd->chunksize = 0x6c + 574; fd->need_init = 0; fd->sequence = SafeNewArray(fd->dsect,struct fparm2); fd->sizecode = 2; if ( fd->rate & 0x40 ) fd->fmt_gap = 0x54; else fd->fmt_gap = 0x6c; fd->min = 0; for(i=0; isequence[i].sect = i+1; fd->sequence[i].size = 2; fd->sequence[i].offset = i; } } fdutils-5.5-20060227/src/msdos_fs.h0000444000175000017500000000425507464324643015770 0ustar anibalanibal #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ #define packed __attribute__ ((packed)) #define p packed struct msdos_boot_sector { char jump[3] p; /* 0 - Boot strap short or near jump */ char banner[8] p; /* 3 - Name - can be used to special case partition manager volumes */ unsigned short sector_size p; /* 11 - bytes per logical sector */ unsigned char cluster_size p; /* 13 - sectors/cluster */ unsigned short res_sect p; /* 14 - reserved sectors */ unsigned char fats p; /* 16 - number of FATs */ unsigned short dir_entries p; /* 17 - root directory entries */ unsigned short sectors p; /* 19 - number of sectors */ unsigned char media p; /* 21 - media code (unused) */ unsigned short fat_length p; /* 22 - sectors/FAT */ unsigned short secs_track p; /* 24 - sectors per track */ unsigned short heads p; /* 26 - number of heads */ unsigned long hidden p; /* 28 - hidden sectors (unused) */ unsigned long total_sect p; /* 32 - number of sectors (if sectors == 0) */ unsigned char physdrive p; /* 36 physical drive ? */ unsigned char _reserved p; /* 37 reserved */ unsigned char dos4 p; /* 38 DOS > 4.0 diskette */ unsigned long serial p; /* 39 serial number */ unsigned char label[11] p; /* 43 disk label */ unsigned char fat_type[8] p; /* 54 FAT type */ #ifdef USE_2M unsigned char res_2m p; /* 62 reserved by 2M */ unsigned char CheckSum p; /* 63 2M checksum (not used) */ unsigned char fmt_2mf p; /* 64 2MF format version */ unsigned char wt p; /* 65 1 if write track after format */ unsigned char rate_0 p; /* 66 data transfer rate on track 0 */ unsigned char rate_any p; /* 67 data transfer rate on track<>0 */ unsigned short BootP p; /* 68 offset to boot program */ unsigned short Infp0 p; /* 70 T1: information for track 0 */ unsigned short InfpX p; /* 72 T2: information for track<>0 */ unsigned short InfTm p; /* 74 T3: track sectors size table */ unsigned char junk[126 - 76] p; /* 76 remaining data */ #else unsigned char junk[126 - 62] p; /* 76 remaining data */ #endif unsigned short bootid p; /* 510 should be 0xAA55 */ }; #undef p fdutils-5.5-20060227/src/parse.c0000444000175000017500000000141707464324643015255 0ustar anibalanibal#include #include #include "parse.h" int _set_int(char *name, keyword_t *ids, int size, int *mask) { int i, slot; char *ptr; int *var; ptr = strchr(name,'='); if(ptr) { *ptr = '\0'; ptr++; } for(i=0; i #ifdef HAVE_SYS_SYSMACROS_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "enh_options.h" #include "fdutils.h" #include "driveprm.h" #define NON_INTERACTIVE 1 long long gettime(void) { struct timeval tv; int ret; ret = gettimeofday(&tv, 0); if ( ret < 0 ){ perror("get time of day\n"); exit(1); } return ( (long long) tv.tv_usec + ( (long long) tv.tv_sec ) * 1000000LL); } int dtr[4] = { 500000, 300000, 250000, 1000000 }; struct { int time_per_rot; /* nominal time per rotation */ int sp_offset; int rate[3]; } cmos_table[]= { { 0, 0, { 0x100, 0x100, 0x100} }, /* no drive */ { 200000, 0, { 0x002, 0x100, 0x100} }, /* 5 1/4 DD */ { 200000, 0, { 0x002, 0x100, 0x100} }, /* 3 1/2 DD */ { 166666, 0, { 0x001, 0x000, 0x100} }, /* 5 1/4 HD */ { 200000, 0, { 0x002, 0x000, 0x100} }, /* 3 1/2 HD */ { 200000, 0, { 0x002, 0x000, 0x043} }, /* 3 1/2 ED */ { 200000, 0, { 0x002, 0x000, 0x043} } /* 3 1/2 ED */ }; struct reg { long long time; int rot; }; int sliding_avg(struct reg *reg, int n) { int i; long long sum_x, sum_y, sum_xy, sum_x2, sum2_x; sum_x = sum_y = sum_xy = sum_x2 = 0; for(i=0; i> 5); if(ioctl(fd, FDGETDRVPRM, &dpr) < 0) { perror("get drive parameter"); exit(1); } if(dpr.cmos < 1 || dpr.cmos > 6) { fprintf(stderr, "Bad cmos type\n"); exit(1); } if(density == 3) { do { density--; rate = cmos_table[(int) dpr.cmos].rate[density]; } while(rate >= 256); } else rate = cmos_table[(int) dpr.cmos].rate[density]; if(rate >= 256) { fprintf(stderr,"density not supported by this drive\n"); exit(1); } /* measure its capacity */ measure_raw_capacity(fd, dn, rate, cylinder, warmup, !(mask & NON_INTERACTIVE)); readid(fd, dn, rate, cylinder); base_time = last_time = gettime(); missed = rot = 0; avg = cmos_table[(int)dpr.cmos].time_per_rot; reg = (struct reg *) calloc(window, sizeof(struct reg)); for(j=0; j avg * 3 / 2) { /* if it takes unusually long, we may have missed one rotation */ rot += (time - last_time - avg / 2) / avg; missed += (time - last_time - avg / 2) / avg; } last_time = time; reg[j].time = time; reg[j].rot = rot; sum_x += rot; sum_y += time; sum_xy += rot * time; sum_x2 += rot * rot; sum2_x = sum_x * sum_x; n++; avg = ((n*sum_xy - sum_x*sum_y) / (n*sum_x2 - sum2_x)); if(!(mask & NON_INTERACTIVE)){ fprintf(stderr,"|%6d |%8d |%8d |%3d |\r", rot, (int)avg, sliding_avg(reg,window), missed); fflush(stderr); } j++; if(j>=window) j=0; } if(!(mask & NON_INTERACTIVE)) { fprintf(stderr,"\n"); fprintf(stderr, "|___________|___________|___________|_________|\n"); } cap = measure_raw_capacity(fd, dn, rate, cylinder, 0, !(mask & NON_INTERACTIVE)); shall_time = cmos_table[(int)dpr.cmos].time_per_rot; shall_cap = dtr[rate] * 2 * shall_time / 1000000LL; printf("\n"); printf("capacity=%d half bits (should be %d half bits)\n", cap, (int) shall_cap); printf("time_per_rotation=%d microseconds (should be %d)\n", (int) avg, (int) shall_time); my_dtr = ((long long)cap) * 500000 / avg; printf("data transfer rate=%d bits per second (should be %d)\n", (int) my_dtr, dtr[rate]); printf("\n"); printf("deviation on capacity: %+d ppm\n", (int) ((cap - shall_cap) * 1000000 / shall_cap)); printf("deviation on time_per_rotation: %+d ppm\n", (int) ((avg - shall_time) * 1000000 / shall_time)); printf("deviation on data transfer rate: %+d ppm\n", (int) ((my_dtr - dtr[rate]) * 1000000 / dtr[rate])); printf("\nInsert the following line to your " DRIVEPRMFILE " file:\n"); printf("drive%d: deviation=%d\n\n", dn, (int) ((cap - shall_cap) * 1000000 / shall_cap )); #if 0 margin = (shall_cap - cap + 15)/10; if(margin > 0) printf("recommended margin: %d\n", margin); #endif exit(0); } fdutils-5.5-20060227/src/mediaprm.lex0000444000175000017500000000207410446366017016302 0ustar anibalanibal%{ #include #include #include "parse.h" #include "mediaprmP.h" #include "mediaprm.h" static int lineno; static int col; %} %option noyywrap %option pointer fid [^\"]+ vid [A-Za-z_][A-Za-z0-9_-]* number (0x[a-zA-Z0-9]+|-?[0-9]+)(KB|k|b)? %% \n { col = 0; lineno++; } [ \t] { col++;} #.*\n { col = 0; lineno++;} \042{fid}\042: { col += yyleng; if(*found) return 0; _zero_all(ids, size, mask); yytext[yyleng-2]='\0'; if(!strcasecmp(yytext+1, name)) *found = 1; } alias=\042{fid}\042 { col += yyleng; yytext[yyleng-1]='\0'; if(!strcasecmp(yytext+7, name)) *found = 1; } swapsides | zerobased | zero-based | mss | 2m | 2M | ss | SS | ds | DS | sd | SD | dd | DD | qd | QD | hd | HD | ed | ED | {vid}={number} { col += yyleng; _set_int(yytext, ids, size, mask); } [^\t \n][^\t =\n]* { yytext[yyleng-1]='\0'; fprintf(stderr, "Syntax error in " MEDIAPRMFILE " at line %d col %d: %s unexpected\n", lineno+1, col+1, yytext_ptr); return 1; } %% fdutils-5.5-20060227/src/driveprm.c0000444000175000017500000000712310211673562015762 0ustar anibalanibal#include #ifdef HAVE_SYS_SYSMACROS_H # include #endif #include #include #include #include #include #include #include "parse.h" #include "driveprm.h" #include "driveprmP.h" typedef drive_field_t field_t; static int TPI, RPM, DEVIATION, FF, DENSITY, CMOS; #define F_CMOS FE__CMOS,&CMOS #define F_TPI FE__TPI,&TPI #define F_FF FE__FF,&FF #define F_RPM FE__RPM,&RPM #define F_DEVIATION FE__DEVIATION,&DEVIATION #define F_DENSITY FE__DENSITY,&DENSITY drivetypedesc_t cmos_types[]= { { 0, FF_UNKNOWN, DENS_UNKNOWN, 0, 0 }, { 1, FF_525, DENS_DD, 48, 300, 0 }, { 2, FF_525, DENS_HD, 96, 360, 0 }, { 3, FF_35, DENS_DD, 0, 300, 0 }, { 4, FF_35, DENS_HD, 0, 300, 0 }, { 5, FF_35, DENS_ED, 0, 300, 0 }, { 6, FF_35, DENS_ED, 0, 300, 0 } }; static keyword_t ids[]= { { "cmos", F_CMOS, 0}, { "tpi", F_TPI, 0 }, { "rpm", F_RPM, 0}, { "deviation", F_DEVIATION, 0}, { "sd", F_DENSITY, DENS_SD }, { "dd", F_DENSITY, DENS_DD }, { "qd", F_DENSITY, DENS_QD }, { "hd", F_DENSITY, DENS_HD }, { "ed", F_DENSITY, DENS_ED }, { "5.25", F_FF, FF_525 }, { "3.5", F_FF, FF_35 }, { "8", F_FF, FF_8 } }; static int mask; #define ISSET(x) ((mask) & ( 1 << FE__##x)) static void compute_params(drivedesc_t *drive) { /* initialize out array */ drive->type.cmos = 0; drive->type.ff = FF_UNKNOWN; drive->type.max_density = DENS_UNKNOWN; drive->type.tpi = 0; drive->type.rpm = 0; drive->type.deviation = 0; if(!ISSET(CMOS)) { if(ISSET(FF) && ISSET(DENSITY)) { switch(DENSITY) { case DENS_DD: if(FF == FF_525) CMOS = 1; else CMOS = 3; break; case DENS_HD: switch(FF) { case FF_525: CMOS = 2; break; case FF_35: CMOS = 4; break; } break; case DENS_ED: switch(FF) { case FF_35: CMOS = 6; break; } break; } } else { CMOS = drive->drvprm.cmos; if (CMOS < 1 || CMOS > 6) CMOS = 4; } } if(CMOS) { if(CMOS > 6 || CMOS < 1) { fprintf(stderr, "Bad cmos code %d\n", CMOS); exit(1); } drive->type = cmos_types[CMOS]; } if(ISSET(RPM)) drive->type.rpm = RPM; if(ISSET(TPI)) drive->type.tpi = TPI; if(ISSET(FF)) drive->type.ff = FF; if(ISSET(DENSITY)) drive->type.max_density = DENSITY; if(ISSET(RPM)) drive->type.rpm = RPM; if(ISSET(DEVIATION)) drive->type.deviation = DEVIATION; drive->mask = mask; } static int getdrivenum(int fd, struct stat *buf) { int num; if (fstat (fd, buf) < 0) { perror("Can't fstat drive"); exit(1); } if (!S_ISBLK(buf->st_mode) || major(buf->st_rdev) != FLOPPY_MAJOR) { fprintf(stderr,"Not a floppy drive\n"); exit(1); } num = minor( buf->st_rdev ); return (num & 3) + ((num & 0x80) >> 5); } /* ========================================= * * Routines called by other parts of fdutils * * ========================================= */ int parse_driveprm(int fd, drivedesc_t *drive) { int found; drive->drivenum = getdrivenum(fd, &drive->buf); if(drive->drivenum < 0) return -1; ioctl(fd, FDRESET, FD_RESET_IF_RAWCMD); if (ioctl(fd, FDGETDRVPRM, & drive->drvprm ) < 0 ){ perror("get drive characteristics"); exit(1); } zero_all(ids, &mask); driveprmin = fopen(DRIVEPRMFILE, "r"); if(driveprmin) { /* if the file doesn't exist, infer all info from the cmos type * stored in the floppy driver */ found = 0; driveprmlex(drive->drivenum, ids, sizeof(ids)/sizeof(ids[0]), &mask, &found); if(!found) zero_all(ids, &mask); fclose(driveprmin); } compute_params(drive); return 0; } fdutils-5.5-20060227/src/driveprm.h0000444000175000017500000000151707464324643016001 0ustar anibalanibal#ifndef DRIVEPRM_H #define DRIVEPRM_H #define DRIVEPRMFILE SYSCONFDIR "/driveprm" #include #include /* different densities */ typedef enum { DENS_UNKNOWN, DENS_SD, DENS_DD, DENS_QD, DENS_HD, DENS_ED } density_t; /* various drive form factors */ typedef enum { FF_UNKNOWN, FF_35, FF_525, FF_8 } ff_t; typedef struct { int cmos; ff_t ff; density_t max_density; /* maximal supported density */ int tpi; int rpm; int deviation; } drivetypedesc_t; /* drive descriptor */ typedef struct { drivetypedesc_t type; int drivenum; /* the drive number [0-7] */ struct stat buf; struct floppy_drive_params drvprm; int mask; } drivedesc_t; int parse_driveprm(int fd, drivedesc_t *drive); typedef enum { FE__UNKNOWN, FE__CMOS, FE__TPI, FE__FF, FE__RPM, FE__DEVIATION, FE__DENSITY, } drive_field_t; #endif fdutils-5.5-20060227/src/typescript0000444000175000017500000000020007464324643016115 0ustar anibalanibalScript started on Wed Apr 23 21:54:31 1997 > ]0;~/floppy/fdutils/src>  Script done on Wed Apr 23 21:54:33 1997 fdutils-5.5-20060227/src/fdrawcmd.c0000444000175000017500000002053710203641046015716 0ustar anibalanibal#include #include #include #include #include #include #include #include #include #include struct lookup_table { char *name; int cmd; int flags; } tabl[]= { { "read", FD_READ, FD_RAW_READ | FD_RAW_INTR }, { "read_track", 0x42, FD_RAW_READ | FD_RAW_INTR }, { "write", FD_WRITE, FD_RAW_WRITE | FD_RAW_INTR }, { "intr", 0, FD_RAW_INTR }, #ifdef FD_RAW_NO_MOTOR { "no_motor", 0, FD_RAW_NO_MOTOR }, { "no_motor_after", 0, FD_RAW_NO_MOTOR_AFTER }, #endif { "sensei", FD_SENSEI, 0 }, { "disk", 0, FD_RAW_NEED_DISK }, { "need_seek", 0, FD_RAW_NEED_SEEK }, { "spin", 0, FD_RAW_SPIN }, { "sense", FD_GETSTATUS, 0}, { "recalibrate", FD_RECALIBRATE, FD_RAW_INTR }, { "seek", FD_SEEK, FD_RAW_INTR }, #ifdef FD_RSEEK_OUT { "seek_out", FD_RSEEK_OUT, FD_RAW_INTR }, #endif #ifdef FD_RSEEK_IN { "seek_in", FD_RSEEK_IN, FD_RAW_INTR }, #endif #ifdef FD_LOCK { "lock", FD_LOCK, 0 }, { "unlock", FD_UNLOCK, 0 }, #endif { "specify", FD_SPECIFY, 0 }, { "format", FD_FORMAT, FD_RAW_WRITE | FD_RAW_INTR }, { "version", FD_VERSION, 0 }, { "configure", FD_CONFIGURE, 0 }, { "perpendicular", FD_PERPENDICULAR, 0 }, { "readid", FD_READID, FD_RAW_INTR }, { "dumpregs", FD_DUMPREGS, 0 }, #ifdef FD_SAVE { "save", FD_SAVE, 0 }, { "partid", FD_SAVE, 0 }, #endif #ifdef FD_FORMAT_N_WRITE { "format_n_write", FD_FORMAT_N_WRITE, FD_RAW_WRITE | FD_RAW_INTR }, { "restore", FD_RESTORE, 0 }, { "powerdown", FD_POWERDOWN, 0 }, { "option", FD_OPTION, 0 }, { "drivespec", FD_DRIVESPEC, 0 }, #endif { 0, 0, 0 } }; int print_time = 0; int do_buffer = 0; int do_short = 0; int tostdout = 0; FILE *f; int lookup(char *name, int *cmd, int *flags) { struct lookup_table *ptr; ptr = tabl; while ( ptr->name && strcmp(ptr->name, name) ) ptr++; if ( ! ptr->name) return 0; *cmd = ptr->cmd; *flags = ptr->flags; return 1; } long long new_gettime(void) { struct timeval tv; int ret; ret = gettimeofday(&tv, 0); if ( ret < 0 ){ perror("get time of day\n"); exit(1); } return ( (long long) tv.tv_usec + ( (long long) tv.tv_sec ) * 1000000LL); } void print_result(struct floppy_raw_cmd *raw_cmd, long long date) { int i; if ( do_short ){ if ( raw_cmd->flags & ( FD_RAW_READ | FD_RAW_WRITE )) fprintf(f,"%lu ", raw_cmd->length ); for( i=0; i< raw_cmd->reply_count; i++ ) fprintf(f,"0x%02x ", raw_cmd->reply[i] ); #ifdef FD_RAW_DISK_CHANGE if( raw_cmd->flags & FD_RAW_DISK_CHANGE) fprintf(f,"disk_change "); else fprintf(f,"no_disk_change "); #endif } else { if ( raw_cmd->flags & ( FD_RAW_READ | FD_RAW_WRITE )) fprintf(f,"remaining= %lu\n", raw_cmd->length ); for( i=0; i< raw_cmd->reply_count; i++ ) fprintf(f,"%d: %x\n", i, raw_cmd->reply[i] ); #ifdef FD_RAW_DISK_CHANGE if( raw_cmd->flags & FD_RAW_DISK_CHANGE) fprintf(f,"disk change\n"); else fprintf(f,"no disk change\n"); #endif } if ( print_time ) fprintf(f,"%Ld\n", date); else fprintf(f,"\n"); } int main(int argc, char **argv) { int have_flags=0; int delay=0; struct timeval tv; long long start_date; int i,tmp, flags, cmd, size, fd; char *drive,*s,*end; int repeat=1; struct floppy_raw_cmd raw_cmd; int r_flags; int e_flags; struct floppy_raw_cmd *results=0; long long *times=0; long long *timesb4=0; int fm_mode = 0; int nomt_mode = 0; char *eptr; char buffer[ 512 * 2 * 24 ]; f = stderr; raw_cmd.length= 512 * 2 * 24; raw_cmd.data = buffer; r_flags = e_flags = 0; raw_cmd.rate = 0; raw_cmd.track = 0; raw_cmd.cmd_count = 0; drive="/dev/fd0"; if (( s=getenv("length") ) || (s = getenv("LENGTH")) ) { raw_cmd.length= strtoul( s,& eptr, 0); switch(*eptr) { case 'b': raw_cmd.length *= 512; break; case 'k': case 'K': raw_cmd.length *= 1024; break; } } if ((s = getenv("rate") ) || (s = getenv("RATE")) ) raw_cmd.rate = strtoul( s,0,0); if ((s = getenv("track")) || (s = getenv("TRACK")) || (s = getenv("cylinder")) || (s = getenv("CYLINDER"))) { e_flags |= FD_RAW_NEED_SEEK; raw_cmd.track = strtoul( s,0,0); } if ((s = getenv("drive") ) || (s = getenv("DRIVE")) ) drive = s; fd = -1; while(argc){ argv++; argc--; r_flags = 0; have_flags = 0; for ( ; argc; argc--, argv++){ if (strcmp(";" , *argv ) == 0 ){ break; } if ((lookup( *argv, &cmd, &flags ))){ /* if this is a command, and we don't have a command * yet, use it as such */ if (cmd && raw_cmd.cmd_count == 0 ){ raw_cmd.cmd[raw_cmd.cmd_count++] = cmd; if(!have_flags) /* use the default flags from the command, if * we don't have an explicit flag set yet */ r_flags |= flags; } else { /* this is not a command. Always or it to the set of * of flags */ have_flags = 1; r_flags |= flags; } continue; } if ( strncmp( "length=", *argv, 7 ) == 0 ){ raw_cmd.length= strtoul( (*argv)+7,&eptr, 0); switch(*eptr) { case 'b': raw_cmd.length *= 512; break; case 'k': case 'K': raw_cmd.length *= 1024; break; } continue; } if ( strncmp( "rate=", *argv, 5 ) == 0 ){ raw_cmd.rate= strtoul( (*argv)+5,0,0); continue; } if ( strncmp( "track=", *argv, 6 ) == 0 ){ r_flags |= FD_RAW_NEED_SEEK; raw_cmd.track= strtoul( (*argv)+6,0,0); continue; } if ( strncmp( "cylinder=", *argv, 9 ) == 0 ){ r_flags |= FD_RAW_NEED_SEEK; raw_cmd.track= strtoul( (*argv)+9,0,0); continue; } if ( strncmp( "repeat=", *argv, 7 ) == 0 ){ repeat= strtoul( (*argv)+7,0,0); continue; } if ( strncmp( "delay=", *argv, 6 ) == 0 ){ delay= strtoul( (*argv)+6,0,0); continue; } if ( strncmp( "drive=", *argv, 6 ) == 0){ drive=(*argv)+6; continue; } if ( strcmp( "print_time", *argv) == 0){ print_time = 1; continue; } if ( strcmp( "do_buffer", *argv) == 0){ do_buffer = 1; continue; } if ( strcmp( "fm", *argv) == 0){ fm_mode = 1; continue; } if ( strcmp( "no-mt", *argv) == 0){ nomt_mode = 1; continue; } if ( strcmp( "short", *argv) == 0){ do_short = 1; continue; } if ( strcmp( "to_stdout", *argv) == 0){ f = stdout; continue; } if ( *argv[0] == '/' ){ drive = *argv; continue; } cmd = strtoul( *argv, &end, 0); if ( *end ){ fprintf(stderr,"Unrecognized keyword: %s\n", *argv ); exit(1); } if ( end == *argv ) continue; raw_cmd.cmd[raw_cmd.cmd_count++] = cmd; } if(fm_mode) raw_cmd.cmd[0] &= ~0x40; if(nomt_mode) raw_cmd.cmd[0] &= ~0x80; if ( r_flags & FD_RAW_WRITE ){ size = 0; while(1){ tmp=read(0, buffer+size, raw_cmd.length - size ); if ( tmp == 0 ){ raw_cmd.length = size ; break; } if ( tmp < 0 ){ perror("read"); exit(1); } size += tmp; if ( size == raw_cmd.length ) break; } } else size = raw_cmd.length; if ( *drive ){ if ( fd >= 0 ) close(fd); fd = strtoul(drive, &end, 0); if ( *end ){ fd = open( drive, O_ACCMODE | O_NDELAY); if ( fd < 0 ){ perror("open floppy"); exit(1); } } } if (do_buffer){ timesb4 =(long long *) calloc(repeat, sizeof(long long)); times =(long long *) calloc(repeat, sizeof(long long)); results = (struct floppy_raw_cmd *) calloc(repeat, sizeof(struct floppy_raw_cmd)); if ( !times || !results){ fprintf(stderr,"Out of memory error\n"); exit(1); } } start_date = new_gettime(); for ( i=0; i< repeat; i++){ if(do_buffer) timesb4[i] = new_gettime() - start_date; raw_cmd.flags = r_flags; tmp = ioctl( fd, FDRAWCMD, & raw_cmd ); if ( tmp < 0 ){ perror("raw cmd"); exit(1); } if ( !do_buffer ){ if ( r_flags & ( FD_RAW_READ )) write(1, buffer, size ); print_result(&raw_cmd, new_gettime() - start_date); } else { times[i] = new_gettime() - start_date; results[i] = raw_cmd; } if (delay){ tv.tv_sec = 0; tv.tv_usec = delay; select(0, 0,0,0, &tv); } } if (do_buffer) { for(i=0; i < repeat; i++){ print_result(results + i, times[i]); } } } close(fd); exit(0); } fdutils-5.5-20060227/src/mediaprm0000444000175000017500000002673710020206511015503 0ustar anibalanibal# /etc/fdprm - floppy disk parameter table ######################################################################## # Standard linux disk formats. Names are of the form # actual media capacity/maximum drive capacity # (Note: although 5.25" HD drives can format disks at 1.44M, they're listed # as 1200 because that's the common maximum size.) # size sec/t hds trk stre gap rate spec1 fmt_gap "360/360": DS DD sect=9 "1200/1200": DS HD sect=15 "360/720": SS DD sect=9 "720/720": DS DD sect=9 "360/1200": DS DD sect=9 "720/1200": DS QD sect=9 "1440/1440": DS HD sect=18 "2880/2880": DS ED sect=36 "2880/2880": DS ED sect=36 "2880/2880": DS ED sect=36 "1440/1200": DS HD sect=18 "1680/1440": DS HD sect=21 "410/1200": DS DD sect=10 cyl=41 "820/1440": DS DD sect=10 cyl=82 "1476/1200": DS HD sect=18 cyl=82 "1722/1440": DS HD sect=21 cyl=82 "420/1200": DS DD sect=10 cyl=42 "830/1440": DS DD sect=10 cyl=83 "1494/1200": DS HD sect=18 cyl=83 "1743/1440": DS HD sect=21 cyl=83 "1743/1440": DS HD sect=21 cyl=83 "880/1200": DS QD tracksize=11b ssize=1KB "1040/720": DS QD sect=13 "1120/720": DS QD tracksize=7KB mss "1600/1200": DS HD tracksize=10KB mss "1760/1440": DS HD sect=11 ssize=1KB "1920/1440": DS HD tracksize=12KB mss "3200/2880": DS ED sect=5 ssize=4KB "3520/2880": DS ED tracksize=22KB ssize=4KB "3840/2880": DS ED sect=3 ssize=8KB "3840/2880": DS ED sect=3 ssize=8KB "1840/1440": DS HD tracksize=23b ssize=2KB "800/720": DS DD sect=10 "1600/1440": DS HD sect=20 ######################################################################## # CP/M formats # # the name is constructed as CODsize, where COD identifies the # brand of the computer having formatted the disk # Generic CP/M - SSSD 8" "GEN250": SS DD sect=24 dtr=0 fm=1 cyl=77 ssize=128 # ABC-80 - SSDD 48 tpi 5.25" "ABC160": SS DD sect=16 ssize=256 # Actrix (Access Matrix) - SSDD 48 tpi 5.25" "ACT180": SS DD sect=9 # Adler Textriter - SSDD 48 tpi 5.25" "ADL160": SS DD sect=16 ssize=256 # Advanced Digital Super 6 - SSDD 48 tpi 5.25" "ADV160": SS DD sect=4 ssize=1KB # Advanced Digital Super 6 - DSDD 96 tpi 5.25" "ADV640": DS QD sect=4 ssize=1KB # Altos Series 5 - DSDD 96 tpi 5.25" "ALT720": DS QD sect=9 # Amigo - SSDD 48 tpi 5.25" "AMI200": SS DD sect=10 # Ampro - SSDD 48 tpi 5.25" "AMP200": SS DD sect=10 # Ampro - SSDD 96 tpi 5.25" "AMP400": SS QD sect=5 ssize=1KB # Amstrad PCW8256 - DSDD 96 tpi 5.25" "AMS720": DS QD sect=9 # Archive I - SSDD 96 tpi 5.25" "ARC400": SS QD sect=5 ssize=1KB # Archive II & III - DSDD 96 tpi 5.25" "ARC800": DS QD sect=5 ssize=1KB # Arisia - SSDD 48 tpi 5.25" "ARI180": SS DD sect=18 ssize=256 # ATR-8000 - SSDD 48 tpi 5.25" "ATR200": SS DD sect=5 ssize=1KB # Beehive - DSDD 48 tpi 5.25" "BEE400": DS DD sect=10 # Bitelex - SSDD 48 tpi 5.25" "BIT160": SS DD sect=16 ssize=256 # BMC IF800 Model 20 - DSDD 48 tpi 5.25" "BMC400": DS DD sect=10 # Burr-Brown - DSDD 48 tpi 5.25" "BUR360": DS DD sect=18 ssize=256 # Cal-PC - DSDD 48 tpi 5.25" "CAL400": DS DD sect=5 ssize=1KB # Cashcom 100 - DSDD 96 tpi 5.25" "CAS640": DS QD sect=4 ssize=1KB # CDI-5000 - DSDD 48 tpi 5.25" "CDI400": DS DD sect=5 ssize=1KB # CMC Supersystem 2 - DSDD 96 tpi 5.25" "CMC800": DS QD sect=5 ssize=1KB # Coleco ADAM, 40 track - SSDD 48 tpi 5.25" "COL160": SS DD sect=8 # Compugraphic MCS-5 - SSDD 48 tpi 5.25" "COM160": SS DD sect=16 ssize=256 # Compupro (Viasyn) (1024 bytes/sector) - DSDD 96 tpi 5.25" "COM800": DS QD sect=5 ssize=1KB # Cromemco CDOS - SSSD 48 tpi 5.25" "CRO80": SS SD sect=16 dtr=1 fm=1 ssize=128 # Cromemco CDOS - SSDD 48 tpi 5.25" "CRO200": SS DD sect=10 # Cromemco CP/M - SSDD 48 tpi 5.25" "CRO200": SS DD sect=10 # C/WP Cortex - SSDD 48 tpi 5.25" "CWP200": SS DD sect=10 # Cykey - DSDD 48 tpi 5.25" "CYK320": DS DD sect=16 ssize=256 # DEC DECMate II - SSDD 96 tpi 5.25" "DEC400": SS QD sect=10 # DEC Rainbow - SSDD 96 tpi 5.25" "DEC180": SS DD sect=9 # DEC VT-180 - SSDD 48 tpi 5.25" "DEC180": SS DD sect=9 # Direct 1025 - DSDD 48 tpi 5.25" "DIR320": DS DD sect=16 ssize=256 # Discovery - DSDD 96 tpi 5.25" "DIS640": DS QD sect=8 # Eagle II - SSDD 96 tpi 5.25" "EAG400": SS QD sect=5 ssize=1KB # Epson QX-10 - DSDD 48 tpi 5.25" "EPS400": DS DD sect=10 # Epson QX-10 (256 bytes/sector) - DSDD 48 tpi 5.25" "EPS320": DS DD sect=16 ssize=256 # Epson PX-8 - DSDD 3.5" "EPS320": DS DD sect=8 # Ericsson DTC - SSDD 96 tpi 5.25" "ERI320": SS QD sect=16 ssize=256 # Ericsson Step One - DSDD 96 tpi 5.25" "ERI720": DS QD sect=9 # Florida Graphics - DSDD 96 tpi 5.25" "FLO640": DS QD sect=16 ssize=256 # Formula 1 - DSDD 48 tpi 5.25" "FOR360": DS DD sect=18 ssize=256 # Fujitsu Micro 16 - DSDD 48 tpi 5.25" "FUJ320": DS DD sect=16 ssize=256 # Fujitsu Micro 8 - DSDD 48 tpi 5.25" "FUJ320": DS DD sect=16 ssize=256 # HCL System 2 - DSDD 96 tpi 5.25" "HCL800": DS QD sect=5 ssize=1KB # Heath H89, Magnolia CP/M - SSDD 48 tpi 5.25" "HEA180": SS DD sect=9 # Heurikon MLZ-91A - DSDD 96 tpi 5.25" "HEU640": DS QD sect=16 ssize=256 # IBM PC, CP/M-86 - SSDD 48 tpi 5.25" "IBM160": SS DD sect=8 # IMS 5000 - SSDD 48 tpi 5.25" "IMS160": SS DD sect=16 ssize=256 # IMS 5000 TurboDOS - DSDD 96 tpi 5.25" "IMS800": DS QD sect=5 ssize=1KB # Intel iPDS 100 - DSDD 96 tpi 5.25" "INT640": DS QD sect=16 ssize=256 # Insight Enterprises - DSDD 48 tpi 5.25" "INS320": DS DD sect=16 ssize=256 # Ithaca Intersystems - SSDD 96 tpi 5.25" "ITH360": SS QD sect=18 ssize=256 # Jet-80 - DSDD 48 tpi 5.25" "JET400": DS DD sect=5 ssize=1KB # Lexoriter - SSDD 48 tpi 5.25" "LEX160": SS DD sect=16 ssize=256 # LNW 2 - SSDD 48 tpi 5.25" "LNW180": SS DD sect=18 ssize=256 # Macsym 150 - SSDD 96 tpi 5.25" "MAC320": SS QD sect=8 # Magic - DSDD 48 tpi 5.25" "MAG400": DS DD sect=10 # MAI Basic Four - DSDD 96 tpi 5.25" "MAI640": DS QD sect=16 ssize=256 # Micron Quark - DSDD 48 tpi 5.25" "MIC320": DS DD sect=4 ssize=1KB # Monroe 8800 Series - SSDD 96 tpi 5.25" "MON320": SS QD sect=16 ssize=256 # Morrow MD2 - SSDD 48 tpi 5.25" "MOR200": SS DD sect=5 ssize=1KB # Morrow MD3, 5, 11, 16, 34 - DSDD 48 tpi 5.25" "MOR400": DS DD sect=5 ssize=1KB # Morrow TurboDOS - DSDD 48 tpi 5.25" "MOR320": DS DD sect=4 ssize=1KB # NCR FirstStep - DSDD 96 tpi 5.25" "NCR640": DS QD sect=16 ssize=256 # NEC PC-8001A - SSDD 48 tpi 5.25" "NEC160": SS DD sect=16 ssize=256 # NEC PC 8801A/8831A - DSDD 48 tpi 5.25" "NEC320": DS DD sect=8 # NEC PC 8500/8431A, Starlet - DSDD 3.5" "NEC320": SS QD sect=16 ssize=256 # Nixdorf 8810/30 - DSDD 96 tpi 5.25" "NIX800": DS QD sect=10 # OKI IF800 Model 20 - DSDD 48 tpi 5.25" "OKI400": DS DD sect=10 # Olivetti ETV300 - SSDD 48 tpi 5.25" "OLI180": SS DD sect=18 ssize=256 # Olivetti M20 - DSDD 48 tpi 5.25" "OLI320": DS DD sect=16 ssize=256 # Olivetti 250 - SSDD 3.5" "OLI320": SS QD sect=16 ssize=256 # Olympia EX-100 - DSDD 48 tpi 5.25" "OLY360": DS DD sect=9 # Olympia ETX II - SSDD 48 tpi 5.25" "OLY180": SS DD sect=9 # Osborne 1 - SSSD 48 tpi 5.25" "OSB100": SS SD sect=10 dtr=1 fm=1 ssize=256 # Osborne 1 - SSDD 48 tpi 5.25" "OSB200": SS DD sect=5 ssize=1KB # Osborne Executive - SSDD 48 tpi 5.25" "OSB200": SS DD sect=5 ssize=1KB # Osborne 1 + Osmosis - DSDD 96 tpi 5.25" "OSB400": DS DD sect=10 # Osborne Vixen - DSDD 48 tpi 5.25" "OSB400": DS DD sect=5 ssize=1KB # Osborne Executive w/Z3 - DSDD 96 tpi 5.25" "OSB800": DS QD sect=5 ssize=1KB # OSM Zeus 4 - DSDD 96 tpi 5.25" "OSM640": DS QD sect=8 # Panasonic KX-E828 - DSDD 48 tpi 5.25" "PAN320": DS DD sect=16 ssize=256 # Pegasus Data Logger - DSDD 48 tpi 5.25" "PEG360": DS DD sect=9 # Philips PC-2010 - SSDD 48 tpi 5.25" "PHI160": SS DD sect=16 ssize=256 # Philips PC-3000 - 3004 - SSDD 96 tpi 5.25" "PHI320": SS QD sect=16 ssize=256 # Pied Piper - DSDD 96 tpi 5.25" "PIE800": DS QD sect=10 # PMC Micromate - DSDD 48 tpi 5.25" "PMC400": DS DD sect=5 ssize=1KB # Proglas 770KB - DSDD 96 tpi 5.25" "PRO800": DS QD sect=10 # Royal Alphatronic - DSDD 48 tpi 5.25" "ROY320": DS DD sect=16 ssize=256 # Sage IV - DSDD 96 tpi 5.25" "SAG640": DS QD sect=8 # Sanyo MBC-1000, MBC-1150 - DSDD 48 tpi 5.25" "SAN320": DS DD sect=16 ssize=256 # Sanyo MBC-1250 - DSDD 96 tpi 5.25" "SAN640": DS QD sect=16 ssize=256 # Seequa Chameleon - SSDD 48 tpi 5.25" "SEE160": SS DD sect=8 # Seiko - DSDD 96 tpi 5.25" "SEI640": DS QD sect=16 ssize=256 # Siemens PG-685 - DSDD 96 tpi 5.25" "SIE720": DS QD sect=9 # Siemens PG-675 DSDD 48 tpi 5.25" "SIE360": DS DD sect=9 # Siemens PG-635 DSDD 3.5" "SIE720": DS QD sect=9 # Sorbus TurboDOS - 5.25" DSHD (or 8" DSDD) "SOR1232": DS HD sect=8 cyl=77 ssize=1KB # Sperry UTS 30, UTS 5000 - DSDD 96 tpi 5.25" "SPE720": DS QD sect=9 # Superbrain JR - SSDD 48 tpi 5.25" "SUP175": SS DD sect=10 cyl=35 # Superbrain 40 track - SSDD 48 tpi 5.25" "SUP200": SS DD sect=10 # Systel 2 - SSDD 48 tpi 5.25" "SYS180": SS DD sect=9 # Systel 3 - DSDD 48 tpi 5.25" "SYS360": DS DD sect=9 # Televideo 801, 806 - DSDD 48 tpi 5.25" "TEL360": DS DD sect=18 ssize=256 # Televideo 1603 - DSDD 96 tpi 5.25" "TEL720": DS QD sect=9 # TI Professional, CP/M-86 - SSDD 48 tpi 5.25" "TI1160": SS DD sect=8 # Toshiba T100, T200 - DSDD 48 tpi 5.25" "TOS320": DS DD sect=16 ssize=256 # TRS-80 Model 1, Omikron CP/M - SSSD 48 tpi 5.25" "TRS0": SS SD sect=16 dtr=1 fm=1 cyl=0 ssize=128 # TRS-80 Model 1, Color Power II - SSDD 48 tpi 5.25" "TRS180": SS DD sect=18 ssize=256 # TRS-80, MM CP/M - SSDD 48 tpi 5.25" "TRS200": SS DD sect=10 # TRS-80 Model 4, MT CP/M - SSDD 48 tpi 5.25" "TRS180": SS DD sect=18 ssize=256 # TRS-80 Model 4, MT CP/M - DSDD 48 tpi 5.25" "TRS360": DS DD sect=18 ssize=256 # TRS-80 Model 4 - SSDD 48 tpi 5.25" "TRS160": SS DD sect=8 # Visual 1050 - SSDD 96 tpi 5.25" "VIS400": SS QD sect=10 # Wangwriter - DSDD 48 tpi 5.25" "WAN320": DS DD sect=16 ssize=256 # Wave Mate Bullet - SSDD 48 tpi 5.25" "WAV200": SS DD sect=5 ssize=1KB # Xerox 820 - SSSD 48 tpi 5.25" "XER80": SS SD sect=16 dtr=1 fm=1 ssize=128 # Xerox 820 II - SSDD 48 tpi 5.25" "XER160": SS DD sect=16 ssize=256 # Zenith Z-37 Disk - SSSD 48 tpi 5.25" "ZEN100": SS SD sect=10 dtr=1 fm=1 ssize=256 # Zenith Z-37 Disk - DSDD 96 tpi 5.25" "ZEN640": DS QD sect=16 ssize=256 # Zenith Z89, Heath H89 - DSDD 48 tpi 5.25" "ZEN320": DS DD sect=16 ssize=256 # Zenith Z89, Heath H89 - DSDD 96 tpi 5.25" "ZEN640": DS QD sect=16 ssize=256 # Zenith Z90 - SSDD 48 tpi 5.25" "ZEN160": SS DD sect=16 ssize=256 # Zenith Z90 - DSDD 48 tpi 5.25" "ZEN320": DS DD sect=16 ssize=256 # Zenith Z-100 - SSDD 48 tpi 5.25" "ZEN160": SS DD sect=8 # Zenith Z-100 - DSDD 48 tpi 5.25" "ZEN320": DS DD sect=8 ######################################################################## # Other interesting formats, please contribute ;-) # # Commodore 1581 (the 3 1/2 drive of the Commodore 128) "CBM1581": DS DD sect=10 cyl=80 ssize=512 fmt_gap=35 gap=12 swapsides # CMD FD2000 disk drive, a third party floppy disk drive for the # Commodore line of computers with double of the capacity: "CMDFD2M": DS HD sect=10 cyl=81 ssize=1024 fmt_gap=100 gap=12 swapsides # Color computer, sides 1 and 2 "COCO1": SS DD sect=18 cyl=35 ssize=256 "COCO2": SS DD sect=18 cyl=35 ssize=256 # TRS-8- Color Computer os9 formats (to be confirmed). Needs # zero-based floppy patch "COCO360": DS DD sect=18 cyl=40 ssize=256 tpi=48 zero-based "COCO720": DS DD sect=18 cyl=80 ssize=256 tpi=96 zero-based # TO7 (Thomson), sides 1 and 2 "TO7-1": SS DD sect=16 ssize=256 "TO7-2": SS DD sect=16 ssize=256 swapsides fdutils-5.5-20060227/src/MAKEFLOPPIES0000555000175000017500000001173707560752410015604 0ustar anibalanibal#!/bin/sh # # MAKEFLOPPIES # # requires: expr # Note quirk of expr: if it prints "0", it always # returns "1" regardless of whether this makes sense! # # 1995.01.03 David Niemi Created set -e set -u MAJOR=2 TMPDEVICE=/dev/tmpfloppy$$ if [ ! -b /dev/fd0 ] ; then mknod /dev/fd0 b $MAJOR 0 fi if floppycontrol 2>/dev/null; then FLOPPYCONTROL=yes else FLOPPYCONTROL=no fi MINORNAMES='d360 h1200 D360 D720 h360 h720 H1440 E2880 CompaQ h1440 H1680 h410 H820 h1476 H1722 h420 H830 h1494 H1743 h880 D1040 D1120 h1600 H1760 H1920 E3200 E3520 E3840 H1840 D800 H1600' CMOSNAMES='360K_PC 1.2M_AT 720K 1.44M 2.88M_AMI_BIOS 2.88M' ## Used only with -t option CMOSLETTERS='d h D H E E' UCMOSLETTERS='d h u u u u' CMOSFORMATS='d h D DH DHE DHE' LOCAL= DRIVES= USAGE= TYPE_OVERRIDE=u REMAINDER= DRYRUN= VERBOSE= ## getword nth parameter of all the subsequent parameters getword () { if [ $# -lt 1 ]; then return fi if [ "$1" -lt 1 -o "$1" -ge $# ]; then return fi shift $1 echo $1 } basenumber() { if [ $1 -ge 4 ] ; then expr $1 + 124 else echo $1 fi } minorname () { if [ "$FLOPPYCONTROL" = no ]; then ## No floppycontrol program, so use default values getword "$1" $MINORNAMES else rm -f "$TMPDEVICE" mknod "$TMPDEVICE" b "$MAJOR" "$1" floppycontrol -T "$TMPDEVICE" 2>/dev/null || : rm -f "$TMPDEVICE" fi } cmosid () { if [ "$FLOPPYCONTROL" = yes ]; then case `minorname $1` in d360) echo 1 ;; h1200) echo 2 ;; D720) echo 3 ;; H1440) echo 4 ;; E2880) echo 6 ;; "(null)") echo none ;; "") echo none ;; *) echo unknown ;; esac elif [ "$1" = 0 ]; then echo 4 # 1.44MB default for drive 0 elif [ "$1" = 1 ]; then echo 2 # 1.2MB AT default for drive 1 else echo none # Nothing for everybody else fi } # main() PERMISSION=666 while [ $# -ge 1 -o -n "${REMAINDER}" ]; do if [ -n "$REMAINDER" ]; then ## Continue processing options stuck together ARG=$REMAINDER else ## Get a fresh argument ARG=$1 shift case "$ARG" in ## Remove dash in front of option(s) -?*) ARG=`expr "-$ARG" : '-*\(.*\)' || :` ;; esac fi ## Break compound options up case "$ARG" in ??*) REMAINDER=`expr "$ARG" : '.\(.*\)' || :` ARG=`expr "$ARG" : '\(.\)' || :` ;; *) REMAINDER= ;; esac case $ARG in ## Process drive number(s) [0-7]) DRIVES="$DRIVES $ARG" ;; [nN]) DRYRUN=yes ;; ## Make devices in current directory, not /dev [lL]) LOCAL=yes ;; ## Base device name on drive type [tT]) TYPE_OVERRIDE=yes ;; [dD]) TYPE_OVERRIDE=yes ;; ## Base device name on media type [mM]) TYPE_OVERRIDE=no ;; ## New naming scheme [uU]) TYPE_OVERRIDE=no ;; [vV]) VERBOSE=yes ;; ## Allow access only for group floppy [gG]) PERMISSION=660 ;; *) echo "$0: unrecognized argument \"$ARG\"." >&2 USAGE=yes ;; esac done if [ -n "$USAGE" ]; then echo "Usage: $0 [