Beispiel #1
0
static int Open(DC_RendererCtx *ctx) {
    WholeSpace *priv = ctx->priv;
    DC_ProcedureCtx *actctx = ctx->procedure_ctx;

    priv->nb_blocks = actctx->dev->capacity / actctx->blk_size;
    if (actctx->dev->capacity % actctx->blk_size)
        priv->nb_blocks++;
    priv->unread_count = actctx->progress.den;
    priv->sectors_per_block = actctx->blk_size / 512;
    priv->blocks_map = calloc(priv->nb_blocks, sizeof(uint8_t));
    assert(priv->blocks_map);
    int journal_fd = ((CopyPriv*)actctx->priv)->journal_fd;
    lseek(journal_fd, 0, SEEK_SET);
    if (((CopyPriv*)actctx->priv)->use_journal) {
        priv->unread_count = 0;
        uint8_t journal_chunk[1*1024*1024];
        int64_t chunklen;
        int64_t end_lba = ((CopyPriv*)actctx->priv)->end_lba;
        for (int64_t i = 0; i < priv->nb_blocks; i++) {
            int64_t lba = i * priv->sectors_per_block;
            if (lba % sizeof(journal_chunk) == 0) {
                chunklen = (end_lba - lba) < (int64_t)sizeof(journal_chunk) ? (end_lba - lba) : (int64_t)sizeof(journal_chunk);
                int ret = read(journal_fd, journal_chunk, chunklen);
                if (ret != chunklen)
                    return 1;
            }
            char sector_status = journal_chunk[lba % sizeof(journal_chunk)];
            priv->blocks_map[i] = sector_status;
            int sectors_in_block = priv->sectors_per_block;
            if (i == priv->nb_blocks - 1)  // Last block may be smaller
                sectors_in_block = (actctx->dev->capacity % actctx->blk_size) / 512;
            switch ((enum SectorStatus)sector_status) {
                case SectorStatus_eUnread:
                    priv->unread_count += sectors_in_block;
                    break;
                case SectorStatus_eReadOk:
                    priv->read_ok_count += sectors_in_block;
                    break;
                case SectorStatus_eBlockReadError:
                case SectorStatus_eSectorReadError:
                    priv->errors_count += sectors_in_block;
                    break;
            }
        }
    }
    priv->legend = derwin(stdscr, 9 /* legend win height */, LEGEND_WIDTH, 4, COLS-LEGEND_WIDTH); // leave 1st and last lines untouched
    assert(priv->legend);
    wbkgd(priv->legend, COLOR_PAIR(MY_COLOR_GRAY));

    priv->w_stats = derwin(stdscr, 3, LEGEND_WIDTH, 4+9, COLS-LEGEND_WIDTH);
    assert(priv->w_stats);

    priv->vis_height = LINES - 5;
    priv->vis_width = COLS - LEGEND_WIDTH - 1;
    int vis_cells_avail = priv->vis_height * priv->vis_width;
    priv->blocks_per_vis = priv->nb_blocks / vis_cells_avail;
    if (priv->nb_blocks % vis_cells_avail)
        priv->blocks_per_vis++;
    priv->vis = derwin(stdscr, priv->vis_height, priv->vis_width, 2, 0); // leave 1st and last lines untouched
    assert(priv->vis);
    wrefresh(priv->vis);

    whole_space_show_legend(priv);

    priv->avg_speed = derwin(stdscr, 1, LEGEND_WIDTH, 2, COLS-LEGEND_WIDTH);
    assert(priv->avg_speed);
    wbkgd(priv->avg_speed, COLOR_PAIR(MY_COLOR_GRAY));

    priv->eta = derwin(stdscr, 1, LEGEND_WIDTH, 1, COLS-LEGEND_WIDTH);
    assert(priv->eta);
    wbkgd(priv->eta, COLOR_PAIR(MY_COLOR_GRAY));

    priv->summary = derwin(stdscr, 10, LEGEND_WIDTH, 16, COLS-LEGEND_WIDTH);
    assert(priv->summary);
    wbkgd(priv->summary, COLOR_PAIR(MY_COLOR_GRAY));

    priv->w_end_lba = derwin(stdscr, 1, 20, 1, COLS-41);
    assert(priv->w_end_lba);
    wbkgd(priv->w_end_lba, COLOR_PAIR(MY_COLOR_GRAY));

    priv->w_cur_lba = derwin(stdscr, 1, 20, 1, COLS-61);
    assert(priv->w_cur_lba);
    wbkgd(priv->w_cur_lba, COLOR_PAIR(MY_COLOR_GRAY));

    priv->w_log = derwin(stdscr, 2, COLS, LINES-3, 0);
    assert(priv->w_log);
    scrollok(priv->w_log, TRUE);
    wbkgd(priv->w_log, COLOR_PAIR(MY_COLOR_GRAY));

    priv->reports[0].seqno = 1; // anything but zero

    char comma_lba_buf[30], *comma_lba_p;
    comma_lba_p = commaprint(actctx->dev->capacity / 512, comma_lba_buf, sizeof(comma_lba_buf));
    wprintw(priv->w_end_lba, "/ %s", comma_lba_p);
    wnoutrefresh(priv->w_end_lba);
    wprintw(priv->summary,
            "%s %s\n"
            "Ctrl+C to abort\n",
            actctx->procedure->display_name, actctx->dev->dev_path);
    wrefresh(priv->summary);
    int r = pthread_create(&priv->render_thread, NULL, render_thread_proc, priv);
    if (r)
        return r; // FIXME leak
    return 0;
}
/*
25x80

                                                             <--LEGEND_WIDTH=20->
+--------------------------------------------------------------------------------+
|                   LBA:       xxx,xxx / xxx,xxx,xxx         ETA           xx:xx |
|ZZZZZZZZZZZZZZZxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx SPEED    xxxxx kb/s |
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                     |
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x unread space      |^
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                     ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x copied space,     ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   no read errors    ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x read errors       ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   occured           || LEGEND_HEIGHT=9
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Display block is XXX||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx XXX blocks by 256 se||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ctors               |v
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x NNNNNNNNNN        |^
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x NNNNNNNNNN        || W_STATS_HEIGHT=3
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x NNNNNNNNNN        |v
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                     |
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Device copying /dev/|^
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx XXX                 ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Ctrl+C to abort     ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                     || SUMMARY
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                     ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                     ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                     ||
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx                               |v
| WHDD rev. X.X-X-gXXXXXXX                                                       |
+--------------------------------------------------------------------------------+
*/
static int Open(DC_RendererCtx *ctx) {
    WholeSpace *priv = ctx->priv;
    DC_ProcedureCtx *actctx = ctx->procedure_ctx;

    // TODO Raise error message
    if (LINES < 25 || COLS < 80)
        return -1;

    priv->nb_blocks = actctx->dev->capacity / actctx->blk_size;
    if (actctx->dev->capacity % actctx->blk_size)
        priv->nb_blocks++;
    priv->unread_count = actctx->progress.den;
    priv->sectors_per_block = actctx->blk_size / 512;
    priv->blocks_map = calloc(priv->nb_blocks, sizeof(uint8_t));
    assert(priv->blocks_map);
    int journal_fd = ((CopyPriv*)actctx->priv)->journal_fd;
    lseek(journal_fd, 0, SEEK_SET);
    if (((CopyPriv*)actctx->priv)->use_journal) {
        priv->unread_count = 0;
        uint8_t journal_chunk[1*1024*1024];
        int64_t chunklen;
        int64_t end_lba = ((CopyPriv*)actctx->priv)->end_lba;
        for (int64_t i = 0; i < priv->nb_blocks; i++) {
            int64_t lba = i * priv->sectors_per_block;
            if (lba % sizeof(journal_chunk) == 0) {
                chunklen = (end_lba - lba) < (int64_t)sizeof(journal_chunk) ? (end_lba - lba) : (int64_t)sizeof(journal_chunk);
                int ret = read(journal_fd, journal_chunk, chunklen);
                if (ret != chunklen)
                    return 1;
            }
            char sector_status = journal_chunk[lba % sizeof(journal_chunk)];
            priv->blocks_map[i] = sector_status;
            int sectors_in_block = priv->sectors_per_block;
            if (i == priv->nb_blocks - 1)  // Last block may be smaller
                sectors_in_block = (actctx->dev->capacity % actctx->blk_size) / 512;
            switch ((enum SectorStatus)sector_status) {
                case SectorStatus_eUnread:
                    priv->unread_count += sectors_in_block;
                    break;
                case SectorStatus_eReadOk:
                    priv->read_ok_count += sectors_in_block;
                    break;
                case SectorStatus_eBlockReadError:
                case SectorStatus_eSectorReadError:
                    priv->errors_count += sectors_in_block;
                    break;
            }
        }
    }

#define LBA_WIDTH 20
#define LEGEND_WIDTH 20
#define LEGEND_HEIGHT 9
#define LEGEND_VERT_OFFSET 3 /* ETA & SPEED are above, 1 for spacing */

    priv->w_cur_lba = derwin(stdscr, 1, LBA_WIDTH, 0 /* at the top */, COLS - LEGEND_WIDTH - 1 - (LBA_WIDTH * 2) );
    assert(priv->w_cur_lba);
    wbkgd(priv->w_cur_lba, COLOR_PAIR(MY_COLOR_GRAY));

    priv->w_end_lba = derwin(stdscr, 1, LBA_WIDTH, 0 /* at the top */, COLS - LEGEND_WIDTH - 1 - LBA_WIDTH);
    assert(priv->w_end_lba);
    wbkgd(priv->w_end_lba, COLOR_PAIR(MY_COLOR_GRAY));

    priv->eta = derwin(stdscr, 1, LEGEND_WIDTH, 0 /* at the top */, COLS-LEGEND_WIDTH);
    assert(priv->eta);
    wbkgd(priv->eta, COLOR_PAIR(MY_COLOR_GRAY));

    priv->avg_speed = derwin(stdscr, 1, LEGEND_WIDTH, 1 /* ETA is above */, COLS-LEGEND_WIDTH);
    assert(priv->avg_speed);
    wbkgd(priv->avg_speed, COLOR_PAIR(MY_COLOR_GRAY));

    priv->legend = derwin(stdscr, LEGEND_HEIGHT, LEGEND_WIDTH, LEGEND_VERT_OFFSET, COLS-LEGEND_WIDTH);
    assert(priv->legend);
    wbkgd(priv->legend, COLOR_PAIR(MY_COLOR_GRAY));

#define W_STATS_HEIGHT 3
#define W_STATS_VERT_OFFSET ( LEGEND_VERT_OFFSET + LEGEND_HEIGHT + 1 /* spacing */ )
    priv->w_stats = derwin(stdscr, W_STATS_HEIGHT, LEGEND_WIDTH, W_STATS_VERT_OFFSET, COLS-LEGEND_WIDTH);
    assert(priv->w_stats);

#define SUMMARY_VERT_OFFSET ( W_STATS_VERT_OFFSET + W_STATS_HEIGHT + 1 /* spacing */ )
#define SUMMARY_HEIGHT ( LINES - SUMMARY_VERT_OFFSET - 1 /* don't touch bottom line */ )
    priv->summary = derwin(stdscr, SUMMARY_HEIGHT, LEGEND_WIDTH, SUMMARY_VERT_OFFSET, COLS-LEGEND_WIDTH);
    assert(priv->summary);
    wbkgd(priv->summary, COLOR_PAIR(MY_COLOR_GRAY));

    priv->vis_height = LINES - 2; /* LBA is above, version is below */
    priv->vis_width = COLS - LEGEND_WIDTH - 1;
    int vis_cells_avail = priv->vis_height * priv->vis_width;
    priv->blocks_per_vis = priv->nb_blocks / vis_cells_avail;
    if (priv->nb_blocks % vis_cells_avail)
        priv->blocks_per_vis++;
    priv->vis = derwin(stdscr, priv->vis_height, priv->vis_width, 1 /* LBA is above */, 0);
    assert(priv->vis);
    wrefresh(priv->vis);

    whole_space_show_legend(priv);

    priv->reports[0].seqno = 1; // anything but zero

    char comma_lba_buf[30], *comma_lba_p;
    comma_lba_p = commaprint(actctx->dev->capacity / 512, comma_lba_buf, sizeof(comma_lba_buf));
    wprintw(priv->w_end_lba, "/ %s", comma_lba_p);
    wnoutrefresh(priv->w_end_lba);
    wprintw(priv->summary,
            "%s %s\n"
            "Ctrl+C to abort\n",
            actctx->procedure->display_name, actctx->dev->dev_path);
    wrefresh(priv->summary);
    int r = pthread_create(&priv->render_thread, NULL, render_thread_proc, priv);
    if (r)
        return r; // FIXME leak
    return 0;
}