Home | History | Annotate | Download | only in format
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * This file contains the main entry point of the program and other
     28  * routines relating to the general flow.
     29  */
     30 #include "global.h"
     31 #include <stdio.h>
     32 #include <unistd.h>
     33 #include <stdlib.h>
     34 #include <signal.h>
     35 #include <memory.h>
     36 #include <string.h>
     37 #include <errno.h>
     38 
     39 #ifdef sparc
     40 #include <sys/hdio.h>
     41 #include <sys/dkbad.h>
     42 #endif
     43 
     44 #include <sys/time.h>
     45 #include "main.h"
     46 #include "analyze.h"
     47 #include "menu.h"
     48 #include "param.h"
     49 #include "misc.h"
     50 #include "startup.h"
     51 #include "menu_command.h"
     52 #include "menu_partition.h"
     53 #include "prompts.h"
     54 #include "checkdev.h"
     55 #include "label.h"
     56 
     57 extern	struct menu_item menu_command[];
     58 
     59 #ifdef	__STDC__
     60 
     61 /*
     62  *	Local prototypes for ANSI C compilers
     63  */
     64 static void	get_disk_characteristics(void);
     65 
     66 
     67 #else	/* __STDC__ */
     68 
     69 /*
     70  *	Local prototypes for non-ANSI C compilers
     71  */
     72 static void	get_disk_characteristics();
     73 
     74 #endif	/* __STDC__ */
     75 
     76 /*
     77  * This is the main entry point.
     78  */
     79 int
     80 main(int argc, char *argv[])
     81 {
     82 	int	i;
     83 	int	ret_code = 1;
     84 	char	**arglist;
     85 	struct	disk_info *disk = NULL;
     86 	struct	disk_type *type, *oldtype;
     87 	struct	partition_info *parts;
     88 	struct	sigaction act;
     89 
     90 	solaris_offset = 0;
     91 	/*
     92 	 * Initialize cur_ctype to avoid null pointer dereference
     93 	 * in auto_efi_sense().
     94 	 */
     95 	cur_ctype = (struct ctlr_type *)NULL;
     96 	/*
     97 	 * Decode the command line options.
     98 	 */
     99 	i = do_options(argc, argv);
    100 	/*
    101 	 * If we are to run from a command file, open it up.
    102 	 */
    103 	if (option_f) {
    104 		if (freopen(option_f, "r", stdin) == NULL) {
    105 			err_print("Unable to open command file '%s'.\n",
    106 			    option_f);
    107 			fullabort();
    108 		}
    109 	}
    110 	/*
    111 	 * If we are logging, open the log file.
    112 	 */
    113 	if (option_l) {
    114 		if ((log_file = fopen(option_l, "w")) == NULL) {
    115 			err_print("Unable to open log file '%s'.\n",
    116 			    option_l);
    117 			fullabort();
    118 		}
    119 	}
    120 	/*
    121 	 * Read in the data file and initialize the hardware structs.
    122 	 */
    123 	sup_init();
    124 	/*
    125 	 * If there are no disks on the command line, search the
    126 	 * appropriate device directory for character devices that
    127 	 * look like disks.
    128 	 */
    129 	if (i < 0) {
    130 		arglist = (char **)NULL;
    131 	/*
    132 	 * There were disks on the command line.  They comprise the
    133 	 * search list.
    134 	 */
    135 	} else {
    136 		arglist = &argv[i];
    137 	}
    138 	/*
    139 	 * Perform the search for disks.
    140 	 */
    141 	do_search(arglist);
    142 	/*
    143 	 * Catch ctrl-C and ctrl-Z so critical sections can be
    144 	 * implemented.  We use sigaction, as this sets up the
    145 	 * signal handler permanently, and also automatically
    146 	 * restarts any interrupted system call.
    147 	 */
    148 	act.sa_handler = cmdabort;
    149 	(void) memset(&act.sa_mask, 0, sizeof (sigset_t));
    150 	act.sa_flags = SA_RESTART | SA_NODEFER;
    151 	if (sigaction(SIGINT, &act, (struct sigaction *)NULL) == -1) {
    152 		err_print("sigaction(SIGINT) failed - %s\n",
    153 		    strerror(errno));
    154 		fullabort();
    155 	}
    156 
    157 	act.sa_handler = onsusp;
    158 	(void) memset(&act.sa_mask, 0, sizeof (sigset_t));
    159 	act.sa_flags = SA_RESTART | SA_NODEFER;
    160 	if (sigaction(SIGTSTP, &act, (struct sigaction *)NULL) == -1) {
    161 		err_print("sigaction(SIGTSTP) failed - %s\n",
    162 		    strerror(errno));
    163 		fullabort();
    164 	}
    165 
    166 	act.sa_handler = onalarm;
    167 	(void) memset(&act.sa_mask, 0, sizeof (sigset_t));
    168 	act.sa_flags = SA_RESTART;
    169 	if (sigaction(SIGALRM, &act, (struct sigaction *)NULL) == -1) {
    170 		err_print("sigaction(SIGALRM) failed - %s\n",
    171 		    strerror(errno));
    172 		fullabort();
    173 	}
    174 
    175 	/*
    176 	 * If there was only 1 disk on the command line, mark it
    177 	 * to be the current disk.  If it wasn't found, it's an error.
    178 	 */
    179 	if (i == argc - 1) {
    180 		disk = disk_list;
    181 		if (disk == NULL) {
    182 			err_print("Unable to find specified disk '%s'.\n",
    183 			    argv[i]);
    184 			fullabort();
    185 		}
    186 	}
    187 	/*
    188 	 * A disk was forced on the command line.
    189 	 */
    190 	if (option_d) {
    191 		/*
    192 		 * Find it in the list of found disks and mark it to
    193 		 * be the current disk.
    194 		 */
    195 		for (disk = disk_list; disk != NULL; disk = disk->disk_next)
    196 			if (diskname_match(option_d, disk))
    197 				break;
    198 		/*
    199 		 * If it wasn't found, it's an error.
    200 		 */
    201 		if (disk == NULL) {
    202 			err_print("Unable to find specified disk '%s'.\n",
    203 			    option_d);
    204 			fullabort();
    205 		}
    206 	}
    207 	/*
    208 	 * A disk type was forced on the command line.
    209 	 */
    210 	if (option_t != NULL) {
    211 		/*
    212 		 * Only legal if a disk was also forced.
    213 		 */
    214 		if (disk == NULL) {
    215 			err_print("Must specify disk as well as type.\n");
    216 			fullabort();
    217 		}
    218 		oldtype = disk->disk_type;
    219 		/*
    220 		 * Find the specified type in the list of legal types
    221 		 * for the disk.
    222 		 */
    223 		for (type = disk->disk_ctlr->ctlr_ctype->ctype_dlist;
    224 		    type != NULL; type = type->dtype_next)
    225 			if (strcmp(option_t, type->dtype_asciilabel) == 0)
    226 				break;
    227 		/*
    228 		 * If it wasn't found, it's an error.
    229 		 */
    230 		if (type == NULL) {
    231 			err_print(
    232 "Specified type '%s' is not a known type.\n", option_t);
    233 			fullabort();
    234 		}
    235 		/*
    236 		 * If the specified type is not the same as the type
    237 		 * in the disk label, update the type and nullify the
    238 		 * partition map.
    239 		 */
    240 		if (type != oldtype) {
    241 			disk->disk_type = type;
    242 			disk->disk_parts = NULL;
    243 		}
    244 	}
    245 	/*
    246 	 * A partition map was forced on the command line.
    247 	 */
    248 	if (option_p) {
    249 		/*
    250 		 * Only legal if both disk and type were also forced.
    251 		 */
    252 		if (disk == NULL || disk->disk_type == NULL) {
    253 			err_print("Must specify disk and type as well ");
    254 			err_print("as partitiion.\n");
    255 			fullabort();
    256 		}
    257 		/*
    258 		 * Find the specified map in the list of legal maps
    259 		 * for the type.
    260 		 */
    261 		for (parts = disk->disk_type->dtype_plist; parts != NULL;
    262 		    parts = parts->pinfo_next)
    263 			if (strcmp(option_p, parts->pinfo_name) == 0)
    264 				break;
    265 		/*
    266 		 * If it wasn't found, it's an error.
    267 		 */
    268 		if (parts == NULL) {
    269 			err_print(
    270 "Specified table '%s' is not a known table.\n", option_p);
    271 			fullabort();
    272 		}
    273 		/*
    274 		 * Update the map.
    275 		 */
    276 		disk->disk_parts = parts;
    277 	}
    278 	/*
    279 	 * If a disk was marked to become current, initialize the state
    280 	 * to make it current.  If not, ask user to pick one.
    281 	 */
    282 	if (disk != NULL) {
    283 		init_globals(disk);
    284 	} else if (option_f == 0 && option_d == 0) {
    285 		while (ret_code) {
    286 			ret_code = c_disk();
    287 		}
    288 	}
    289 
    290 #ifdef	BUG1134748
    291 	/*
    292 	 * if -f command-file is specified, check for disk and disktype
    293 	 * input also. For SCSI disks, the type input may not be needed
    294 	 * since format would have figured that using inquiry information.
    295 	 */
    296 	if (option_f) {
    297 		if (cur_disk == NULL) {
    298 			err_print("Must specify a disk using -d option.\n");
    299 			fullabort();
    300 		}
    301 		if (cur_dtype == NULL) {
    302 			err_print("Must specify disk as well as type.\n");
    303 			fullabort();
    304 		}
    305 	}
    306 #endif	/* BUG1134748 */
    307 
    308 	/*
    309 	 * Run the command menu.
    310 	 */
    311 	cur_menu = last_menu = 0;
    312 	run_menu(menu_command, "FORMAT", "format", 1);
    313 
    314 	/*
    315 	 * normal ending. Explicitly return(0);
    316 	 */
    317 	return (0);
    318 }
    319 
    320 /*
    321  * This routine initializes the internal state to ready it for a new
    322  * current disk.  There are a zillion state variables that store
    323  * information on the current disk, and they must all be updated.
    324  * We also tell SunOS about the disk, since it may not know if the
    325  * disk wasn't labeled at boot time.
    326  */
    327 void
    328 init_globals(disk)
    329 	struct	disk_info *disk;
    330 {
    331 	int		status;
    332 	int		found_mount;
    333 	int		found_inuse;
    334 #ifdef sparc
    335 	int		i;
    336 	caddr_t		bad_ptr = (caddr_t)&badmap;
    337 #endif
    338 
    339 	/*
    340 	 * If there was an old current disk, close the file for it.
    341 	 */
    342 	if (cur_disk != NULL)
    343 		(void) close(cur_file);
    344 	/*
    345 	 * Kill off any defect lists still lying around.
    346 	 */
    347 	kill_deflist(&cur_list);
    348 	kill_deflist(&work_list);
    349 	/*
    350 	 * If there were any buffers, free them up.
    351 	 */
    352 	if ((char *)cur_buf != NULL) {
    353 		destroy_data((char *)cur_buf);
    354 		cur_buf = NULL;
    355 	}
    356 	if ((char *)pattern_buf != NULL) {
    357 		destroy_data((char *)pattern_buf);
    358 		pattern_buf = NULL;
    359 	}
    360 	/*
    361 	 * Fill in the hardware struct pointers for the new disk.
    362 	 */
    363 	cur_disk = disk;
    364 	cur_dtype = cur_disk->disk_type;
    365 	cur_label = cur_disk->label_type;
    366 	cur_ctlr = cur_disk->disk_ctlr;
    367 	cur_parts = cur_disk->disk_parts;
    368 	cur_blksz = cur_disk->disk_lbasize;
    369 	cur_ctype = cur_ctlr->ctlr_ctype;
    370 	cur_ops = cur_ctype->ctype_ops;
    371 	cur_flags = 0;
    372 	/*
    373 	 * Open a file for the new disk.
    374 	 */
    375 	if ((cur_file = open_disk(cur_disk->disk_path,
    376 					O_RDWR | O_NDELAY)) < 0) {
    377 		err_print(
    378 "Error: can't open selected disk '%s'.\n", cur_disk->disk_name);
    379 		fullabort();
    380 	}
    381 #ifdef sparc
    382 	/*
    383 	 * If the new disk uses bad-144, initialize the bad block table.
    384 	 */
    385 	if (cur_ctlr->ctlr_flags & DKI_BAD144) {
    386 		badmap.bt_mbz = badmap.bt_csn = badmap.bt_flag = 0;
    387 		for (i = 0; i < NDKBAD; i++) {
    388 			badmap.bt_bad[i].bt_cyl = -1;
    389 			badmap.bt_bad[i].bt_trksec = -1;
    390 		}
    391 	}
    392 #endif
    393 	/*
    394 	 * If the type of the new disk is known...
    395 	 */
    396 	if (cur_dtype != NULL) {
    397 		/*
    398 		 * Initialize the physical characteristics.
    399 		 * If need disk specs, prompt for undefined disk
    400 		 * characteristics.  If running from a file,
    401 		 * use defaults.
    402 		 */
    403 		if (cur_dtype->dtype_flags & DT_NEED_SPEFS) {
    404 			get_disk_characteristics();
    405 			cur_dtype->dtype_flags &= ~DT_NEED_SPEFS;
    406 		}
    407 
    408 		ncyl = cur_dtype->dtype_ncyl;
    409 		acyl = cur_dtype->dtype_acyl;
    410 		pcyl = cur_dtype->dtype_pcyl;
    411 		nhead = cur_dtype->dtype_nhead;
    412 		nsect = cur_dtype->dtype_nsect;
    413 		phead = cur_dtype->dtype_phead;
    414 		psect = cur_dtype->dtype_psect;
    415 		/*
    416 		 * Alternates per cylinder are forced to 0 or 1,
    417 		 * independent of what the label says.  This works
    418 		 * because we know which ctlr we are dealing with.
    419 		 */
    420 		if (cur_ctype->ctype_flags & CF_APC)
    421 			apc = 1;
    422 		else
    423 			apc = 0;
    424 		/*
    425 		 * Initialize the surface analysis info.  We always start
    426 		 * out with scan set for the whole disk.  Note,
    427 		 * for SCSI disks, we can only scan the data area.
    428 		 */
    429 		scan_lower = 0;
    430 		scan_size = BUF_SECTS;
    431 		if ((cur_ctype->ctype_flags & CF_SCSI) &&
    432 		    (cur_disk->label_type == L_TYPE_SOLARIS)) {
    433 			scan_upper = datasects() - 1;
    434 		} else if (cur_disk->label_type == L_TYPE_SOLARIS) {
    435 			scan_upper = physsects() - 1;
    436 		} else if (cur_disk->label_type == L_TYPE_EFI) {
    437 			scan_upper = cur_parts->etoc->efi_last_lba;
    438 		}
    439 
    440 		/*
    441 		 * Allocate the buffers.
    442 		 */
    443 		cur_buf = (void *) zalloc(BUF_SECTS * cur_blksz);
    444 		pattern_buf = (void *) zalloc(BUF_SECTS * cur_blksz);
    445 
    446 		/*
    447 		 * Tell the user which disk (s)he selected.
    448 		 */
    449 		if (chk_volname(cur_disk)) {
    450 			fmt_print("selecting %s: ", cur_disk->disk_name);
    451 			print_volname(cur_disk);
    452 			fmt_print("\n");
    453 		} else {
    454 			fmt_print("selecting %s\n", cur_disk->disk_name);
    455 		}
    456 
    457 		/*
    458 		 * If the drive is formatted...
    459 		 */
    460 		if ((*cur_ops->op_ck_format)()) {
    461 			/*
    462 			 * Mark it formatted.
    463 			 */
    464 			cur_flags |= DISK_FORMATTED;
    465 			/*
    466 			 * Read the defect list, if we have one.
    467 			 */
    468 			if (!EMBEDDED_SCSI) {
    469 				read_list(&cur_list);
    470 			}
    471 #ifdef sparc
    472 			/*
    473 			 * If the disk does BAD-144, we do an ioctl to
    474 			 * tell SunOS about the bad block table.
    475 			 */
    476 			if (cur_ctlr->ctlr_flags & DKI_BAD144) {
    477 				if (ioctl(cur_file, HDKIOCSBAD, &bad_ptr)) {
    478 					err_print(
    479 "Warning: error telling SunOS bad block map table.\n");
    480 				}
    481 			}
    482 #endif
    483 			fmt_print("[disk formatted");
    484 			if (!EMBEDDED_SCSI) {
    485 				if (cur_list.list != NULL) {
    486 					fmt_print(", defect list found");
    487 				} else {
    488 					fmt_print(", no defect list found");
    489 				}
    490 			}
    491 			fmt_print("]");
    492 		/*
    493 		 * Drive wasn't formatted.  Tell the user in case he
    494 		 * disagrees.
    495 		 */
    496 		} else if (EMBEDDED_SCSI) {
    497 			fmt_print("[disk unformatted]");
    498 		} else {
    499 			/*
    500 			 * Make sure the user is serious.  Note, for
    501 			 * SCSI disks since this is instantaneous, we
    502 			 * will just do it and not ask for confirmation.
    503 			 */
    504 			status = 0;
    505 			if (!(cur_ctype->ctype_flags & CF_CONFIRM)) {
    506 				if (check("\n\
    507 Ready to get manufacturer's defect list from unformatted drive.\n\
    508 This cannot be interrupted and takes a long while.\n\
    509 Continue"))
    510 					status = 1;
    511 				else
    512 					fmt_print(
    513 				"Extracting manufacturer's defect list...");
    514 			}
    515 			/*
    516 			 * Extract manufacturer's defect list.
    517 			 */
    518 			if ((status == 0) && (cur_ops->op_ex_man != NULL)) {
    519 				status = (*cur_ops->op_ex_man)(&cur_list);
    520 			} else {
    521 				status = 1;
    522 			}
    523 			fmt_print("[disk unformatted");
    524 			if (status != 0) {
    525 				fmt_print(", no defect list found]");
    526 			} else {
    527 				fmt_print(", defect list found]");
    528 			}
    529 		}
    530 	} else {
    531 		/*
    532 		 * Disk type is not known.
    533 		 * Initialize physical characteristics to 0 and tell the
    534 		 * user we don't know what type the disk is.
    535 		 */
    536 		ncyl = acyl = nhead = nsect = psect = 0;
    537 	}
    538 
    539 	fmt_print("\n");
    540 
    541 	/*
    542 	 * Check to see if there are any mounted file systems on the
    543 	 * disk.  If there are, print a warning.
    544 	 */
    545 	if ((found_mount = checkmount((diskaddr_t)-1, (diskaddr_t)-1)) != 0)
    546 		err_print("Warning: Current Disk has mounted partitions.\n");
    547 
    548 	/*
    549 	 * If any part of this device is also part of an SVM, VxVM or
    550 	 * Live Upgrade device, print a warning.
    551 	 */
    552 	found_inuse =  checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
    553 	    (diskaddr_t)-1, 1, 0);
    554 
    555 	/*
    556 	 * Get the Solaris Fdisk Partition information
    557 	 */
    558 	(void) copy_solaris_part(&cur_disk->fdisk_part);
    559 
    560 	if (!found_mount && !found_inuse &&
    561 	    cur_disk->label_type == L_TYPE_EFI) {
    562 
    563 		/*
    564 		 * If alter_lba is 1, we are using the backup label.
    565 		 * Since we can locate the backup label by disk capacity,
    566 		 * there must be no space expanded after backup label.
    567 		 */
    568 		if ((cur_parts->etoc->efi_altern_lba != 1) &&
    569 		    (cur_parts->etoc->efi_altern_lba <
    570 		    cur_parts->etoc->efi_last_lba)) {
    571 
    572 			/*
    573 			 * Lun expansion detected. Prompt user now and actually
    574 			 * adjust the label in <partition> command.
    575 			 */
    576 			fmt_print(
    577 "Note: capacity in disk label is smaller than the real disk capacity.\n\
    578 Select <partition> <expand> to adjust the label capacity. \n");
    579 		}
    580 	}
    581 }
    582 
    583 
    584 /*
    585  * Prompt for some undefined disk characteristics.
    586  * Used when there is no disk definition, but the
    587  * disk has a valid label, so basically we're
    588  * prompting for everything that isn't in the label.
    589  */
    590 static void
    591 get_disk_characteristics()
    592 {
    593 	/*
    594 	 * The need_spefs flag is used to tell us that this disk
    595 	 * is not a known type and the ctlr specific info must
    596 	 * be prompted for.  We only prompt for the info that applies
    597 	 * to this ctlr.
    598 	 */
    599 	assert(cur_dtype->dtype_flags & DT_NEED_SPEFS);
    600 
    601 	/*
    602 	 * If we're running with input from a file, use
    603 	 * reasonable defaults, since prompting for the
    604 	 * information will probably mess things up.
    605 	 */
    606 	if (option_f) {
    607 		cur_dtype->dtype_pcyl = ncyl + acyl;
    608 		cur_dtype->dtype_rpm = AVG_RPM;
    609 		cur_dtype->dtype_bpt = INFINITY;
    610 		cur_dtype->dtype_phead = 0;
    611 		cur_dtype->dtype_psect = 0;
    612 		cur_dtype->dtype_cyl_skew = 0;
    613 		cur_dtype->dtype_trk_skew = 0;
    614 		cur_dtype->dtype_trks_zone = 0;
    615 		cur_dtype->dtype_atrks = 0;
    616 		cur_dtype->dtype_asect = 0;
    617 		cur_dtype->dtype_cache = 0;
    618 		cur_dtype->dtype_threshold = 0;
    619 		cur_dtype->dtype_prefetch_min = 0;
    620 		cur_dtype->dtype_prefetch_max = 0;
    621 
    622 		if (cur_ctype->ctype_flags & CF_SMD_DEFS) {
    623 			cur_dtype->dtype_bps = AVG_BPS;
    624 		}
    625 	} else {
    626 
    627 		cur_dtype->dtype_pcyl = get_pcyl(ncyl, cur_dtype->dtype_acyl);
    628 		cur_dtype->dtype_bpt = get_bpt(cur_dtype->dtype_nsect,
    629 		    &cur_dtype->dtype_options);
    630 		cur_dtype->dtype_rpm = get_rpm();
    631 		cur_dtype->dtype_fmt_time =
    632 		    get_fmt_time(&cur_dtype->dtype_options);
    633 		cur_dtype->dtype_cyl_skew =
    634 		    get_cyl_skew(&cur_dtype->dtype_options);
    635 		cur_dtype->dtype_trk_skew =
    636 		    get_trk_skew(&cur_dtype->dtype_options);
    637 		cur_dtype->dtype_trks_zone =
    638 		    get_trks_zone(&cur_dtype->dtype_options);
    639 		cur_dtype->dtype_atrks = get_atrks(&cur_dtype->dtype_options);
    640 		cur_dtype->dtype_asect = get_asect(&cur_dtype->dtype_options);
    641 		cur_dtype->dtype_cache = get_cache(&cur_dtype->dtype_options);
    642 		cur_dtype->dtype_threshold =
    643 		    get_threshold(&cur_dtype->dtype_options);
    644 		cur_dtype->dtype_prefetch_min =
    645 		    get_min_prefetch(&cur_dtype->dtype_options);
    646 		cur_dtype->dtype_prefetch_max =
    647 		    get_max_prefetch(cur_dtype->dtype_prefetch_min,
    648 		    &cur_dtype->dtype_options);
    649 		cur_dtype->dtype_phead =
    650 		    get_phead(nhead, &cur_dtype->dtype_options);
    651 		cur_dtype->dtype_psect = get_psect(&cur_dtype->dtype_options);
    652 		cur_dtype->dtype_bps = get_bps();
    653 #ifdef sparc
    654 		cur_dtype->dtype_dr_type = 0;
    655 #endif
    656 	}
    657 }
    658