📄 gui.cpp
字号:
/* * Graphical user interface for AIMAGE *//* * Copyright (c) 2005,2006 * Simson L. Garfinkel and Basis Technology Corp. * All rights reserved. * * This code is derrived from software contributed by * Simson L. Garfinkel * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Simson L. Garfinkel * and Basis Technology Corp. * 4. Neither the name of Simson Garfinkel, Basis Technology, or other * contributors to this program may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY SIMSON GARFINKEL, BASIS TECHNOLOGY, * AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL SIMSON GARFINKEL, BAIS TECHNOLOGy, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "config.h"#include "afflib.h" #include "afflib_i.h" #include "aimage.h"#include "aftimer.h"#include "imager.h"bool show_help = false;/* Screen Layout */const unsigned time_row = 0;const unsigned preview_row = 6;const unsigned preview_rows = 4;const unsigned arrow_row = 10;const unsigned current_row = 12;const unsigned sectors_row = 13; // "Sectors Read"const unsigned blank_sectors_row = 14;const unsigned done_in_row = 15;const unsigned reading_row = 16;const unsigned bad_sectors_row = 17;const unsigned bytes_read_row = 18;const unsigned bytes_written_row = 19;const unsigned compression_row = 21;const unsigned space_row = 23;const unsigned phase_row = 24;static unsigned old_status_col = 0;static int old_status_dir = -10;#define cols 80 // optimize it for 80#ifndef CTRL#define CTRL(x) (x&037)#endifint repaint_screen = 1;/* comma_printw(): * Print a value with commas. If space!=0, allow this many characters * and right-justify */void comma_printw(int64 val,unsigned int space){ char buf[64]; af_commas(buf,val); while(strlen(buf) < space && space>0){ printw(" "); space--; } printw(buf); // send it to standard output}/**************************************************************** *** Simson's termcap routines. ****************************************************************/void boldw(const char *str){ if(str[0]){ attr_on(WA_BOLD,0); printw("%s",str); attr_off(WA_BOLD,0); }}void boldrc(int row,int col,char *str){ if(str[0]){ attr_on(WA_BOLD,0); mvprintw(row,col,"%s",str); attr_off(WA_BOLD,0); }}void help_window(){ WINDOW *help = subwin(stdscr,25,25,1,1); box(help,0,0); wrefresh(help);}void my_keyboard(){ switch(getch()){ case 'h': help_window(); return; case ERR: return; case CTRL('l'): return; }}uint64 total_sectors_all_drives(){ uint64 ret = 0; for(int i=0;i<num_imagers;i++){ ret += imagers[i]->total_sectors; } return ret;}uint64 total_sectors_read_all_drives(){ uint64 ret = 0; for(int i=0;i<num_imagers;i++){ ret += imagers[i]->total_sectors_read; } return ret;}#define xstr(s) str(s)#define str(s) #sstatic int batch_first = 0;void my_paint_screen(imager *im){ /* Put up the aimage version */ char *version = "aimage " xstr(PACKAGE_VERSION); mvprintw(space_row,79-strlen(version),"%s",version); /* First time through, paint the stuff that doesn't change much */ /* Source Device */ int ncol = 16; // where to put the first numeric column mvprintw(1, 0, "Source device: "); boldrc(1,ncol, im->infile); mvprintw(2, 0, "Model #:"); boldrc(2,ncol, im->device_model); if(im->serial_number[0]){ mvprintw(3,0,"S/N:"); boldrc(3,ncol,im->serial_number); } if(im->firmware_revision[0]){ mvprintw(4,0,"firmware: "); boldrc(4,ncol,im->firmware_revision); } /* Output */ if(im->fname_aff[0]){ mvprintw(1,38,"AFF Output: "); boldw(im->fname_aff); } if(im->fname_raw[0]){ mvprintw(2,40,"Raw Output: "); boldw(im->fname_raw); } mvprintw(3,35," Disk Size: "); uint64 disk_size = im->sector_size * im->total_sectors; if(disk_size>1000000000){ printw("%d GB",(int)(disk_size/1000000000)); } else if(disk_size>1000000){ printw("%d MB",(int)(disk_size/1000000)); } else if(disk_size>1024){ printw("%d KB",(int)(disk_size/1024)); } else printw("?? "); printw(" (%d byte sectors) ",im->sector_size); mvprintw(4,35,"Total sectors: "); if(im->total_sectors){ comma_printw(im->total_sectors,0); } else { printw("????"); } /* Print the bar graph */ mvprintw(arrow_row,0,"["); for(unsigned int i=1;i<cols-2;i++){ mvprintw(arrow_row,i," "); } mvprintw(arrow_row,cols-1,"]");}int column_for_sector(uint64 sector,imager *im){ return (int)(((float)im->last_sector_read /im->total_sectors) * (cols-2)) + 1; }static inline int min(int a,int b) { return a<b ? a : b;}static inline int max(int a,int b) { return a>b ? a : b;}/* Static variables to see if we need to refresh again */int previous_direction = -99;int64 previous_bytes_read = 0;int previous_phase = -99;inline int64 abs64(int64 a){ if(a<0) return -a; return a;}void my_refresh(imager *im,struct affcallback_info *acbi){ if(opt_batch){ if(batch_first){ printf("Source device: %s\n",im->infile); printf("Model #: %s\n",im->device_model); printf("S/N: %s\n",im->serial_number); printf("firmware: %s\n",im->firmware_revision); if(im->fname_aff[0]) printf("AFF output: %s\n",im->fname_aff); if(im->fname_raw[0]) printf("Raw output: %s\n",im->fname_raw); printf("Sector size: %d\n",im->sector_size); printf("Total sectors: %qd\n",im->total_sectors); batch_first = 0; } printf("Current sector: %qd\n",im->last_sector_read); printf("Last sectors read: %d\n",im->last_sectors_read); printf("Total sectors read: %qd\n",im->total_sectors_read); printf("Total blank sectors: %qd\n",im->total_blank_sectors); printf("Total bad sectors: %qd\n",im->bad_sectors_read); printf("Consecutive bad regions: %d\n",im->consecutive_read_error_regions); printf("Bytes read: %qd\n",im->total_bytes_read); printf("Bytes written: %qd\n",im->callback_bytes_written); if(acbi){ printf("Current phase: %d\n",acbi->phase); } printf("Free space on capture drive: %qd\n",im->output_ident->freebytes()); printf("\n"); return; } if(repaint_screen){ my_paint_screen(im); repaint_screen = 0; } //my_keyboard(); // process keyboard commands one day /* Optimization: Don't update the screen unless either the direction has changed * or else more than a million byte have been read since last time */ int current_phase = acbi ? acbi->phase : 0; if((previous_direction == im->last_direction) && (abs64(previous_bytes_read - im->total_bytes_read) < 1000000) && (previous_phase == current_phase)){ return; } previous_direction = im->last_direction; previous_bytes_read = im->total_bytes_read; previous_phase = current_phase; /* Stuff that changes a lot; this needs to be redone * to use curses... */ mvprintw(time_row,0,"Elapsed Time: %s",im->imaging_timer.timer_text()); if(im->imaging){ attr_on(WA_BOLD,0); if(opt_blink) attr_on(WA_BLINK,0); mvprintw(0,(cols-strlen(opt_title))/2,"%s",opt_title); attr_off(WA_BLINK,0); attr_off(WA_BOLD,0); } /* Display the time */ char timebuf[64]; time_t now = time(0); strcpy(timebuf,ctime(&now)); timebuf[25] = '\000'; mvprintw(time_row,cols-24,"%s",timebuf); mvprintw(current_row,0," Currently reading sector: "); comma_printw(im->last_sector_read,15); printw(" (%3d sector chunks) ",im->last_sectors_read); /* Don't print 'Sectors read' unless the hash is not valid * (which indicates that we have had a bad block or a direction reverasl.) */ if(im->hash_invalid){ mvprintw(sectors_row,0," Sectors read: "); comma_printw(im->total_sectors_read,15); } double fraction_done = -1; if(im->total_sectors>0){ // can we figure this out? fraction_done = ((double)im->total_sectors_read / (double)im->total_sectors); printw(" (%5.2f%% done) ", fraction_done * 100.0); } mvprintw(blank_sectors_row,0," blank sectors: "); comma_printw(im->total_blank_sectors,15); if(im->total_sectors_read == im->total_blank_sectors){ printw(" NO DATA YET!"); } clrtoeol(); // clear to end of line if(opt_use_timers){ mvprintw(reading_row,0," Time spent reading: %15s ", im->read_timer.timer_text()); } if(fraction_done>0){ mvprintw(done_in_row,0," Done in: %s ", im->imaging_timer.eta_text(fraction_done)); if(num_imagers>0){ printw("(this drive)"); if(current_imager+1<num_imagers){ // don't display for the last imager /* Figure out total fraction done */ double tsr_ad = total_sectors_read_all_drives(); double ts_ad = total_sectors_all_drives(); if(ts_ad>0){ double total_fraction_done = tsr_ad / ts_ad; if(total_fraction_done>0 && total_fraction_done<100){ printw(" %s (all drives)", total_time.eta_text(total_fraction_done)); } } } } } clrtoeol(); if(im->bad_sectors_read){ mvprintw(bad_sectors_row,0," BAD SECTORS: "); comma_printw(im->bad_sectors_read,15); if(im->consecutive_read_error_regions){ printw(" (%d consecutive bad regions)", im->consecutive_read_error_regions); } } clrtoeol(); mvprintw(bytes_read_row,0," Bytes read: "); comma_printw(im->total_bytes_read,15); mvprintw(bytes_written_row, 0," Bytes written: "); comma_printw(im->callback_bytes_written,15); if(opt_use_timers){ printw(" (%s)", im->write_timer.timer_text()); } if(im->callback_bytes_to_write>0 && im->callback_bytes_written>0 && acbi && acbi->af){ if(af_compression_type(acbi->af)==AF_COMPRESSION_ALG_NONE){ mvprintw(compression_row,0,""); clrtoeol(); } else{ double fraction = (double)im->callback_bytes_written / (double)im->callback_bytes_to_write; double overall_compression_ratio = 100.0 - fraction*100.0; if(overall_compression_ratio>0.0 && overall_compression_ratio<100.0){ mvprintw(compression_row,0,"Overall compression ratio: %6.2f%% " "(0%% is none; 100%% is perfect)", overall_compression_ratio); } } } attr_on(WA_BOLD,0); attr_on(WA_BLINK,0); if(current_phase==1) mvprintw(phase_row,30,"===> COMPRESSING"); if(current_phase==3) mvprintw(phase_row,30," WRITING ===>"); attr_off(WA_BOLD,0); attr_off(WA_BLINK,0); clrtoeol(); /* Update the arrow */ if(im->total_sectors){ unsigned new_status_col = column_for_sector(im->last_sector_read,im); const char *dir_str = (im->last_direction==1) ? ">" : "<"; attr_on(WA_REVERSE,0); if(old_status_col && old_status_col != new_status_col){ /* Need to erase old status */ if(old_status_dir == im->last_direction){ /* We can draw a line */ for(int i=min(old_status_col,new_status_col); i<=max(old_status_col,new_status_col); i++){ mvprintw(arrow_row,i,"="); } } mvprintw(arrow_row,old_status_col,"="); } old_status_col = new_status_col; old_status_dir = im->last_direction; mvprintw(arrow_row,new_status_col,dir_str); attr_off(WA_REVERSE,0); } /* Data preview... */ if(opt_preview && im->buf){ for(unsigned int i=0;i<preview_rows;i++){ char row[80]; for(unsigned j=0;j<79;j++){ char cc = *(char *)(im->buf+i*80+j); if(isprint(cc)) row[j] = cc; else row[j] = '.'; } row[79] = 0; mvprintw(preview_row+i,0,"%s",row); } } char buf[64]; mvprintw(space_row,0,"Free space on capture drive: %s MB", af_commas(buf,im->output_ident->freebytes()/((long long)1024*1024))); clrtoeol(); /* Are we imaging more than one drive? */ if(num_imagers>1){ mvprintw(0,0,"Drive %d of %d: ",current_imager+1,num_imagers); } refresh();}int gui_active = 0;void gui_shutdown(){ if(opt_quiet) return; if(opt_batch){ printf("aimage: shutdown gui\n"); batch_first = 0; return; } if(gui_active){ endwin(); // turn off curses gui_active = 0; }}void gui_startup(){ if(opt_quiet) return; if(opt_batch){ setvbuf(stdout,0,_IONBF,0); // unbuffered output printf("aimage: startup gui\n"); batch_first = 1; return; } initscr(); // Turn on Curses nodelay(stdscr,1); // don't delay stuff to stdscr repaint_screen = 1; atexit(gui_shutdown); gui_active = 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -