dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / format / misc.c
blobc2d520e672d14c3aedf5be9452da7e80fe384233
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This file contains miscellaneous routines.
28 #include "global.h"
30 #include <stdlib.h>
31 #include <signal.h>
32 #include <malloc.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <sys/ioctl.h>
38 #include <sys/fcntl.h>
39 #include <sys/time.h>
40 #include <ctype.h>
41 #include <termio.h>
42 #include "misc.h"
43 #include "analyze.h"
44 #include "label.h"
45 #include "startup.h"
47 #ifdef __STDC__
49 /* Function prototypes for ANSI C Compilers */
50 static void cleanup(int sig);
52 #else /* __STDC__ */
54 /* Function prototypes for non-ANSI C Compilers */
55 static void cleanup();
57 #endif /* __STDC__ */
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[] = {
75 "yes",
76 "no",
77 NULL,
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.
84 void *
85 zalloc(count)
86 int count;
88 void *ptr;
90 if ((ptr = (void *) calloc(1, (unsigned)count)) == NULL) {
91 err_print("Error: unable to calloc more space.\n");
92 fullabort();
94 return (ptr);
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
101 * zeroed.
103 void *
104 rezalloc(ptr, count)
105 void *ptr;
106 int count;
108 void *new_ptr;
111 if ((new_ptr = (void *) realloc((char *)ptr,
112 (unsigned)count)) == NULL) {
113 err_print("Error: unable to realloc more space.\n");
114 fullabort();
116 return (new_ptr);
120 * This routine is a wrapper for free.
122 void
123 destroy_data(data)
124 char *data;
126 free((char *)data);
129 #ifdef not
131 * This routine takes the space number returned by an ioctl call and
132 * returns a mnemonic name for that space.
134 char *
135 space2str(space)
136 uint_t space;
138 char *name;
140 switch (space&SP_BUSMASK) {
141 case SP_VIRTUAL:
142 name = "virtual";
143 break;
144 case SP_OBMEM:
145 name = "obmem";
146 break;
147 case SP_OBIO:
148 name = "obio";
149 break;
150 case SP_MBMEM:
151 name = "mbmem";
152 break;
153 case SP_MBIO:
154 name = "mbio";
155 break;
156 default:
157 err_print("Error: unknown address space type encountered.\n");
158 fullabort();
160 return (name);
162 #endif /* not */
165 * This routine asks the user the given yes/no question and returns
166 * the response.
169 check(question)
170 char *question;
172 int answer;
173 u_ioparam_t ioparam;
176 * If we are running out of a command file, assume a yes answer.
178 if (option_f)
179 return (0);
181 * Ask the user.
183 ioparam.io_charlist = confirm_list;
184 answer = input(FIO_MSTR, question, '?', &ioparam, NULL, DATA_INPUT);
185 return (answer);
189 * This routine aborts the current command. It is called by a ctrl-C
190 * interrupt and also under certain error conditions.
192 /*ARGSUSED*/
193 void
194 cmdabort(sig)
195 int sig;
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:"
202 * prompt.
204 if (current_env == NULL || !(current_env->flags & ENV_USE))
205 fullabort();
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;
212 return;
215 * All interruptions when we are running out of a command file
216 * cause the program to gracefully exit.
218 if (option_f)
219 fullabort();
220 fmt_print("\n");
222 * Clean up any state left by the interrupted command.
224 cleanup(sig);
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.
235 /*ARGSUSED*/
236 void
237 onsusp(sig)
238 int sig;
240 int fix_term;
241 #ifdef NOT_DEF
242 sigset_t sigmask;
243 #endif /* NOT_DEF */
246 * If we are in a critical zone, note the attempt and return.
248 if (current_env != NULL && current_env->flags & ENV_CRITICAL) {
249 stop_pending = 1;
250 return;
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;
257 fmt_print("\n");
259 * Clean up any state left by the interrupted command.
261 cleanup(sig);
262 #ifdef NOT_DEF
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);
271 #endif /* NOT_DEF */
272 (void) signal(SIGTSTP, SIG_DFL);
273 (void) kill(0, SIGTSTP);
275 * PC stops here
278 * We are started again. Set us up to intercept the suspend
279 * signal once again.
281 (void) signal(SIGTSTP, onsusp);
283 * Re-muck the terminal if necessary.
285 if (fix_term & TTY_ECHO_OFF)
286 echo_off();
287 if (fix_term & TTY_CBREAK_ON)
288 charmode_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
294 * is received.
296 /*ARGSUSED*/
297 void
298 onalarm(sig)
299 int sig;
305 * This routine gracefully exits the program.
307 void
308 fullabort()
311 fmt_print("\n");
313 * Clean up any state left by an interrupted command.
314 * Avoid infinite loops caused by a clean-up
315 * routine failing again...
317 if (!aborting) {
318 aborting = 1;
319 cleanup(SIGKILL);
321 exit(1);
322 /*NOTREACHED*/
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.
331 static void
332 cleanup(int sig)
336 * Lock out interrupts to avoid recursion.
338 enter_critical();
340 * Fix up the tty if necessary.
342 if (ttystate.ttyflags & TTY_CBREAK_ON) {
343 charmode_off();
345 if (ttystate.ttyflags & TTY_ECHO_OFF) {
346 echo_on();
350 * If the defect list is dirty, write it out.
352 if (cur_list.flags & LIST_DIRTY) {
353 cur_list.flags = 0;
354 if (!EMBEDDED_SCSI)
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);
370 log_print("\n");
372 if (scan_blocks_fixed >= 0)
373 fmt_print("Total of %lld defective blocks repaired.\n",
374 scan_blocks_fixed);
375 if (sig != SIGSTOP) { /* Don't reset on suspend (converted to stop) */
376 scan_cur_block = scan_blocks_fixed = -1;
378 exit_critical();
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().
387 void
388 enter_critical()
392 * If there is no saved environment, interrupts will be ignored.
394 if (current_env == NULL)
395 return;
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.
407 void
408 exit_critical()
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.
419 if (stop_pending) {
420 stop_pending = 0;
421 onsusp(SIGSTOP);
424 * If there is an abort pending, execute the abort.
426 if (current_env == NULL)
427 return;
428 if (current_env->flags & ENV_ABORT) {
429 current_env->flags &= ~ENV_ABORT;
430 cmdabort(SIGINT);
435 * This routine turns off echoing on the controlling tty for the program.
437 void
438 echo_off()
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");
447 fullabort();
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");
455 fullabort();
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");
460 fullabort();
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.
473 void
474 echo_on()
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");
483 fullabort();
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.
497 void
498 charmode_on()
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");
508 fullabort();
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");
516 fullabort();
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");
527 fullabort();
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.
541 void
542 charmode_off()
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");
553 fullabort();
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
568 * an empty string.
569 * Use destroy_data() to free when no longer used.
571 char *
572 alloc_string(s)
573 char *s;
575 char *ns;
577 if (s == NULL) {
578 ns = (char *)zalloc(1);
579 } else {
580 ns = (char *)zalloc(strlen(s) + 1);
581 (void) strcpy(ns, s);
583 return (ns);
589 * This function can be used to build up an array of strings
590 * dynamically, with a trailing NULL to terminate the list.
592 * Parameters:
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.
605 * Returns:
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
615 char **
616 build_argvlist(argvlist, size, alloc, str)
617 char **argvlist;
618 int *size;
619 int *alloc;
620 char *str;
622 if (*size + 2 > *alloc) {
623 if (*alloc == 0) {
624 *alloc = INITIAL_LISTSIZE;
625 argvlist = (char **)
626 zalloc(sizeof (char *) * (*alloc));
627 } else {
628 *alloc += INCR_LISTSIZE;
629 argvlist = (char **)
630 rezalloc((void *) argvlist,
631 sizeof (char *) * (*alloc));
635 argvlist[*size] = alloc_string(str);
636 *size += 1;
637 argvlist[*size] = NULL;
639 return (argvlist);
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 */
651 /* be processed. */
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)
662 must_be(name, 'c');
663 skip_digits(name);
664 if (*name == 't') {
665 name++;
666 skip_digit_or_hexupper(name);
668 must_be(name, 'd');
669 skip_digits(name);
670 must_be(name, 's');
671 skip_digits(name);
672 return (*name == 0);
675 #ifdef i386
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)) {
695 skip_digits(name);
696 if ((*name >= 'a') && (*name <= 'p')) {
697 name ++;
698 if ((*name >= '0') && (*name <= '4')) {
699 name++;
702 return (*name == '\0');
705 return (0);
707 #endif
710 * Return true if a device name matches the intel physical name conventions
711 * for the particular system.
714 fdisk_physical_name(char *name)
716 must_be(name, 'c');
717 skip_digits(name);
718 if (*name == 't') {
719 name++;
720 skip_digit_or_hexupper(name);
722 must_be(name, 'd');
723 skip_digits(name);
724 must_be(name, 'p');
725 skip_digits(name);
726 return (*name == 0);
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)
737 char *name;
739 must_be(name, 'c');
740 skip_digits(name);
741 if (*name == 't') {
742 name++;
743 skip_digit_or_hexupper(name);
745 must_be(name, 'd');
746 skip_digits(name);
747 must_be(name, 's');
748 must_be(name, '2');
749 return (*name == 0);
754 * Return true if a name is in the internal canonical form
757 canonical_name(name)
758 char *name;
760 must_be(name, 'c');
761 skip_digits(name);
762 if (*name == 't') {
763 name++;
764 skip_digit_or_hexupper(name);
766 must_be(name, 'd');
767 skip_digits(name);
768 return (*name == 0);
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)
778 char *name;
780 char **p;
781 int i;
783 p = disk_4x_identifiers;
784 for (i = N_DISK_4X_IDS; i > 0; i--, p++) {
785 if (match_substr(name, *p)) {
786 name += strlen(*p);
787 break;
790 if (i == 0)
791 return (0);
792 skip_digits(name);
793 return (*name == 0);
798 * Map a conventional name into the internal canonical form:
800 * /dev/rdsk/c0t0d0s0 -> c0t0d0
802 void
803 canonicalize_name(dst, src)
804 char *dst;
805 char *src;
807 char *s;
810 * Copy from the 'c' to the end to the destination string...
812 s = strchr(src, 'c');
813 if (s != NULL) {
814 (void) strcpy(dst, s);
816 * Remove the trailing slice (partition) reference
818 s = dst + strlen(dst) - 2;
819 if (*s == 's') {
820 *s = 0;
822 } else {
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
834 match_substr(s1, s2)
835 char *s1;
836 char *s2;
838 while (*s2 != 0) {
839 if (*s1++ != *s2++)
840 return (0);
843 return (1);
848 * Dump a structure in hexadecimal, for diagnostic purposes
850 #define BYTES_PER_LINE 16
852 void
853 dump(hdr, src, nbytes, format)
854 char *hdr;
855 caddr_t src;
856 int nbytes;
857 int format;
859 int i;
860 int n;
861 char *p;
862 char s[256];
864 assert(format == HEX_ONLY || format == HEX_ASCII);
866 (void) strcpy(s, hdr);
867 for (p = s; *p; p++) {
868 *p = ' ';
871 p = hdr;
872 while (nbytes > 0) {
873 err_print("%s", p);
874 p = s;
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--) {
881 err_print(" ");
883 err_print(" ");
884 for (i = 0; i < n; i++) {
885 err_print("%c",
886 isprint(src[i]) ? src[i] : '.');
889 err_print("\n");
890 nbytes -= n;
891 src += n;
896 float
897 bn2mb(uint64_t nblks)
899 float n;
901 n = (float)nblks / 1024.0;
902 return ((n / 1024.0) * cur_blksz);
906 diskaddr_t
907 mb2bn(float mb)
909 diskaddr_t n;
911 n = (diskaddr_t)(mb * 1024.0 * (1024.0 / cur_blksz));
912 return (n);
915 float
916 bn2gb(uint64_t nblks)
918 float n;
920 n = (float)nblks / (1024.0 * 1024.0);
921 return ((n/1024.0) * cur_blksz);
925 float
926 bn2tb(uint64_t nblks)
928 float n;
930 n = (float)nblks / (1024.0 * 1024.0 * 1024.0);
931 return ((n/1024.0) * cur_blksz);
934 diskaddr_t
935 gb2bn(float gb)
937 diskaddr_t n;
939 n = (diskaddr_t)(gb * 1024.0 * 1024.0 * (1024.0 / cur_blksz));
940 return (n);
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.
948 get_tty_lines()
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
957 winsize.ws_row = 0;
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;
968 return (tty_lines);