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