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.
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.
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]
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This file contains miscellaneous routines.
37 #include <sys/ioctl.h>
38 #include <sys/fcntl.h>
49 /* Function prototypes for ANSI C Compilers */
50 static void cleanup(int sig
);
54 /* Function prototypes for non-ANSI C Compilers */
55 static void cleanup();
59 struct env
*current_env
= NULL
; /* ptr to current environment */
60 static int stop_pending
= 0; /* ctrl-Z is pending */
61 struct ttystate ttystate
; /* tty info */
62 static int aborting
= 0; /* in process of aborting */
65 * For 4.x, limit the choices of valid disk names to this set.
67 static char *disk_4x_identifiers
[] = { "sd", "id"};
68 #define N_DISK_4X_IDS (sizeof (disk_4x_identifiers)/sizeof (char *))
72 * This is the list of legal inputs for all yes/no questions.
74 char *confirm_list
[] = {
81 * This routine is a wrapper for malloc. It allocates pre-zeroed space,
82 * and checks the return value so the caller doesn't have to.
90 if ((ptr
= (void *) calloc(1, (unsigned)count
)) == NULL
) {
91 err_print("Error: unable to calloc more space.\n");
98 * This routine is a wrapper for realloc. It reallocates the given
99 * space, and checks the return value so the caller doesn't have to.
100 * Note that the any space added by this call is NOT necessarily
111 if ((new_ptr
= (void *) realloc((char *)ptr
,
112 (unsigned)count
)) == NULL
) {
113 err_print("Error: unable to realloc more space.\n");
120 * This routine is a wrapper for free.
131 * This routine takes the space number returned by an ioctl call and
132 * returns a mnemonic name for that space.
140 switch (space
&SP_BUSMASK
) {
157 err_print("Error: unknown address space type encountered.\n");
165 * This routine asks the user the given yes/no question and returns
176 * If we are running out of a command file, assume a yes answer.
183 ioparam
.io_charlist
= confirm_list
;
184 answer
= input(FIO_MSTR
, question
, '?', &ioparam
,
185 (int *)NULL
, DATA_INPUT
);
190 * This routine aborts the current command. It is called by a ctrl-C
191 * interrupt and also under certain error conditions.
200 * If there is no usable saved environment, gracefully exit. This
201 * allows the user to interrupt the program even when input is from
202 * a file, or if there is no current menu, like at the "Select disk:"
205 if (current_env
== NULL
|| !(current_env
->flags
& ENV_USE
))
209 * If we are in a critical zone, note the attempt and return.
211 if (current_env
->flags
& ENV_CRITICAL
) {
212 current_env
->flags
|= ENV_ABORT
;
216 * All interruptions when we are running out of a command file
217 * cause the program to gracefully exit.
223 * Clean up any state left by the interrupted command.
227 * Jump to the saved environment.
229 longjmp(current_env
->env
, 0);
233 * This routine implements the ctrl-Z suspend mechanism. It is called
234 * when a suspend signal is received.
247 * If we are in a critical zone, note the attempt and return.
249 if (current_env
!= NULL
&& current_env
->flags
& ENV_CRITICAL
) {
254 * If the terminal is mucked up, note that we will need to
255 * re-muck it when we start up again.
257 fix_term
= ttystate
.ttyflags
;
260 * Clean up any state left by the interrupted command.
264 /* Investigate whether all this is necessary */
266 * Stop intercepting the suspend signal, then send ourselves one
267 * to cause us to stop.
269 sigmask
.sigbits
[0] = (ulong_t
)0xffffffff;
270 if (sigprocmask(SIG_SETMASK
, &sigmask
, (sigset_t
*)NULL
) == -1)
271 err_print("sigprocmask failed %d\n", errno
);
273 (void) signal(SIGTSTP
, SIG_DFL
);
274 (void) kill(0, SIGTSTP
);
279 * We are started again. Set us up to intercept the suspend
282 (void) signal(SIGTSTP
, onsusp
);
284 * Re-muck the terminal if necessary.
286 if (fix_term
& TTY_ECHO_OFF
)
288 if (fix_term
& TTY_CBREAK_ON
)
293 * This routine implements the timing function used during long-term
294 * disk operations (e.g. formatting). It is called when an alarm signal
306 * This routine gracefully exits the program.
314 * Clean up any state left by an interrupted command.
315 * Avoid infinite loops caused by a clean-up
316 * routine failing again...
327 * This routine cleans up the state of the world. It is a hodge-podge
328 * of kludges to allow us to interrupt commands whenever possible.
330 * Some cleanup actions may depend on the type of signal.
337 * Lock out interrupts to avoid recursion.
341 * Fix up the tty if necessary.
343 if (ttystate
.ttyflags
& TTY_CBREAK_ON
) {
346 if (ttystate
.ttyflags
& TTY_ECHO_OFF
) {
351 * If the defect list is dirty, write it out.
353 if (cur_list
.flags
& LIST_DIRTY
) {
356 write_deflist(&cur_list
);
359 * If the label is dirty, write it out.
361 if (cur_flags
& LABEL_DIRTY
) {
362 cur_flags
&= ~LABEL_DIRTY
;
363 (void) write_label();
366 * If we are logging and just interrupted a scan, print out
367 * some summary info to the log file.
369 if (log_file
&& scan_cur_block
>= 0) {
370 pr_dblock(log_print
, scan_cur_block
);
373 if (scan_blocks_fixed
>= 0)
374 fmt_print("Total of %lld defective blocks repaired.\n",
376 if (sig
!= SIGSTOP
) { /* Don't reset on suspend (converted to stop) */
377 scan_cur_block
= scan_blocks_fixed
= -1;
383 * This routine causes the program to enter a critical zone. Within the
384 * critical zone, no interrupts are allowed. Note that calls to this
385 * routine for the same environment do NOT nest, so there is not
386 * necessarily pairing between calls to enter_critical() and exit_critical().
393 * If there is no saved environment, interrupts will be ignored.
395 if (current_env
== NULL
)
398 * Mark the environment to be in a critical zone.
400 current_env
->flags
|= ENV_CRITICAL
;
404 * This routine causes the program to exit a critical zone. Note that
405 * calls to enter_critical() for the same environment do NOT nest, so
406 * one call to exit_critical() will erase any number of such calls.
413 * If there is a saved environment, mark it to be non-critical.
415 if (current_env
!= NULL
)
416 current_env
->flags
&= ~ENV_CRITICAL
;
418 * If there is a stop pending, execute the stop.
425 * If there is an abort pending, execute the abort.
427 if (current_env
== NULL
)
429 if (current_env
->flags
& ENV_ABORT
) {
430 current_env
->flags
&= ~ENV_ABORT
;
436 * This routine turns off echoing on the controlling tty for the program.
442 * Open the tty and store the file pointer for later.
444 if (ttystate
.ttyflags
== 0) {
445 if ((ttystate
.ttyfile
= open("/dev/tty",
446 O_RDWR
| O_NDELAY
)) < 0) {
447 err_print("Unable to open /dev/tty.\n");
452 * Get the parameters for the tty, turn off echoing and set them.
454 if (tcgetattr(ttystate
.ttyfile
, &ttystate
.ttystate
) < 0) {
455 err_print("Unable to get tty parameters.\n");
458 ttystate
.ttystate
.c_lflag
&= ~ECHO
;
459 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
460 err_print("Unable to set tty to echo off state.\n");
465 * Remember that we've successfully turned
466 * ECHO mode off, so we know to fix it later.
468 ttystate
.ttyflags
|= TTY_ECHO_OFF
;
472 * This routine turns on echoing on the controlling tty for the program.
479 * Using the saved parameters, turn echoing on and set them.
481 ttystate
.ttystate
.c_lflag
|= ECHO
;
482 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
483 err_print("Unable to set tty to echo on state.\n");
487 * Close the tty and mark it ok again.
489 ttystate
.ttyflags
&= ~TTY_ECHO_OFF
;
490 if (ttystate
.ttyflags
== 0) {
491 (void) close(ttystate
.ttyfile
);
496 * This routine turns off single character entry mode for tty.
503 * If tty unopened, open the tty and store the file pointer for later.
505 if (ttystate
.ttyflags
== 0) {
506 if ((ttystate
.ttyfile
= open("/dev/tty",
507 O_RDWR
| O_NDELAY
)) < 0) {
508 err_print("Unable to open /dev/tty.\n");
513 * Get the parameters for the tty, turn on char mode.
515 if (tcgetattr(ttystate
.ttyfile
, &ttystate
.ttystate
) < 0) {
516 err_print("Unable to get tty parameters.\n");
519 ttystate
.vmin
= ttystate
.ttystate
.c_cc
[VMIN
];
520 ttystate
.vtime
= ttystate
.ttystate
.c_cc
[VTIME
];
522 ttystate
.ttystate
.c_lflag
&= ~ICANON
;
523 ttystate
.ttystate
.c_cc
[VMIN
] = 1;
524 ttystate
.ttystate
.c_cc
[VTIME
] = 0;
526 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
527 err_print("Unable to set tty to cbreak on state.\n");
532 * Remember that we've successfully turned
533 * CBREAK mode on, so we know to fix it later.
535 ttystate
.ttyflags
|= TTY_CBREAK_ON
;
539 * This routine turns on single character entry mode for tty.
540 * Note, this routine must be called before echo_on.
547 * Using the saved parameters, turn char mode on.
549 ttystate
.ttystate
.c_lflag
|= ICANON
;
550 ttystate
.ttystate
.c_cc
[VMIN
] = ttystate
.vmin
;
551 ttystate
.ttystate
.c_cc
[VTIME
] = ttystate
.vtime
;
552 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
553 err_print("Unable to set tty to cbreak off state.\n");
557 * Close the tty and mark it ok again.
559 ttystate
.ttyflags
&= ~TTY_CBREAK_ON
;
560 if (ttystate
.ttyflags
== 0) {
561 (void) close(ttystate
.ttyfile
);
567 * Allocate space for and return a pointer to a string
568 * on the stack. If the string is null, create
570 * Use destroy_data() to free when no longer used.
578 if (s
== (char *)NULL
) {
579 ns
= (char *)zalloc(1);
581 ns
= (char *)zalloc(strlen(s
) + 1);
582 (void) strcpy(ns
, s
);
590 * This function can be used to build up an array of strings
591 * dynamically, with a trailing NULL to terminate the list.
594 * argvlist: a pointer to the base of the current list.
595 * does not have to be initialized.
596 * size: pointer to an integer, indicating the number
597 * of string installed in the list. Must be
598 * initialized to zero.
599 * alloc: pointer to an integer, indicating the amount
600 * of space allocated. Must be initialized to
601 * zero. For efficiency, we allocate the list
602 * in chunks and use it piece-by-piece.
603 * str: the string to be inserted in the list.
604 * A copy of the string is malloc'ed, and
605 * appended at the end of the list.
607 * a pointer to the possibly-moved argvlist.
609 * No attempt to made to free unused memory when the list is
610 * completed, although this would not be hard to do. For
611 * reasonably small lists, this should suffice.
613 #define INITIAL_LISTSIZE 32
614 #define INCR_LISTSIZE 32
617 build_argvlist(argvlist
, size
, alloc
, str
)
623 if (*size
+ 2 > *alloc
) {
625 *alloc
= INITIAL_LISTSIZE
;
627 zalloc(sizeof (char *) * (*alloc
));
629 *alloc
+= INCR_LISTSIZE
;
631 rezalloc((void *) argvlist
,
632 sizeof (char *) * (*alloc
));
636 argvlist
[*size
] = alloc_string(str
);
638 argvlist
[*size
] = NULL
;
645 * Useful parsing macros
647 #define must_be(s, c) if (*s++ != c) return (0)
648 #define skip_digits(s) while (isdigit(*s)) s++
649 /* Parsing macro below is created to handle fabric devices which contains */
650 /* upper hex digits like c2t210000203708B8CEd0s0. */
651 /* To get the target id(tid) the digit and hex upper digit need to */
653 #define skip_digit_or_hexupper(s) while (isdigit(*s) || \
654 (isxdigit(*s) && isupper(*s))) s++
657 * Return true if a device name matches the conventions
658 * for the particular system.
661 conventional_name(char *name
)
667 skip_digit_or_hexupper(name
);
678 * Return true if a device name match the emc powerpath name scheme:
679 * emcpowerN[a-p,p0,p1,p2,p3,p4]
682 emcpower_name(char *name
)
684 char *emcp
= "emcpower";
685 char *devp
= "/dev/dsk";
686 char *rdevp
= "/dev/rdsk";
688 if (strncmp(devp
, name
, strlen(devp
)) == 0) {
689 name
+= strlen(devp
) + 1;
690 } else if (strncmp(rdevp
, name
, strlen(rdevp
)) == 0) {
691 name
+= strlen(rdevp
) + 1;
693 if (strncmp(emcp
, name
, strlen(emcp
)) == 0) {
694 name
+= strlen(emcp
);
695 if (isdigit(*name
)) {
697 if ((*name
>= 'a') && (*name
<= 'p')) {
699 if ((*name
>= '0') && (*name
<= '4')) {
703 return (*name
== '\0');
711 * Return true if a device name matches the intel physical name conventions
712 * for the particular system.
715 fdisk_physical_name(char *name
)
721 skip_digit_or_hexupper(name
);
731 * Return true if a device name matches the conventions
732 * for a "whole disk" name for the particular system.
733 * The name in this case must match exactly that which
734 * would appear in the device directory itself.
737 whole_disk_name(name
)
744 skip_digit_or_hexupper(name
);
755 * Return true if a name is in the internal canonical form
765 skip_digit_or_hexupper(name
);
774 * Return true if a name is in the internal canonical form for 4.x
775 * Used to support 4.x naming conventions under 5.0.
778 canonical4x_name(name
)
784 p
= disk_4x_identifiers
;
785 for (i
= N_DISK_4X_IDS
; i
> 0; i
--, p
++) {
786 if (match_substr(name
, *p
)) {
799 * Map a conventional name into the internal canonical form:
801 * /dev/rdsk/c0t0d0s0 -> c0t0d0
804 canonicalize_name(dst
, src
)
811 * Copy from the 'c' to the end to the destination string...
813 s
= strchr(src
, 'c');
815 (void) strcpy(dst
, s
);
817 * Remove the trailing slice (partition) reference
819 s
= dst
+ strlen(dst
) - 2;
824 *dst
= 0; /* be tolerant of garbage input */
830 * Return true if we find an occurance of s2 at the
831 * beginning of s1. We don't have to match all of
832 * s1, but we do have to match all of s2
849 * Dump a structure in hexadecimal, for diagnostic purposes
851 #define BYTES_PER_LINE 16
854 dump(hdr
, src
, nbytes
, format
)
865 assert(format
== HEX_ONLY
|| format
== HEX_ASCII
);
867 (void) strcpy(s
, hdr
);
868 for (p
= s
; *p
; p
++) {
876 n
= min(nbytes
, BYTES_PER_LINE
);
877 for (i
= 0; i
< n
; i
++) {
878 err_print("%02x ", src
[i
] & 0xff);
880 if (format
== HEX_ASCII
) {
881 for (i
= BYTES_PER_LINE
-n
; i
> 0; i
--) {
885 for (i
= 0; i
< n
; i
++) {
887 isprint(src
[i
]) ? src
[i
] : '.');
898 bn2mb(uint64_t nblks
)
902 n
= (float)nblks
/ 1024.0;
903 return ((n
/ 1024.0) * cur_blksz
);
912 n
= (diskaddr_t
)(mb
* 1024.0 * (1024.0 / cur_blksz
));
917 bn2gb(uint64_t nblks
)
921 n
= (float)nblks
/ (1024.0 * 1024.0);
922 return ((n
/1024.0) * cur_blksz
);
927 bn2tb(uint64_t nblks
)
931 n
= (float)nblks
/ (1024.0 * 1024.0 * 1024.0);
932 return ((n
/1024.0) * cur_blksz
);
940 n
= (diskaddr_t
)(gb
* 1024.0 * 1024.0 * (1024.0 / cur_blksz
));
945 * This routine finds out the number of lines (rows) in a terminal
946 * window. The default value of TTY_LINES is returned on error.
951 int tty_lines
= TTY_LINES
;
952 struct winsize winsize
;
954 if ((option_f
== (char *)NULL
) && isatty(0) == 1 && isatty(1) == 1) {
956 * We have a real terminal for std input and output
959 if (ioctl(1, TIOCGWINSZ
, &winsize
) == 0) {
960 if (winsize
.ws_row
> 2) {
962 * Should be atleast 2 lines, for division
963 * by (tty_lines - 1, tty_lines - 2) to work.
965 tty_lines
= winsize
.ws_row
;