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 (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * This file contains miscellaneous routines.
27 */
28 #include "global.h"
29
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"
46
47 #ifdef __STDC__
48
49 /* Function prototypes for ANSI C Compilers */
50 static void cleanup(int sig);
51
52 #else /* __STDC__ */
53
54 /* Function prototypes for non-ANSI C Compilers */
55 static void cleanup();
56
57 #endif /* __STDC__ */
58
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 */
63
64 /*
65 * For 4.x, limit the choices of valid disk names to this set.
66 */
67 static char *disk_4x_identifiers[] = { "sd", "id"};
68 #define N_DISK_4X_IDS (sizeof (disk_4x_identifiers)/sizeof (char *))
69
70
71 /*
72 * This is the list of legal inputs for all yes/no questions.
73 */
74 char *confirm_list[] = {
75 "yes",
76 "no",
77 NULL,
78 };
79
80 /*
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.
83 */
84 void *
zalloc(count)85 zalloc(count)
86 int count;
87 {
88 void *ptr;
89
90 if ((ptr = (void *) calloc(1, (unsigned)count)) == NULL) {
91 err_print("Error: unable to calloc more space.\n");
92 fullabort();
93 }
94 return (ptr);
95 }
96
97 /*
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.
102 */
103 void *
rezalloc(ptr,count)104 rezalloc(ptr, count)
105 void *ptr;
106 int count;
107 {
108 void *new_ptr;
109
110
111 if ((new_ptr = (void *) realloc((char *)ptr,
112 (unsigned)count)) == NULL) {
113 err_print("Error: unable to realloc more space.\n");
114 fullabort();
115 }
116 return (new_ptr);
117 }
118
119 /*
120 * This routine is a wrapper for free.
121 */
122 void
destroy_data(data)123 destroy_data(data)
124 char *data;
125 {
126 free((char *)data);
127 }
128
129 #ifdef not
130 /*
131 * This routine takes the space number returned by an ioctl call and
132 * returns a mnemonic name for that space.
133 */
134 char *
space2str(space)135 space2str(space)
136 uint_t space;
137 {
138 char *name;
139
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();
159 }
160 return (name);
161 }
162 #endif /* not */
163
164 /*
165 * This routine asks the user the given yes/no question and returns
166 * the response.
167 */
168 int
check(question)169 check(question)
170 char *question;
171 {
172 int answer;
173 u_ioparam_t ioparam;
174
175 /*
176 * If we are running out of a command file, assume a yes answer.
177 */
178 if (option_f)
179 return (0);
180 /*
181 * Ask the user.
182 */
183 ioparam.io_charlist = confirm_list;
184 answer = input(FIO_MSTR, question, '?', &ioparam,
185 (int *)NULL, DATA_INPUT);
186 return (answer);
187 }
188
189 /*
190 * This routine aborts the current command. It is called by a ctrl-C
191 * interrupt and also under certain error conditions.
192 */
193 /*ARGSUSED*/
194 void
cmdabort(sig)195 cmdabort(sig)
196 int sig;
197 {
198
199 /*
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:"
203 * prompt.
204 */
205 if (current_env == NULL || !(current_env->flags & ENV_USE))
206 fullabort();
207
208 /*
209 * If we are in a critical zone, note the attempt and return.
210 */
211 if (current_env->flags & ENV_CRITICAL) {
212 current_env->flags |= ENV_ABORT;
213 return;
214 }
215 /*
216 * All interruptions when we are running out of a command file
217 * cause the program to gracefully exit.
218 */
219 if (option_f)
220 fullabort();
221 fmt_print("\n");
222 /*
223 * Clean up any state left by the interrupted command.
224 */
225 cleanup(sig);
226 /*
227 * Jump to the saved environment.
228 */
229 longjmp(current_env->env, 0);
230 }
231
232 /*
233 * This routine implements the ctrl-Z suspend mechanism. It is called
234 * when a suspend signal is received.
235 */
236 /*ARGSUSED*/
237 void
onsusp(sig)238 onsusp(sig)
239 int sig;
240 {
241 int fix_term;
242 #ifdef NOT_DEF
243 sigset_t sigmask;
244 #endif /* NOT_DEF */
245
246 /*
247 * If we are in a critical zone, note the attempt and return.
248 */
249 if (current_env != NULL && current_env->flags & ENV_CRITICAL) {
250 stop_pending = 1;
251 return;
252 }
253 /*
254 * If the terminal is mucked up, note that we will need to
255 * re-muck it when we start up again.
256 */
257 fix_term = ttystate.ttyflags;
258 fmt_print("\n");
259 /*
260 * Clean up any state left by the interrupted command.
261 */
262 cleanup(sig);
263 #ifdef NOT_DEF
264 /* Investigate whether all this is necessary */
265 /*
266 * Stop intercepting the suspend signal, then send ourselves one
267 * to cause us to stop.
268 */
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);
272 #endif /* NOT_DEF */
273 (void) signal(SIGTSTP, SIG_DFL);
274 (void) kill(0, SIGTSTP);
275 /*
276 * PC stops here
277 */
278 /*
279 * We are started again. Set us up to intercept the suspend
280 * signal once again.
281 */
282 (void) signal(SIGTSTP, onsusp);
283 /*
284 * Re-muck the terminal if necessary.
285 */
286 if (fix_term & TTY_ECHO_OFF)
287 echo_off();
288 if (fix_term & TTY_CBREAK_ON)
289 charmode_on();
290 }
291
292 /*
293 * This routine implements the timing function used during long-term
294 * disk operations (e.g. formatting). It is called when an alarm signal
295 * is received.
296 */
297 /*ARGSUSED*/
298 void
onalarm(sig)299 onalarm(sig)
300 int sig;
301 {
302 }
303
304
305 /*
306 * This routine gracefully exits the program.
307 */
308 void
fullabort()309 fullabort()
310 {
311
312 fmt_print("\n");
313 /*
314 * Clean up any state left by an interrupted command.
315 * Avoid infinite loops caused by a clean-up
316 * routine failing again...
317 */
318 if (!aborting) {
319 aborting = 1;
320 cleanup(SIGKILL);
321 }
322 exit(1);
323 /*NOTREACHED*/
324 }
325
326 /*
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.
329 *
330 * Some cleanup actions may depend on the type of signal.
331 */
332 static void
cleanup(int sig)333 cleanup(int sig)
334 {
335
336 /*
337 * Lock out interrupts to avoid recursion.
338 */
339 enter_critical();
340 /*
341 * Fix up the tty if necessary.
342 */
343 if (ttystate.ttyflags & TTY_CBREAK_ON) {
344 charmode_off();
345 }
346 if (ttystate.ttyflags & TTY_ECHO_OFF) {
347 echo_on();
348 }
349
350 /*
351 * If the defect list is dirty, write it out.
352 */
353 if (cur_list.flags & LIST_DIRTY) {
354 cur_list.flags = 0;
355 if (!EMBEDDED_SCSI)
356 write_deflist(&cur_list);
357 }
358 /*
359 * If the label is dirty, write it out.
360 */
361 if (cur_flags & LABEL_DIRTY) {
362 cur_flags &= ~LABEL_DIRTY;
363 (void) write_label();
364 }
365 /*
366 * If we are logging and just interrupted a scan, print out
367 * some summary info to the log file.
368 */
369 if (log_file && scan_cur_block >= 0) {
370 pr_dblock(log_print, scan_cur_block);
371 log_print("\n");
372 }
373 if (scan_blocks_fixed >= 0)
374 fmt_print("Total of %lld defective blocks repaired.\n",
375 scan_blocks_fixed);
376 if (sig != SIGSTOP) { /* Don't reset on suspend (converted to stop) */
377 scan_cur_block = scan_blocks_fixed = -1;
378 }
379 exit_critical();
380 }
381
382 /*
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().
387 */
388 void
enter_critical()389 enter_critical()
390 {
391
392 /*
393 * If there is no saved environment, interrupts will be ignored.
394 */
395 if (current_env == NULL)
396 return;
397 /*
398 * Mark the environment to be in a critical zone.
399 */
400 current_env->flags |= ENV_CRITICAL;
401 }
402
403 /*
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.
407 */
408 void
exit_critical()409 exit_critical()
410 {
411
412 /*
413 * If there is a saved environment, mark it to be non-critical.
414 */
415 if (current_env != NULL)
416 current_env->flags &= ~ENV_CRITICAL;
417 /*
418 * If there is a stop pending, execute the stop.
419 */
420 if (stop_pending) {
421 stop_pending = 0;
422 onsusp(SIGSTOP);
423 }
424 /*
425 * If there is an abort pending, execute the abort.
426 */
427 if (current_env == NULL)
428 return;
429 if (current_env->flags & ENV_ABORT) {
430 current_env->flags &= ~ENV_ABORT;
431 cmdabort(SIGINT);
432 }
433 }
434
435 /*
436 * This routine turns off echoing on the controlling tty for the program.
437 */
438 void
echo_off()439 echo_off()
440 {
441 /*
442 * Open the tty and store the file pointer for later.
443 */
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");
448 fullabort();
449 }
450 }
451 /*
452 * Get the parameters for the tty, turn off echoing and set them.
453 */
454 if (tcgetattr(ttystate.ttyfile, &ttystate.ttystate) < 0) {
455 err_print("Unable to get tty parameters.\n");
456 fullabort();
457 }
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");
461 fullabort();
462 }
463
464 /*
465 * Remember that we've successfully turned
466 * ECHO mode off, so we know to fix it later.
467 */
468 ttystate.ttyflags |= TTY_ECHO_OFF;
469 }
470
471 /*
472 * This routine turns on echoing on the controlling tty for the program.
473 */
474 void
echo_on()475 echo_on()
476 {
477
478 /*
479 * Using the saved parameters, turn echoing on and set them.
480 */
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");
484 fullabort();
485 }
486 /*
487 * Close the tty and mark it ok again.
488 */
489 ttystate.ttyflags &= ~TTY_ECHO_OFF;
490 if (ttystate.ttyflags == 0) {
491 (void) close(ttystate.ttyfile);
492 }
493 }
494
495 /*
496 * This routine turns off single character entry mode for tty.
497 */
498 void
charmode_on()499 charmode_on()
500 {
501
502 /*
503 * If tty unopened, open the tty and store the file pointer for later.
504 */
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");
509 fullabort();
510 }
511 }
512 /*
513 * Get the parameters for the tty, turn on char mode.
514 */
515 if (tcgetattr(ttystate.ttyfile, &ttystate.ttystate) < 0) {
516 err_print("Unable to get tty parameters.\n");
517 fullabort();
518 }
519 ttystate.vmin = ttystate.ttystate.c_cc[VMIN];
520 ttystate.vtime = ttystate.ttystate.c_cc[VTIME];
521
522 ttystate.ttystate.c_lflag &= ~ICANON;
523 ttystate.ttystate.c_cc[VMIN] = 1;
524 ttystate.ttystate.c_cc[VTIME] = 0;
525
526 if (tcsetattr(ttystate.ttyfile, TCSANOW, &ttystate.ttystate) < 0) {
527 err_print("Unable to set tty to cbreak on state.\n");
528 fullabort();
529 }
530
531 /*
532 * Remember that we've successfully turned
533 * CBREAK mode on, so we know to fix it later.
534 */
535 ttystate.ttyflags |= TTY_CBREAK_ON;
536 }
537
538 /*
539 * This routine turns on single character entry mode for tty.
540 * Note, this routine must be called before echo_on.
541 */
542 void
charmode_off()543 charmode_off()
544 {
545
546 /*
547 * Using the saved parameters, turn char mode on.
548 */
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");
554 fullabort();
555 }
556 /*
557 * Close the tty and mark it ok again.
558 */
559 ttystate.ttyflags &= ~TTY_CBREAK_ON;
560 if (ttystate.ttyflags == 0) {
561 (void) close(ttystate.ttyfile);
562 }
563 }
564
565
566 /*
567 * Allocate space for and return a pointer to a string
568 * on the stack. If the string is null, create
569 * an empty string.
570 * Use destroy_data() to free when no longer used.
571 */
572 char *
alloc_string(s)573 alloc_string(s)
574 char *s;
575 {
576 char *ns;
577
578 if (s == (char *)NULL) {
579 ns = (char *)zalloc(1);
580 } else {
581 ns = (char *)zalloc(strlen(s) + 1);
582 (void) strcpy(ns, s);
583 }
584 return (ns);
585 }
586
587
588
589 /*
590 * This function can be used to build up an array of strings
591 * dynamically, with a trailing NULL to terminate the list.
592 *
593 * Parameters:
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.
606 * Returns:
607 * a pointer to the possibly-moved argvlist.
608 *
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.
612 */
613 #define INITIAL_LISTSIZE 32
614 #define INCR_LISTSIZE 32
615
616 char **
build_argvlist(argvlist,size,alloc,str)617 build_argvlist(argvlist, size, alloc, str)
618 char **argvlist;
619 int *size;
620 int *alloc;
621 char *str;
622 {
623 if (*size + 2 > *alloc) {
624 if (*alloc == 0) {
625 *alloc = INITIAL_LISTSIZE;
626 argvlist = (char **)
627 zalloc(sizeof (char *) * (*alloc));
628 } else {
629 *alloc += INCR_LISTSIZE;
630 argvlist = (char **)
631 rezalloc((void *) argvlist,
632 sizeof (char *) * (*alloc));
633 }
634 }
635
636 argvlist[*size] = alloc_string(str);
637 *size += 1;
638 argvlist[*size] = NULL;
639
640 return (argvlist);
641 }
642
643
644 /*
645 * Useful parsing macros
646 */
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 */
652 /* be processed. */
653 #define skip_digit_or_hexupper(s) while (isdigit(*s) || \
654 (isxdigit(*s) && isupper(*s))) s++
655
656 /*
657 * Return true if a device name matches the conventions
658 * for the particular system.
659 */
660 int
conventional_name(char * name)661 conventional_name(char *name)
662 {
663 must_be(name, 'c');
664 skip_digits(name);
665 if (*name == 't') {
666 name++;
667 skip_digit_or_hexupper(name);
668 }
669 must_be(name, 'd');
670 skip_digits(name);
671 must_be(name, 's');
672 skip_digits(name);
673 return (*name == 0);
674 }
675
676 #ifdef i386
677 /*
678 * Return true if a device name match the emc powerpath name scheme:
679 * emcpowerN[a-p,p0,p1,p2,p3,p4]
680 */
681 int
emcpower_name(char * name)682 emcpower_name(char *name)
683 {
684 char *emcp = "emcpower";
685 char *devp = "/dev/dsk";
686 char *rdevp = "/dev/rdsk";
687
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;
692 }
693 if (strncmp(emcp, name, strlen(emcp)) == 0) {
694 name += strlen(emcp);
695 if (isdigit(*name)) {
696 skip_digits(name);
697 if ((*name >= 'a') && (*name <= 'p')) {
698 name ++;
699 if ((*name >= '0') && (*name <= '4')) {
700 name++;
701 }
702 }
703 return (*name == '\0');
704 }
705 }
706 return (0);
707 }
708 #endif
709
710 /*
711 * Return true if a device name matches the intel physical name conventions
712 * for the particular system.
713 */
714 int
fdisk_physical_name(char * name)715 fdisk_physical_name(char *name)
716 {
717 must_be(name, 'c');
718 skip_digits(name);
719 if (*name == 't') {
720 name++;
721 skip_digit_or_hexupper(name);
722 }
723 must_be(name, 'd');
724 skip_digits(name);
725 must_be(name, 'p');
726 skip_digits(name);
727 return (*name == 0);
728 }
729
730 /*
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.
735 */
736 int
whole_disk_name(name)737 whole_disk_name(name)
738 char *name;
739 {
740 must_be(name, 'c');
741 skip_digits(name);
742 if (*name == 't') {
743 name++;
744 skip_digit_or_hexupper(name);
745 }
746 must_be(name, 'd');
747 skip_digits(name);
748 must_be(name, 's');
749 must_be(name, '2');
750 return (*name == 0);
751 }
752
753
754 /*
755 * Return true if a name is in the internal canonical form
756 */
757 int
canonical_name(name)758 canonical_name(name)
759 char *name;
760 {
761 must_be(name, 'c');
762 skip_digits(name);
763 if (*name == 't') {
764 name++;
765 skip_digit_or_hexupper(name);
766 }
767 must_be(name, 'd');
768 skip_digits(name);
769 return (*name == 0);
770 }
771
772
773 /*
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.
776 */
777 int
canonical4x_name(name)778 canonical4x_name(name)
779 char *name;
780 {
781 char **p;
782 int i;
783
784 p = disk_4x_identifiers;
785 for (i = N_DISK_4X_IDS; i > 0; i--, p++) {
786 if (match_substr(name, *p)) {
787 name += strlen(*p);
788 break;
789 }
790 }
791 if (i == 0)
792 return (0);
793 skip_digits(name);
794 return (*name == 0);
795 }
796
797
798 /*
799 * Map a conventional name into the internal canonical form:
800 *
801 * /dev/rdsk/c0t0d0s0 -> c0t0d0
802 */
803 void
canonicalize_name(dst,src)804 canonicalize_name(dst, src)
805 char *dst;
806 char *src;
807 {
808 char *s;
809
810 /*
811 * Copy from the 'c' to the end to the destination string...
812 */
813 s = strchr(src, 'c');
814 if (s != NULL) {
815 (void) strcpy(dst, s);
816 /*
817 * Remove the trailing slice (partition) reference
818 */
819 s = dst + strlen(dst) - 2;
820 if (*s == 's') {
821 *s = 0;
822 }
823 } else {
824 *dst = 0; /* be tolerant of garbage input */
825 }
826 }
827
828
829 /*
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
833 */
834 int
match_substr(s1,s2)835 match_substr(s1, s2)
836 char *s1;
837 char *s2;
838 {
839 while (*s2 != 0) {
840 if (*s1++ != *s2++)
841 return (0);
842 }
843
844 return (1);
845 }
846
847
848 /*
849 * Dump a structure in hexadecimal, for diagnostic purposes
850 */
851 #define BYTES_PER_LINE 16
852
853 void
dump(hdr,src,nbytes,format)854 dump(hdr, src, nbytes, format)
855 char *hdr;
856 caddr_t src;
857 int nbytes;
858 int format;
859 {
860 int i;
861 int n;
862 char *p;
863 char s[256];
864
865 assert(format == HEX_ONLY || format == HEX_ASCII);
866
867 (void) strcpy(s, hdr);
868 for (p = s; *p; p++) {
869 *p = ' ';
870 }
871
872 p = hdr;
873 while (nbytes > 0) {
874 err_print("%s", p);
875 p = s;
876 n = min(nbytes, BYTES_PER_LINE);
877 for (i = 0; i < n; i++) {
878 err_print("%02x ", src[i] & 0xff);
879 }
880 if (format == HEX_ASCII) {
881 for (i = BYTES_PER_LINE-n; i > 0; i--) {
882 err_print(" ");
883 }
884 err_print(" ");
885 for (i = 0; i < n; i++) {
886 err_print("%c",
887 isprint(src[i]) ? src[i] : '.');
888 }
889 }
890 err_print("\n");
891 nbytes -= n;
892 src += n;
893 }
894 }
895
896
897 float
bn2mb(uint64_t nblks)898 bn2mb(uint64_t nblks)
899 {
900 float n;
901
902 n = (float)nblks / 1024.0;
903 return ((n / 1024.0) * cur_blksz);
904 }
905
906
907 diskaddr_t
mb2bn(float mb)908 mb2bn(float mb)
909 {
910 diskaddr_t n;
911
912 n = (diskaddr_t)(mb * 1024.0 * (1024.0 / cur_blksz));
913 return (n);
914 }
915
916 float
bn2gb(uint64_t nblks)917 bn2gb(uint64_t nblks)
918 {
919 float n;
920
921 n = (float)nblks / (1024.0 * 1024.0);
922 return ((n/1024.0) * cur_blksz);
923
924 }
925
926 float
bn2tb(uint64_t nblks)927 bn2tb(uint64_t nblks)
928 {
929 float n;
930
931 n = (float)nblks / (1024.0 * 1024.0 * 1024.0);
932 return ((n/1024.0) * cur_blksz);
933 }
934
935 diskaddr_t
gb2bn(float gb)936 gb2bn(float gb)
937 {
938 diskaddr_t n;
939
940 n = (diskaddr_t)(gb * 1024.0 * 1024.0 * (1024.0 / cur_blksz));
941 return (n);
942 }
943
944 /*
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.
947 */
948 int
get_tty_lines()949 get_tty_lines()
950 {
951 int tty_lines = TTY_LINES;
952 struct winsize winsize;
953
954 if ((option_f == (char *)NULL) && isatty(0) == 1 && isatty(1) == 1) {
955 /*
956 * We have a real terminal for std input and output
957 */
958 winsize.ws_row = 0;
959 if (ioctl(1, TIOCGWINSZ, &winsize) == 0) {
960 if (winsize.ws_row > 2) {
961 /*
962 * Should be atleast 2 lines, for division
963 * by (tty_lines - 1, tty_lines - 2) to work.
964 */
965 tty_lines = winsize.ws_row;
966 }
967 }
968 }
969 return (tty_lines);
970 }
971