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
, NULL
, DATA_INPUT
);
189 * This routine aborts the current command. It is called by a ctrl-C
190 * interrupt and also under certain error conditions.
199 * If there is no usable saved environment, gracefully exit. This
200 * allows the user to interrupt the program even when input is from
201 * a file, or if there is no current menu, like at the "Select disk:"
204 if (current_env
== NULL
|| !(current_env
->flags
& ENV_USE
))
208 * If we are in a critical zone, note the attempt and return.
210 if (current_env
->flags
& ENV_CRITICAL
) {
211 current_env
->flags
|= ENV_ABORT
;
215 * All interruptions when we are running out of a command file
216 * cause the program to gracefully exit.
222 * Clean up any state left by the interrupted command.
226 * Jump to the saved environment.
228 longjmp(current_env
->env
, 0);
232 * This routine implements the ctrl-Z suspend mechanism. It is called
233 * when a suspend signal is received.
246 * If we are in a critical zone, note the attempt and return.
248 if (current_env
!= NULL
&& current_env
->flags
& ENV_CRITICAL
) {
253 * If the terminal is mucked up, note that we will need to
254 * re-muck it when we start up again.
256 fix_term
= ttystate
.ttyflags
;
259 * Clean up any state left by the interrupted command.
263 /* Investigate whether all this is necessary */
265 * Stop intercepting the suspend signal, then send ourselves one
266 * to cause us to stop.
268 sigmask
.sigbits
[0] = (ulong_t
)0xffffffff;
269 if (sigprocmask(SIG_SETMASK
, &sigmask
, (sigset_t
*)NULL
) == -1)
270 err_print("sigprocmask failed %d\n", errno
);
272 (void) signal(SIGTSTP
, SIG_DFL
);
273 (void) kill(0, SIGTSTP
);
278 * We are started again. Set us up to intercept the suspend
281 (void) signal(SIGTSTP
, onsusp
);
283 * Re-muck the terminal if necessary.
285 if (fix_term
& TTY_ECHO_OFF
)
287 if (fix_term
& TTY_CBREAK_ON
)
292 * This routine implements the timing function used during long-term
293 * disk operations (e.g. formatting). It is called when an alarm signal
305 * This routine gracefully exits the program.
313 * Clean up any state left by an interrupted command.
314 * Avoid infinite loops caused by a clean-up
315 * routine failing again...
326 * This routine cleans up the state of the world. It is a hodge-podge
327 * of kludges to allow us to interrupt commands whenever possible.
329 * Some cleanup actions may depend on the type of signal.
336 * Lock out interrupts to avoid recursion.
340 * Fix up the tty if necessary.
342 if (ttystate
.ttyflags
& TTY_CBREAK_ON
) {
345 if (ttystate
.ttyflags
& TTY_ECHO_OFF
) {
350 * If the defect list is dirty, write it out.
352 if (cur_list
.flags
& LIST_DIRTY
) {
355 write_deflist(&cur_list
);
358 * If the label is dirty, write it out.
360 if (cur_flags
& LABEL_DIRTY
) {
361 cur_flags
&= ~LABEL_DIRTY
;
362 (void) write_label();
365 * If we are logging and just interrupted a scan, print out
366 * some summary info to the log file.
368 if (log_file
&& scan_cur_block
>= 0) {
369 pr_dblock(log_print
, scan_cur_block
);
372 if (scan_blocks_fixed
>= 0)
373 fmt_print("Total of %lld defective blocks repaired.\n",
375 if (sig
!= SIGSTOP
) { /* Don't reset on suspend (converted to stop) */
376 scan_cur_block
= scan_blocks_fixed
= -1;
382 * This routine causes the program to enter a critical zone. Within the
383 * critical zone, no interrupts are allowed. Note that calls to this
384 * routine for the same environment do NOT nest, so there is not
385 * necessarily pairing between calls to enter_critical() and exit_critical().
392 * If there is no saved environment, interrupts will be ignored.
394 if (current_env
== NULL
)
397 * Mark the environment to be in a critical zone.
399 current_env
->flags
|= ENV_CRITICAL
;
403 * This routine causes the program to exit a critical zone. Note that
404 * calls to enter_critical() for the same environment do NOT nest, so
405 * one call to exit_critical() will erase any number of such calls.
412 * If there is a saved environment, mark it to be non-critical.
414 if (current_env
!= NULL
)
415 current_env
->flags
&= ~ENV_CRITICAL
;
417 * If there is a stop pending, execute the stop.
424 * If there is an abort pending, execute the abort.
426 if (current_env
== NULL
)
428 if (current_env
->flags
& ENV_ABORT
) {
429 current_env
->flags
&= ~ENV_ABORT
;
435 * This routine turns off echoing on the controlling tty for the program.
441 * Open the tty and store the file pointer for later.
443 if (ttystate
.ttyflags
== 0) {
444 if ((ttystate
.ttyfile
= open("/dev/tty",
445 O_RDWR
| O_NDELAY
)) < 0) {
446 err_print("Unable to open /dev/tty.\n");
451 * Get the parameters for the tty, turn off echoing and set them.
453 if (tcgetattr(ttystate
.ttyfile
, &ttystate
.ttystate
) < 0) {
454 err_print("Unable to get tty parameters.\n");
457 ttystate
.ttystate
.c_lflag
&= ~ECHO
;
458 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
459 err_print("Unable to set tty to echo off state.\n");
464 * Remember that we've successfully turned
465 * ECHO mode off, so we know to fix it later.
467 ttystate
.ttyflags
|= TTY_ECHO_OFF
;
471 * This routine turns on echoing on the controlling tty for the program.
478 * Using the saved parameters, turn echoing on and set them.
480 ttystate
.ttystate
.c_lflag
|= ECHO
;
481 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
482 err_print("Unable to set tty to echo on state.\n");
486 * Close the tty and mark it ok again.
488 ttystate
.ttyflags
&= ~TTY_ECHO_OFF
;
489 if (ttystate
.ttyflags
== 0) {
490 (void) close(ttystate
.ttyfile
);
495 * This routine turns off single character entry mode for tty.
502 * If tty unopened, open the tty and store the file pointer for later.
504 if (ttystate
.ttyflags
== 0) {
505 if ((ttystate
.ttyfile
= open("/dev/tty",
506 O_RDWR
| O_NDELAY
)) < 0) {
507 err_print("Unable to open /dev/tty.\n");
512 * Get the parameters for the tty, turn on char mode.
514 if (tcgetattr(ttystate
.ttyfile
, &ttystate
.ttystate
) < 0) {
515 err_print("Unable to get tty parameters.\n");
518 ttystate
.vmin
= ttystate
.ttystate
.c_cc
[VMIN
];
519 ttystate
.vtime
= ttystate
.ttystate
.c_cc
[VTIME
];
521 ttystate
.ttystate
.c_lflag
&= ~ICANON
;
522 ttystate
.ttystate
.c_cc
[VMIN
] = 1;
523 ttystate
.ttystate
.c_cc
[VTIME
] = 0;
525 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
526 err_print("Unable to set tty to cbreak on state.\n");
531 * Remember that we've successfully turned
532 * CBREAK mode on, so we know to fix it later.
534 ttystate
.ttyflags
|= TTY_CBREAK_ON
;
538 * This routine turns on single character entry mode for tty.
539 * Note, this routine must be called before echo_on.
546 * Using the saved parameters, turn char mode on.
548 ttystate
.ttystate
.c_lflag
|= ICANON
;
549 ttystate
.ttystate
.c_cc
[VMIN
] = ttystate
.vmin
;
550 ttystate
.ttystate
.c_cc
[VTIME
] = ttystate
.vtime
;
551 if (tcsetattr(ttystate
.ttyfile
, TCSANOW
, &ttystate
.ttystate
) < 0) {
552 err_print("Unable to set tty to cbreak off state.\n");
556 * Close the tty and mark it ok again.
558 ttystate
.ttyflags
&= ~TTY_CBREAK_ON
;
559 if (ttystate
.ttyflags
== 0) {
560 (void) close(ttystate
.ttyfile
);
566 * Allocate space for and return a pointer to a string
567 * on the stack. If the string is null, create
569 * Use destroy_data() to free when no longer used.
578 ns
= (char *)zalloc(1);
580 ns
= (char *)zalloc(strlen(s
) + 1);
581 (void) strcpy(ns
, s
);
589 * This function can be used to build up an array of strings
590 * dynamically, with a trailing NULL to terminate the list.
593 * argvlist: a pointer to the base of the current list.
594 * does not have to be initialized.
595 * size: pointer to an integer, indicating the number
596 * of string installed in the list. Must be
597 * initialized to zero.
598 * alloc: pointer to an integer, indicating the amount
599 * of space allocated. Must be initialized to
600 * zero. For efficiency, we allocate the list
601 * in chunks and use it piece-by-piece.
602 * str: the string to be inserted in the list.
603 * A copy of the string is malloc'ed, and
604 * appended at the end of the list.
606 * a pointer to the possibly-moved argvlist.
608 * No attempt to made to free unused memory when the list is
609 * completed, although this would not be hard to do. For
610 * reasonably small lists, this should suffice.
612 #define INITIAL_LISTSIZE 32
613 #define INCR_LISTSIZE 32
616 build_argvlist(argvlist
, size
, alloc
, str
)
622 if (*size
+ 2 > *alloc
) {
624 *alloc
= INITIAL_LISTSIZE
;
626 zalloc(sizeof (char *) * (*alloc
));
628 *alloc
+= INCR_LISTSIZE
;
630 rezalloc((void *) argvlist
,
631 sizeof (char *) * (*alloc
));
635 argvlist
[*size
] = alloc_string(str
);
637 argvlist
[*size
] = NULL
;
644 * Useful parsing macros
646 #define must_be(s, c) if (*s++ != c) return (0)
647 #define skip_digits(s) while (isdigit(*s)) s++
648 /* Parsing macro below is created to handle fabric devices which contains */
649 /* upper hex digits like c2t210000203708B8CEd0s0. */
650 /* To get the target id(tid) the digit and hex upper digit need to */
652 #define skip_digit_or_hexupper(s) while (isdigit(*s) || \
653 (isxdigit(*s) && isupper(*s))) s++
656 * Return true if a device name matches the conventions
657 * for the particular system.
660 conventional_name(char *name
)
666 skip_digit_or_hexupper(name
);
677 * Return true if a device name match the emc powerpath name scheme:
678 * emcpowerN[a-p,p0,p1,p2,p3,p4]
681 emcpower_name(char *name
)
683 char *emcp
= "emcpower";
684 char *devp
= "/dev/dsk";
685 char *rdevp
= "/dev/rdsk";
687 if (strncmp(devp
, name
, strlen(devp
)) == 0) {
688 name
+= strlen(devp
) + 1;
689 } else if (strncmp(rdevp
, name
, strlen(rdevp
)) == 0) {
690 name
+= strlen(rdevp
) + 1;
692 if (strncmp(emcp
, name
, strlen(emcp
)) == 0) {
693 name
+= strlen(emcp
);
694 if (isdigit(*name
)) {
696 if ((*name
>= 'a') && (*name
<= 'p')) {
698 if ((*name
>= '0') && (*name
<= '4')) {
702 return (*name
== '\0');
710 * Return true if a device name matches the intel physical name conventions
711 * for the particular system.
714 fdisk_physical_name(char *name
)
720 skip_digit_or_hexupper(name
);
730 * Return true if a device name matches the conventions
731 * for a "whole disk" name for the particular system.
732 * The name in this case must match exactly that which
733 * would appear in the device directory itself.
736 whole_disk_name(name
)
743 skip_digit_or_hexupper(name
);
754 * Return true if a name is in the internal canonical form
764 skip_digit_or_hexupper(name
);
773 * Return true if a name is in the internal canonical form for 4.x
774 * Used to support 4.x naming conventions under 5.0.
777 canonical4x_name(name
)
783 p
= disk_4x_identifiers
;
784 for (i
= N_DISK_4X_IDS
; i
> 0; i
--, p
++) {
785 if (match_substr(name
, *p
)) {
798 * Map a conventional name into the internal canonical form:
800 * /dev/rdsk/c0t0d0s0 -> c0t0d0
803 canonicalize_name(dst
, src
)
810 * Copy from the 'c' to the end to the destination string...
812 s
= strchr(src
, 'c');
814 (void) strcpy(dst
, s
);
816 * Remove the trailing slice (partition) reference
818 s
= dst
+ strlen(dst
) - 2;
823 *dst
= 0; /* be tolerant of garbage input */
829 * Return true if we find an occurance of s2 at the
830 * beginning of s1. We don't have to match all of
831 * s1, but we do have to match all of s2
848 * Dump a structure in hexadecimal, for diagnostic purposes
850 #define BYTES_PER_LINE 16
853 dump(hdr
, src
, nbytes
, format
)
864 assert(format
== HEX_ONLY
|| format
== HEX_ASCII
);
866 (void) strcpy(s
, hdr
);
867 for (p
= s
; *p
; p
++) {
875 n
= min(nbytes
, BYTES_PER_LINE
);
876 for (i
= 0; i
< n
; i
++) {
877 err_print("%02x ", src
[i
] & 0xff);
879 if (format
== HEX_ASCII
) {
880 for (i
= BYTES_PER_LINE
-n
; i
> 0; i
--) {
884 for (i
= 0; i
< n
; i
++) {
886 isprint(src
[i
]) ? src
[i
] : '.');
897 bn2mb(uint64_t nblks
)
901 n
= (float)nblks
/ 1024.0;
902 return ((n
/ 1024.0) * cur_blksz
);
911 n
= (diskaddr_t
)(mb
* 1024.0 * (1024.0 / cur_blksz
));
916 bn2gb(uint64_t nblks
)
920 n
= (float)nblks
/ (1024.0 * 1024.0);
921 return ((n
/1024.0) * cur_blksz
);
926 bn2tb(uint64_t nblks
)
930 n
= (float)nblks
/ (1024.0 * 1024.0 * 1024.0);
931 return ((n
/1024.0) * cur_blksz
);
939 n
= (diskaddr_t
)(gb
* 1024.0 * 1024.0 * (1024.0 / cur_blksz
));
944 * This routine finds out the number of lines (rows) in a terminal
945 * window. The default value of TTY_LINES is returned on error.
950 int tty_lines
= TTY_LINES
;
951 struct winsize winsize
;
953 if ((option_f
== NULL
) && isatty(0) == 1 && isatty(1) == 1) {
955 * We have a real terminal for std input and output
958 if (ioctl(1, TIOCGWINSZ
, &winsize
) == 0) {
959 if (winsize
.ws_row
> 2) {
961 * Should be atleast 2 lines, for division
962 * by (tty_lines - 1, tty_lines - 2) to work.
964 tty_lines
= winsize
.ws_row
;