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