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