(root)/
util-linux-2.39/
disk-utils/
fdformat.c
       1  /*
       2   * fdformat.c  -  Low-level formats a floppy disk - Werner Almesberger
       3   */
       4  #include <errno.h>
       5  #include <fcntl.h>
       6  #include <getopt.h>
       7  #include <linux/fd.h>
       8  #include <stdio.h>
       9  #include <stdlib.h>
      10  #include <sys/ioctl.h>
      11  #include <sys/stat.h>
      12  #include <unistd.h>
      13  
      14  #include "c.h"
      15  #include "blkdev.h"
      16  #include "strutils.h"
      17  #include "closestream.h"
      18  #include "nls.h"
      19  #include "xalloc.h"
      20  
      21  #define SECTOR_SIZE 512
      22  
      23  static struct floppy_struct param;
      24  
      25  
      26  static void format_begin(int ctrl)
      27  {
      28  	if (ioctl(ctrl, FDFMTBEG, NULL) < 0)
      29  		err(EXIT_FAILURE, "ioctl: FDFMTBEG");
      30  }
      31  
      32  static void format_end(int ctrl)
      33  {
      34  	if (ioctl(ctrl, FDFMTEND, NULL) < 0)
      35  		err(EXIT_FAILURE, "ioctl: FDFMTEND");
      36  }
      37  
      38  static void format_track_head(int ctrl, struct format_descr *descr)
      39  {
      40  	if (ioctl(ctrl, FDFMTTRK, (long) descr) < 0)
      41  		err(EXIT_FAILURE, "ioctl: FDFMTTRK");
      42  }
      43  
      44  static void seek_track_head(int ctrl, struct format_descr *descr)
      45  {
      46  	lseek(ctrl, ((off_t) descr->track * param.head + descr->head)
      47  			* param.sect * SECTOR_SIZE, SEEK_SET);
      48  }
      49  
      50  static void format_disk(int ctrl, unsigned int track_from, unsigned int track_to)
      51  {
      52  	struct format_descr current;
      53  
      54  	printf(_("Formatting ... "));
      55  	fflush(stdout);
      56  
      57  	format_begin(ctrl);
      58  
      59  	for (current.track = track_from; current.track <= track_to; current.track++) {
      60  		for (current.head = 0; current.head < param.head; current.head++) {
      61  			printf("%3u/%u\b\b\b\b\b", current.track, current.head);
      62  			fflush(stdout);
      63  			format_track_head(ctrl, &current);
      64  		}
      65  	}
      66  
      67  	format_end(ctrl);
      68  
      69  	printf("     \b\b\b\b\b%s", _("done\n"));
      70  }
      71  
      72  static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair)
      73  {
      74  	unsigned char *data;
      75  	struct format_descr current;
      76  	int track_size, count;
      77  	unsigned int retries_left;
      78  
      79  	track_size = param.sect * SECTOR_SIZE;
      80  	data = xmalloc(track_size);
      81  	printf(_("Verifying ... "));
      82  	fflush(stdout);
      83  
      84  	current.track = track_from;
      85  	current.head = 0;
      86  	seek_track_head (ctrl, &current);
      87  
      88  	for (current.track = track_from; current.track <= track_to; current.track++) {
      89  		for (current.head = 0; current.head < param.head; current.head++) {
      90  			int read_bytes;
      91  
      92  			printf("%3u\b\b\b", current.track);
      93  			fflush(stdout);
      94  
      95  			retries_left = repair;
      96  			do {
      97  				read_bytes = read(ctrl, data, track_size);
      98  				if (read_bytes != track_size) {
      99  					if (retries_left) {
     100  						format_begin(ctrl);
     101  						format_track_head(ctrl, &current);
     102  						format_end(ctrl);
     103  						seek_track_head (ctrl, &current);
     104  						retries_left--;
     105  						if (retries_left)
     106  							continue;
     107  					}
     108  					if (read_bytes < 0)
     109  						perror(_("Read: "));
     110  					fprintf(stderr,
     111  						_("Problem reading track/head %u/%u,"
     112  						  " expected %d, read %d\n"),
     113  						current.track, current.head, track_size, read_bytes);
     114  					free(data);
     115  					exit(EXIT_FAILURE);
     116  				}
     117  				for (count = 0; count < track_size; count++)
     118  					if (data[count] != FD_FILL_BYTE) {
     119  						if (retries_left) {
     120  							format_begin(ctrl);
     121  							format_track_head(ctrl, &current);
     122  							format_end(ctrl);
     123  							seek_track_head (ctrl, &current);
     124  							retries_left--;
     125  							if (retries_left)
     126  								continue;
     127  						}
     128  						printf(_("bad data in track/head %u/%u\n"
     129  							 "Continuing ... "), current.track, current.head);
     130  						fflush(stdout);
     131  						break;
     132  					}
     133  				break;
     134  			} while (retries_left);
     135  		}
     136  	}
     137  
     138  	free(data);
     139  	printf(_("done\n"));
     140  }
     141  
     142  static void __attribute__((__noreturn__)) usage(void)
     143  {
     144  	FILE *out = stdout;
     145  	fputs(USAGE_HEADER, out);
     146  	fprintf(out, _(" %s [options] <device>\n"),
     147  		program_invocation_short_name);
     148  
     149  	fputs(USAGE_SEPARATOR, out);
     150  	fputs(_("Do a low-level formatting of a floppy disk.\n"), out);
     151  
     152  	fputs(USAGE_OPTIONS, out);
     153  	fputs(_(" -f, --from <N>    start at the track N (default 0)\n"), out);
     154  	fputs(_(" -t, --to <N>      stop at the track N\n"), out);
     155  	fputs(_(" -r, --repair <N>  try to repair tracks failed during\n"
     156                  "                     the verification (max N retries)\n"), out);
     157  	fputs(_(" -n, --no-verify   disable the verification after the format\n"), out);
     158  
     159  	fputs(USAGE_SEPARATOR, out);
     160  	printf(USAGE_HELP_OPTIONS(19));
     161  	printf(USAGE_MAN_TAIL("fdformat(8)"));
     162  
     163  	exit(EXIT_SUCCESS);
     164  }
     165  
     166  int main(int argc, char **argv)
     167  {
     168  	int ch;
     169  	int ctrl;
     170  	int verify = 1;
     171  	unsigned int repair = 0;
     172  	unsigned int track_from = 0;
     173  	unsigned int track_to = 0;
     174  	int has_user_defined_track_to = 0;
     175  	struct stat st;
     176  
     177  	static const struct option longopts[] = {
     178  		{"from", required_argument, NULL, 'f'},
     179  		{"to", required_argument, NULL, 't'},
     180  		{"repair", required_argument, NULL, 'r'},
     181  		{"no-verify", no_argument, NULL, 'n'},
     182  		{"version", no_argument, NULL, 'V'},
     183  		{"help", no_argument, NULL, 'h'},
     184  		{NULL, 0, NULL, 0}
     185  	};
     186  
     187  	setlocale(LC_ALL, "");
     188  	bindtextdomain(PACKAGE, LOCALEDIR);
     189  	textdomain(PACKAGE);
     190  	close_stdout_atexit();
     191  
     192  	while ((ch = getopt_long(argc, argv, "f:t:r:nVh", longopts, NULL)) != -1)
     193  		switch (ch) {
     194  		case 'f':
     195  			track_from = strtou32_or_err(optarg, _("invalid argument - from"));
     196  			break;
     197  		case 't':
     198  			has_user_defined_track_to = 1;
     199  			track_to = strtou32_or_err(optarg, _("invalid argument - to"));
     200  			break;
     201  		case 'r':
     202  			repair = strtou32_or_err(optarg, _("invalid argument - repair"));
     203  			break;
     204  		case 'n':
     205  			verify = 0;
     206  			break;
     207  		case 'V':
     208  			print_version(EXIT_SUCCESS);
     209  		case 'h':
     210  			usage();
     211  		default:
     212  			errtryhelp(EXIT_FAILURE);
     213  		}
     214  
     215  	argc -= optind;
     216  	argv += optind;
     217  
     218  	if (argc < 1) {
     219  		warnx(_("no device specified"));
     220  		errtryhelp(EXIT_FAILURE);
     221  	}
     222  	if (stat(argv[0], &st) < 0)
     223  		err(EXIT_FAILURE, _("stat of %s failed"), argv[0]);
     224  	if (!S_ISBLK(st.st_mode))
     225  		/* do not test major - perhaps this was a USB floppy */
     226  		errx(EXIT_FAILURE, _("%s: not a block device"), argv[0]);
     227  	ctrl = open_blkdev_or_file(&st, argv[0], O_RDWR);
     228  	if (ctrl < 0)
     229  		err(EXIT_FAILURE, _("cannot open %s"), argv[0]);
     230  	if (ioctl(ctrl, FDGETPRM, (long) &param) < 0)
     231  		err(EXIT_FAILURE, _("could not determine current format type"));
     232  
     233  	printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"),
     234  		(param.head == 2) ? _("Double") : _("Single"),
     235  		param.track, param.sect, param.size >> 1);
     236  
     237  	if (!has_user_defined_track_to)
     238  		track_to = param.track - 1;
     239  
     240  	if (track_from >= param.track)
     241  		err(EXIT_FAILURE, _("user defined start track exceeds the medium specific maximum"));
     242  	if (track_to >= param.track)
     243  		err(EXIT_FAILURE, _("user defined end track exceeds the medium specific maximum"));
     244  	if (track_from > track_to)
     245  		err(EXIT_FAILURE, _("user defined start track exceeds the user defined end track"));
     246  
     247  	format_disk(ctrl, track_from, track_to);
     248  
     249  	if (verify)
     250  		verify_disk(ctrl, track_from, track_to, repair);
     251  
     252  	if (close_fd(ctrl) != 0)
     253  		err(EXIT_FAILURE, _("close failed"));
     254  
     255  	return EXIT_SUCCESS;
     256  }