From 6136e07b77799accfa2d228bd29caa3d4ec2832d Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 9 Feb 2020 07:29:15 -0500 Subject: [PATCH 01/30] drone: new builders --- .drone.yml | 4 ++-- README.md | 2 +- configure.ac | 2 +- debian/control | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.drone.yml b/.drone.yml index 885e2bd0..941c41f6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-01-18a + image: dankamongmen/unstable_builder:2020-02-05a commands: - apt-get update - apt-get -y install devscripts git-buildpackage @@ -22,7 +22,7 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-01-18a + image: dankamongmen/focal:2020-02-07a commands: - apt-get update - apt-get -y install devscripts git-buildpackage equivs diff --git a/README.md b/README.md index 5845531a..a4f991a5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ https://nick-black.com/dankwiki/index.php/Growlight Dependencies: - - notcurses 1.1.2+ + - notcurses 1.1.6+ - libudev 175+ - libblkid 2.20.1+ - libpci 3.1.9+ diff --git a/configure.ac b/configure.ac index cb19881f..75648a58 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ AC_CHECK_LIB(pci, pci_get_dev, [have_libpci=yes], LIBS+=" -lpci" if test "x$notcurses" = "xtrue" ; then - PKG_CHECK_MODULES([notcurses], [notcurses >= 1.1.2]) + PKG_CHECK_MODULES([notcurses], [notcurses >= 1.1.6]) notcurses_CFLAGS+=" $notcurses_CFLAGS" notcurses_LIBS+=" $notcurses_LIBS" fi diff --git a/debian/control b/debian/control index 39004471..2a7575bb 100644 --- a/debian/control +++ b/debian/control @@ -5,7 +5,7 @@ Maintainer: Nick Black Build-Depends: debhelper (>= 12), libatasmart-dev, libblkid-dev, libcryptsetup-dev, libpci-dev, libpciaccess-dev, libdevmapper-dev, libudev-dev, autoconf-archive, libncurses-dev, libreadline-dev, libcunit1-ncurses-dev, - pkg-config, xsltproc, docbook-xsl, libssl-dev, libnotcurses-dev (>= 1.1.2), + pkg-config, xsltproc, docbook-xsl, libssl-dev, libnotcurses-dev (>= 1.1.6), libzfslinux-dev (>= 0.8.0) Standards-Version: 4.5.0 Homepage: https://nick-black.com/dankwiki/index.php/Growlight From 05b3d0b87bc76f57ac547eeb7f0df1b50ff9016d Mon Sep 17 00:00:00 2001 From: nick black Date: Mon, 10 Feb 2020 16:49:53 -0500 Subject: [PATCH 02/30] adapt to notcurses 1.1.6 api changes --- src/notcurses.c | 325 ++++++++++++++++++++++++------------------------ 1 file changed, 160 insertions(+), 165 deletions(-) diff --git a/src/notcurses.c b/src/notcurses.c index 77333cc0..e461ba3e 100644 --- a/src/notcurses.c +++ b/src/notcurses.c @@ -354,7 +354,7 @@ static void compat_set_fg_all(struct ncplane* nc, int attr){ switch(attr){ case SUBDISPLAY_ATTR: - ncplane_styles_set(nc, CELL_STYLE_BOLD); + ncplane_styles_set(nc, NCSTYLE_BOLD); compat_set_fg(nc, SUBDISPLAY_COLOR); break; case SUBDISPLAY_INVAL_ATTR: @@ -400,13 +400,13 @@ subscript(int in){ } static struct notcurses* NC; -static struct panelreel* PR; +static struct ncreel* PR; static inline void screen_update(void){ - // must do the panelreel first, as it can create new ones at the top + // must do the ncreel first, as it can create new ones at the top if(PR){ - panelreel_redraw(PR); + ncreel_redraw(PR); } if(active){ ncplane_move_top(active->p); @@ -456,8 +456,8 @@ typedef struct blockobj { zobj* zone; } blockobj; -// An adapter, which might be invisible (in which case the tablet is NULL). If a -// tablet exists for this adapter, its userptr is the adapterstate. +// An adapter, which might be invisible (in which case the nctablet is NULL). If a +// nctablet exists for this adapter, its userptr is the adapterstate. typedef struct adapterstate { controller* c; unsigned devs; @@ -470,7 +470,7 @@ typedef struct adapterstate { struct adapterstate* next; struct adapterstate* prev; blockobj* bobjs; - struct tablet* rb; // FIXME name is an anachronism + struct nctablet* rb; // FIXME name is an anachronism } adapterstate; #define EXPANSION_MAX EXPANSION_FULL @@ -483,8 +483,8 @@ static unsigned count_adapters; static adapterstate * get_current_adapter(void){ - struct tablet* t = panelreel_focused(PR); - adapterstate* as = tablet_userptr(t); + struct nctablet* t = ncreel_focused(PR); + adapterstate* as = nctablet_userptr(t); return as; } @@ -656,21 +656,21 @@ bevel_all(struct ncplane* nc){ static int cwattrset(struct ncplane* n, int style){ ncplane_styles_set(n, style); - compat_set_fg(n, style & ~CELL_STYLE_MASK); + compat_set_fg(n, style & ~NCSTYLE_MASK); return 0; } static int cwattroff(struct ncplane* n, int style){ ncplane_styles_off(n, style); - compat_set_fg(n, style & ~CELL_STYLE_MASK); + compat_set_fg(n, style & ~NCSTYLE_MASK); return 0; } static int cwattron(struct ncplane* n, int style){ ncplane_styles_on(n, style); - compat_set_fg(n, style & ~CELL_STYLE_MASK); + compat_set_fg(n, style & ~NCSTYLE_MASK); return 0; } @@ -741,12 +741,7 @@ cwprintw(struct ncplane* n, const char* fmt, ...){ static int cwbkgd(struct ncplane* nc){ - cell cl = CELL_TRIVIAL_INITIALIZER; - cell_load(nc, &cl, " "); - cell_set_fg_rgb(&cl, 0, 0, 0); - ncplane_set_base(nc, &cl); - cell_release(nc, &cl); - return 0; + return ncplane_set_base(nc, 0, 0, " "); } static void @@ -762,7 +757,7 @@ draw_main_window(struct ncplane* n){ ncplane_cursor_yx(n, &y, &x); assert(x >= 0); cols -= x + 2; - cwattron(n, CELL_STYLE_BOLD | STATUS_COLOR); + cwattron(n, NCSTYLE_BOLD | STATUS_COLOR); cwprintw(n, " %-*.*s", cols, cols, statusmsg); } @@ -863,10 +858,10 @@ new_display_panel(struct ncplane* nc, struct panel_state* ps, locked_diag("Couldn't create subpanel, uh-oh"); return -1; } - cwattron(ps->p, CELL_STYLE_BOLD); + cwattron(ps->p, NCSTYLE_BOLD); compat_set_fg(ps->p, borderpair); bevel_all(ps->p); - cwattroff(ps->p, CELL_STYLE_BOLD); + cwattroff(ps->p, NCSTYLE_BOLD); compat_set_fg(ps->p, PHEADING_COLOR); if(hstr){ cmvwaddwstr(ps->p, 0, START_COL * 2, hstr); @@ -908,7 +903,7 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int if(d->mnttype && (d->layout != LAYOUT_NONE || !d->blkdev.pttable)){ int co = mnttype_aggregablep(d->mnttype) ? PART_COLOR0 : FS_COLOR; - cwattrset(n, CELL_STYLE_BOLD|co); + cwattrset(n, NCSTYLE_BOLD|co); qprefix(zs, 1, pre, 1); if(!d->mnt.count || swprintf(wbuf, wchars, L" %s%s%ls%s%ls%s%s%sat %s ", d->label ? "" : "nameless ", @@ -940,13 +935,13 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int cmvwadd_wch(n, y, ex - 1, L" "); selstr = d->name; }else if(d->layout == LAYOUT_NONE && d->blkdev.unloaded){ - cwattrset(n, CELL_STYLE_BOLD|OPTICAL_COLOR); + cwattrset(n, NCSTYLE_BOLD|OPTICAL_COLOR); selstr = "No media detected in drive"; cmvwprintw(n, y, sx, "%-*.*s", ex - sx, ex - sx, selstr); }else if((d->layout == LAYOUT_NONE && d->blkdev.pttable == NULL) || (d->layout == LAYOUT_MDADM && d->mddev.pttable == NULL) || (d->layout == LAYOUT_DM && d->dmdev.pttable == NULL)){ - cwattrset(n, CELL_STYLE_BOLD|EMPTY_COLOR); + cwattrset(n, NCSTYLE_BOLD|EMPTY_COLOR); selstr = d->layout == LAYOUT_NONE ? "unpartitioned space" : "unpartitionable space"; snprintf(buf, sizeof(buf), " %s %s ", qprefix(d->size, 1, pre, 1), selstr) < (int)sizeof(buf); @@ -957,9 +952,9 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int } if((z = bo->zchain) == NULL){ if(selected){ - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); cmvwprintw(n, y - 1, sx + 1, "⇗⇨⇨⇨%.*s", (int)(ex - (sx + 5)), selstr); - cwattroff(n, CELL_STYLE_REVERSE); + cwattroff(n, NCSTYLE_REVERSE); } return; } @@ -981,7 +976,7 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int if(selected && z == bo->zone){ selstr = repstr; - cwattrset(n, CELL_STYLE_BOLD|CELL_STYLE_UNDERLINE|co); + cwattrset(n, NCSTYLE_BOLD|NCSTYLE_UNDERLINE|co); }else{ cwattrset(n, co); } @@ -994,15 +989,15 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int }else{ // dedicated partition if(selected && z == bo->zone){ // partition and device are selected if(targeted_p(z->p)){ - cwattrset(n, CELL_STYLE_BOLD|CELL_STYLE_UNDERLINE|targco); + cwattrset(n, NCSTYLE_BOLD|NCSTYLE_UNDERLINE|targco); targco = next_targco(targco); }else if(z->p->mnt.count){ - cwattrset(n, CELL_STYLE_BOLD|CELL_STYLE_UNDERLINE|mountco); + cwattrset(n, NCSTYLE_BOLD|NCSTYLE_UNDERLINE|mountco); mountco = next_mountco(mountco); }else if(z->p->mnttype && !mnttype_aggregablep(z->p->mnttype)){ - cwattrset(n, CELL_STYLE_BOLD|CELL_STYLE_UNDERLINE|FS_COLOR); + cwattrset(n, NCSTYLE_BOLD|NCSTYLE_UNDERLINE|FS_COLOR); }else{ - cwattrset(n, CELL_STYLE_BOLD|CELL_STYLE_UNDERLINE|partco); + cwattrset(n, NCSTYLE_BOLD|NCSTYLE_UNDERLINE|partco); partco = next_partco(partco); } // FIXME need to store pname as multibyte char * @@ -1035,7 +1030,7 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int } } if(z->p->partdev.alignment < d->physsec){ // misaligned! - cwattrset(n, CELL_STYLE_BOLD|FUCKED_COLOR); + cwattrset(n, NCSTYLE_BOLD|FUCKED_COLOR); } if(z->p->mnttype){ if((!z->p->mnt.count || swprintf(wbuf, wchars - 2, L"%s at %s (%s)", z->p->mnttype, z->p->mnt.list[0], pre) >= wchars - 2)){ @@ -1065,7 +1060,7 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int break; } } - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); if(selstr){ if(och < ex / 2u){ cmvwprintw(n, y - 1, och, "⇗⇨⇨⇨%.*s", (int)(ex - (off + strlen(selstr) + 4)), selstr); @@ -1073,7 +1068,7 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int cmvwprintw(n, y - 1, off - 4 - strlen(selstr), "%s⇦⇦⇦⇖", selstr); } } - cwattroff(n, CELL_STYLE_REVERSE); + cwattroff(n, NCSTYLE_REVERSE); // Truncate it at whitespace until it's small enough to fit while(wcslen(wbuf) && wcslen(wbuf) + 2 > (off - och + 1)){ wchar_t *wtrunc = wcsrchr(wbuf, L' '); @@ -1087,7 +1082,7 @@ print_blockbar(struct ncplane* n, const blockobj* bo, int y, int sx, int ex, int if(wcslen(wbuf)){ size_t start = och + ((off - och + 1) - wcslen(wbuf)) / 2; - cwattron(n, CELL_STYLE_BOLD); + cwattron(n, NCSTYLE_BOLD); cmvwaddwstr(n, y, start, wbuf); cmvwadd_wch(n, y, start - 1, L" "); cmvwadd_wch(n, y, start + wcslen(wbuf), L" "); @@ -1151,7 +1146,7 @@ case LAYOUT_NONE: if(bo->d->size){ line += 2; }else if(selected){ - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); } cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, @@ -1185,7 +1180,7 @@ case LAYOUT_MDADM: if(bo->d->size){ line += 2; }else if(selected){ - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); } cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, @@ -1212,7 +1207,7 @@ case LAYOUT_DM: if(bo->d->size){ line += 2; }else if(selected){ - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); } cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, @@ -1240,7 +1235,7 @@ case LAYOUT_ZPOOL: if(bo->d->size){ line += 2; }else if(selected){ - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); } cmvwprintw(n, line, 1, "%11.11s %-16.16s %4ju " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, @@ -1262,8 +1257,8 @@ case LAYOUT_ZPOOL: if(bo->d->size == 0){ return 1; } - cwattroff(n, CELL_STYLE_REVERSE); - cwattrset(n, CELL_STYLE_BOLD|SUBDISPLAY_COLOR); + cwattroff(n, NCSTYLE_REVERSE); + cwattrset(n, NCSTYLE_BOLD|SUBDISPLAY_COLOR); // Box-diagram (3-line) mode. Print the name on the first line. if(line + !!cliptop >= 1){ @@ -1276,19 +1271,19 @@ case LAYOUT_ZPOOL: wchar_t rep = L' '; if(bo->d->blkdev.smart >= 0){ if(bo->d->blkdev.smart == SK_SMART_OVERALL_GOOD){ - cwattrset(n, CELL_STYLE_BOLD|GREEN_COLOR); + cwattrset(n, NCSTYLE_BOLD|GREEN_COLOR); rep = L'✔'; }else if(bo->d->blkdev.smart != SK_SMART_OVERALL_BAD_STATUS && bo->d->blkdev.smart != SK_SMART_OVERALL_BAD_SECTOR_MANY){ - cwattrset(n, CELL_STYLE_BOLD|ORANGE_COLOR); + cwattrset(n, NCSTYLE_BOLD|ORANGE_COLOR); rep = L'☠'; }else{ - cwattrset(n, CELL_STYLE_BOLD|FUCKED_COLOR); + cwattrset(n, NCSTYLE_BOLD|FUCKED_COLOR); rep = L'✗'; } } cmvwprintw(n, line + 1, START_COL, "%lc", rep); - cwattrset(n, CELL_STYLE_BOLD|SUBDISPLAY_COLOR); + cwattrset(n, NCSTYLE_BOLD|SUBDISPLAY_COLOR); if(strlen(rolestr)){ cwprintw(n, "%10.10s", rolestr); }else{ @@ -1301,9 +1296,9 @@ case LAYOUT_ZPOOL: if(bo->d->layout == LAYOUT_NONE){ if(bo->d->blkdev.celsius && bo->d->blkdev.celsius < 100u){ if(bo->d->blkdev.celsius >= 60u){ - cwattrset(n, CELL_STYLE_BOLD|FUCKED_COLOR); + cwattrset(n, NCSTYLE_BOLD|FUCKED_COLOR); }else if(bo->d->blkdev.celsius >= 40u){ - cwattrset(n, CELL_STYLE_BOLD|ORANGE_COLOR); + cwattrset(n, NCSTYLE_BOLD|ORANGE_COLOR); }else{ cwattrset(n, GREEN_COLOR); } @@ -1314,7 +1309,7 @@ case LAYOUT_ZPOOL: } }else if(bo->d->layout == LAYOUT_MDADM){ if(bo->d->mddev.degraded){ - cwattrset(n, CELL_STYLE_BOLD|FUCKED_COLOR); + cwattrset(n, NCSTYLE_BOLD|FUCKED_COLOR); cmvwprintw(n, sumline, START_COL, "%1lux☠ ", bo->d->mddev.degraded); }else{ @@ -1327,7 +1322,7 @@ case LAYOUT_ZPOOL: cmvwprintw(n, sumline, START_COL, "up "); }else if(bo->d->layout == LAYOUT_ZPOOL){ if(bo->d->zpool.state != POOL_STATE_ACTIVE){ - cwattrset(n, CELL_STYLE_BOLD|FUCKED_COLOR); + cwattrset(n, NCSTYLE_BOLD|FUCKED_COLOR); cmvwprintw(n, sumline, START_COL, "☠☠☠ "); }else{ cwattrset(n, GREEN_COLOR); @@ -1351,9 +1346,9 @@ case LAYOUT_ZPOOL: } } - cwattrset(n, CELL_STYLE_BOLD | DBORDER_COLOR); + cwattrset(n, NCSTYLE_BOLD | DBORDER_COLOR); if(selected){ - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); } if(line + !!cliptop >= 1){ cmvwadd_wch(n, line, START_COL + 10 + 1, L"╭"); @@ -1369,10 +1364,10 @@ case LAYOUT_ZPOOL: print_blockbar(n, bo, line, START_COL + 10 + 2, cols - START_COL - 1, selected); } - attr = CELL_STYLE_BOLD | DBORDER_COLOR; + attr = NCSTYLE_BOLD | DBORDER_COLOR; cwattrset(n, attr); if(selected){ - cwattron(n, CELL_STYLE_REVERSE); + cwattron(n, NCSTYLE_REVERSE); } if(line + !!cliptop >= 1){ cmvwadd_wch(n, line, cols - START_COL * 2, L"│"); @@ -1406,9 +1401,9 @@ adapter_box(const adapterstate* as, struct ncplane* nc, int abovetop, ncplane_dim_yx(nc, NULL, &cols); if(current){ - hcolor = UHEADING_COLOR; // plus CELL_STYLE_BOLD + hcolor = UHEADING_COLOR; // plus NCSTYLE_BOLD bcolor = SELBORDER_COLOR; - attrs = CELL_STYLE_BOLD; + attrs = NCSTYLE_BOLD; }else{ hcolor = UNHEADING_COLOR;; bcolor = UBORDER_COLOR; @@ -1430,9 +1425,9 @@ adapter_box(const adapterstate* as, struct ncplane* nc, int abovetop, ncplane_set_bg_default(nc); if(abovetop == 0){ if(current){ - cwattron(nc, CELL_STYLE_BOLD); + cwattron(nc, NCSTYLE_BOLD); }else{ - cwattroff(nc, CELL_STYLE_BOLD); + cwattroff(nc, NCSTYLE_BOLD); } cmvwprintw(nc, 0, 7, "%ls", L"["); compat_set_fg(nc, hcolor); @@ -1459,7 +1454,7 @@ adapter_box(const adapterstate* as, struct ncplane* nc, int abovetop, } cwattron(nc, bcolor); cwprintw(nc, "]"); - cwattron(nc, CELL_STYLE_BOLD); + cwattron(nc, NCSTYLE_BOLD); ncplane_cursor_move_yx(nc, 0, cols - 5); cwaddwstr(nc, as->expansion != EXPANSION_MAX ? L"[+]" : L"[-]"); cwattron(nc, attrs); @@ -1468,9 +1463,9 @@ adapter_box(const adapterstate* as, struct ncplane* nc, int abovetop, if(as->c->bus == BUS_PCIe){ compat_set_fg(nc, bcolor); if(current){ - cwattron(nc, CELL_STYLE_BOLD); + cwattron(nc, NCSTYLE_BOLD); }else{ - cwattroff(nc, CELL_STYLE_BOLD); + cwattroff(nc, NCSTYLE_BOLD); } cmvwprintw(nc, rows - 1, 6, "["); compat_set_fg(nc, hcolor); @@ -1576,9 +1571,9 @@ print_adapter_devs(struct ncplane* n, const adapterstate *as, int rows, int cols } static int -redraw_adapter(struct tablet* t, int begx, int begy, int maxx, int maxy, bool cliptop){ - struct ncplane* n = tablet_ncplane(t); - const adapterstate *as = tablet_userptr(t); +redraw_adapter(struct nctablet* t, int begx, int begy, int maxx, int maxy, bool cliptop){ + struct ncplane* n = nctablet_ncplane(t); + const adapterstate *as = nctablet_userptr(t); //ncplane_erase(n); //fprintf(stderr, "ADAPTER-redraw %s begx/y %d/%d -> maxx/y %d/%d ASS %p\n", as->c->name, begx, begy, maxx, maxy, as); int lines = print_adapter_devs(n, as, maxy - begy + 1, maxx - begx + 1, cliptop); @@ -1613,7 +1608,7 @@ struct panel_state* show_splash(const wchar_t* msg){ } int cols; ncplane_dim_yx(ps->p, NULL, &cols); - cwattrset(ps->p, CELL_STYLE_BOLD|SPLASHTEXT_COLOR); + cwattrset(ps->p, NCSTYLE_BOLD|SPLASHTEXT_COLOR); cmvwhline(ps->p, 1, 1, " ", cols - 2); cmvwhline(ps->p, 2, 1, " ", cols - 2); cmvwaddwstr(ps->p, 2, 2, msg); @@ -1714,7 +1709,7 @@ multiform_options(struct form_state *fs){ assert(fs->formtype == FORM_MULTISELECT); ncplane_dim_yx(fsw, &maxz, &cols); cwattrset(fsw, FORMBORDER_COLOR); - cwattron(fsw, CELL_STYLE_BOLD); + cwattron(fsw, NCSTYLE_BOLD); cmvwadd_wch(fsw, 1, 1, L"╭"); cmvwadd_wch(fsw, 1, fs->longop + 4, L"╮"); maxz -= 3; @@ -1723,7 +1718,7 @@ multiform_options(struct form_state *fs){ assert(op >= 0); assert(op < fs->opcount); - cwattroff(fsw, CELL_STYLE_BOLD); + cwattroff(fsw, NCSTYLE_BOLD); compat_set_fg(fsw, FORMBORDER_COLOR); if(fs->selectno >= z){ cmvwprintw(fsw, z + 1, START_COL * 2, "%d", z); @@ -1731,12 +1726,12 @@ multiform_options(struct form_state *fs){ cmvwprintw(fsw, z + 2, START_COL * 2, "%d", z); } if(z < fs->opcount + 1){ - cwattron(fsw, CELL_STYLE_BOLD); + cwattron(fsw, NCSTYLE_BOLD); compat_set_fg(fsw, FORMTEXT_COLOR); cmvwprintw(fsw, z + 1, START_COL * 2 + fs->longop + 4, "%-*.*s ", fs->longop, fs->longop, opstrs[op].option); if(op == fs->idx){ - cwattron(fsw, CELL_STYLE_REVERSE); + cwattron(fsw, NCSTYLE_REVERSE); } compat_set_fg(fsw, INPUT_COLOR); for(selidx = 0 ; selidx < fs->selections ; ++selidx){ @@ -1747,11 +1742,11 @@ multiform_options(struct form_state *fs){ } cwprintw(fsw, "%-*.*s", cols - fs->longop * 2 - 9, cols - fs->longop * 2 - 9, opstrs[op].desc); - cwattroff(fsw, CELL_STYLE_REVERSE); + cwattroff(fsw, NCSTYLE_REVERSE); } } cwattrset(fsw, FORMBORDER_COLOR); - cwattron(fsw, CELL_STYLE_BOLD); + cwattron(fsw, NCSTYLE_BOLD); for(z = 0 ; z < fs->selections ; ++z){ cmvwaddstr(fsw, z >= fs->selectno ? 3 + z : 2 + z, 4, fs->selarray[z]); } @@ -1768,18 +1763,18 @@ check_options(struct form_state *fs){ ncplane_dim_yx(fs->p, &maxz, &cols); maxz -= 3; cwattrset(fs->p, FORMBORDER_COLOR); - cwattron(fs->p, CELL_STYLE_BOLD); + cwattron(fs->p, NCSTYLE_BOLD); for(z = 1 ; z < maxz ; ++z){ int op = ((z - 1) + fs->scrolloff) % fs->opcount; assert(op >= 0); assert(op < fs->opcount); - cwattroff(fs->p, CELL_STYLE_BOLD); + cwattroff(fs->p, NCSTYLE_BOLD); compat_set_fg(fs->p, FORMBORDER_COLOR); if(z < fs->opcount + 1){ wchar_t ballot = L'☐'; - cwattron(fs->p, CELL_STYLE_BOLD); + cwattron(fs->p, NCSTYLE_BOLD); compat_set_fg(fs->p, FORMTEXT_COLOR); for(selidx = 0 ; selidx < fs->selections ; ++selidx){ if(strcmp(opstrs[op].option, fs->selarray[selidx]) == 0){ @@ -1788,7 +1783,7 @@ check_options(struct form_state *fs){ } } if(op == fs->idx){ - cwattron(fs->p, CELL_STYLE_REVERSE); + cwattron(fs->p, NCSTYLE_REVERSE); }else{ compat_set_fg(fs->p, INPUT_COLOR); } @@ -1796,7 +1791,7 @@ check_options(struct form_state *fs){ ballot, fs->longop, fs->longop, opstrs[op].option); cwprintw(fs->p, "%-*.*s", cols - fs->longop - 7, cols - fs->longop - 7, opstrs[op].desc); - cwattroff(fs->p, CELL_STYLE_REVERSE); + cwattroff(fs->p, NCSTYLE_REVERSE); } } cwattrset(fs->p, FORMBORDER_COLOR); @@ -1811,7 +1806,7 @@ form_options(struct form_state *fs){ return; } ncplane_dim_yx(fs->p, &rows, &cols); - cwattron(fs->p, CELL_STYLE_BOLD); + cwattron(fs->p, NCSTYLE_BOLD); for(z = 1 ; z < rows - 3 ; ++z){ int op = ((z - 1) + fs->scrolloff) % fs->opcount; @@ -1821,12 +1816,12 @@ form_options(struct form_state *fs){ cmvwprintw(fs->p, z + 1, START_COL * 2, "%-*.*s ", fs->longop, fs->longop, opstrs[op].option); if(op == fs->idx){ - cwattron(fs->p, CELL_STYLE_REVERSE); + cwattron(fs->p, NCSTYLE_REVERSE); } compat_set_fg(fs->p, INPUT_COLOR); cwprintw(fs->p, "%-*.*s", cols - fs->longop - 1 - START_COL * 4, cols - fs->longop - 1 - START_COL * 4, opstrs[op].desc); - cwattroff(fs->p, CELL_STYLE_REVERSE); + cwattroff(fs->p, NCSTYLE_REVERSE); } } @@ -1953,14 +1948,14 @@ void raise_multiform(const char *str, void (*fxn)(const char *, char **, int, in fs->opcount = ops; fs->selarray = selarray; fs->selections = selections; - cwattroff(fs->p, CELL_STYLE_BOLD); + cwattroff(fs->p, NCSTYLE_BOLD); compat_set_fg(fs->p, FORMBORDER_COLOR); bevel_all(fs->p); - cwattron(fs->p, CELL_STYLE_BOLD); + cwattron(fs->p, NCSTYLE_BOLD); cmvwprintw(fs->p, 0, cols - strlen(fs->boxstr) - 4, "%s", fs->boxstr); cmvwaddwstr(fs->p, rows - 1, cols - wcslen(ESCSTR) - 1, ESCSTR); #undef ESCSTR - cwattroff(fs->p, CELL_STYLE_BOLD); + cwattroff(fs->p, NCSTYLE_BOLD); fs->longop = longop; fs->ops = opstrs; fs->selectno = selectno; @@ -2034,16 +2029,16 @@ raise_checkform(const char* str, void (*fxn)(const char*, char**, int, int), fs->opcount = ops; fs->selarray = selarray; fs->selections = selections; - cwattroff(fsw, CELL_STYLE_BOLD); + cwattroff(fsw, NCSTYLE_BOLD); compat_set_fg(fsw, FORMBORDER_COLOR); bevel_all(fsw); - cwattron(fsw, CELL_STYLE_BOLD); + cwattron(fsw, NCSTYLE_BOLD); cmvwprintw(fsw, 0, cols - strlen(fs->boxstr) - 2, "%s", fs->boxstr); int nrows; ncplane_dim_yx(fsw, &nrows, NULL); cmvwaddwstr(fsw, nrows - 1, cols - wcslen(ESCSTR) - 1, ESCSTR); #undef ESCSTR - cwattroff(fsw, CELL_STYLE_BOLD); + cwattroff(fsw, NCSTYLE_BOLD); fs->longop = longop; fs->ops = opstrs; check_options(fs); @@ -2109,13 +2104,13 @@ void raise_form(const char* str, void (*fxn)(const char*), fs->idx = defidx = 0; } fs->opcount = ops; - cwattroff(fs->p, CELL_STYLE_BOLD); + cwattroff(fs->p, NCSTYLE_BOLD); compat_set_fg(fs->p, FORMBORDER_COLOR); bevel_all(fs->p); - cwattron(fs->p, CELL_STYLE_BOLD); + cwattron(fs->p, NCSTYLE_BOLD); cmvwprintw(fs->p, 0, cols - strlen(fs->boxstr), "%s", fs->boxstr); cmvwaddwstr(fs->p, rows - 1, cols - wcslen(L"⎋esc returns"), L"⎋esc returns"); - cwattroff(fs->p, CELL_STYLE_BOLD); + cwattroff(fs->p, NCSTYLE_BOLD); fs->longop = longop; fs->ops = opstrs; form_options(fs); @@ -2136,13 +2131,13 @@ form_string_options(struct form_state* fs){ return; } ncplane_dim_yx(n, NULL, &cols); - ncplane_styles_set(n, CELL_STYLE_BOLD); + ncplane_styles_set(n, NCSTYLE_BOLD); compat_set_fg(n, FORMTEXT_COLOR); cmvwhline(n, 1, 1, " ", cols - 2); cmvwprintw(n, 1, START_COL, "%-*.*s: ", fs->longop, fs->longop, fs->inp.prompt); compat_set_fg(n, INPUT_COLOR); cwprintw(n, "%.*s", cols - fs->longop - 2 - 2, fs->inp.buffer); - ncplane_styles_off(n, CELL_STYLE_BOLD); + ncplane_styles_off(n, NCSTYLE_BOLD); } void raise_str_form(const char* str, void (*fxn)(const char*), @@ -2170,10 +2165,10 @@ void raise_str_form(const char* str, void (*fxn)(const char*), free_form(fs); return; } - cwattroff(fs->p, CELL_STYLE_BOLD); + cwattroff(fs->p, NCSTYLE_BOLD); compat_set_fg(fs->p, FORMBORDER_COLOR); bevel_all(fs->p); - cwattron(fs->p, CELL_STYLE_BOLD); + cwattron(fs->p, NCSTYLE_BOLD); cmvwprintw(fs->p, 0, cols - strlen(fs->boxstr), "%s", fs->boxstr); cmvwaddwstr(fs->p, 2, cols - wcslen(L"⎋esc returns"), L"⎋esc returns"); fs->inp.prompt = fs->boxstr; @@ -2944,7 +2939,7 @@ new_partition(void){ // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- -// - partition tabletype form, for new partition table creation +// - partition nctabletype form, for new partition table creation // ------------------------------------------------------------------------- static inline int partition_table_makeablep(const blockobj *b){ @@ -3053,21 +3048,21 @@ detail_fs(struct ncplane* hw, const device* d, int row){ if(d->mnttype){ char buf[BPREFIXSTRLEN + 1]; - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cmvwprintw(hw, row, START_COL, BPREFIXFMT "%c ", d->mntsize ? bprefix(d->mntsize, 1, buf, 1) : "", d->mntsize ? 'B' : ' '); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "%s%s", d->label ? "" : "unlabeled ", d->mnttype); if(d->label){ - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, " %lc%s%lc", L'“', d->label, L'”'); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); } cwprintw(hw, "%s", d->mnt.count ? " at " : ""); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%s", d->mnt.count ? d->mnt.list[0] : ""); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); } } @@ -3105,19 +3100,19 @@ update_details(struct ncplane* hw){ cmvwprintw(hw, 2, START_COL, "%-*.*s", cols - 2, cols - 2, "No details available"); }else{ cmvwprintw(hw, 2, START_COL, "Firmware: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwaddstr(hw, c->fwver ? c->fwver : "Unknown"); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwaddstr(hw, " BIOS: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwaddstr(hw, c->biosver ? c->biosver : "Unknown"); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwaddstr(hw, " Load: "); qprefix(c->demand, 1, buf, 1); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwaddstr(hw, buf); cwaddstr(hw, "bps"); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); } if((b = get_selected_blockobj()) == NULL){ return 0; @@ -3128,14 +3123,14 @@ update_details(struct ncplane* hw){ const char *sn = d->blkdev.serial; cmvwprintw(hw, 3, START_COL, "%s: ", d->name); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwaddstr(hw, d->model ? d->model : "n/a"); cwaddstr(hw, d->revision ? d->revision : ""); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, " (%sB) S/N: ", bprefix(d->size, 1, buf, 1)); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwaddstr(hw, sn ? sn : "n/a"); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); if(cols - curcol > 13){ cwprintw(hw, " WC%lc WRV%lc RO%lc", d->blkdev.wcache ? L'+' : L'-', @@ -3145,26 +3140,26 @@ update_details(struct ncplane* hw){ } assert(d->physsec <= 4096); cmvwprintw(hw, 4, START_COL, "Sectors: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%ju ", d->size / (d->logsec ? d->logsec : 1)); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "("); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%uB ", d->logsec); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "logical / "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%uB ", d->physsec); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "physical) %s", transport_str(d->blkdev.transport)); if(transport_bw(d->blkdev.transport)){ uintmax_t transbw = transport_bw(d->blkdev.transport); cwprintw(hw, " ("); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); // FIXME throws -Wformat-truncation on gcc9 cwprintw(hw, "%sbps", qprefix(transbw, 1, buf, 1)); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, ")"); } }else{ @@ -3175,49 +3170,49 @@ update_details(struct ncplane* hw){ d->roflag ? L'+' : L'-'); if(d->layout == LAYOUT_MDADM){ cwprintw(hw, " Stride: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); if(d->mddev.stride == 0){ cwaddstr(hw, "n/a"); }else{ cwprintw(hw, "%sB", bprefix(d->mddev.stride, 1, buf, 1)); } - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, " SWidth: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); if(d->mddev.swidth == 0){ cwaddstr(hw, "n/a"); }else{ cwprintw(hw, "%u", d->mddev.swidth); } - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); } assert(d->physsec <= 4096); cmvwprintw(hw, 4, START_COL, "Sectors: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%ju ", d->size / (d->logsec ? d->logsec : 1)); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "("); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%uB ", d->logsec); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "logical / "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%uB ", d->physsec); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "physical)"); } cmvwprintw(hw, 5, START_COL, "Partitioning: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); pttype = (d->layout == LAYOUT_NONE ? d->blkdev.pttable ? d->blkdev.pttable : "none" : d->layout == LAYOUT_MDADM ? d->mddev.pttable ? d->mddev.pttable : "none" : d->layout == LAYOUT_DM ? d->dmdev.pttable ? d->dmdev.pttable : "none" : "n/a"); cwprintw(hw, "%s", pttype); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwaddstr(hw, " I/O scheduler: "); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwaddstr(hw, d->sched ? d->sched : "custom"); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); if(blockobj_unloadedp(b)){ cmvwprintw(hw, 6, START_COL, "Media is not loaded"); return 0; @@ -3225,10 +3220,10 @@ update_details(struct ncplane* hw){ if(blockobj_unpartitionedp(b)){ char ubuf[BPREFIXSTRLEN + 1]; - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cmvwprintw(hw, 6, START_COL, BPREFIXFMT "B ", bprefix(d->size, 1, ubuf, 1)); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "%s", "unpartitioned media"); detail_fs(hw, b->d, 7); return 0; @@ -3241,27 +3236,27 @@ update_details(struct ncplane* hw){ assert(b->zone->p->layout == LAYOUT_PARTITION); bprefix(b->zone->p->partdev.alignment, 1, align, 1); // FIXME limit length! - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cmvwprintw(hw, 6, START_COL, BPREFIXFMT "B ", bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1), 1, zbuf, 1)); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "P%lc%lc ", subscript((b->zone->p->partdev.pnumber % 100 / 10)), subscript((b->zone->p->partdev.pnumber % 10))); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%ju", b->zone->fsector); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "→"); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%ju ", b->zone->lsector); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwaddstr(hw, b->zone->p->name); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); if(b->zone->p->partdev.pname){ cwprintw(hw, " “%ls” ", b->zone->p->partdev.pname); }else{ cwprintw(hw, " (%s) ", "unnamed"); } - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); if(curcol <= cols - 2 - 4){ cwprintw(hw, "%04x", get_code_specific(pttype, b->zone->p->partdev.ptype)); } @@ -3273,17 +3268,17 @@ update_details(struct ncplane* hw){ // FIXME print alignment for unpartitioned space as well, // but not until we implement zones in core (bug 252) // or we'll need recreate alignment() etc here - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cmvwprintw(hw, 6, START_COL, BPREFIXFMT "B ", bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1), 1, zbuf, 1)); - ncplane_styles_on(hw, CELL_STYLE_BOLD); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%ju", b->zone->fsector); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "→"); - ncplane_styles_off(hw, CELL_STYLE_BOLD); + ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%ju ", b->zone->lsector); - ncplane_styles_on(hw, CELL_STYLE_BOLD); + ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "%s ", b->zone->rep == REP_METADATA ? "partition table metadata" : "unpartitioned space"); } @@ -3638,13 +3633,13 @@ detail_mounts(struct ncplane* w, int* row, int maxy, const device* d){ if(++*row == maxy){ return; } - cwattroff(w, CELL_STYLE_BOLD); + cwattroff(w, NCSTYLE_BOLD); if((r = snprintf(b, sizeof(b), " %s %s", d->mnt.list[z], d->mntops.list[z])) >= (int)sizeof(b)){ b[sizeof(b) - 1] = '\0'; } cmvwhline(w, *row, START_COL, " ", cols - 2); cmvwprintw(w, *row, START_COL, "%-*.*s", cols - 2, cols - 2, b); - cwattron(w, CELL_STYLE_BOLD); + cwattron(w, NCSTYLE_BOLD); ++*row; } } @@ -3676,13 +3671,13 @@ detail_targets(struct ncplane* w, int* row, int both, const device* d){ if(!both){ return; } - cwattroff(w, CELL_STYLE_BOLD); + cwattroff(w, NCSTYLE_BOLD); if((r = snprintf(b, sizeof(b), " %s %s", d->mnt.list[z], d->mntops.list[z])) >= (int)sizeof(b)){ b[sizeof(b) - 1] = '\0'; } cmvwhline(w, *row, START_COL, " ", cols - 2); cmvwprintw(w, *row, START_COL, "%-*.*s", cols - 2, cols - 2, b); - cwattron(w, CELL_STYLE_BOLD); + cwattron(w, NCSTYLE_BOLD); ++*row; break; // FIXME no space currently } @@ -3700,7 +3695,7 @@ map_details(struct ncplane *hw){ if(growlight_target){ int blockout; - cwattrset(hw, CELL_STYLE_BOLD|PHEADING_COLOR); + cwattrset(hw, NCSTYLE_BOLD|PHEADING_COLOR); cmvwprintw(hw, y, 1, "Operating in target mode (%s)", growlight_target); ncplane_cursor_yx(hw, NULL, &curcol); if( (blockout = cols - curcol - 1) ){ @@ -3708,7 +3703,7 @@ map_details(struct ncplane *hw){ } ++y; } - cwattrset(hw, CELL_STYLE_BOLD|FORMTEXT_COLOR); + cwattrset(hw, NCSTYLE_BOLD|FORMTEXT_COLOR); // First we list the target fstab, and then the targets // FIXME this is probably multibyte input and needs be handled as such if( (fstab = dump_targets()) ){ @@ -3739,7 +3734,7 @@ map_details(struct ncplane *hw){ } free(fstab); } - cwattrset(hw, CELL_STYLE_BOLD|SUBDISPLAY_COLOR); + cwattrset(hw, NCSTYLE_BOLD|SUBDISPLAY_COLOR); cmvwhline(hw, y, 1, " ", cols - 2); cmvwprintw(hw, y, 1, "%-*.*s %-5.5s %-36.36s " PREFIXFMT " %s", FSLABELSIZ, FSLABELSIZ, "Label", @@ -3747,7 +3742,7 @@ map_details(struct ncplane *hw){ if(++y >= rows){ return 0; } - cwattrset(hw, CELL_STYLE_BOLD|FORMTEXT_COLOR); + cwattrset(hw, NCSTYLE_BOLD|FORMTEXT_COLOR); for(c = get_controllers() ; c ; c = c->next){ const device *d; @@ -3767,7 +3762,7 @@ map_details(struct ncplane *hw){ } } // Now list the existing maps, a superset of the targets - cwattrset(hw, CELL_STYLE_BOLD|SUBDISPLAY_COLOR); + cwattrset(hw, NCSTYLE_BOLD|SUBDISPLAY_COLOR); for(c = get_controllers() ; c ; c = c->next){ const device *d; @@ -5372,7 +5367,7 @@ handle_ncurses_input(struct ncplane* w){ int sel; lock_notcurses(); sel = selection_active(); - panelreel_prev(PR); + ncreel_prev(PR); if(sel){ select_adapter(); } @@ -5385,7 +5380,7 @@ handle_ncurses_input(struct ncplane* w){ // fprintf(stderr, "-------------- BEGIN PgDown ---------------\n"); sel = selection_active(); deselect_adapter_locked(); - panelreel_next(PR); + ncreel_next(PR); if(sel){ select_adapter(); } @@ -5638,7 +5633,7 @@ adapter_callback(controller *a, void *state){ //fprintf(stderr, "NEW ADAPTER STATE ASSIGNED %s %p\n", as->c->name, as); notcurses_term_dim_yx(NC, &rows, &cols); - if((as->rb = panelreel_add(PR, NULL, NULL, redraw_adapter, as)) == NULL){ + if((as->rb = ncreel_add(PR, NULL, NULL, redraw_adapter, as)) == NULL){ free_adapter_state(as); unlock_notcurses_growlight(); return NULL; @@ -5877,7 +5872,7 @@ adapter_free(void *cv){ as->prev->next = as->next; as->next->prev = as->prev; if(as->rb){ - panelreel_del(PR, as->rb); + ncreel_del(PR, as->rb); } as->next->prev = as->prev; as->prev->next = as->next; @@ -5894,7 +5889,7 @@ vdiag(const char *fmt, va_list v){ unlock_notcurses_growlight(); } -// FIXME destroy panelreel +// FIXME destroy ncreel static void shutdown_cycle(void){ struct panel_state *ps; @@ -5945,10 +5940,10 @@ static void raise_info_form(const char *str, const char *text){ free_form(fs); return; } - cwattroff(fs->p, CELL_STYLE_BOLD); + cwattroff(fs->p, NCSTYLE_BOLD); compat_set_fg(fs->p, FORMBORDER_COLOR); bevel_all(fs->p); - cwattron(fs->p, CELL_STYLE_BOLD); + cwattron(fs->p, NCSTYLE_BOLD); cmvwprintw(fs->p, 1, START_COL, "%-*.*s", cols, cols, str); form_string_options(fs); actform = fs; @@ -6002,14 +5997,14 @@ int main(int argc, char * const *argv){ } struct ncplane* n = notcurses_stdplane(NC); ps = show_splash(L"Initializing..."); - panelreel_options popts; + ncreel_options popts; memset(&popts, 0, sizeof(popts)); popts.bordermask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM | NCBOXMASK_LEFT | NCBOXMASK_RIGHT; popts.tabletmask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM | NCBOXMASK_LEFT | NCBOXMASK_RIGHT; popts.boff = 1; - PR = panelreel_create(n, &popts, -1); + PR = ncreel_create(n, &popts, -1); if(PR == NULL){ kill_splash(ps); notcurses_stop(NC); @@ -6018,7 +6013,7 @@ int main(int argc, char * const *argv){ } locked_diag("by nick black "); if(growlight_init(argc, argv, &ui, &showhelp)){ - panelreel_destroy(PR); + ncreel_destroy(PR); kill_splash(ps); notcurses_stop(NC); dump_diags(); From ad3ba22ea40848ea05fb4fd5d500f9ac9f13823d Mon Sep 17 00:00:00 2001 From: nick black Date: Mon, 10 Feb 2020 22:22:59 -0500 Subject: [PATCH 03/30] 1.2.1 rebuild against notcurses 1.1.7 --- configure.ac | 2 +- debian/changelog | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 75648a58..50f51acb 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.61]) -AC_INIT([growlight], [1.2.0], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) +AC_INIT([growlight], [1.2.1], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([-Wall foreign dist-xz no-dist-gzip std-options subdir-objects nostdinc]) AC_CONFIG_HEADER([src/config.h]) diff --git a/debian/changelog b/debian/changelog index 06a698f0..fdd3c253 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -growlight (1.2.1-1) UNRELEASED; urgency=medium +growlight (1.2.1-1) unstable; urgency=medium * Debian policy 4.5.0 * Update copyrights From bd99776e52a3989b856217cd44573f1e4dc2778b Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 20 Feb 2020 05:43:51 -0500 Subject: [PATCH 04/30] use new notcurses include path --- src/growlight.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/growlight.h b/src/growlight.h index f10a0552..9d2677ef 100644 --- a/src/growlight.h +++ b/src/growlight.h @@ -15,7 +15,7 @@ extern "C" { #include #include #include -#include +#include #include "gpt.h" #include "stats.h" From d9f99216755101be97f23a17b024359cea34b5e8 Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 20 Feb 2020 06:11:18 -0500 Subject: [PATCH 05/30] drone: use new 2020-02-17a --- .drone.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 941c41f6..61c00b12 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-02-05a + image: dankamongmen/unstable_builder:2020-02-17a commands: - apt-get update - apt-get -y install devscripts git-buildpackage @@ -22,7 +22,7 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-02-07a + image: dankamongmen/focal:2020-02-17a commands: - apt-get update - apt-get -y install devscripts git-buildpackage equivs From 3f96e67040b4a36e14139a75581de9b55f852b90 Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 20 Feb 2020 06:13:22 -0500 Subject: [PATCH 06/30] v1.2.2 --- configure.ac | 2 +- debian/changelog | 51 ++---------------------------------------------- 2 files changed, 3 insertions(+), 50 deletions(-) diff --git a/configure.ac b/configure.ac index 50f51acb..a20b3137 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.61]) -AC_INIT([growlight], [1.2.1], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) +AC_INIT([growlight], [1.2.2], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([-Wall foreign dist-xz no-dist-gzip std-options subdir-objects nostdinc]) AC_CONFIG_HEADER([src/config.h]) diff --git a/debian/changelog b/debian/changelog index fdd3c253..8c6580f0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,53 +1,6 @@ -growlight (1.2.1-1) unstable; urgency=medium +growlight (1.2.2-1) unstable; urgency=medium * Debian policy 4.5.0 * Update copyrights - -- Nick Black Wed, 22 Jan 2020 22:40:15 -0500 - -growlight (1.2.0-1) unstable; urgency=medium - - * Swap out GUI for notcurses, add dep on notcurses - - -- Nick Black Thu, 12 Dec 2019 11:51:45 -0500 - -growlight (1.1.3.3-1) unstable; urgency=medium - - * Reenable ZFS support; build-dep on libzfslinux-dev - * Require outcurses 0.0.7+ - - -- Nick Black Sun, 17 Nov 2019 06:38:28 -0500 - -growlight (1.1.3-1) unstable; urgency=medium - - * New upstream release, fixes assert()s in ncurses UI - * Compile with -D_FORTIFY_SOURCE=2 - - -- Nick Black Sun, 27 Oct 2019 05:37:40 -0400 - -growlight (1.1.1.1-1) unstable; urgency=medium - - * New upstream release - * Debian policy 4.4.1.1, no changes necessary - * Use liboutcurses-dev for enmetric() - - -- Nick Black Sat, 26 Oct 2019 14:12:15 -0400 - -growlight (1.1.1-1) unstable; urgency=medium - - * New upstream release - * Debhelper 12 - - -- Nick Black Thu, 19 Sep 2019 09:07:34 -0400 - -growlight (1.1.0.1-2) unstable; urgency=medium - - * Debian standards -> 4.4.0.1 - - -- nick black Sun, 25 Aug 2019 18:47:15 -0400 - -growlight (1.1.0.1-1) unstable; urgency=medium - - * Initial debianization - - -- nick black Fri, 09 Aug 2019 01:03:03 -0400 + -- Nick Black Thu, 20 Feb 2020 06:12:54 -0500 From d0e1cebfa34ee43f6324e58ae64c03fd769049da Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 20 Feb 2020 06:14:52 -0500 Subject: [PATCH 07/30] Debian/autotools: dep on notcurses 1.2.1. --- configure.ac | 2 +- debian/control | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a20b3137..b6593384 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ AC_CHECK_LIB(pci, pci_get_dev, [have_libpci=yes], LIBS+=" -lpci" if test "x$notcurses" = "xtrue" ; then - PKG_CHECK_MODULES([notcurses], [notcurses >= 1.1.6]) + PKG_CHECK_MODULES([notcurses], [notcurses >= 1.2.1]) notcurses_CFLAGS+=" $notcurses_CFLAGS" notcurses_LIBS+=" $notcurses_LIBS" fi diff --git a/debian/control b/debian/control index 2a7575bb..3eb859f7 100644 --- a/debian/control +++ b/debian/control @@ -5,7 +5,7 @@ Maintainer: Nick Black Build-Depends: debhelper (>= 12), libatasmart-dev, libblkid-dev, libcryptsetup-dev, libpci-dev, libpciaccess-dev, libdevmapper-dev, libudev-dev, autoconf-archive, libncurses-dev, libreadline-dev, libcunit1-ncurses-dev, - pkg-config, xsltproc, docbook-xsl, libssl-dev, libnotcurses-dev (>= 1.1.6), + pkg-config, xsltproc, docbook-xsl, libssl-dev, libnotcurses-dev (>= 1.2.1), libzfslinux-dev (>= 0.8.0) Standards-Version: 4.5.0 Homepage: https://nick-black.com/dankwiki/index.php/Growlight From f36891104657a1dbc48e567d7a91b780766cd545 Mon Sep 17 00:00:00 2001 From: nick black Date: Mon, 24 Feb 2020 23:50:18 -0500 Subject: [PATCH 08/30] purge growlight-ncurses --- Makefile.am | 5 - debian/control | 29 +- doc/man/man8/growlight-curses.xml | 233 - src/ncurses.c | 7117 ----------------------------- src/ncurses.h | 54 - src/ui-aggregate.c | 397 -- src/ui-aggregate.h | 14 - 7 files changed, 22 insertions(+), 7827 deletions(-) delete mode 100644 doc/man/man8/growlight-curses.xml delete mode 100644 src/ncurses.c delete mode 100644 src/ncurses.h delete mode 100644 src/ui-aggregate.c delete mode 100644 src/ui-aggregate.h diff --git a/Makefile.am b/Makefile.am index 3c809e62..3e34c70f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,6 @@ AM_CPPFLAGS=-D_GNU_SOURCE bin_PROGRAMS=growlight-readline bin_PROGRAMS+=growlight -bin_PROGRAMS+=growlight-curses bin_PROGRAMS+=growlight-test TESTS=growlight-test @@ -52,10 +51,6 @@ growlight_SOURCES=$(common_SOURCES) growlight_SOURCES+=src/notcurses.c src/notcurses.h src/notui-aggregate.h src/notui-aggregate.c growlight_LDADD=@notcurses_LIBS@ -growlight_curses_SOURCES=$(common_SOURCES) -growlight_curses_SOURCES+=src/ncurses.c src/ncurses.h src/ui-aggregate.h src/ui-aggregate.c -growlight_curses_LDADD=@notcurses_LIBS@ @PANEL_LIBS@ @CURSES_LIBS@ - growlight_test_SOURCES=$(common_SOURCES) growlight_test_SOURCES+=test/growlight.c growlight_test_LDADD=$(CUNIT_LIBS) diff --git a/debian/control b/debian/control index 3eb859f7..f91dfd91 100644 --- a/debian/control +++ b/debian/control @@ -1,20 +1,35 @@ Source: growlight -Section: utils Priority: optional Maintainer: Nick Black -Build-Depends: debhelper (>= 12), libatasmart-dev, libblkid-dev, - libcryptsetup-dev, libpci-dev, libpciaccess-dev, libdevmapper-dev, libudev-dev, - autoconf-archive, libncurses-dev, libreadline-dev, libcunit1-ncurses-dev, - pkg-config, xsltproc, docbook-xsl, libssl-dev, libnotcurses-dev (>= 1.2.1), - libzfslinux-dev (>= 0.8.0) +Build-Depends: + autoconf-archive, + debhelper (>= 12), + docbook-xsl, + libatasmart-dev, + libblkid-dev, + libcryptsetup-dev, + libcunit1-ncurses-dev, + libdevmapper-dev, + libnotcurses-dev (>= 1.2.1), + libpci-dev, + libpciaccess-dev, + libreadline-dev, + libssl-dev, + libudev-dev, + libzfslinux-dev (>= 0.8.0), + pkg-config, + xsltproc, +Section: utils Standards-Version: 4.5.0 +Rules-Requires-Root: no Homepage: https://nick-black.com/dankwiki/index.php/Growlight Vcs-Browser: https://github.com/dankamongmen/growlight Vcs-Git: https://github.com/dankamongmen/growlight.git Package: growlight Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} +Multi-Arch: foreign +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Disk manipulation and system preparation tool Growlight can manipulate both real and virtual (mdadm, device-mapper, and ZFS) disks, find bottlenecks in a storage setup, create partitions and filesystems, diff --git a/doc/man/man8/growlight-curses.xml b/doc/man/man8/growlight-curses.xml deleted file mode 100644 index c48cb7c2..00000000 --- a/doc/man/man8/growlight-curses.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - -%growlightents; - - - - - - - - - - - - - - - - - - - - - -]> - - - - &dhtitle; - - &dhproduct; - &dhrelease; - - - &dhfirstname; - &dhsurname; - Design and implementation. -
- &dhemail; -
-
-
- - 2012-2020 - &dhusername; - -
- - &dhucpackage; - &dhsection; - - - &dhpackage; - System disk preparation - - - - &dhpackage; - -h | --help - -i | --import - -v | --verbose - -V | --version - --disphelp - -t path | --target=path - - - - DESCRIPTION - &dhpackage; detects and describes - disk pools, block devices, partition tables, and partitions. - It can partition devices, manipulate ZFS, MD, DM, LVM and - hardware RAID virtual devices, and prepare an fstab file - for using the devices to boot or in a chroot, and is fully - aware of variable sector sizes, GPT, and UEFI. &dhpackage; - facilitates use of UUID/WWN- and HBA-based identification of block devices. -This page describes the fullscreen ncurses(3ncurses) implementation. -Consult growlight-readline(8) for a line-oriented readline(3) - variant, or growlight(8) for the flagship - notcurses-based tool. - - - OPTIONS - - -h | --help - - Print a brief usage summary and exit. - - - - -i | --import - -Attempt to assemble aggregates (zpools, MD devices, etc) based on block -device scans at startup. - - - - -v | --verbose - - Be more verbose. - - - - -V | --version - - Print version information and exit. - - - - --disphelp - - Display the help subdisplay upon startup. - - - - -t path | --target=path - -Run in system installation mode, using path as the temporary mountpoint -for the target's root filesystem. "map" commands will populate the hierarchy -rooted at this mountpoint. System installation mode can also be entered at run -time with the "target" command. The "map" command will not result in active -mounts unless &dhpackage; is operating in system installation mode (they will -merely be used to construct target fstab output). Once system installation mode -is entered, &dhpackage; will return 0 only as a result of a successful invocation -of the "target finalize" command. -path must exist at the time of its -specification. - - - - - USAGE - FIXME - - - BUGS - Search . - Mail bug reports and/or patches to the authors. - -Pedantic collections of ambiguous identifiers (for instance, if a label -equals another device's /dev/ name) will lead to questionable results. This -ought be fixed. - - - SEE ALSO - GitHub: - Project wiki: - - - blkid - 8 - , - dmraid - 8 - , - dmsetup - 8 - , - fstab - 5 - , - grub-install - 8 - , - grub-mkdevicemap - 8 - , - hdparm - 8 - , - inotify - 7 - , - libblkid - 3 - , - losetup - 8 - , - lsblk - 8 - , - mdadm - 8 - , - mkfs - 8 - , - mount - 2 - , - mount - 8 - , - ncurses - 3ncurses - , - parted - 8 - , - proc - 5 - , - sfdisk - 8 - , - swapoff - 2 - , - swapon - 2 - , - udev - 7 - , - umount - 2 - , - umount - 8 - , - zfs - 8 - , - zpool - 8 - - - -
diff --git a/src/ncurses.c b/src/ncurses.c deleted file mode 100644 index 3bbe448b..00000000 --- a/src/ncurses.c +++ /dev/null @@ -1,7117 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fs.h" -#include "mbr.h" -#include "zfs.h" -#include "swap.h" -#include "mdadm.h" -#include "config.h" -#include "health.h" -#include "ptable.h" -#include "ptypes.h" -#include "ncurses.h" -#include "growlight.h" -#include "aggregate.h" -#include "ui-aggregate.h" - -#define KEY_ESC 27 - -static void shutdown_cycle(void) __attribute__ ((noreturn)); - -void locked_diag(const char *fmt,...) __attribute__ ((format (printf,1,2))); - -// For the ANSI standard terminal, we can fit only 4 lines of explicative text -// onto the screen, so make each glyph count. By default, 76 characters can be -// placed on each row. -static const char SEARCH_TEXT[] = -"Your search term will be matched against device names, UUIDs, partition " -"names, filesystem names (volume labels), manufacturers, model numbers, and " -"serial numbers."; - -static const char LOOP_TEXT[] = -"The specified file will be treated as a block device once associated with " -"the selected loop device."; - -static const char PARTFLAG_TEXT[] = -"Select a collection of flags to set on the partition."; - -static const char MOUNTOPS_TEXT[] = -"Select a collection of options to apply to this mount."; - -static const char TARGET_TEXT[] = -"Enter a mount point relative to the target's root."; - -static const char TARG_TEXT[] = -"Enter a mount point relative to the target's root. It must already exist, and " -"no other filesystem should yet be mounted there. The filesystem will be made " -"available for use now, and included in the target /etc/fstab for use later."; - -static const char MOUNT_TEXT[] = -"Enter a mount point. It must already exist, and no other filesystem should " -"yet be mounted there."; - -static const char PTTYPE_TEXT[] = -"Select a partition table type. GPT is recommended unless you must use tools " -"and/or hardware which don't understand it. Please note that MSDOS partition " -"tables do not support partitions in excess of 2TB."; - -static const char PSPEC_TEXT[] = -"Specify the new partition size as either a percentage of the containing " -"space, a number of bytes, or a starting and ending sector (inclusive), " -"separated by a colon (':')."; - -static const char FSNAME_TEXT[] = -"Named filesystems can be more easily used in bootloaders and other tools, and " -"provide references independent of dynamic device topology. "; - -static const char PNAME_TEXT[] = -"Named partitions can be more easily used in bootloaders and other tools, and " -"provide references independent of dynamic device topology. A GPT partition's " -"name consists of up to 32 UTF-16LE codepoints."; - -static const char PARTTYPE_TEXT[] = // characters here will be bumped ---v -"Creating a given filesystem is generally neither enabled nor prohibited due " -"to partition type, but mismatched types might confuse tools, hardware, and " -"users. UEFI through version 1.1 boots from a GPT's ESP partition. UEFI+MBR " -"and BIOS boot from a primary (as opposed to logical) MBR partition."; - -static const char FSTYPE_TEXT[] = -"UEFI through version 1.1 requires FAT16 for the EFI System Partition. As of " -"version 3.5, ext4 is the default Linux filesystem, but Windows and OS X do " -"not natively support it. I recommend use of EXT4 or FAT16 for root and ZFS " -"(in a redundant configuration) for other filesystems."; - -static pthread_mutex_t bfl = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; - -struct panel_state { - PANEL *p; -}; - -#define PANEL_STATE_INITIALIZER { .p = NULL, } -#define SUBDISPLAY_ATTR (COLOR_PAIR(SUBDISPLAY_COLOR) | A_BOLD) -#define SUBDISPLAY_INVAL_ATTR (COLOR_PAIR(SUBDISPLAY_COLOR)) - -static struct panel_state *splash; -static struct panel_state *active; -static struct panel_state maps = PANEL_STATE_INITIALIZER; -static struct panel_state help = PANEL_STATE_INITIALIZER; -static struct panel_state diags = PANEL_STATE_INITIALIZER; -static struct panel_state details = PANEL_STATE_INITIALIZER; -static struct panel_state environment = PANEL_STATE_INITIALIZER; - -static int helpstrs(WINDOW *); -static int map_details(WINDOW *); -static int update_details(WINDOW *); - -static inline void -update_details_cond(PANEL *p){ - if(p){ - update_details(panel_window(p)); - } -} - -static inline void -update_help_cond(PANEL *p){ - if(p){ - helpstrs(panel_window(p)); - } -} - -static inline void -update_map_cond(PANEL *p){ - if(p){ - map_details(panel_window(p)); - } -} - -struct form_option { - char *option; // option key (the string passed to cb) - char *desc; // longer description -}; - -struct form_input { - const char *prompt; // short prompt. currently aliases boxstr - char *longprompt; // longer prompt, not currently used - char *buffer; // input buffer, initialized to "" -}; - -typedef enum { - FORM_SELECT, // form_option[] - FORM_STRING_INPUT, // form_input - FORM_MULTISELECT, // form_options[] - FORM_CHECKBOXEN, // form_options[] - FORM_SPLASH_PROMPT, // form_input -} form_enum; - -// Regarding scrolling selection windows: the movement model is the same as -// the main scrollwindow: moving up at the topmost line keeps you at the top -// of the widget, and rotates the selections. scrolloff equals the number of -// lines options have been rotated down, and takes values between 0 and -// opcount - 1. All option selection windows scroll, even if they fit all their -// options, to maintain continuity of UI. -struct form_state { - PANEL *p; - void (*fxn)(const char *); // callback once form is done - void (*mcb)(const char *,char **,int,int); // multiform callback - int longop; // length of prompt or longest op - char *boxstr; // string for box label - form_enum formtype; // type of form - struct panel_state *extext; // explication text, above the form - union { - struct { - // There's padding on the interface, and a border -- 4 - // lines total. idx maps to true array indices, and has - // nothing to do with what's currently displayed (save - // that it's guaranteed to be onscreen). scrollidx also - // maps to true array indices, and identifies the first - // option listed. Thus: - // - // idx - scrollidx % opcount == current display line - // current display line + scrollidx % opcount == idx - // idx == scrollidx -> display at top - // idx == scrollidx + ysize - 4 -> display at bottom - // - int idx; // selection index - int scrolloff; // scroll offset - struct form_option *ops;// form_option array for *this instance* - int opcount; // total number of ops - int selectno; // number of selections, total - int selections; // number of active selections - char **selarray; // array of selections by name - }; - struct form_input inp; // form_input state for this instance - }; -}; - -static struct form_state *actform; - -// Our color pairs -enum { - HEADER_COLOR = 1, - STATUS_COLOR, - UHEADING_COLOR, - UNHEADING_COLOR, - UBORDER_COLOR, // Adapters - SELBORDER_COLOR, // Current adapter - DBORDER_COLOR, // Block bar borders - PBORDER_COLOR, - PHEADING_COLOR, - SUBDISPLAY_COLOR, - OPTICAL_COLOR, - ROTATE_COLOR, - VIRTUAL_COLOR, - SSD_COLOR, - FS_COLOR, - EMPTY_COLOR, // Empty sectors - METADATA_COLOR, // Partition table metadata - MDADM_COLOR, - ZPOOL_COLOR, - PART_COLOR0, // A defined but unused partition - PART_COLOR1, - PART_COLOR2, - PART_COLOR3, - FORMBORDER_COLOR, - FORMTEXT_COLOR, - INPUT_COLOR, // Form input color - SELECTED_COLOR, // Selected options in multiform - MOUNT_COLOR0, // Mounted, untargeted filesystems - MOUNT_COLOR1, - MOUNT_COLOR2, - MOUNT_COLOR3, - TARGET_COLOR0, // Targeted filesystems - TARGET_COLOR1, - TARGET_COLOR2, - TARGET_COLOR3, - FUCKED_COLOR, // Things that warrant attention - SPLASHBORDER_COLOR, - SPLASHTEXT_COLOR, - - ORANGE_COLOR, - GREEN_COLOR, - BLACK_COLOR, - - FIRST_FREE_COLOR -}; - -static inline int -next_targco(int targco){ - if(++targco > TARGET_COLOR3){ - targco = TARGET_COLOR0; - } - return targco; -} - -static inline int -next_mountco(int mountco){ - if(++mountco > MOUNT_COLOR3){ - mountco = MOUNT_COLOR0; - } - return mountco; -} - -static inline int -next_partco(int partco){ - if(++partco > PART_COLOR3){ - partco = PART_COLOR0; - } - return partco; -} - -#define COLOR_LIGHTRED 9 -#define COLOR_LIGHTGREEN 10 -#define COLOR_LIGHTYELLOW 11 -#define COLOR_LIGHTBLUE 12 -#define COLOR_LIGHTMAGENTA 13 // (pink) -#define COLOR_LIGHTCYAN 14 -#define COLOR_LIGHTWHITE 15 -#define COLOR_HIDDEN 16 -#define COLOR_SKYBLUE 0x20 // 32 (xterm color cube) -#define COLOR_PURPLE 0x39 // incredibly vibrant 0x68 -#define COLOR_CRAP 0x6f -#define COLOR_LIGHTPURPLE 0x3f -#define COLOR_CYAN0 0x7b -#define COLOR_CYAN1 0x23 -#define COLOR_CYAN2 0x2c -#define COLOR_CYAN3 0x33 -#define COLOR_MAGENTA0 0x44 -#define COLOR_MAGENTA1 0x46 -#define COLOR_MAGENTA2 0x48 -#define COLOR_MAGENTA3 0x4a -#define COLOR_MAIZE 0xdc -#define COLOR_WHITE0 0xfc -#define COLOR_WHITE1 0xfa -#define COLOR_WHITE2 0xf8 -#define COLOR_WHITE3 0xf6 - -#define REP_METADATA L'm' //L'\u1d50'//L'M', L'ᵐ' -#define REP_EMPTY L'e' //L'\u2091' //L'E', L'ₑ' - -static inline wchar_t -subscript(int in){ - assert(in >= 0 && in < 10); - return L'\u2080' + in; -} - -static inline void -screen_update(void){ - if(active){ - assert(top_panel(active->p) != ERR); - } - if(actform){ - if(actform->extext){ - assert(top_panel(actform->extext->p) != ERR); - } - assert(top_panel(actform->p) != ERR); - } - if(splash){ - assert(top_panel(splash->p) != ERR); - } - update_panels(); - assert(doupdate() == OK); -} - -static int -setup_colors(void){ - int z; - - if(init_pair(HEADER_COLOR,COLOR_LIGHTPURPLE,-1) == ERR){ - assert(init_pair(HEADER_COLOR,COLOR_BLUE,-1) == OK); - } - if(init_pair(STATUS_COLOR,COLOR_SKYBLUE,-1) == ERR){ - assert(init_pair(STATUS_COLOR,COLOR_YELLOW,-1) != ERR); - } - if(init_pair(UHEADING_COLOR,COLOR_WHITE,-1) == ERR){ - assert(init_pair(UHEADING_COLOR,COLOR_BLUE,-1) != ERR); - assert(init_pair(SELBORDER_COLOR,COLOR_CYAN,-1) != ERR); - }else{ - assert(init_pair(SELBORDER_COLOR,COLOR_BLUE,-1) != ERR); - } - if(init_pair(UNHEADING_COLOR,COLOR_SKYBLUE,-1) == ERR){ - assert(init_pair(UNHEADING_COLOR,COLOR_BLUE,-1) != ERR); - } - assert(init_pair(UBORDER_COLOR,COLOR_CYAN,-1) != ERR); - assert(init_pair(PBORDER_COLOR,COLOR_YELLOW,COLOR_BLACK) == OK); - if(init_pair(DBORDER_COLOR,COLOR_CRAP,-1) == ERR){ - assert(init_pair(DBORDER_COLOR,COLOR_RED,-1) != ERR); - } - assert(init_pair(PHEADING_COLOR,COLOR_RED,COLOR_BLACK) == OK); - assert(init_pair(SUBDISPLAY_COLOR,COLOR_WHITE,-1) == OK); - assert(init_pair(OPTICAL_COLOR,COLOR_YELLOW,-1) == OK); - if(init_pair(ROTATE_COLOR,COLOR_LIGHTWHITE,-1) == ERR){ - assert(init_pair(ROTATE_COLOR,COLOR_WHITE,-1) != ERR); - } - assert(init_pair(VIRTUAL_COLOR,COLOR_WHITE,-1) == OK); - if(init_pair(SSD_COLOR,COLOR_LIGHTWHITE,-1) == ERR){ - assert(init_pair(SSD_COLOR,COLOR_WHITE,-1) != ERR); - } - assert(init_pair(FS_COLOR,COLOR_GREEN,-1) == OK); - if(init_pair(EMPTY_COLOR,COLOR_MAIZE,-1) == ERR){ - assert(init_pair(EMPTY_COLOR,COLOR_GREEN,-1) == OK); - } - if(init_pair(METADATA_COLOR,COLOR_LIGHTYELLOW,-1) == ERR){ - assert(init_pair(METADATA_COLOR,COLOR_YELLOW,-1) == OK); - } - if(init_pair(MDADM_COLOR,COLOR_LIGHTBLUE,-1) == ERR){ - assert(init_pair(MDADM_COLOR,COLOR_BLUE,-1) != ERR); - } - assert(init_pair(ZPOOL_COLOR,COLOR_BLUE,-1) == OK); - if(init_pair(PART_COLOR0,COLOR_CYAN0,-1) == ERR){ - assert(init_pair(PART_COLOR0,COLOR_CYAN,-1) == OK); - } - if(init_pair(PART_COLOR1,COLOR_CYAN1,-1) == ERR){ - assert(init_pair(PART_COLOR1,COLOR_CYAN,-1) == OK); - } - if(init_pair(PART_COLOR2,COLOR_CYAN2,-1) == ERR){ - assert(init_pair(PART_COLOR2,COLOR_CYAN,-1) == OK); - } - if(init_pair(PART_COLOR3,COLOR_CYAN3,-1) == ERR){ - assert(init_pair(PART_COLOR3,COLOR_CYAN,-1) == OK); - } - assert(init_pair(FORMBORDER_COLOR,COLOR_MAGENTA,COLOR_BLACK) == OK); - if(init_pair(FORMTEXT_COLOR,COLOR_LIGHTCYAN,COLOR_BLACK) == ERR){ - assert(init_pair(FORMTEXT_COLOR,COLOR_CYAN,COLOR_BLACK) != ERR); - } - if(init_pair(INPUT_COLOR,COLOR_LIGHTGREEN,COLOR_BLACK) == ERR){ - assert(init_pair(INPUT_COLOR,COLOR_GREEN,COLOR_BLACK) != ERR); - } - if(init_pair(SELECTED_COLOR,COLOR_LIGHTCYAN,-1) == ERR){ - assert(init_pair(SELECTED_COLOR,COLOR_CYAN,-1) != ERR); - } - if(init_pair(MOUNT_COLOR0,COLOR_WHITE0,-1) == ERR){ - assert(init_pair(MOUNT_COLOR0,COLOR_WHITE,-1) == OK); - } - if(init_pair(MOUNT_COLOR1,COLOR_WHITE1,-1) == ERR){ - assert(init_pair(MOUNT_COLOR1,COLOR_WHITE,-1) == OK); - } - if(init_pair(MOUNT_COLOR2,COLOR_WHITE2,-1) == ERR){ - assert(init_pair(MOUNT_COLOR2,COLOR_WHITE,-1) == OK); - } - if(init_pair(MOUNT_COLOR3,COLOR_WHITE3,-1) == ERR){ - assert(init_pair(MOUNT_COLOR3,COLOR_WHITE,-1) == OK); - } - if(init_pair(TARGET_COLOR0,COLOR_MAGENTA0,-1) == ERR){ - assert(init_pair(TARGET_COLOR0,COLOR_MAGENTA,-1) == OK); - } - if(init_pair(TARGET_COLOR1,COLOR_MAGENTA1,-1) == ERR){ - assert(init_pair(TARGET_COLOR1,COLOR_MAGENTA,-1) == OK); - } - if(init_pair(TARGET_COLOR2,COLOR_MAGENTA2,-1) == ERR){ - assert(init_pair(TARGET_COLOR2,COLOR_MAGENTA,-1) == OK); - } - if(init_pair(TARGET_COLOR3,COLOR_MAGENTA3,-1) == ERR){ - assert(init_pair(TARGET_COLOR3,COLOR_MAGENTA,-1) == OK); - } - if(init_pair(FUCKED_COLOR,COLOR_LIGHTRED,-1) == ERR){ - assert(init_pair(FUCKED_COLOR,COLOR_RED,-1) != ERR); - } - if(init_pair(SPLASHBORDER_COLOR,COLOR_PURPLE,COLOR_BLACK) == ERR){ - assert(init_pair(SPLASHBORDER_COLOR,COLOR_GREEN,COLOR_BLACK) != ERR); - } - if(init_pair(SPLASHTEXT_COLOR,COLOR_LIGHTCYAN,COLOR_BLACK) == ERR){ - assert(init_pair(SPLASHTEXT_COLOR,COLOR_CYAN,COLOR_BLACK) != ERR); - } - assert(init_pair(ORANGE_COLOR,COLOR_YELLOW,-1) == OK); - assert(init_pair(GREEN_COLOR,COLOR_GREEN,-1) == OK); - assert(init_pair(BLACK_COLOR,COLOR_BLACK,COLOR_BLACK) == OK); - for(z = FIRST_FREE_COLOR ; z < COLORS ; ++z){ - init_pair(z,z,-1); - } - wrefresh(curscr); - screen_update(); - return 0; -} - -static void -form_colors(void){ - // Don't reset the status color or header color, nor (obviously) the - // form nor splash colors. - locked_diag("%s",""); // Don't leave a highlit status up from long ago - init_pair(UBORDER_COLOR,-1,-1); - init_pair(SELBORDER_COLOR,-1,-1); - init_pair(UHEADING_COLOR,-1,-1); - init_pair(UNHEADING_COLOR,-1,-1); - init_pair(PBORDER_COLOR,-1,-1); - init_pair(DBORDER_COLOR,-1,-1); - init_pair(PHEADING_COLOR,-1,-1); - init_pair(SUBDISPLAY_COLOR,-1,-1); - init_pair(OPTICAL_COLOR,-1,-1); - init_pair(ROTATE_COLOR,-1,-1); - init_pair(VIRTUAL_COLOR,-1,-1); - init_pair(SSD_COLOR,-1,-1); - init_pair(FS_COLOR,-1,-1); - init_pair(EMPTY_COLOR,-1,-1); - init_pair(METADATA_COLOR,-1,-1); - init_pair(MDADM_COLOR,-1,-1); - init_pair(ZPOOL_COLOR,-1,-1); - init_pair(PART_COLOR0,-1,-1); - init_pair(PART_COLOR1,-1,-1); - init_pair(PART_COLOR2,-1,-1); - init_pair(PART_COLOR3,-1,-1); - init_pair(MOUNT_COLOR0,-1,-1); - init_pair(MOUNT_COLOR1,-1,-1); - init_pair(MOUNT_COLOR2,-1,-1); - init_pair(MOUNT_COLOR3,-1,-1); - init_pair(TARGET_COLOR0,-1,-1); - init_pair(TARGET_COLOR1,-1,-1); - init_pair(TARGET_COLOR2,-1,-1); - init_pair(TARGET_COLOR3,-1,-1); - init_pair(FUCKED_COLOR,-1,-1); - init_pair(ORANGE_COLOR,-1,-1); - init_pair(GREEN_COLOR,-1,-1); - wrefresh(curscr); - screen_update(); -} - -static int update_diags(struct panel_state *); - -struct adapterstate; - -struct partobj; - -// See below (blockobj) for description of zones. -typedef struct zobj { - int zoneno; // in-order, starting at 0 - uintmax_t fsector,lsector; // first and last logical sector, inclusive - device *p; // partition/block device, NULL for empty space - wchar_t rep; // character used for representation - // if ->p is NULL - int following; // Number of zones following us on disk - struct zobj *prev,*next; -} zobj; - -typedef struct blockobj { - struct blockobj *next,*prev; - device *d; - // Zones refer to sets of contiguously allocated or unallocated sectors - // on a block object. Each partition is a zone. Each empty space - // between partitions is a zone. Empty space at the beginning or end of - // the disk is a zone. The entire disk is one zone if it has not yet - // been partitioned. When a blockobj is selected, one of its zones is - // always selected. The first time a blockobj is selected, zone 0 is - // selected. The selected zone is preserved across de- and reselection - // of the block device. Zones are indexed by 0, obviously. - // zchain: list of zone objects - // zone: currently selected zone, NULL iff |zchain| == 0 - zobj *zchain,*zone; -} blockobj; - -typedef struct reelbox { - WINDOW *win; - PANEL *panel; - struct reelbox *next,*prev; - struct adapterstate *as; - int scrline,selline; - blockobj *selected; -} reelbox; - -typedef struct adapterstate { - controller *c; - unsigned devs; - enum { - EXPANSION_NONE, - EXPANSION_FULL, - } expansion; - struct adapterstate *next,*prev; - blockobj *bobjs; - reelbox *rb; -} adapterstate; - -#define EXPANSION_MAX EXPANSION_FULL - -static char statusmsg[BUFSIZ]; - -static unsigned count_adapters; -// dequeue + single selection -static reelbox *current_adapter,*top_reelbox,*last_reelbox; - -#define START_COL 1 // Room to leave for borders -#define PAD_COLS(cols) ((cols)) - -static blockobj * -get_selected_blockobj(void){ - reelbox *rb; - - if((rb = current_adapter) == NULL){ - return NULL; - } - return rb->selected; -} - -static inline int -blockobj_unloadedp(const blockobj *bo){ - return bo && ((bo->d->layout == LAYOUT_NONE && bo->d->blkdev.unloaded) - || bo->d->size == 0); -} - -static inline int -selected_unloadedp(void){ - return blockobj_unloadedp(get_selected_blockobj()); -} - -static inline int -blockobj_unpartitionedp(const blockobj *bo){ - return bo && !bo->zone && - (bo->d->mnttype || - (bo->d->layout == LAYOUT_NONE && !bo->d->blkdev.pttable) - || (bo->d->layout == LAYOUT_MDADM && !bo->d->mddev.pttable) - || (bo->d->layout == LAYOUT_DM && !bo->d->dmdev.pttable) - || bo->d->layout == LAYOUT_ZPOOL); -} - -static inline int -selected_unpartitionedp(void){ - return blockobj_unpartitionedp(get_selected_blockobj()); -} - -static inline int -blockobj_emptyp(const blockobj *bo){ - return bo && bo->zone && !bo->zone->p; -} - -static inline int -selected_emptyp(void){ - return blockobj_emptyp(get_selected_blockobj()); -} - -static inline int -blockobj_partitionp(const blockobj *bo){ - return bo && bo->zone && bo->zone->p; -} - -static inline int -selected_partitionp(void){ - return blockobj_partitionp(get_selected_blockobj()); -} - -static inline device * -selected_filesystem(void){ - blockobj *bo; - - if((bo = get_selected_blockobj()) == NULL){ - return NULL; - } - if(blockobj_unpartitionedp(bo)){ - if(bo->d->mnttype){ - return bo->d; - } - }else{ - if(blockobj_partitionp(bo)){ - if(bo->zone->p->mnttype){ - return bo->zone->p; - } - } - } - return NULL; -} - -static inline int -mkfs_safe_p(const device *d){ - if(d->mnttype){ - locked_diag("Filesystem signature already exists on %s",d->name); - return 0; - } - return 1; -} - -static inline int -selected_mkfs_safe_p(void){ - const blockobj *bo = get_selected_blockobj(); - - if(bo && bo->d){ - if(bo->zone && bo->zone->p){ - return mkfs_safe_p(bo->zone->p); - }else if(bo->zone){ - locked_diag("Can't make filesystem in empty space"); - return 0; - } - return mkfs_safe_p(bo->d); - } - return 0; -} - -static int -selection_active(void){ - if(current_adapter == NULL){ - return 0; - } - if(current_adapter->selected == NULL){ - return 0; - } - return 1; -} - -static int -bevel_bottom(WINDOW *w){ - static const cchar_t bchr[] = { - { .attr = 0, .chars = L"╰", }, - { .attr = 0, .chars = L"╯", }, - { .attr = 0, .chars = L"─", }, - { .attr = 0, .chars = L"│", }, - }; - int rows,cols,z; - - getmaxyx(w,rows,cols); - assert(mvwadd_wch(w,rows - 1,0,&bchr[0]) != ERR); - for(z = 1 ; z < cols - 1 ; ++z){ - assert(mvwadd_wch(w,rows - 1,z,&bchr[2]) != ERR); - } - assert(mvwins_wch(w,rows - 1,cols - 1,&bchr[1]) != ERR); - for(z = 0 ; z < rows - 1 ; ++z){ - mvwadd_wch(w,z,0,&bchr[3]); - mvwins_wch(w,z,cols - 1,&bchr[3]); - } - return OK; -} - -static int -bevel_top(WINDOW *w){ - static const cchar_t bchr[] = { - { .attr = 0, .chars = L"╭", }, - { .attr = 0, .chars = L"╮", }, - { .attr = 0, .chars = L"─", }, - { .attr = 0, .chars = L"│", }, - }; - int rows,cols,z; - - getmaxyx(w,rows,cols); - assert(rows && cols); - assert(mvwadd_wch(w,0,0,&bchr[0]) != ERR); - for(z = 1 ; z < cols - 1 ; ++z){ - assert(mvwadd_wch(w,0,z,&bchr[2]) != ERR); - } - assert(mvwins_wch(w,0,cols - 1,&bchr[1]) != ERR); - for(z = 1 ; z < rows ; ++z){ - mvwadd_wch(w,z,0,&bchr[3]); - mvwins_wch(w,z,cols - 1,&bchr[3]); - } - return OK; -} - -static int -bevel(WINDOW *w){ - static const cchar_t bchr[] = { - { .attr = 0, .chars = L"╭", }, - { .attr = 0, .chars = L"╮", }, - { .attr = 0, .chars = L"╰", }, - { .attr = 0, .chars = L"╯", }, - { .attr = 0, .chars = L"│", }, - { .attr = 0, .chars = L"─", }, - }; - int rows,cols,z; - - getmaxyx(w,rows,cols); - assert(rows && cols); - // called as one expects: 'mvwadd_wch(w,rows - 1,cols - 1,&bchr[3]);' - // we get ERR returned. this is known behavior: fuck ncurses. instead, - // we use mvwins_wch, which doesn't update the cursor position. - // see http://lists.gnu.org/archive/html/bug-ncurses/2007-09/msg00001.html - assert(mvwadd_wch(w,0,0,&bchr[0]) != ERR); - for(z = 1 ; z < cols - 1 ; ++z){ - assert(mvwadd_wch(w,0,z,&bchr[5]) != ERR); - } - for(z = rows - 2 ; z > 0 ; --z){ - assert(mvwadd_wch(w,z,0,&bchr[4]) != ERR); - assert(mvwins_wch(w,z,cols - 1,&bchr[4]) != ERR); - } - assert(mvwins_wch(w,0,cols - 1,&bchr[1]) != ERR); - assert(mvwadd_wch(w,rows - 1,0,&bchr[2]) != ERR); - for(z = 1 ; z < cols - 1 ; ++z){ - assert(mvwadd_wch(w,rows - 1,z,&bchr[5]) != ERR); - } - assert(mvwins_wch(w,rows - 1,cols - 1,&bchr[3]) != ERR); - return OK; -} - -static void -draw_main_window(WINDOW *w){ - int rows,cols,scol,x,y; - char buf[BUFSIZ]; - - scol = snprintf(buf, sizeof(buf), "%s %s (%d)", PACKAGE,VERSION, count_adapters - 1); - assert(scol > 0 && (unsigned)scol < sizeof(buf)); - getmaxyx(w,rows,cols); - assert(wattrset(w,COLOR_PAIR(HEADER_COLOR)) != ERR); - mvwaddstr(w,rows - 1,0,buf); - getyx(w,y,x); - assert(y >= 0); - cols -= x + 2; - assert(wattron(w,A_BOLD | COLOR_PAIR(STATUS_COLOR)) != ERR); - assert(wprintw(w," %-*.*s",cols,cols,statusmsg) != ERR); -} - -static void -locked_vdiag(const char *fmt,va_list v){ - size_t off; - - vsnprintf(statusmsg,sizeof(statusmsg) / sizeof(*statusmsg) - 1,fmt,v); - statusmsg[sizeof(statusmsg) / sizeof(*statusmsg) - 1] = '\0'; - for(off = 0 ; off < sizeof(statusmsg) / sizeof(*statusmsg) - 1 ; ++off){ - if(!isgraph(statusmsg[off])){ - if(!statusmsg[off]){ - break; - } - statusmsg[off] = ' '; - } - } - draw_main_window(stdscr); - if(diags.p){ - update_diags(&diags); - } - screen_update(); -} - -void locked_diag(const char *fmt,...){ - va_list v; - - va_start(v,fmt); - locked_vdiag(fmt,v); - va_end(v); -} - -static inline int -device_lines(int expa,const blockobj *bo){ - int l = 0; - - if(expa != EXPANSION_NONE){ - if(bo->d->size){ - l += 2; - } - ++l; - } - return l; -} - -// This is the number of lines we'd have in an optimal world; we might have -// fewer available to us on this screen at this time. -static int -lines_for_adapter(const struct adapterstate *as){ - int l = 2; - - const blockobj *bo; - - for(bo = as->bobjs ; bo ; bo = bo->next){ - l += device_lines(as->expansion,bo); - } - return l; -} - -static zobj * -create_zobj(zobj *prev,unsigned zno,uintmax_t fsector,uintmax_t lsector, - device *p,wchar_t rep){ - zobj *z; - - assert(lsector >= fsector); - assert(fsector > 0 || zno == 0); - assert(fsector == 0 || zno > 0); - if( (z = malloc(sizeof(*z))) ){ - z->zoneno = zno; - z->fsector = fsector; - z->lsector = lsector; - z->rep = rep; - z->p = p; - if( (z->prev = prev) ){ - prev->next = z; - } - z->next = NULL; - } - return z; -} - -static inline int -adapter_lines_bounded(const adapterstate *as,int rows){ - int l = lines_for_adapter(as); - - if(l > rows - 1){ // bottom summary line - l = rows - 1; - } - return l; -} - -static inline int -adapter_lines_unbounded(const adapterstate *is){ - return adapter_lines_bounded(is,INT_MAX); -} - -// Is the adapter window entirely visible? We can't draw it otherwise, as it -// will obliterate the global bounding box. -static int -adapter_wholly_visible_p(int rows, const reelbox *rb){ - const adapterstate *as = rb->as; - -// fprintf(stderr, " %s at %d wants %d\n", rb->as->c->name, rb->scrline, adapter_lines_bounded(as, rows)); - if(rb->scrline + adapter_lines_bounded(as,rows) >= rows){ - return 0; - }else if(rb->scrline < 0){ - return 0; - }else if(rb->scrline == 0 && adapter_lines_bounded(as,rows) != getmaxy(rb->win)){ - return 0; - } - return 1; -} - -// Returns the amount of space available at the bottom. -static inline int -bottom_space_p(int rows){ - if(!last_reelbox){ - return rows; - } - if(getmaxy(last_reelbox->win) + getbegy(last_reelbox->win) >= rows - 2){ - return 0; - } - return (rows - 1) - (getmaxy(last_reelbox->win) + getbegy(last_reelbox->win)); -} - -// Create a panel at the bottom of the window, referred to as the "subdisplay". -// Only one can currently be active at a time. Window decoration and placement -// is managed here; only the rows needed for display ought be provided. -static int -new_display_panel(WINDOW *w,struct panel_state *ps,int rows,int cols, - const wchar_t *hstr,const wchar_t *bstr,int borderpair){ - const int crightlen = bstr ? wcslen(bstr) : 0; - int ybelow,yabove; - WINDOW *psw; - int x,y; - - // Desired space above and below, which will be impugned upon as needed - ybelow = 3; - yabove = 5; - getmaxyx(w,y,x); - if(cols == 0){ - cols = x - START_COL * 2; // indent 2 on the left, 0 on the right - }else{ - assert(x >= cols + START_COL * 2); - } - if(rows + ybelow + yabove >= y){ - if(rows + ybelow >= y){ - yabove = 0; - }else{ - yabove = y - (rows + ybelow); - } - }else{ - yabove += y - (rows + ybelow + yabove); - } - if((psw = newwin(rows + 2,cols,yabove,0)) == NULL){ - locked_diag("Can't display subwindow, uh-oh"); - return ERR; - } - if((ps->p = new_panel(psw)) == NULL){ - locked_diag("Couldn't create subpanel, uh-oh"); - delwin(psw); - return ERR; - } - assert(top_panel(ps->p) != ERR); - // memory leaks follow if we're compiled with NDEBUG! FIXME - assert(wattron(psw,A_BOLD) != ERR); - assert(wcolor_set(psw,borderpair,NULL) == OK); - assert(bevel(psw) == OK); - assert(wattroff(psw,A_BOLD) != ERR); - assert(wcolor_set(psw,PHEADING_COLOR,NULL) == OK); - if(hstr){ - assert(mvwaddwstr(psw,0,START_COL * 2,hstr) != ERR); - } - if(bstr){ - assert(mvwaddwstr(psw,rows + 1,cols - (crightlen + START_COL * 2),bstr) != ERR); - } - return OK; -} - -static void -hide_panel_locked(struct panel_state *ps){ - if(ps){ - WINDOW *psw; - - psw = panel_window(ps->p); - hide_panel(ps->p); - assert(del_panel(ps->p) == OK); - ps->p = NULL; - assert(delwin(psw) == OK); - } -} - -// Print the contents of the block device in a horizontal bar of arbitrary size -static void -print_blockbar(WINDOW *w,const blockobj *bo,int y,int sx,int ex,int selected){ - static const cchar_t bchr[] = { - { .attr = 0, .chars = L"∾", }, - { .attr = 0, .chars = L" ", }, - { .attr = 0, .chars = L" ", }, - }; - char pre[BPREFIXSTRLEN + 1]; - const char *selstr = NULL; - wchar_t wbuf[ex - sx + 2]; - const int wchars = sizeof(wbuf) / sizeof(*wbuf); - int targco,mountco,partco; - const device *d = bo->d; - char buf[ex - sx + 2]; - const zobj *z; - int off = sx; - uintmax_t zs; - - zs = d->mntsize ? d->mntsize : - (last_usable_sector(d) - first_usable_sector(d) + 1) * bo->d->logsec; - // Sometimes, a partitioned block device will be given a mnttype by - // libblkid (usually due to a filesystem signature in unpartitioned - // space at the beginning). In that case, don't try to print based off - // the bogon block device mnttype. - if(d->mnttype && (d->layout != LAYOUT_NONE || !d->blkdev.pttable)){ - int co = mnttype_aggregablep(d->mnttype) ? - COLOR_PAIR(PART_COLOR0) : COLOR_PAIR(FS_COLOR); - - assert(wattrset(w,A_BOLD|co) == OK); - qprefix(zs,1,pre,1); - if(!d->mnt.count || swprintf(wbuf, wchars , L" %s%s%ls%s%ls%s%s%sat %s ", - d->label ? "" : "nameless ", - d->mnttype, - d->label ? L" “" : L"", - d->label ? d->label : "", - d->label ? L"” " : L" ", - zs ? "(" : "", zs ? pre : "", zs ? ") " : "", - d->mnt.list[0]) >= wchars){ - if(swprintf(wbuf, wchars, L" %s%s%ls%s%ls%s%s%s ", - d->label ? "" : "nameless ", - d->mnttype, - d->label ? L" “" : L"", - d->label ? d->label : "", - d->label ? L"” " : L" ", - zs ? "(" : "", zs ? pre : "", zs ? ")" : "" - ) >= wchars){ - if(swprintf(wbuf, wchars, L" %s%s%s%s ", - d->mnttype, - zs ? "(" : "", zs ? pre : "", zs ? ")" : "" - ) >= wchars){ - assert(swprintf(wbuf, wchars, L"%s",d->mnttype) < wchars); - } - } - } - mvwhline_set(w,y,sx,&bchr[0],ex - sx + 1); - mvwadd_wch(w,y,sx,&bchr[1]); - mvwaddwstr(w,y,sx + (ex - sx + 1 - wcslen(wbuf)) / 2,wbuf); - mvwadd_wch(w,y,ex - 1,&bchr[2]); - selstr = d->name; - }else if(d->layout == LAYOUT_NONE && d->blkdev.unloaded){ - assert(wattrset(w,A_BOLD|COLOR_PAIR(OPTICAL_COLOR)) == OK); - selstr = "No media detected in drive"; - mvwprintw(w,y,sx,"%-*.*s",ex - sx,ex - sx,selstr); - }else if((d->layout == LAYOUT_NONE && d->blkdev.pttable == NULL) || - (d->layout == LAYOUT_MDADM && d->mddev.pttable == NULL) || - (d->layout == LAYOUT_DM && d->dmdev.pttable == NULL)){ - assert(wattrset(w,A_BOLD|COLOR_PAIR(EMPTY_COLOR)) == OK); - selstr = d->layout == LAYOUT_NONE ? "unpartitioned space" : - "unpartitionable space"; - assert(snprintf(buf,sizeof(buf)," %s %s ", - qprefix(d->size,1,pre,1), - selstr) < (int)sizeof(buf)); - mvwhline_set(w,y,sx,&bchr[0],ex - sx + 1); - mvwadd_wch(w,y,sx,&bchr[1]); - mvwaddstr(w,y,sx + (ex - sx + 1 - strlen(buf)) / 2,buf); - mvwadd_wch(w,y,ex - 1,&bchr[2]); - } - if((z = bo->zchain) == NULL){ - if(selected){ - wattron(w,A_REVERSE); - mvwprintw(w,y - 1,sx + 1,"⇗⇨⇨⇨%.*s",(int)(ex - (sx + 5)),selstr); - wattroff(w,A_REVERSE); - } - return; - } - partco = PART_COLOR0; - targco = TARGET_COLOR0; - mountco = MOUNT_COLOR0; - do{ - unsigned ch,och; - wchar_t rep; - - wbuf[0] = L'\0'; - zs = (z->lsector - z->fsector + 1) * bo->d->logsec; - qprefix(zs, 1, pre, 1); - if(z->p == NULL){ // unused space among partitions, or metadata - int co = (z->rep == REP_METADATA ? COLOR_PAIR(METADATA_COLOR) : - COLOR_PAIR(EMPTY_COLOR)); - const char *repstr = z->rep == REP_METADATA ? - "partition table metadata" : "empty space"; - - if(selected && z == bo->zone){ - selstr = repstr; - assert(wattrset(w,A_BOLD|A_UNDERLINE|co) == OK); - }else{ - assert(wattrset(w,co) == OK); - } - if(swprintf(wbuf, wchars - 2, L"%s %s", pre, repstr) >= wchars - 2){ - if(swprintf(wbuf, wchars - 2,L"%s",repstr) >= wchars - 2){ - wbuf[0] = L'\0'; - } - } - rep = z->rep; - }else{ // dedicated partition - if(selected && z == bo->zone){ // partition and device are selected - if(targeted_p(z->p)){ - assert(wattrset(w,A_BOLD|A_UNDERLINE|COLOR_PAIR(targco)) == OK); - targco = next_targco(targco); - }else if(z->p->mnt.count){ - assert(wattrset(w,A_BOLD|A_UNDERLINE|COLOR_PAIR(mountco)) == OK); - mountco = next_mountco(mountco); - }else if(z->p->mnttype && !mnttype_aggregablep(z->p->mnttype)){ - assert(wattrset(w,A_BOLD|A_UNDERLINE|COLOR_PAIR(FS_COLOR)) == OK); - }else{ - assert(wattrset(w,A_BOLD|A_UNDERLINE|COLOR_PAIR(partco)) == OK); - partco = next_partco(partco); - } - // FIXME need to store pname as multibyte char * - // selstr = z->p->partdev.pname; - // selstr = selstr ? selstr : z->p->name; - if( (selstr = z->p->name) ){ - if(swprintf(wbuf, wchars - 2, L"%s %s", pre,selstr) >= wchars - 2){ - if(swprintf(wbuf, wchars - 2, L"%s", selstr) >= wchars - 2){ - wbuf[0] = L'\0'; - } - } - } - }else{ // partition is not selected - if(targeted_p(z->p)){ - assert(wattrset(w,COLOR_PAIR(targco)) == OK); - targco = next_targco(targco); - }else if(z->p->mnt.count){ - assert(wattrset(w,COLOR_PAIR(mountco)) == OK); - mountco = next_mountco(mountco); - }else if(z->p->mnttype && !mnttype_aggregablep(z->p->mnttype)){ - assert(wattrset(w,COLOR_PAIR(FS_COLOR)) == OK); - }else{ - assert(wattrset(w,COLOR_PAIR(partco)) == OK); - partco = next_partco(partco); - } - if(swprintf(wbuf, wchars - 2,L"%s %s", pre,z->p->name) >= wchars - 2){ - if(swprintf(wbuf, wchars - 2,L"%s",z->p->name) >= wchars - 2){ - wbuf[0] = L'\0'; - } - } - } - if(z->p->partdev.alignment < d->physsec){ // misaligned! - assert(wattrset(w,A_BOLD|COLOR_PAIR(FUCKED_COLOR)) == OK); - } - if(z->p->mnttype){ - if((!z->p->mnt.count || swprintf(wbuf, wchars - 2, L"%s at %s (%s)",z->p->mnttype,z->p->mnt.list[0],pre) >= wchars - 2)){ - if(!z->p->label || swprintf(wbuf, wchars - 2, L"%s “%s” (%s)", z->p->mnttype,z->p->label,pre) >= wchars - 2){ - if(swprintf(wbuf, wchars - 2,L"%s (%s)", z->p->mnttype, pre) >= wchars - 2){ - wbuf[0] = L'\0'; - } - } - } - } - rep = z->p->partdev.pnumber % 16; - if(rep >= 10){ - rep = L'a' + (rep - 10); // FIXME lame - }else{ - rep = L'0' + rep; // FIXME lame - } - } - ch = (((z->lsector - z->fsector) * 1000) / ((d->size * 1000 / d->logsec) / (ex - sx))); - if(ch == 0){ - ch = 1; - } - och = off; - while(ch--){ - cchar_t crep[] = { { .attr = 0, .chars[0] = rep, }, }; - mvwadd_wch(w,y,off,crep); - if(++off > ex - z->following){ - off = ex - z->following; - break; - } - } - wattron(w,A_REVERSE); - if(selstr){ - if(och < ex / 2u){ - mvwprintw(w,y - 1,och,"⇗⇨⇨⇨%.*s",(int)(ex - (off + strlen(selstr) + 4)),selstr); - }else{ - mvwprintw(w,y - 1,off - 4 - strlen(selstr),"%s⇦⇦⇦⇖",selstr); - } - } - wattroff(w,A_REVERSE); - // Truncate it at whitespace until it's small enough to fit - while(wcslen(wbuf) && wcslen(wbuf) + 2 > (off - och + 1)){ - wchar_t *wtrunc = wcsrchr(wbuf,L' '); - - if(wtrunc){ - *wtrunc = L'\0'; - }else{ - wbuf[0] = L'\0'; - } - } - if(wcslen(wbuf)){ - size_t start = och + ((off - och + 1) - wcslen(wbuf)) / 2; - - wattron(w,A_BOLD); - mvwaddwstr(w,y,start,wbuf); - mvwaddch(w,y,start - 1,' '); - mvwaddch(w,y,start + wcslen(wbuf),' '); - } - selstr = NULL; - }while((z = z->next) != bo->zchain); -} - -static void -print_dev(const reelbox *rb,const blockobj *bo,int line,int rows, - unsigned cols,int topp,unsigned endp){ - char buf[BPREFIXSTRLEN + 1]; - int selected,co,rx,attr; - char rolestr[12]; // taken from %-11.11s below - -//fprintf(stderr, " HERE FOR %s: %s line %d rows %d cols %d lout %d\n", rb->as->c->name, bo->d->name, line, rows, cols, bo->d->layout); - if(line >= rows - !endp){ - return; - } - strcpy(rolestr, ""); - selected = line >= 1 && line == rb->selline; - rx = cols - 79; - switch(bo->d->layout){ -case LAYOUT_NONE: - if(bo->d->blkdev.realdev){ - if(bo->d->blkdev.rotation == SSD_ROTATION){ - wattrset(rb->win, COLOR_PAIR(SSD_COLOR)); - strncpy(rolestr,"solidstate",sizeof(rolestr)); - }else if(bo->d->blkdev.rotation > 0){ - int32_t speed = bo->d->blkdev.rotation; - wattrset(rb->win,COLOR_PAIR(ROTATE_COLOR)); - if(speed > 0){ - if(speed > 99999){ - speed = 99999; - } - snprintf(rolestr, sizeof(rolestr), - "%d rpm", speed); - }else{ - strncpy(rolestr, "ferromag", sizeof(rolestr)); - } - }else if(bo->d->kerneltype == TYPE_ROM){ - wattrset(rb->win, COLOR_PAIR(OPTICAL_COLOR)); - strncpy(rolestr, "optical", sizeof(rolestr)); - }else if(bo->d->kerneltype == TYPE_TAPE){ - wattrset(rb->win, COLOR_PAIR(OPTICAL_COLOR)); - strncpy(rolestr, "tape", sizeof(rolestr)); - } - // FIXME do we want a default here? - }else{ - wattrset(rb->win, COLOR_PAIR(VIRTUAL_COLOR)); - strncpy(rolestr, "virtual", sizeof(rolestr)); - } - if(line + !!topp >= 1){ - if(!bo->d->size || line + 2 < rows - !endp){ - if(bo->d->size){ - line += 2; - }else if(selected){ - wattron(rb->win, A_REVERSE); - } - mvwprintw(rb->win,line,1,"%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", - bo->d->name, - bo->d->model ? bo->d->model : "n/a", - bo->d->revision ? bo->d->revision : "n/a", - qprefix(bo->d->size,1,buf,0), - bo->d->physsec, - bo->d->blkdev.pttable ? bo->d->blkdev.pttable : "none", - bo->d->blkdev.wwn ? bo->d->blkdev.wwn : "n/a", - bo->d->blkdev.realdev ? transport_str(bo->d->blkdev.transport) : "n/a", - rx,rx,""); - if(bo->d->size){ - line -= 2; - } - } - } - break; -case LAYOUT_MDADM: - if(bo->d->mddev.level){ - strncpy(rolestr, bo->d->mddev.level, sizeof(rolestr) - 1); - rolestr[sizeof(rolestr) - 1] = '\0'; - } - if(bo->d->mddev.degraded){ - co = COLOR_PAIR(FUCKED_COLOR); - }else{ - co = COLOR_PAIR(MDADM_COLOR); - } - assert(wattrset(rb->win,co) == OK); - if(line + !!topp >= 1){ - if(!bo->d->size || line + 2 < rows - !endp){ - if(bo->d->size){ - line += 2; - }else if(selected){ - wattron(rb->win,A_REVERSE); - } - mvwprintw(rb->win,line,1,"%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", - bo->d->name, - bo->d->model ? bo->d->model : "n/a", - bo->d->revision ? bo->d->revision : "n/a", - qprefix(bo->d->size,1,buf,0), - bo->d->physsec, - bo->d->mddev.pttable ? bo->d->mddev.pttable : "none", - bo->d->mddev.mdname ? bo->d->mddev.mdname : "n/a", - transport_str(bo->d->mddev.transport), - rx,rx,""); - if(bo->d->size){ - line -= 2; - } - } - } - assert(wattrset(rb->win,COLOR_PAIR(MDADM_COLOR)) == OK); - break; -case LAYOUT_DM: - strncpy(rolestr,"dm",sizeof(rolestr)); - assert(wattrset(rb->win,COLOR_PAIR(MDADM_COLOR)) == OK); - if(line + !!topp >= 1){ - if(!bo->d->size || line + 2 < rows - !endp){ - if(bo->d->size){ - line += 2; - }else if(selected){ - wattron(rb->win,A_REVERSE); - } - mvwprintw(rb->win,line,1,"%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", - bo->d->name, - bo->d->model ? bo->d->model : "n/a", - bo->d->revision ? bo->d->revision : "n/a", - qprefix(bo->d->size,1,buf,0), - bo->d->physsec, - bo->d->dmdev.pttable ? bo->d->dmdev.pttable : "none", - bo->d->dmdev.dmname ? bo->d->dmdev.dmname : "n/a", - transport_str(bo->d->dmdev.transport), - rx,rx,""); - if(bo->d->size){ - line -= 2; - } - } - } - break; -case LAYOUT_PARTITION: - break; -case LAYOUT_ZPOOL: - strncpy(rolestr,"zpool",sizeof(rolestr)); - assert(wattrset(rb->win,COLOR_PAIR(ZPOOL_COLOR)) == OK); - if(line + !!topp >= 1){ - if(!bo->d->size || line + 2 < rows - !endp){ - if(bo->d->size){ - line += 2; - }else if(selected){ - wattron(rb->win,A_REVERSE); - } - mvwprintw(rb->win,line,1,"%11.11s %-16.16s %4ju " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", - bo->d->name, - bo->d->model ? bo->d->model : "n/a", - (uintmax_t)bo->d->zpool.zpoolver, - qprefix(bo->d->size,1,buf,0), - bo->d->physsec, - "spa", - "n/a", // FIXME - transport_str(bo->d->zpool.transport), - rx,rx,""); - if(bo->d->size){ - line -= 2; - } - } - } - break; - } - if(bo->d->size == 0){ - return; - } - wattroff(rb->win, A_REVERSE); - wattrset(rb->win, A_BOLD|COLOR_PAIR(SUBDISPLAY_COLOR)); - - // Box-diagram (3-line) mode. Print the name on the first line. - if(line + !!topp >= 1){ - mvwprintw(rb->win, line, START_COL, "%11.11s", bo->d->name); - } - - // Print summary below device name, in the same color, but prefix it - // with the single-character SMART status when applicable. - if(line + 1 < rows - !endp && line + !!topp + 1 >= 1){ - wchar_t rep = L' '; - if(bo->d->blkdev.smart >= 0){ - if(bo->d->blkdev.smart == SK_SMART_OVERALL_GOOD){ - wattrset(rb->win, A_BOLD|COLOR_PAIR(GREEN_COLOR)); - rep = L'✔'; - }else if(bo->d->blkdev.smart != SK_SMART_OVERALL_BAD_STATUS - && bo->d->blkdev.smart != SK_SMART_OVERALL_BAD_SECTOR_MANY){ - wattrset(rb->win, A_BOLD|COLOR_PAIR(ORANGE_COLOR)); - rep = L'☠'; - }else{ - wattrset(rb->win, A_BOLD|COLOR_PAIR(FUCKED_COLOR)); - rep = L'✗'; - } - } - mvwprintw(rb->win, line + 1, START_COL, "%lc", rep); - wattrset(rb->win, A_BOLD|COLOR_PAIR(SUBDISPLAY_COLOR)); - if(strlen(rolestr)){ - wprintw(rb->win, "%10.10s", rolestr); - }else{ - wprintw(rb->win, " "); - } - } - // ...and finally the temperature/vfailure status, and utilization... - if((line + 2 < rows - !endp) && (line + !!topp + 2 >= 1)){ - int sumline = line + 2; - if(bo->d->layout == LAYOUT_NONE){ - if(bo->d->blkdev.celsius && bo->d->blkdev.celsius < 100u){ - if(bo->d->blkdev.celsius >= 60u){ - wattrset(rb->win, A_BOLD|COLOR_PAIR(FUCKED_COLOR)); - }else if(bo->d->blkdev.celsius >= 40u){ - wattrset(rb->win, A_BOLD|COLOR_PAIR(ORANGE_COLOR)); - }else{ - wattrset(rb->win, COLOR_PAIR(GREEN_COLOR)); - } - // FIXME would be nice to use ℃ , but it looks weird - mvwprintw(rb->win, sumline, START_COL, "%2.ju° ", bo->d->blkdev.celsius); - }else{ - mvwprintw(rb->win, sumline, START_COL, " "); - } - }else if(bo->d->layout == LAYOUT_MDADM){ - if(bo->d->mddev.degraded){ - wattrset(rb->win,A_BOLD|COLOR_PAIR(FUCKED_COLOR)); - mvwprintw(rb->win, sumline, START_COL, - "%1lux☠ ", bo->d->mddev.degraded); - }else{ - wattrset(rb->win,COLOR_PAIR(GREEN_COLOR)); - mvwprintw(rb->win, sumline, START_COL, "up "); - } - }else if(bo->d->layout == LAYOUT_DM){ - // FIXME add more detail...type of dm etc - wattrset(rb->win,COLOR_PAIR(GREEN_COLOR)); - mvwprintw(rb->win,sumline,START_COL,"up "); - }else if(bo->d->layout == LAYOUT_ZPOOL){ - if(bo->d->zpool.state != POOL_STATE_ACTIVE){ - wattrset(rb->win,A_BOLD|COLOR_PAIR(FUCKED_COLOR)); - mvwprintw(rb->win,sumline,START_COL,"☠☠☠ "); - }else{ - wattrset(rb->win,COLOR_PAIR(GREEN_COLOR)); - mvwprintw(rb->win,sumline,START_COL,"up "); - } - } - uintmax_t io; - io = bo->d->statdelta.sectors_read; - io += bo->d->statdelta.sectors_written; - io *= bo->d->logsec; - // FIXME normalize according to timeq - wattrset(rb->win, COLOR_PAIR(SELECTED_COLOR)); - // FIXME 'i' shows up only when there are fewer than 3 sigfigs - // to the left of the decimal point...very annoying - if(io){ - char qbuf[BPREFIXSTRLEN + 1]; - bprefix(io, 1, qbuf, 1); - wprintw(rb->win, "%7.7s", qbuf); // might chop off 'i' - }else{ - wprintw(rb->win, " no i/o"); - } - } - - assert(wattrset(rb->win,A_BOLD|COLOR_PAIR(DBORDER_COLOR)) == OK); - if(selected){ - wattron(rb->win,A_REVERSE); - } - if(line + !!topp >= 1){ - mvwaddch(rb->win,line,START_COL + 10 + 1,ACS_ULCORNER); - mvwhline(rb->win,line,START_COL + 2 + 10,ACS_HLINE,cols - START_COL * 2 - 2 - 10); - mvwaddch(rb->win,line,cols - START_COL * 2,ACS_URCORNER); - } - if(++line >= rows - !endp){ - return; - } - - if(line + !!topp >= 1){ - mvwaddch(rb->win,line,START_COL + 10 + 1,ACS_VLINE); - print_blockbar(rb->win,bo,line,START_COL + 10 + 2, - cols - START_COL - 1,selected); - } - attr = A_BOLD | COLOR_PAIR(DBORDER_COLOR); - wattrset(rb->win,attr); - if(selected){ - wattron(rb->win,A_REVERSE); - } - if(line + !!topp >= 1){ - mvwaddch(rb->win,line,cols - START_COL * 2,ACS_VLINE); - } - if(++line >= rows - !endp){ - return; - } - if(line + !!topp >= 1){ - int c = cols - 80; - static const cchar_t bchrs[] = { - { .attr = 0, .chars = L"┤", }, - { .attr = 0, .chars = L"├", }, - }; - - mvwaddch(rb->win,line,START_COL + 10 + 1,attr | ACS_LLCORNER); - wadd_wch(rb->win,&bchrs[0]); - mvwadd_wch(rb->win,line,cols - 3 - c,&bchrs[1]); - if(c > 0){ - whline(rb->win,ACS_HLINE,c); - wmove(rb->win,line,cols - 2); - } - waddch(rb->win,attr | ACS_LRCORNER); - } - ++line; -} - -static void -print_adapter_devs(const adapterstate *as,int rows,int cols, - unsigned topp,unsigned endp){ - // If the interface is down, we don't lead with the summary line - const blockobj *cur; - const reelbox *rb; - long line; - - if((rb = as->rb) == NULL){ - return; - } - if(as->expansion == EXPANSION_NONE){ - return; - } - // First, print the selected device (if there is one), and those above - cur = rb->selected; - line = rb->selline; - while(cur && line + (long)device_lines(as->expansion,cur) >= !!topp){ - print_dev(rb,cur,line,rows,cols,topp,endp); - // here we traverse, then account... - if( (cur = cur->prev) ){ - line -= device_lines(as->expansion,cur); - } - } - line = rb->selected ? (rb->selline + - (long)device_lines(as->expansion,rb->selected)) : -(long)topp + 1; - cur = (rb->selected ? rb->selected->next : as->bobjs); - while(cur && line < rows){ - print_dev(rb,cur,line,rows,cols,topp,endp); - // here, we account before we traverse. this is correct. - line += device_lines(as->expansion,cur); - cur = cur->next; - } -} - -// Abovetop: lines hidden at the top of the screen -// Belowend: lines hidden at the bottom of the screen -static void -adapter_box(const adapterstate *as,WINDOW *w,unsigned abovetop,unsigned belowend){ - int current = as->rb == current_adapter; - int bcolor,hcolor,rows,cols; - int attrs; - - getmaxyx(w,rows,cols); - if(current){ - hcolor = UHEADING_COLOR; // plus A_BOLD - bcolor = SELBORDER_COLOR; - attrs = A_BOLD; - }else{ - hcolor = UNHEADING_COLOR;; - bcolor = UBORDER_COLOR; - attrs = A_NORMAL; - } - assert(wattrset(w,attrs | COLOR_PAIR(bcolor)) == OK); - if(abovetop == 0){ - if(belowend == 0){ - assert(bevel(w) == OK); - }else{ - assert(bevel_top(w) == OK); - } - }else{ - if(belowend == 0){ - assert(bevel_bottom(w) == OK); - } // otherwise it has no top or bottom visible - } - if(abovetop == 0){ - if(current){ - assert(wattron(w,A_BOLD) == OK); - }else{ - assert(wattroff(w,A_BOLD) == OK); - } - assert(mvwprintw(w,0,7,"%ls",L"[") != ERR); - assert(wcolor_set(w,hcolor,NULL) == OK); - assert(waddstr(w,as->c->ident) != ERR); - if(as->c->numa_node >= 0){ - assert(wprintw(w," [%d]",as->c->numa_node) != ERR); - } - if(as->c->bandwidth){ - char buf[PREFIXSTRLEN + 1],dbuf[PREFIXSTRLEN + 1]; - - if(as->c->demand){ - wprintw(w," (%sbps to Southbridge, %sbps (%ju%%) demanded)", - qprefix(as->c->bandwidth,1,buf,1), - qprefix(as->c->demand,1,dbuf,1), - as->c->demand * 100 / as->c->bandwidth); - }else{ - wprintw(w," (%sbps to Southbridge)", - qprefix(as->c->bandwidth,1,buf,1)); - } - }else if(as->c->bus != BUS_VIRTUAL && as->c->demand){ - char dbuf[PREFIXSTRLEN + 1]; - - wprintw(w," (%sbps demanded)",qprefix(as->c->demand,1,dbuf,1)); - } - assert(wcolor_set(w,bcolor,NULL) != ERR); - assert(wprintw(w,"]") != ERR); - assert(wattron(w,A_BOLD) == OK); - assert(wmove(w,0,cols - 5) != ERR); - waddwstr(w,as->expansion != EXPANSION_MAX ? L"[+]" : L"[-]"); - assert(wattron(w,attrs) != ERR); - } - if(belowend == 0){ - if(as->c->bus == BUS_PCIe){ - assert(wcolor_set(w,bcolor,NULL) != ERR); - if(current){ - assert(wattron(w,A_BOLD) == OK); - }else{ - assert(wattroff(w,A_BOLD) == OK); - } - assert(mvwprintw(w,rows - 1,6,"[") != ERR); - assert(wcolor_set(w,hcolor,NULL) != ERR); - if(as->c->pcie.lanes_neg == 0){ - wprintw(w,"Southbridge device %04x:%02x.%02x.%x", - as->c->pcie.domain,as->c->pcie.bus, - as->c->pcie.dev,as->c->pcie.func); - }else{ - wprintw(w,"PCI Express device %04x:%02x.%02x.%x (x%u, gen %s)", - as->c->pcie.domain,as->c->pcie.bus, - as->c->pcie.dev,as->c->pcie.func, - as->c->pcie.lanes_neg,pcie_gen(as->c->pcie.gen)); - } - assert(wcolor_set(w,bcolor,NULL) != ERR); - assert(wprintw(w,"]") != ERR); - } - } -} - -static int -redraw_adapter(const reelbox *rb){ - const adapterstate *as = rb->as; - int scrrows,scrcols,rows,cols; - unsigned topp,endp; - -// fprintf(stderr, " ASKED TO DRAW %s\n", rb->as->c->name); - if(panel_hidden(rb->panel)){ -// fprintf(stderr, " I'M HIDDEN, BITCH!\n"); - return OK; - } - getmaxyx(stdscr,scrrows,scrcols); - assert(scrcols); // FIXME - if(adapter_wholly_visible_p(scrrows,rb) || active){ // completely visible - topp = endp = 0; - }else if(getbegy(rb->win) == 0){ // no top - topp = adapter_lines_unbounded(as) - getmaxy(rb->win); - endp = 0; - }else{ - topp = 0; - endp = 1; // no bottom FIXME - } - getmaxyx(rb->win,rows,cols); - assert(cols); // FIXME - werase(rb->win); - adapter_box(as,rb->win,topp,endp); - print_adapter_devs(as,rows,cols,topp,endp); - return OK; -} - -// ------------------------------------------------------------------------- -// -- splash API. splashes are displayed during long operations, especially -// those requiring an external program. -// ------------------------------------------------------------------------- -struct panel_state *show_splash(const wchar_t *msg){ - struct panel_state *ps; - - assert(!splash); - if((ps = malloc(sizeof(*ps))) == NULL){ - return NULL; - } - memset(ps,0,sizeof(*ps)); - // FIXME gross, clean all of this up - if(new_display_panel(stdscr,ps,3,wcslen(msg) + 4,NULL,NULL,SPLASHBORDER_COLOR)){ - free(ps); - return NULL; - } - wattrset(panel_window(ps->p),A_BOLD|COLOR_PAIR(SPLASHTEXT_COLOR)); - mvwhline(panel_window(ps->p),1,1,' ',getmaxx(panel_window(ps->p)) - 2); - mvwhline(panel_window(ps->p),2,1,' ',getmaxx(panel_window(ps->p)) - 2); - mvwaddwstr(panel_window(ps->p),2,2,msg); - mvwhline(panel_window(ps->p),3,1,' ',getmaxx(panel_window(ps->p)) - 2); - form_colors(); - move_panel(ps->p,3,3); - return splash = ps; -} -// ------------------------------------------------------------------------- -// -- end splash API -// ------------------------------------------------------------------------- - -// ------------------------------------------------------------------------- -// -- begin form API -// ------------------------------------------------------------------------- -// Forms are modal. They take over the keyboard UI and sit atop everything -// else. Subwindows sit atop the hardware elements of the UI, but do not seize -// any of the input UI. A form and subwindow can coexist. - -// ------------------------------------------------------------------------- -// -- form creation -// ------------------------------------------------------------------------- -static struct form_state * -create_form(const char *str,void (*fxn)(const char *),form_enum ftype,int scrolloff){ - struct form_state *fs; - - if( (fs = malloc(sizeof(*fs))) ){ - memset(fs,0,sizeof(*fs)); - if((fs->boxstr = strdup(str)) == NULL){ - locked_diag("Couldn't create input dialog (%s?)",strerror(errno)); - free(fs); - return NULL; - } - fs->scrolloff = scrolloff; - fs->selectno = 1; - fs->formtype = ftype; - fs->fxn = fxn; - }else{ - locked_diag("Couldn't create input dialog (%s?)",strerror(errno)); - } - return fs; -} - -static void -destroy_form_locked(struct form_state *fs){ - if(fs){ - WINDOW *fsw; - int z; - - assert(fs == actform); - fsw = panel_window(fs->p); - hide_panel(fs->p); - del_panel(fs->p); - fs->p = NULL; - delwin(fsw); - hide_panel_locked(fs->extext); - free(fs->extext); - fs->extext = NULL; - switch(fs->formtype){ - case FORM_SELECT: - case FORM_MULTISELECT: - case FORM_CHECKBOXEN: - for(z = 0 ; z < fs->opcount ; ++z){ - free(fs->ops[z].option); - free(fs->ops[z].desc); - } - free(fs->selarray); - fs->selarray = NULL; - free(fs->ops); - fs->ops = NULL; - break; - case FORM_STRING_INPUT: - free(fs->inp.buffer); - free(fs->inp.longprompt); - fs->inp.longprompt = NULL; - fs->inp.prompt = NULL; - fs->inp.buffer = NULL; - break; - case FORM_SPLASH_PROMPT: - break; - } - actform = NULL; - } -} - -static void -free_form(struct form_state *fs){ - if(fs){ - free(fs->boxstr); - destroy_form_locked(fs); - free(fs); - if(splash == NULL){ - setup_colors(); - } - if(current_adapter){ - touchwin(current_adapter->win); - } - screen_update(); - } -} - -static void -multiform_options(struct form_state *fs){ - static const cchar_t bchr[] = { - { .attr = 0, .chars = L"╮", }, - { .attr = 0, .chars = L"╯", }, - { .attr = 0, .chars = L"╭", }, - { .attr = 0, .chars = L"╰", }, - { .attr = 0, .chars = L"│", }, - }; - const struct form_option *opstrs = fs->ops; - WINDOW *fsw = panel_window(fs->p); - int z,cols,selidx,maxz; - - assert(fs->formtype == FORM_MULTISELECT); - cols = getmaxx(fsw); - wattrset(fsw,COLOR_PAIR(FORMBORDER_COLOR)); - wattron(fsw,A_BOLD); - mvwadd_wch(fsw,1,1,&bchr[2]); - mvwadd_wch(fsw,1,fs->longop + 4,&bchr[0]); - maxz = getmaxy(fsw) - 3; - for(z = 1 ; z < maxz ; ++z){ - int op = ((z - 1) + fs->scrolloff) % fs->opcount; - - assert(op >= 0); - assert(op < fs->opcount); - wattroff(fsw,A_BOLD); - wcolor_set(fsw,FORMBORDER_COLOR,NULL); - if(fs->selectno >= z){ - mvwprintw(fsw,z + 1,START_COL * 2,"%d",z); - }else if(fs->selections >= z){ - mvwprintw(fsw,z + 2,START_COL * 2,"%d",z); - } - if(z < fs->opcount + 1){ - wattron(fsw,A_BOLD); - wcolor_set(fsw,FORMTEXT_COLOR,NULL); - mvwprintw(fsw,z + 1,START_COL * 2 + fs->longop + 4,"%-*.*s ", - fs->longop,fs->longop,opstrs[op].option); - if(op == fs->idx){ - wattron(fsw,A_REVERSE); - } - wcolor_set(fsw,INPUT_COLOR,NULL); - for(selidx = 0 ; selidx < fs->selections ; ++selidx){ - if(strcmp(opstrs[op].option,fs->selarray[selidx]) == 0){ - wcolor_set(fsw,SELECTED_COLOR,NULL); - break; - } - } - wprintw(fsw,"%-*.*s",cols - fs->longop * 2 - 9, - cols - fs->longop * 2 - 9,opstrs[op].desc); - wattroff(fsw,A_REVERSE); - } - } - wattrset(fsw,COLOR_PAIR(FORMBORDER_COLOR)); - wattron(fsw,A_BOLD); - for(z = 0 ; z < fs->selections ; ++z){ - mvwaddstr(fsw,z >= fs->selectno ? 3 + z : 2 + z,4,fs->selarray[z]); - } - mvwadd_wch(fsw,fs->selectno + 2,1,&bchr[3]); - mvwadd_wch(fsw,fs->selectno + 2,fs->longop + 4,&bchr[1]); -} - -static void -check_options(struct form_state *fs){ - const struct form_option *opstrs = fs->ops; - WINDOW *fsw = panel_window(fs->p); - int z,cols,selidx,maxz; - - assert(fs->formtype == FORM_CHECKBOXEN); - cols = getmaxx(fsw); - wattrset(fsw,COLOR_PAIR(FORMBORDER_COLOR)); - wattron(fsw,A_BOLD); - maxz = getmaxy(fsw) - 3; - for(z = 1 ; z < maxz ; ++z){ - int op = ((z - 1) + fs->scrolloff) % fs->opcount; - - assert(op >= 0); - assert(op < fs->opcount); - wattroff(fsw,A_BOLD); - wcolor_set(fsw,FORMBORDER_COLOR,NULL); - if(z < fs->opcount + 1){ - wchar_t ballot = L'☐'; - - wattron(fsw,A_BOLD); - wcolor_set(fsw,FORMTEXT_COLOR,NULL); - for(selidx = 0 ; selidx < fs->selections ; ++selidx){ - if(strcmp(opstrs[op].option,fs->selarray[selidx]) == 0){ - ballot = L'☒'; - break; - } - } - if(op == fs->idx){ - wattron(fsw,A_REVERSE); - }else{ - wcolor_set(fsw,INPUT_COLOR,NULL); - } - mvwprintw(fsw,z + 1,START_COL * 2,"%lc %-*.*s ", - ballot,fs->longop,fs->longop,opstrs[op].option); - wprintw(fsw,"%-*.*s",cols - fs->longop - 7, - cols - fs->longop - 7,opstrs[op].desc); - wattroff(fsw,A_REVERSE); - } - } - wattrset(fsw,COLOR_PAIR(FORMBORDER_COLOR)); -} - -static void -form_options(struct form_state *fs){ - const struct form_option *opstrs = fs->ops; - WINDOW *fsw = panel_window(fs->p); - int z,cols; - - if(fs->formtype != FORM_SELECT){ - return; - } - cols = getmaxx(fsw); - wattron(fsw,A_BOLD); - for(z = 1 ; z < getmaxy(fsw) - 3 ; ++z){ - int op = ((z - 1) + fs->scrolloff) % fs->opcount; - - assert(op >= 0); - assert(op < fs->opcount); - wcolor_set(fsw,FORMTEXT_COLOR,NULL); - mvwprintw(fsw,z + 1,START_COL * 2,"%-*.*s ", - fs->longop,fs->longop,opstrs[op].option); - if(op == fs->idx){ - wattron(fsw,A_REVERSE); - } - wcolor_set(fsw,INPUT_COLOR,NULL); - wprintw(fsw,"%-*.*s",cols - fs->longop - 1 - START_COL * 4, - cols - fs->longop - 1 - START_COL * 4,opstrs[op].desc); - wattroff(fsw,A_REVERSE); - } -} - -#define FORM_Y_OFFSET 5 -static struct panel_state * -raise_form_explication(const WINDOW *w,const char *text,int linesz){ - int linepre[linesz - 1]; - int linelen[linesz - 1]; - struct panel_state *ps; - int cols,x,y,brk,tot; - WINDOW *win; - - // There's two columns of padding surrounding the subwindow - cols = getmaxx(w) - 1; - tot = 0; - for(y = 0 ; (unsigned)y < sizeof(linepre) / sizeof(*linepre) ; ++y){ - while(isspace(text[tot])){ - ++tot; - } - linepre[y] = tot; - linelen[y] = 0; - brk = 0; - for(x = 1 ; x < cols - 1 ; ++x){ - if(!text[tot]){ - brk = x; - linelen[y] = brk - 1; - break; - } - if(isspace(text[tot])){ - brk = x; - } - ++tot; - } - // A brk value of 0 would indicate a single token longer than - // the screen, an unlikely event with which we don't yet deal. - assert(!text[tot] || brk); - // Go to the beginning of the current token, if we're in one. - tot -= (x - brk); - linelen[y] = brk - 1; - if(!text[tot]){ - if(y == 0){ - cols = x + 1; - } - break; - } - } - // If we've not chewed through all the text, we're not going to fit it - // into the provided space. We don't yet deal with this situation FIXME - assert(!text[tot]); - ps = malloc(sizeof(*ps)); - assert(ps); - win = newwin(y + 3,cols,linesz - (y + 2),getmaxx(w) - cols); - assert(win); - ps->p = new_panel(win); - assert(ps->p); - wbkgd(win,COLOR_PAIR(BLACK_COLOR)); - wattrset(win,COLOR_PAIR(FORMBORDER_COLOR)); - bevel(win); - wattrset(win,COLOR_PAIR(FORMTEXT_COLOR)); - do{ - mvwaddnstr(win,y + 1,1,text + linepre[y],linelen[y]); - }while(y--); - top_panel(ps->p); - screen_update(); - return ps; -} - -void raise_multiform(const char *str,void (*fxn)(const char *,char **,int,int), - struct form_option *opstrs,int ops,int defidx, - int selectno,char **selarray,int selections,const char *text, - int scrollidx){ - size_t longop,longdesc; - struct form_state *fs; - int cols,rows; - WINDOW *fsw; - int x,y; - - assert(ops); - assert(opstrs); - if(actform){ - locked_diag("An input dialog is already active"); - return; - } - longdesc = longop = 0; - for(x = 0 ; x < ops ; ++x){ - if(strlen(opstrs[x].option) > longop){ - longop = strlen(opstrs[x].option); - } - if(strlen(opstrs[x].desc) > longdesc){ - longdesc = strlen(opstrs[x].desc); - } - } - cols = longdesc + longop * 2 + 9; -#define ESCSTR L"'C' confirms setup, ⎋esc returns" - if(cols < (int)wcslen(ESCSTR) + 2){ - cols = wcslen(ESCSTR) + 2; - } - rows = (ops > selectno ? ops : selectno) + 4; - getmaxyx(stdscr,y,x); - if(x < cols){ - locked_diag("Window too thin for form, uh-oh"); - return; - } - if(y <= rows + FORM_Y_OFFSET){ - rows = y - FORM_Y_OFFSET - 1; - if(y < FORM_Y_OFFSET + 4 + 1){ // two boundaries + empties, at least 1 selection - locked_diag("Window too short for form, uh-oh"); - return; - } - } - if((fs = create_form(str,NULL,FORM_MULTISELECT,scrollidx)) == NULL){ - return; - } - fs->mcb = fxn; - if((fsw = newwin(rows,cols,FORM_Y_OFFSET,x - cols)) == NULL){ - locked_diag("Couldn't create form window, uh-oh"); - free_form(fs); - return; - } - if((fs->p = new_panel(fsw)) == NULL){ - locked_diag("Couldn't create form panel, uh-oh"); - delwin(fsw); - free_form(fs); - return; - } - wbkgd(fsw,COLOR_PAIR(BLACK_COLOR)); - // FIXME adapt for scrolling (default might be off-window at beginning) - if((fs->idx = defidx) < 0){ - fs->idx = defidx = 0; - } - fs->opcount = ops; - fs->selarray = selarray; - fs->selections = selections; - wattroff(fsw,A_BOLD); - wcolor_set(fsw,FORMBORDER_COLOR,NULL); - bevel(fsw); - wattron(fsw,A_BOLD); - mvwprintw(fsw,0,cols - strlen(fs->boxstr) - 4,"%s",fs->boxstr); - mvwaddwstr(fsw,getmaxy(fsw) - 1,cols - wcslen(ESCSTR) - 1,ESCSTR); -#undef ESCSTR - wattroff(fsw,A_BOLD); - fs->longop = longop; - fs->ops = opstrs; - fs->selectno = selectno; - multiform_options(fs); - fs->extext = raise_form_explication(stdscr,text,FORM_Y_OFFSET); - actform = fs; - form_colors(); - top_panel(fs->p); - screen_update(); -} - -// A collection of checkboxes -static void -raise_checkform(const char *str,void (*fxn)(const char *,char **,int,int), - struct form_option *opstrs,int ops,int defidx, - char **selarray,int selections,const char *text, - int scrollidx){ - size_t longop,longdesc; - struct form_state *fs; - int cols,rows; - WINDOW *fsw; - int x,y; - - assert(ops); - assert(opstrs); - if(actform){ - locked_diag("An input dialog is already active"); - return; - } - longdesc = longop = 0; - for(x = 0 ; x < ops ; ++x){ - if(strlen(opstrs[x].option) > longop){ - longop = strlen(opstrs[x].option); - } - if(strlen(opstrs[x].desc) > longdesc){ - longdesc = strlen(opstrs[x].desc); - } - } - cols = longdesc + longop + 7; -#define ESCSTR L"'C' commits, ⎋esc returns" - if(cols < (int)wcslen(ESCSTR) + 2){ - cols = wcslen(ESCSTR) + 2; - } - rows = ops + 4; - getmaxyx(stdscr,y,x); - if(x < cols){ - locked_diag("Window too thin for form, uh-oh"); - return; - } - if(y <= rows + FORM_Y_OFFSET){ - rows = y - FORM_Y_OFFSET - 1; - if(y < FORM_Y_OFFSET + 4 + 1){ // two boundaries + empties, at least 1 selection - locked_diag("Window too short for form, uh-oh"); - return; - } - } - if((fs = create_form(str,NULL,FORM_CHECKBOXEN,scrollidx)) == NULL){ - return; - } - fs->mcb = fxn; - if((fsw = newwin(rows,cols,FORM_Y_OFFSET,x - cols)) == NULL){ - locked_diag("Couldn't create form window, uh-oh"); - free_form(fs); - return; - } - if((fs->p = new_panel(fsw)) == NULL){ - locked_diag("Couldn't create form panel, uh-oh"); - delwin(fsw); - free_form(fs); - return; - } - wbkgd(fsw,COLOR_PAIR(BLACK_COLOR)); - // FIXME adapt for scrolling (default might be off-window at beginning) - if((fs->idx = defidx) < 0){ - fs->idx = defidx = 0; - } - fs->opcount = ops; - fs->selarray = selarray; - fs->selections = selections; - wattroff(fsw,A_BOLD); - wcolor_set(fsw,FORMBORDER_COLOR,NULL); - bevel(fsw); - wattron(fsw,A_BOLD); - mvwprintw(fsw,0,cols - strlen(fs->boxstr) - 2,"%s",fs->boxstr); - mvwaddwstr(fsw,getmaxy(fsw) - 1,cols - wcslen(ESCSTR) - 1,ESCSTR); -#undef ESCSTR - wattroff(fsw,A_BOLD); - fs->longop = longop; - fs->ops = opstrs; - check_options(fs); - fs->extext = raise_form_explication(stdscr,text,FORM_Y_OFFSET); - actform = fs; - form_colors(); - top_panel(fs->p); - screen_update(); -} - -// ------------------------------------------------------------------------- -// - select type form, for single choice from among a set -// ------------------------------------------------------------------------- -void raise_form(const char *str,void (*fxn)(const char *),struct form_option *opstrs, - int ops,int defidx,const char *text){ - size_t longop,longdesc; - struct form_state *fs; - int cols,rows; - WINDOW *fsw; - int x,y; - - if(opstrs == NULL || !ops){ - locked_diag("Passed empty %u-option string table",ops); - return; - } - if(actform){ - locked_diag("An input dialog is already active"); - return; - } - longdesc = longop = 0; - for(x = 0 ; x < ops ; ++x){ - if(strlen(opstrs[x].option) > longop){ - longop = strlen(opstrs[x].option); - } - if(strlen(opstrs[x].desc) > longdesc){ - longdesc = strlen(opstrs[x].desc); - } - } - cols = longdesc + longop + 1; - rows = ops + 4; - getmaxyx(stdscr,y,x); - if(x < cols + 4){ - locked_diag("Window too thin for form, uh-oh"); - return; - } - if(y <= rows + FORM_Y_OFFSET){ - rows = y - FORM_Y_OFFSET - 1; - if(y < FORM_Y_OFFSET + 4 + 1){ // two boundaries + empties, at least 1 selection - locked_diag("Window too short for form, uh-oh"); - return; - } - } - if((fs = create_form(str,fxn,FORM_SELECT,0)) == NULL){ - return; - } - if((fsw = newwin(rows,cols + START_COL * 4,FORM_Y_OFFSET,x - cols - 4)) == NULL){ - locked_diag("Couldn't create form window, uh-oh"); - free_form(fs); - return; - } - if((fs->p = new_panel(fsw)) == NULL){ - locked_diag("Couldn't create form panel, uh-oh"); - delwin(fsw); - free_form(fs); - return; - } - wbkgd(fsw,COLOR_PAIR(BLACK_COLOR)); - // FIXME adapt for scrolling (default might be off-window at beginning) - if((fs->idx = defidx) < 0){ - fs->idx = defidx = 0; - } - fs->opcount = ops; - wattroff(fsw,A_BOLD); - wcolor_set(fsw,FORMBORDER_COLOR,NULL); - bevel(fsw); - wattron(fsw,A_BOLD); - mvwprintw(fsw,0,cols - strlen(fs->boxstr),"%s",fs->boxstr); - mvwaddwstr(fsw,getmaxy(fsw) - 1,cols - wcslen(L"⎋esc returns"),L"⎋esc returns"); - wattroff(fsw,A_BOLD); - fs->longop = longop; - fs->ops = opstrs; - form_options(fs); - actform = fs; - fs->extext = raise_form_explication(stdscr,text,FORM_Y_OFFSET); - form_colors(); - top_panel(fs->p); - screen_update(); -} - -// ------------------------------------------------------------------------- -// - string type form, for generic input -// ------------------------------------------------------------------------- -static void -form_string_options(struct form_state *fs){ - WINDOW *fsw = panel_window(fs->p); - int cols; - - if(fs->formtype != FORM_STRING_INPUT){ - return; - } - cols = getmaxx(fsw); - wattrset(fsw,A_BOLD); - wcolor_set(fsw,FORMTEXT_COLOR,NULL); - mvwhline(fsw,1,1,' ',cols - 2); - mvwprintw(fsw,1,START_COL,"%-*.*s: ", - fs->longop,fs->longop,fs->inp.prompt); - wcolor_set(fsw,INPUT_COLOR,NULL); - wprintw(fsw,"%.*s",cols - fs->longop - 2 - 2,fs->inp.buffer); - wattroff(fsw,A_BOLD); -} - -void raise_str_form(const char *str,void (*fxn)(const char *), - const char *def,const char *text){ - struct form_state *fs; - WINDOW *fsw; - int cols; - int x,y; - - assert(str && fxn); - if(actform){ - locked_diag("An input dialog is already active"); - return; - } - if((fs = create_form(str,fxn,FORM_STRING_INPUT,0)) == NULL){ - return; - } - fs->longop = strlen(str); - cols = fs->longop + 40 + 1; // FIXME? 40 for input currently - getmaxyx(stdscr,y,x); - assert(x >= cols + 3); - assert(y >= 3); - if((fsw = newwin(3,cols + START_COL * 2,FORM_Y_OFFSET,x - cols - 3)) == NULL){ - locked_diag("Couldn't create form window, uh-oh"); - free_form(fs); - return; - } - if((fs->p = new_panel(fsw)) == NULL){ - locked_diag("Couldn't create form panel, uh-oh"); - delwin(fsw); - free_form(fs); - return; - } - top_panel(fs->p); - wattroff(fsw,A_BOLD); - wcolor_set(fsw,FORMBORDER_COLOR,NULL); - bevel(fsw); - wattron(fsw,A_BOLD); - mvwprintw(fsw,0,cols - strlen(fs->boxstr),"%s",fs->boxstr); - mvwaddwstr(fsw,getmaxy(fsw) - 1,cols - wcslen(L"⎋esc returns"),L"⎋esc returns"); - fs->inp.prompt = fs->boxstr; - def = def ? def : ""; - fs->inp.buffer = strdup(def); - form_string_options(fs); - actform = fs; - fs->extext = raise_form_explication(stdscr,text,FORM_Y_OFFSET); - curs_set(1); - form_colors(); - screen_update(); -} - -static const struct form_option common_fsops[] = { - { - .option = "ro", - .desc = "Read-only", - //},{ // this is the default - // .option = "rw", - // .desc = "Read-write", - },{ - .option = "async", - .desc = "Only asynchronous I/O", - },{ - .option = "sync", - .desc = "Only synchronous I/O", - },{ - .option = "noatime", - .desc = "No access time updates", - },{ - .option = "relatime", - .desc = "Relative access time updates", - },{ - .option = "strictatime", - .desc = "Full access time updates", - },{ - .option = "nostrictatime", - .desc = "Use the kernel's default policy", - },{ - .option = "noauto", - .desc = "Do not mount when running 'mount -a'", - },{ - .option = "nofail", - .desc = "Don't halt the boot on filesystem error", - },{ - .option = "suid", - .desc = "Honor set-user-ID and set-group-ID bits", - },{ - .option = "nosuid", - .desc = "Ignore set-user-ID and set-group-ID bits", - },{ - .option = "users", - .desc = "Allow arbitrary users to mount the filesystem", - }, -}; - -static struct form_option * -ops_table(int *count,const char *match,int *defidx,char ***selarray,int *selections, - const struct form_option *flags,unsigned fcount){ - struct form_option *fo = NULL; - int z = 0; - - *count = 0; - *defidx = -1; - if((*count = fcount) == 0){ - goto err; - } - if((fo = malloc(sizeof(*fo) * *count)) == NULL){ - goto err; - } - while(z < *count){ - const char *key = flags[z].option; - - if((fo[z].desc = strdup(flags[z].desc)) == NULL){ - goto err; - } - if((fo[z].option = strdup(key)) == NULL){ - free(fo[z].desc); - goto err; - } - if(match && strcmp(match,fo[z].option) == 0){ - int zz; - - *defidx = z; - for(zz = 0 ; selections && zz < *selections ; ++zz){ - if(strcmp(key,(*selarray)[zz]) == 0){ - free((*selarray)[zz]); - (*selarray)[zz] = NULL; - if(zz < *selections - 1){ - memmove(&(*selarray)[zz],&(*selarray)[zz + 1],sizeof(**selarray) * (*selections - 1 - zz)); - } - --*selections; - zz = -1; - break; - } - } - if(zz >= *selections){ - typeof(*selarray) tmp; - - if((tmp = realloc(*selarray,sizeof(*selarray) * (*selections + 1))) == NULL){ - free(fo[zz].option); - free(fo[zz].desc); - goto err; - } - *selarray = tmp; - (*selarray)[*selections] = strdup(match); - ++*selections; - } - } - ++z; - } - *defidx = (*defidx + 1) % *count; - return fo; - -err: - while(z--){ - free(fo[z].option); - free(fo[z].desc); - } - free(fo); - return NULL; -} - -static char forming_targ[PATH_MAX + 1]; - -static void -mountop_callback(const char *op,char **selarray,int selections,int scrollidx){ - struct form_option *ops_agg; - int opcount,defidx; - blockobj *b; - - if(op == NULL){ - locked_diag("User cancelled target operation"); - return; - } - if(!growlight_target){ - locked_diag("No target is set"); - return; - } - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a filesystem to mount"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(strcmp(op,"") == 0){ - unsigned mntos = 0; - - while(selections--){ - mntos |= flag_for_mountop(selarray[selections]); - } - if(blockobj_unpartitionedp(b)){ - mmount(b->d,forming_targ,mntos,NULL); - redraw_adapter(current_adapter); - }else if(blockobj_emptyp(b)){ - locked_diag("%s is not a partition, aborting.\n",b->zone->p->name); - }else{ - mmount(b->zone->p,forming_targ,mntos,NULL); - redraw_adapter(current_adapter); - } - return; - } - ops_agg = NULL; - opcount = 0; - defidx = 1; - if((ops_agg = ops_table(&opcount,op,&defidx,&selarray,&selections, - common_fsops,sizeof(common_fsops) / sizeof(*common_fsops))) == NULL){ - // FIXME free - return; - } - raise_checkform("set mount options",mountop_callback,ops_agg, - opcount,defidx,selarray,selections,MOUNTOPS_TEXT,scrollidx); -} - -// ------------------------------------------------------------------------- -// - target mountpoint form, for mapping within the target -// ------------------------------------------------------------------------- -static void -targpoint_callback(const char *path){ - struct form_option *ops_agg; - int scrollidx = 0; - blockobj *b; - - if(path == NULL){ - locked_diag("User cancelled target operation"); - return; - } - if(!growlight_target){ - locked_diag("No target is set"); - return; - } - if((unsigned)snprintf(forming_targ,sizeof(forming_targ),"%s%s",growlight_target,path) >= sizeof(forming_targ)){ - locked_diag("Bad mountpoint: %s",path); - return; - } - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a filesystem to mount"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(blockobj_emptyp(b)){ - locked_diag("%s is not a partition, aborting.\n",b->zone->p->name); - return; - }else{ - int opcount = 0,defidx = 0; - ops_agg = NULL; - char **selarray = NULL; - int selections = 0; - - if((ops_agg = ops_table(&opcount,NULL,&defidx,&selarray,&selections, - common_fsops,sizeof(common_fsops) / sizeof(*common_fsops))) == NULL){ - // FIXME free - return; - } - raise_checkform("set mount options",mountop_callback,ops_agg, - opcount,defidx,selarray,selections,MOUNTOPS_TEXT,scrollidx); - return; - } - locked_diag("I'm confused. Aborting.\n"); -} - -// ------------------------------------------------------------------------- -// - filesystem type form, for new filesystem creation -// ------------------------------------------------------------------------- -static struct form_option * -fs_table(int *count,const char *match,int *defidx){ - struct form_option *fo = NULL,*tmp; - pttable_type *types; - int z; - - *defidx = -1; - if((types = get_fs_types(count)) == NULL){ - return NULL; - } - for(z = 0 ; z < *count ; ++z){ - char *key,*desc; - - if((key = strdup(types[z].name)) == NULL){ - goto err; - } - if(match){ - if(strcmp(key,match) == 0){ - *defidx = z; - } - }else{ - if(fstype_default_p(key)){ - *defidx = z; - } - } - if((desc = strdup(types[z].desc)) == NULL){ - free(key); - goto err; - } - if((tmp = realloc(fo,sizeof(*fo) * (*count + 1))) == NULL){ - free(key); - free(desc); - goto err; - } - fo = tmp; - fo[z].option = key; - fo[z].desc = desc; - } - return fo; - -err: - while(z--){ - free(fo[z].option); - free(fo[z].desc); - } - free(fo); - *count = 0; - return NULL; -} - -static char *pending_fstype; - -static void fs_callback(const char *); - -static void -destroy_fs_forms(void){ - free(pending_fstype); - pending_fstype = NULL; -} - -void kill_splash(struct panel_state *ps){ - if(splash == ps){ - splash = NULL; - } - hide_panel_locked(ps); - free(ps); - if(actform == NULL){ - setup_colors(); - }else{ - /*assert(top_panel(actform->p) != ERR); - if(actform->extext){ - assert(top_panel(actform->extext->p) != ERR); - }*/ - } -} - -static int -fs_do_internal(device *d,const char *fst,const char *name){ - struct panel_state *ps; - int r; - - if(!mkfs_safe_p(d)){ - return -1; - } - ps = show_splash(L"Creating filesystem..."); - r = make_filesystem(d,fst,name); - if(ps){ - kill_splash(ps); - } - return r; -} - -static void -fs_do(const char *name){ - blockobj *b = get_selected_blockobj(); - int r = -1; - - if(b == NULL){ - locked_diag("A block device must be selected"); - return; - } - if(!current_adapter || !(b = current_adapter->selected)){ - locked_diag("Lost selection while targeting"); - destroy_fs_forms(); - return; - } - if(selected_unloadedp()){ - locked_diag("%s is unloaded, aborting.\n",b->d->name); - }else if(selected_unpartitionedp()){ - r = fs_do_internal(b->d,pending_fstype,name); - }else if(selected_partitionp()){ - r = fs_do_internal(b->zone->p,pending_fstype,name); - }else if(selected_emptyp()){ - locked_diag("Cannot make filesystems in empty space"); - } - if(r == 0){ - locked_diag("Successfully created %s filesystem",pending_fstype); - } - redraw_adapter(current_adapter); - destroy_fs_forms(); -} - -static void -fs_named_callback(const char *name){ - if(name == NULL){ - struct form_option *ops_fs; - int opcount,defidx; - - if((ops_fs = fs_table(&opcount,pending_fstype,&defidx)) == NULL){ - destroy_fs_forms(); - return; - } - raise_form("select a filesystem type",fs_callback,ops_fs, - opcount,defidx,FSTYPE_TEXT); - return; - } - fs_do(name); -} - -static void -fs_callback(const char *fs){ - if(fs == NULL){ // user cancelled - locked_diag("Filesystem creation cancelled by the user"); - return; - } - free(pending_fstype); - pending_fstype = NULL; - if((pending_fstype = strdup(fs)) == NULL){ - destroy_fs_forms(); - return; - } - if(fstype_named_p(fs) == 0){ - fs_do(NULL); - return; - } - // FIXME come up with a good default - raise_str_form("enter filesystem name",fs_named_callback,NULL,FSNAME_TEXT); -} - -// ------------------------------------------------------------------------- -// -- end filesystem type form -// ------------------------------------------------------------------------- - -// A NULL return is only an error if *count is set to -1. If *count is set to -// 0, it simply means this partition table type doesn't have type tags. -static struct form_option * -ptype_table(const device *d,int *count,int match,int *defidx){ - struct form_option *fo = NULL,*tmp; - const char *pttable; - const ptype *pt; - - assert(d); - if(d->layout == LAYOUT_NONE){ - pttable = d->blkdev.pttable; - }else if(d->layout == LAYOUT_MDADM){ - pttable = d->mddev.pttable; - }else{ - locked_diag("Can't partition this type of device"); - return NULL; - } - *count = 0; - for(pt = ptypes ; pt->name ; ++pt){ - const size_t KEYSIZE = 5; // 4 hex digit code - char *key,*desc; - - if(!ptype_supported(pttable,pt)){ - continue; - } - if((key = malloc(KEYSIZE)) == NULL){ - goto err; - } - if((desc = strdup(pt->name)) == NULL){ - free(key); - goto err; - } - if(snprintf(key,KEYSIZE,"%04x",pt->code) >= (int)KEYSIZE){ - locked_diag("Couldn't convert key 0x%x",pt->code); - free(key); - free(desc); - goto err; - } - if((tmp = realloc(fo,sizeof(*fo) * (*count + 1))) == NULL){ - free(key); - free(desc); - goto err; - } - fo = tmp; - fo[*count].option = key; - fo[*count].desc = desc; - if(match == -1){ - if(ptype_default_p(pt->code)){ - *defidx = *count; - } - }else if(match == pt->code){ - *defidx = *count; - } - ++*count; - } - return fo; - -err: - while(*count--){ - free(fo[*count].option); - free(fo[*count].desc); - } - *count = -1; - free(fo); - return NULL; -} - -// ------------------------------------------------------------------------- -// - partition name form, for new partition creation -// ------------------------------------------------------------------------- -static void ptype_callback(const char *); -static void psectors_callback(const char *); - -static unsigned long pending_ptype; // set by partition type callback -static uintmax_t pending_fsect,pending_lsect; // set by partition spec callback -static char *pending_spec; // set by spec callback; heap-allocated - -// Call on exit from the new partition form path -static void -cleanup_new_partition(void){ - free(pending_spec); - pending_spec = NULL; - pending_fsect = pending_lsect = 0; - pending_ptype = 0; -} - -// Verify that the current selection is a place suitable for partition creation. -// Returns the selected blockobj, or NULL. -static blockobj * -partition_base_p(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition creation requires selection of a block device"); - return NULL; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return NULL; - } - if(selected_unpartitionedp()){ - locked_diag("Partition creation requires a partition table"); - return NULL; - } - if(b->zone->rep == REP_METADATA){ - locked_diag("Remove partition table on %s to reclaim metadata",b->d->name); - return NULL; - } - if(b->zone->p){ - locked_diag("Partition %s exists; remove it first",b->zone->p->name); - return NULL; - } - return b; -} - -static void -ptype_name_callback(const char *name){ - struct panel_state *sps; - const char *n; - wchar_t *wstr; - mbstate_t ps; - blockobj *b; - size_t wcs; - int r; - - if(name == NULL){ // go back to partition spec - raise_str_form("enter partition spec",psectors_callback, - pending_spec,PSPEC_TEXT); - return; - } - if((b = partition_base_p()) == NULL){ - return; - } - n = name; - memset(&ps,0,sizeof(ps)); - if((wcs = mbsrtowcs(NULL,&n,0,&ps)) == (size_t)-1){ - locked_diag("Couldn't interpret multibyte '%s'",name); - cleanup_new_partition(); - return; - } - if((wstr = malloc(sizeof(*wstr) * (wcs + 1))) == NULL){ - locked_diag("Couldn't allocate wide string"); - cleanup_new_partition(); - return; - } - n = name; - memset(&ps,0,sizeof(ps)); - if(mbsrtowcs(wstr,&n,wcs + 1,&ps) != wcs){ - locked_diag("Error converting multibyte '%s'",name); - cleanup_new_partition(); - return; - } - sps = show_splash(L"Creating partition..."); - // Cannot reference b further until we've had a callback - r = add_partition(b->d,wstr,pending_fsect,pending_lsect,pending_ptype); - if(sps){ - kill_splash(sps); - } - free(wstr); - cleanup_new_partition(); - if(!r){ - if(strcmp(name,"")){ - locked_diag("Created new partition %s on %s\n",name,b->d->name); - }else{ - locked_diag("Created new unnamed partition on %s\n",b->d->name); - } - } -} - -static int -lex_part_spec(const char *psects,zobj *z,size_t sectsize, - uintmax_t *fsect,uintmax_t *lsect){ - unsigned long long ull; - const char *col,*pct; - char *el; - - // If we have a percent, it must be the last character, and there may - // not be a colon present, and the value must be between 1 and 100, - // inclusive, and the value must be an integer. - if( (pct = strchr(psects,'%')) ){ - unsigned long ul; - - if(pct[1]){ - return -1; - } - if(pct - psects > 3){ - return -1; - } - if(pct == psects){ - return -1; - } - if((ul = strtoul(psects,&el,10)) > 100){ - return -1; - } - *fsect = z->fsector; - *lsect = ((z->lsector - z->fsector) * ul) / 100 + *fsect; - return 0; - }else if( (col = strchr(psects,':')) ){ - unsigned long long ull2; - - if(*psects == '-'){ // reject negative numbers - locked_diag("Not a number: %s",psects); - return -1; - } - if((ull = strtoull(psects,&el,0)) == ULLONG_MAX){ - locked_diag("Not a number: %s",psects); - return -1; - } - if(el != col){ - locked_diag("Invalid delimiter: %s",psects); - return -1; - } - ++el; - ++col; - if(*col == '-'){ // reject negative numbers - locked_diag("Not a number: %s",psects); - return -1; - } - if((ull2 = strtoull(col,&el,0)) == ULLONG_MAX){ - locked_diag("Not a number: %s",col); - return -1; - } - if(*el){ - locked_diag("Not a number: %s",col); - return -1; - } - *fsect = ull; - *lsect = ull2; - return 0; - } - while(isspace(*psects)){ - ++psects; - } - if(*psects == '-'){ // reject negative numbers - locked_diag("Not a number: %s",psects); - return -1; - } - if((ull = strtoull(psects,&el,0)) == ULLONG_MAX && errno == ERANGE){ - locked_diag("Not a number: %s",psects); - return -1; - } - if(el == psects){ - return -1; - } - if(*el){ - if(el[1]){ - return -1; - } - switch(*el){ - case 'E': case 'e': - ull *= 1024llu * 1024 * 1024 * 1024 * 1024 * 1024; break; - case 'P': case 'p': - ull *= 1024llu * 1024 * 1024 * 1024 * 1024; break; - case 'T': case 't': - ull *= 1024llu * 1024 * 1024 * 1024; break; - case 'G': case 'g': - ull *= 1024llu * 1024 * 1024; break; - case 'M': case 'm': - ull *= 1024llu * 1024; break; - case 'K': case 'k': - ull *= 1024llu; break; - default: - return -1; - } - } - if(ull % sectsize){ - locked_diag("%llu is not a multiple of %zu",ull,sectsize); - return -1; - } - ull /= sectsize; - if(ull > (z->lsector - z->fsector + 1)){ - locked_diag("There are only %ju sectors available\n",z->lsector - z->fsector); - return -1; - } - *fsect = z->fsector; - *lsect = z->fsector + ull - 1; - return 0; -} - -static void -psectors_callback(const char *psects){ - uintmax_t fsect,lsect; - struct panel_state *ps; - blockobj *b; - int r; - - if((b = partition_base_p()) == NULL){ - return; - } - if(psects == NULL){ // go back to partition type - struct form_option *ops_ptype; - int opcount,defidx; - - if((ops_ptype = ptype_table(b->d,&opcount,pending_ptype,&defidx)) == NULL){ - if(opcount == 0){ - raise_str_form("enter partition spec",psectors_callback, - pending_spec ? pending_spec : "100%",PSPEC_TEXT); - return; - } - cleanup_new_partition(); - return; - } - raise_form("select a partition type",ptype_callback,ops_ptype, - opcount,defidx,PARTTYPE_TEXT); - return; - } - pending_spec = strdup(psects); - if(lex_part_spec(psects,b->zone,b->d->logsec,&fsect,&lsect)){ - locked_diag("Not a valid partition spec: \"%s\"\n",psects); - raise_str_form("enter partition spec",psectors_callback, - psects,PSPEC_TEXT); - return; - } - if(partitions_named_p(b->d)){ - pending_spec = strdup(psects); - pending_fsect = fsect; - pending_lsect = lsect; - raise_str_form("enter partition name",ptype_name_callback, - NULL,PNAME_TEXT); - return; - } - ps = show_splash(L"Creating partition..."); - r = add_partition(b->d,NULL,fsect,lsect,pending_ptype); - if(ps){ - kill_splash(ps); - } - cleanup_new_partition(); - if(!r){ - locked_diag("Created new partition on %s\n",b->d->name); - } -} - -// ------------------------------------------------------------------------- -// - partition type form, for new partition creation -// ------------------------------------------------------------------------- -static void -ptype_callback(const char *pty){ - unsigned long pt; - char *pend; - - if(pty == NULL){ // user cancelled - locked_diag("Partition creation cancelled by the user"); - cleanup_new_partition(); - return; - } - if(((pt = strtoul(pty,&pend,16)) == ULONG_MAX && errno == ERANGE) || *pend){ - locked_diag("Bad partition type selection: %s",pty); - cleanup_new_partition(); - return; - } - pending_ptype = pt; - raise_str_form("enter partition spec",psectors_callback, - pending_spec ? pending_spec : "100%",PSPEC_TEXT); -} - -static void -new_partition(void){ - struct form_option *ops_ptype; - blockobj *b; - int opcount; - int defidx; - - if((b = partition_base_p()) == NULL){ - return; - } - if((ops_ptype = ptype_table(b->d,&opcount,-1,&defidx)) == NULL){ - if(opcount == 0){ - raise_str_form("enter partition spec",psectors_callback, - pending_spec ? pending_spec : "100%",PSPEC_TEXT); - return; - } - return; - } - raise_form("select a partition type",ptype_callback,ops_ptype,opcount, - defidx,PARTTYPE_TEXT); -} - -// ------------------------------------------------------------------------- -// -- end partition type form -// ------------------------------------------------------------------------- - -// ------------------------------------------------------------------------- -// - partition tabletype form, for new partition table creation -// ------------------------------------------------------------------------- -static inline int -partition_table_makeablep(const blockobj *b){ - if(!b){ - locked_diag("Lost selection while choosing table type"); - return 0; - } - if(blockobj_unloadedp(b)){ - locked_diag("Media is not loaded on %s",b->d->name); - return 0; - } - if(!selected_unpartitionedp()){ - locked_diag("Partition table exists on %s",b->d->name); - return 0; - } - if(b->d->layout != LAYOUT_NONE){ - locked_diag("Will not create partition table on %s",b->d->name); - return 0; - } - if(b->d->mnttype){ - locked_diag("Filesystem signature exists on %s",b->d->name); - return 0; - } - return 1; -} - -static void -pttype_callback(const char *pttype){ - blockobj *b; - - if(pttype == NULL){ // user cancelled - locked_diag("Partition table creation cancelled by the user"); - return; - } - if(!current_adapter){ - locked_diag("Lost selection while choosing table type"); - return; - } - b = current_adapter->selected; - if(!partition_table_makeablep(b)){ - return; - } - if(make_partition_table(b->d,pttype) == 0){ - locked_diag("Made %s table on %s",pttype,b->d->name); - } -} - -// ------------------------------------------------------------------------- -// -- end partition table type form -// ------------------------------------------------------------------------- -static int -confirm_operation(const char *op,void (*confirmcb)(const char *)){ - struct form_option *ops_confirm; - - if((ops_confirm = malloc(sizeof(*ops_confirm) * 2)) == NULL){ - return -1; - } - ops_confirm[0].option = strdup("abort"); - ops_confirm[0].desc = strdup("do not perform the operation"); - ops_confirm[1].option = strdup("do it"); - ops_confirm[1].desc = strdup(op); - // FIXME check values - raise_form("confirm operation",confirmcb,ops_confirm,2,0, - "Please confirm the request. You will not be able to undo this action."); - return 0; -} -// ------------------------------------------------------------------------- -// -- end form API -// ------------------------------------------------------------------------- - -static int -ncurses_cleanup(WINDOW **w){ - int ret = 0; - - if(*w){ - if(delwin(*w) != OK){ - ret = -1; - } - *w = NULL; - } - if(stdscr){ - if(delwin(stdscr) != OK){ - ret = -2; - } - stdscr = NULL; - } - if(endwin() != OK){ - ret = -3; - } - switch(ret){ - case -3: fprintf(stderr,"Couldn't end main window\n"); break; - case -2: fprintf(stderr,"Couldn't delete main window\n"); break; - case -1: fprintf(stderr,"Couldn't delete main pad\n"); break; - case 0: break; - default: fprintf(stderr,"Couldn't cleanup ncurses\n"); break; - } - return ret; -} - -static WINDOW * -ncurses_setup(void){ - const char *errstr = NULL; - WINDOW *w = NULL; - - if(initscr() == NULL){ - fprintf(stderr,"Couldn't initialize ncurses\n"); - return NULL; - } - w = stdscr; - if(cbreak() != OK){ - errstr = "Couldn't disable input buffering\n"; - goto err; - } - if(noecho() != OK){ - errstr = "Couldn't disable input echoing\n"; - goto err; - } - if(intrflush(stdscr,TRUE) != OK){ - errstr = "Couldn't set flush-on-interrupt\n"; - goto err; - } - leaveok(stdscr, TRUE); // just an optimization - if(scrollok(stdscr,FALSE) != OK){ - errstr = "Couldn't disable scrolling\n"; - goto err; - } - if(nonl() != OK){ - errstr = "Couldn't disable nl translation\n"; - goto err; - } - if(start_color() != OK){ - errstr = "Couldn't initialize ncurses color\n"; - goto err; - } - if(use_default_colors()){ - errstr = "Couldn't initialize ncurses colordefs\n"; - goto err; - } - ESCDELAY = 100; - keypad(stdscr,TRUE); - if(nodelay(stdscr,FALSE) != OK){ - errstr = "Couldn't set blocking input\n"; - goto err; - } - if(setup_colors() != OK){ - errstr = "Couldn't set up colors\n"; - goto err; - } - if(curs_set(0) == ERR){ - errstr = "Couldn't disable cursor\n"; - goto err; - } - locked_diag("by nick black "); - draw_main_window(w); - refresh(); - return w; - -err: - ncurses_cleanup(&w); - fprintf(stderr,"%s",errstr); - return NULL; -} - -// Caller needs set up: next, prev -static reelbox * -create_reelbox(adapterstate *as,int rows,int scrline,int cols){ - reelbox *ret; - int l; - - l = adapter_lines_bounded(as,rows); - if(l >= rows - scrline){ - l = rows - scrline - 1; - } - if( (ret = malloc(sizeof(*ret))) ){ - ret->win = newwin(l,PAD_COLS(cols),scrline,0); - assert(ret->win); - ret->panel = new_panel(ret->win); - assert(ret->panel); - ret->scrline = scrline; - ret->selected = NULL; - ret->selline = -1; - ret->as = as; - as->rb = ret; - } - return ret; -} - -static const controller * -get_current_adapter(void){ - if(current_adapter){ - return current_adapter->as->c; - } - return NULL; -} - -static int -select_adapter_dev(reelbox *rb,blockobj *bo,int delta){ - assert(bo != rb->selected); - if((rb->selected = bo) == NULL){ - rb->selline = -1; - }else{ - rb->selline += delta; - } - return redraw_adapter(rb); -} - -// Positive delta moves down, negative delta moves up, except for l2 == NULL -// where we always move to -1 (and delta is ignored). -static void -select_adapter_node(reelbox *rb,struct blockobj *bo,int delta){ - assert(bo != rb->selected); - if((rb->selected = bo) == NULL){ - rb->selline = -1; - }else{ - rb->selline += delta; - } - redraw_adapter(rb); -} - -static void -deselect_adapter_locked(void){ - reelbox *rb; - - if((rb = current_adapter) == NULL){ - return; - } - if(rb->selected == NULL){ - return; - } - select_adapter_node(rb,NULL,0); // calls redraw_adapter() -} - -// Move this adapter, possibly hiding it. Negative delta indicates movement -// up, positive delta moves down. rows and cols describe the containing window. -static void -move_adapter(reelbox *rb,int targ,int rows,int cols,int delta){ - const adapterstate *as; - int nlines,rr; - - as = rb->as; -// fprintf(stderr," moving %s (%d) from %d to %d (%d)\n", rb->as->c->name, -// adapter_lines_bounded(rb->as, rows), getbegy(rb->win), targ, delta); - assert(rb->as); - assert(rb->as->rb == rb); - werase(rb->win); - screen_update(); - if(adapter_wholly_visible_p(rows,rb)){ - move_panel(rb->panel,targ,0); - if(getmaxy(rb->win) != adapter_lines_bounded(as,rows)){ - wresize(rb->win,adapter_lines_bounded(as,rows),PAD_COLS(cols)); - if(panel_hidden(rb->panel)){ - show_panel(rb->panel); - } - } - redraw_adapter(rb); - return; - } - rr = getmaxy(rb->win); - if(delta > 0){ // moving down - if(targ >= rows - 1){ - hide_panel(rb->panel); - return; - } - nlines = rows - targ - 1; // sans-bottom partial - }else{ - if((rr + getbegy(rb->win)) <= -delta){ -// fprintf(stderr, "THE BIG HIDE #1 (%d / %d / %d)\n", rr, getbegy(rb->win), -delta); - hide_panel(rb->panel); - return; - } - if(targ < 0){ - nlines = rr + targ; - targ = 0; - }else{ - nlines = adapter_lines_bounded(as,rows - targ + 1); - } - } - if(nlines < 1){ -// fprintf(stderr, "THE BIG HIDE #2 (%d)\n", nlines); - hide_panel(rb->panel); - return; - }else if(nlines > rr){ - move_panel(rb->panel,targ,0); - wresize(rb->win,nlines,PAD_COLS(cols)); - }else if(nlines < rr){ - wresize(rb->win,nlines,PAD_COLS(cols)); - move_panel(rb->panel,targ,0); - }else{ - move_panel(rb->panel,targ,0); - } - redraw_adapter(rb); - show_panel(rb->panel); - return; -} - -static inline void -move_adapter_generic(reelbox *rb, int rows, int cols, int delta){ -// fprintf(stderr, " moved %s by %d to %d\n", -// rb->as->c->name, delta, rb->scrline); - move_adapter(rb,rb->scrline,rows,cols,delta); - /*fprintf(stderr, "-------------> CORRECTING SCRLINE: %d becomes %d (%d / %d?)\n", - rb->scrline, getbegy(rb->win), getmaxy(rb->win), getpary(rb->win)); - rb->scrline = getbegy(rb->win);*/ -} - -static void -free_reelbox(reelbox *rb){ - if(rb){ - assert(rb->as); - assert(rb->as->rb == rb); - - rb->as->rb = NULL; - delwin(rb->win); - del_panel(rb->panel); - free(rb); - } -} - -// An adapter (pusher) has had its bottom border moved up or down (positive or -// negative delta, respectively). Update the adapters below it on the screen -// (all those up until those actually displayed above it on the screen). Should -// be called before pusher->scrline has been updated. -static void -push_adapters_below(reelbox *pusher,int rows,int cols,int delta){ - reelbox *rb; - - if(delta <= 0){ - return; - } - //fprintf(stderr,"pushing down %d from %s@%d\n",delta,pusher ? pusher->as ? pusher->as->adapter->name : "destroyed" : "all", - // pusher ? pusher->scrline : 0); - rb = last_reelbox; - while(rb){ - if(rb == pusher){ - break; - } - rb->scrline += delta; - move_adapter_generic(rb,rows,cols,delta); - if(panel_hidden(rb->panel)){ - if((last_reelbox = rb->prev) == NULL){ - top_reelbox = NULL; - }else{ - last_reelbox->next = NULL; - } - free_reelbox(rb); - rb = last_reelbox; - }else{ - rb = rb->prev; - } - } - // Now, if our delta was negative, see if we pulled any down below us - // FIXME pull_adapters_down(); -} - -static void -detail_fs(WINDOW *hw,const device *d,int row){ - if(d->mnttype){ - char buf[BPREFIXSTRLEN + 1]; - - wattroff(hw,A_BOLD); - mvwprintw(hw,row,START_COL,BPREFIXFMT "%c ", - d->mntsize ? bprefix(d->mntsize,1,buf,1) : "", - d->mntsize ? 'B' : ' '); - wattron(hw,A_BOLD); - wprintw(hw,"%s%s",d->label ? "" : "unlabeled ",d->mnttype); - if(d->label){ - wattroff(hw,A_BOLD); - wprintw(hw," %lc%s%lc",L'“',d->label,L'”'); - wattron(hw,A_BOLD); - } - wprintw(hw,"%s",d->mnt.count ? " at " : ""); - wattroff(hw,A_BOLD); - wprintw(hw,"%s",d->mnt.count ? d->mnt.list[0] : ""); - wattron(hw,A_BOLD); - } -} - -// One must not call diag() from any function called by update_details(), or -// else you will get one of a deadlock or a stack overflow due to corecursion. -static int -update_details(WINDOW *hw){ - const controller *c = get_current_adapter(); - char buf[BPREFIXSTRLEN + 1]; - const char *pttype; - const blockobj *b; - const device *d; - int cols,rows,n; - - if(c == NULL){ - return 0; // FIXME hide thyself! - } - getmaxyx(hw,rows,cols); - if(cols < START_COL * 2){ - return 0; - } - if(rows == 0){ - return 0; - } - for(n = 1 ; n < rows - 1 ; ++n){ - mvwhline(hw,n,START_COL,' ',cols - 2); - } - wattrset(hw,SUBDISPLAY_ATTR); - mvwprintw(hw,1,START_COL,"%-*.*s",cols - 2,cols - 2,c->name); - if(rows == 1){ - return 0; - } - if(c->bus == BUS_VIRTUAL){ - mvwprintw(hw,2,START_COL,"%-*.*s",cols - 2,cols - 2,"No details available"); - }else{ - mvwprintw(hw,2,START_COL,"Firmware: "); - wattroff(hw,A_BOLD); - waddstr(hw,c->fwver ? c->fwver : "Unknown"); - wattron(hw,A_BOLD); - waddstr(hw," BIOS: "); - wattroff(hw,A_BOLD); - waddstr(hw,c->biosver ? c->biosver : "Unknown"); - wattron(hw,A_BOLD); - waddstr(hw," Load: "); - qprefix(c->demand,1,buf,1); - wattroff(hw,A_BOLD); - waddstr(hw,buf); - waddstr(hw,"bps"); - wattron(hw,A_BOLD); - } - if((b = current_adapter->selected) == NULL){ - return 0; - } - d = b->d; - if(d->layout == LAYOUT_NONE){ - const char *sn = d->blkdev.serial; - - mvwprintw(hw, 3, START_COL, "%s: ", d->name); - wattroff(hw, A_BOLD); - waddstr(hw, d->model ? d->model : "n/a"); - waddstr(hw, d->revision ? d->revision : ""); - wattron(hw, A_BOLD); - wprintw(hw, " (%sB) S/N: ", bprefix(d->size, 1, buf, 1)); - wattroff(hw, A_BOLD); - waddstr(hw, sn ? sn : "n/a"); - wattron(hw, A_BOLD); - if(getmaxx(hw) - getcurx(hw) > 13){ - wprintw(hw," WC%lc WRV%lc RO%lc", - d->blkdev.wcache ? L'+' : L'-', - d->blkdev.rwverify == RWVERIFY_SUPPORTED_ON ? L'+' : - d->blkdev.rwverify == RWVERIFY_SUPPORTED_OFF ? L'-' : L'x', - d->roflag ? L'+' : L'-'); - } - assert(d->physsec <= 4096); - mvwprintw(hw,4,START_COL,"Sectors: "); - wattroff(hw,A_BOLD); - wprintw(hw,"%ju ",d->size / (d->logsec ? d->logsec : 1)); - wattron(hw,A_BOLD); - wprintw(hw,"("); - wattroff(hw,A_BOLD); - wprintw(hw,"%uB ",d->logsec); - wattron(hw,A_BOLD); - wprintw(hw,"logical / "); - wattroff(hw,A_BOLD); - wprintw(hw,"%uB ",d->physsec); - wattron(hw,A_BOLD); - wprintw(hw,"physical) %s", - transport_str(d->blkdev.transport)); - if(transport_bw(d->blkdev.transport)){ - uintmax_t transbw = transport_bw(d->blkdev.transport); - wprintw(hw," ("); - wattroff(hw,A_BOLD); - // FIXME throws -Wformat-truncation on gcc9 - wprintw(hw, "%sbps", qprefix(transbw, 1, buf, 1)); - wattron(hw,A_BOLD); - wprintw(hw,")"); - } - }else{ - mvwprintw(hw,3,START_COL,"%s: %s %s (%s) RO%lc",d->name, - d->model ? d->model : "n/a", - d->revision ? d->revision : "n/a", - bprefix(d->size,1,buf,1), - d->roflag ? L'+' : L'-'); - if(d->layout == LAYOUT_MDADM){ - wprintw(hw," Stride: "); - wattroff(hw,A_BOLD); - if(d->mddev.stride == 0){ - waddstr(hw,"n/a"); - }else{ - wprintw(hw,"%sB",bprefix(d->mddev.stride,1,buf,1)); - } - wattron(hw,A_BOLD); - wprintw(hw," SWidth: "); - wattroff(hw,A_BOLD); - if(d->mddev.swidth == 0){ - waddstr(hw,"n/a"); - }else{ - wprintw(hw,"%u",d->mddev.swidth); - } - wattron(hw,A_BOLD); - } - assert(d->physsec <= 4096); - mvwprintw(hw,4,START_COL,"Sectors: "); - wattroff(hw,A_BOLD); - wprintw(hw,"%ju ",d->size / (d->logsec ? d->logsec : 1)); - wattron(hw,A_BOLD); - wprintw(hw,"("); - wattroff(hw,A_BOLD); - wprintw(hw,"%uB ",d->logsec); - wattron(hw,A_BOLD); - wprintw(hw,"logical / "); - wattroff(hw,A_BOLD); - wprintw(hw,"%uB ",d->physsec); - wattron(hw,A_BOLD); - wprintw(hw,"physical)"); - } - mvwprintw(hw,5,START_COL,"Partitioning: "); - wattroff(hw,A_BOLD); - pttype = (d->layout == LAYOUT_NONE ? d->blkdev.pttable ? d->blkdev.pttable : "none" : - d->layout == LAYOUT_MDADM ? d->mddev.pttable ? d->mddev.pttable : "none" : - d->layout == LAYOUT_DM ? d->dmdev.pttable ? d->dmdev.pttable : "none" : - "n/a"); - wprintw(hw,"%s",pttype); - wattron(hw,A_BOLD); - waddstr(hw," I/O scheduler: "); - wattroff(hw,A_BOLD); - waddstr(hw,d->sched ? d->sched : "custom"); - wattron(hw,A_BOLD); - if(blockobj_unloadedp(b)){ - mvwprintw(hw,6,START_COL,"Media is not loaded"); - return 0; - } - if(blockobj_unpartitionedp(b)){ - char ubuf[BPREFIXSTRLEN + 1]; - - wattroff(hw,A_BOLD); - mvwprintw(hw,6,START_COL,BPREFIXFMT "B ", - bprefix(d->size,1,ubuf,1)); - wattron(hw,A_BOLD); - wprintw(hw,"%s","unpartitioned media"); - detail_fs(hw,b->d,7); - return 0; - } - if(b->zone){ - char align[BPREFIXSTRLEN + 1]; - char zbuf[BPREFIXSTRLEN + 1]; - - if(b->zone->p){ - assert(b->zone->p->layout == LAYOUT_PARTITION); - bprefix(b->zone->p->partdev.alignment, 1, align, 1); - // FIXME limit length! - wattroff(hw,A_BOLD); - mvwprintw(hw,6,START_COL,BPREFIXFMT "B ", - bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1),1,zbuf,1)); - wattron(hw,A_BOLD); - wprintw(hw,"P%lc%lc ",subscript((b->zone->p->partdev.pnumber % 100 / 10)), - subscript((b->zone->p->partdev.pnumber % 10))); - wattroff(hw,A_BOLD); - wprintw(hw,"%ju",b->zone->fsector); - wattron(hw,A_BOLD); - wprintw(hw,"→"); - wattroff(hw,A_BOLD); - wprintw(hw,"%ju ",b->zone->lsector); - wattron(hw,A_BOLD); - waddstr(hw,b->zone->p->name); - wattroff(hw,A_BOLD); - if(b->zone->p->partdev.pname){ - wprintw(hw," “%ls” ",b->zone->p->partdev.pname); - }else{ - wprintw(hw," (%s) ","unnamed"); - } - wattron(hw,A_BOLD); - if(getcurx(hw) <= cols - 2 - 4){ - wprintw(hw,"%04x", get_code_specific(pttype, b->zone->p->partdev.ptype)); - } - if(getcurx(hw) <= cols - 2 - 11){ - wprintw(hw, " %sB align", align); - } - detail_fs(hw,b->zone->p,7); - }else{ - // FIXME print alignment for unpartitioned space as well, - // but not until we implement zones in core (bug 252) - // or we'll need recreate alignment() etc here - wattroff(hw,A_BOLD); - mvwprintw(hw,6,START_COL,BPREFIXFMT "B ", - bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1),1,zbuf,1)); - wattron(hw,A_BOLD); - wattroff(hw,A_BOLD); - wprintw(hw,"%ju",b->zone->fsector); - wattron(hw,A_BOLD); - wprintw(hw,"→"); - wattroff(hw,A_BOLD); - wprintw(hw,"%ju ",b->zone->lsector); - wattron(hw,A_BOLD); - wprintw(hw,"%s ",b->zone->rep == REP_METADATA ? - "partition table metadata" : "unpartitioned space"); - } - } - return 0; -} - -// When this text is being displayed, the help window is the active window. -// Thus we refer to other window commands as "viewing", while 'H' here is -// described as "toggling". When other windows come up, they list their -// own command as "toggling." We want to avoid having to scroll the help -// synopsis, so keep it under 22 lines (25 lines on an ANSI standard terminal, -// minus two for the top/bottom screen border, minus one for mandatory -// window top padding). -static const wchar_t *helps[] = { - L"'q': quit ctrl+'L': redraw the screen", - L"'e': view environment details 'H': toggle this help display", - L"'v': view selection details 'D': view recent diagnostics", - L"'E': view mounts / targets 'z': modify aggregate", - L"'A': create aggregate 'Z': destroy aggregate", - L"'-': collapse adapter '+': expand adapter", - L"'k'/'↑': navigate up 'j'/'↓': navigate down", - L"'⇞PageUp': previous adapter ⇟PageDown': next adapter", - L"'/': search 'p': configure loop device", - NULL -}; - -static const wchar_t *helps_block[] = { - L"'h'/'←': navigate left 'l'/'→': navigate right", - L"'m': make partition table 'r': remove partition table", - L"'W': wipe master boot record 'B': bad blocks check", - L"'n': new partition 'd': delete partition", - L"'s': set partition attributes 'M': make filesystem/swap", - L"'F': fsck filesystem 'w': wipe filesystem", - L"'U': set filesystem UUID 'L': set filesystem label/name", - L"'o': mount filesystem/swapon 'O': unmount filesystem/swapoff", - NULL -}; - -static const wchar_t *helps_target[] = { - L"'t': mount target 'T': unmount target", - L"'i': enter target mode 'I': leave target mode", - L"'*' finalize UEFI / '#' finalize BIOS / '@' finalize fstab", - NULL -}; - -static size_t -max_helpstr_len(const wchar_t **h){ - size_t max = 0; - - while(*h){ - if(wcslen(*h) > max){ - max = wcslen(*h); - } - ++h; - } - return max; -} - -static int -helpstrs(WINDOW *hw){ - const wchar_t *hs; - int z,rows,cols; - int row = 1; - - rows = getmaxy(hw); - cols = getmaxx(hw); - wattrset(hw,SUBDISPLAY_ATTR); - for(z = 0 ; (hs = helps[z]) && z < rows ; ++z){ - mvwhline(hw,row + z,START_COL,' ',cols - 2); - mvwaddwstr(hw,row + z,START_COL,hs); - } - row += z; - if(!current_adapter || !current_adapter->selected){ - wattrset(hw,SUBDISPLAY_INVAL_ATTR); - }else{ - wattrset(hw,SUBDISPLAY_ATTR); - } - for(z = 0 ; (hs = helps_block[z]) && z < rows ; ++z){ - mvwhline(hw,row + z,START_COL,' ',cols - 2); - mvwaddwstr(hw,row + z,START_COL,hs); - } - row += z; - if(!target_mode_p()){ - wattrset(hw,SUBDISPLAY_INVAL_ATTR); - }else{ - wattrset(hw,SUBDISPLAY_ATTR); - } - for(z = 0 ; (hs = helps_target[z]) && z < rows ; ++z){ - mvwhline(hw,row + z,START_COL,' ',cols - 2); - mvwaddwstr(hw,row + z,START_COL,hs); - } - return OK; -} - -static inline void -lock_ncurses(void){ - lock_growlight(); - pthread_mutex_lock(&bfl); -} - -static inline void -unlock_ncurses(void){ - update_details_cond(details.p); - update_help_cond(help.p); - update_map_cond(maps.p); - screen_update(); - pthread_mutex_unlock(&bfl); - unlock_growlight(); -} - -// Used in growlight callbacks, since the growlight lock will already be held -// in any such case. -static inline void -lock_ncurses_growlight(void){ - pthread_mutex_lock(&bfl); -} - -static inline void -unlock_ncurses_growlight(void){ - update_details_cond(details.p); - update_help_cond(help.p); - update_map_cond(maps.p); - screen_update(); - pthread_mutex_unlock(&bfl); -} - -static void pull_adapters_down(reelbox *,int,int,int); - -// Pass a NULL puller to move all adapters up -static void -pull_adapters_up(reelbox *puller,int rows,int cols,int delta){ - reelbox *rb; - - if(delta <= 0){ - return; - } - rb = puller ? puller->next : top_reelbox; - while(rb){ - rb->scrline -= delta; - move_adapter_generic(rb,rows,cols,-delta); - if(panel_hidden(rb->panel)){ - if((top_reelbox = rb->next) == NULL){ - last_reelbox = NULL; - }else{ - top_reelbox->prev = NULL; - } - free_reelbox(rb); - rb = top_reelbox; - }else{ - rb = rb->next; - } - } - while(last_reelbox){ - struct adapterstate *i; - int scrline; - - if((scrline = last_reelbox->scrline + getmaxy(last_reelbox->win)) >= rows - 2){ - return; - } - i = last_reelbox->as->next; - if(i->rb){ - return; // next adapter is already visible - } - if((rb = create_reelbox(i,rows,scrline + 1,cols)) == NULL){ - return; - } - rb->prev = last_reelbox; - last_reelbox->next = rb; - rb->next = NULL; - last_reelbox = rb; - redraw_adapter(rb); - } -} - - -static inline int -gap_above(reelbox *rb){ - if(!rb->prev){ - return 0; - } - return getbegy(rb->win) - (getmaxy(rb->prev->win) + getbegy(rb->prev->win)) - 1; -} - -static inline int -gap_below(reelbox *rb){ - if(!rb->next){ - return 0; - } - return getbegy(rb->next->win) - (getmaxy(rb->win) + getbegy(rb->win)) - 1; -} - -// An adapter (pusher) has had its top border moved up or down (positive or -// negative delta, respectively). Update the adapters above it on the screen -// (all those up until those actually displayed below it on the screen). -// -// If an adapter is being brought onto the bottom of the screen, ensure that -// last_reelbox has been updated to point to it, and top_reelbox has been -// updated if the adapter came from the top of the screen. Any other updates -// to reelboxes will be made by this function. Otherwise.... -// -// Update before: pusher->scrline, current_adapter -// Updated after: reelbox pointers, affected scrlines. -// -static void -push_adapters_above(reelbox *pusher,int rows,int cols,int delta){ - reelbox *rb; - - if(delta >= 0){ - return; - } - //fprintf(stderr,"pushing up %d from %s@%d\n",delta,pusher ? pusher->as ? pusher->as->adapter->name : "destroyed" : "all", - // pusher ? pusher->scrline : rows); - rb = top_reelbox; - while(rb){ - if(rb == pusher){ - break; - } - rb->scrline += delta; - move_adapter_generic(rb,rows,cols,delta); - if(panel_hidden(rb->panel)){ - if((top_reelbox = rb->next) == NULL){ - last_reelbox = NULL; - }else{ - top_reelbox->prev = NULL; - } - free_reelbox(rb); - rb = top_reelbox; - }else{ - rb = rb->next; - } - } - // Now, if our delta was negative, see if we pulled any down below us - // FIXME pull_adapters_up(pusher,rows,cols,delta); -} - -// Upon entry, the display might not have been updated to reflect a change in -// the adapter's data. If so, the adapter panel is resized (subject to the -// containing window's constraints) and other panels are moved as necessary. -// The adapter's display is synchronized via redraw_adapter() whether a resize -// is performed or not (unless it's invisible). The display ought be partially -// visible -- ie, if we ought be invisible, we ought be already and this is not -// going to make us so. We do not redraw -- that's the callers job (we -// can't redraw, since we might not yet have been moved). -static int -resize_adapter(reelbox *rb){ - const controller *i,*curi = get_current_adapter(); - int rows,cols,subrows; - adapterstate *is; - - i = rb->as->c; - if(panel_hidden(rb->panel)){ // resize upon becoming visible - return OK; - } - is = rb->as; - getmaxyx(stdscr,rows,cols); - const int nlines = adapter_lines_bounded(is,rows); - subrows = getmaxy(rb->win); - if(nlines < subrows){ // Shrink the adapter - werase(rb->win); - // Without screen_update(), the werase() doesn't take effect, - // even if wclear() is used. - screen_update(); - wresize(rb->win,nlines,PAD_COLS(cols)); - replace_panel(rb->panel,rb->win); - if(rb->scrline < current_adapter->scrline){ - rb->scrline += subrows - nlines; - move_panel(rb->panel,rb->scrline,0); - pull_adapters_down(rb,rows,cols,subrows - nlines); - }else{ - pull_adapters_up(rb,rows,cols,subrows - nlines); - } - return OK; - }else if(nlines == subrows){ // otherwise, expansion - return OK; - } - // The current adapter grows in both directions and never becomes a - // partial adapter. We don't try to make it one here, and - // move_adapter() will refuse to perform a move resulting in one. - if(i == curi){ - // We can't already occupy the screen, or the nlines == subrows - // check would have thrown us out. There *is* space to grow. - if(rb->scrline + subrows < rows - 1){ // can we grow down? - int delta = (rows - 1) - (rb->scrline + subrows); - - if(delta + subrows > nlines){ - delta = nlines - subrows; - } - push_adapters_below(rb,rows,cols,delta); - subrows += delta; - } - if(nlines > subrows){ // can we grow up? - int delta; - - if(rb->scrline - 1 + subrows > nlines){ - delta = subrows - nlines; - }else{ - delta = -1; - } - rb->scrline += delta; - push_adapters_above(rb,rows,cols,delta); - move_panel(rb->panel,rb->scrline,0); - } - wresize(rb->win,nlines,PAD_COLS(cols)); - replace_panel(rb->panel,rb->win); - }else{ // we're not the current adapter - int delta; - - if( (delta = bottom_space_p(rows)) ){ // always occupy free rows - if(delta > nlines - subrows){ - delta = nlines - subrows; - } - delta -= gap_below(rb); // FIXME questionable - push_adapters_below(rb,rows,cols,delta); - subrows += delta; - } - if(nlines > subrows){ - if(rb->scrline > current_adapter->scrline){ // only down - delta = (rows - 1) - (rb->scrline + subrows); - if(delta > nlines - subrows){ - delta = nlines - subrows; - } - delta -= gap_below(rb); - if(delta > 0){ - push_adapters_below(rb,rows,cols,delta); - } - }else{ // only up - delta = rb->scrline - 1; - if(delta > nlines - subrows){ - delta = nlines - subrows; - } - delta -= gap_above(rb); - if(delta > 0){ - push_adapters_above(rb,rows,cols,-delta); - rb->scrline -= delta; - move_adapter_generic(rb,rows,cols,-delta); - } - } - if(delta > 0){ - subrows += delta; - } - if(nlines > subrows){ - if( (delta = gap_below(rb)) ){ - subrows += delta > (nlines - subrows) ? - nlines - subrows : delta; - } - } - if(nlines > subrows){ - if( (delta = gap_above(rb)) ){ - subrows += delta > (nlines - subrows) ? - nlines - subrows : delta; - } - } - } - if(subrows != getmaxy(rb->win)){ - if(subrows > 0){ - wresize(rb->win,subrows,PAD_COLS(cols)); - replace_panel(rb->panel,rb->win); - }else{ -// fprintf(stderr, "THE BIGGEST HIDE (%d, %d)\n", subrows, getmaxy(rb->win)); - werase(rb->win); - hide_panel(rb->panel); - if(rb->next){ - rb->next->prev = rb->prev; - }else{ - last_reelbox = rb->prev; - } - if(rb->prev){ - rb->prev->next = rb->next; - }else{ - top_reelbox = rb->next; - } - // need NULL out adapter reference FIXME - } - } - } - return OK; -} - -// Pull the adapters above the puller down to fill unused space. Move from -// the puller out, as we might need make visible some unknown number of -// adapters (and the space has already been made). -// -// If the puller is being removed, it ought already have been spliced out of -// the reelbox list, and all reelbox state updated, but it obviously must not -// yet have been freed. Its ->as pointer must still be valid (though -// ->as->adapter is no longer valid). Its ->next and ->prev pointers ought not -// have been altered. -static void -pull_adapters_down(reelbox *puller,int rows,int cols,int delta){ - reelbox *rb; - - if(delta <= 0){ - return; - } - rb = puller ? puller->prev : last_reelbox; - while(rb){ - int before = getmaxy(rb->win); - - if(adapter_lines_bounded(rb->as,rows) > before){ - assert(rb == top_reelbox); - resize_adapter(rb); - if((delta -= (getmaxy(rb->win) - before)) == 0){ - return; - } - } - rb->scrline += delta; - move_adapter_generic(rb,rows,cols,delta); - if(panel_hidden(rb->panel)){ - if((last_reelbox = rb->prev) == NULL){ - top_reelbox = NULL; - }else{ - last_reelbox->next = NULL; - } - free_reelbox(rb); - rb = last_reelbox; - }else{ - rb = rb->prev; - } - } - while(top_reelbox){ - struct adapterstate *i; - int maxl,newl; - - if(top_reelbox->scrline <= 2){ - return; - } - i = top_reelbox->as->prev; - if(i->rb){ - return; // already visible - } - newl = adapter_lines_bounded(i,top_reelbox->scrline); - maxl = top_reelbox->scrline; - if((rb = create_reelbox(i,maxl,top_reelbox->scrline - 1 - newl,cols)) == NULL){ - return; - } - rb->next = top_reelbox; - top_reelbox->prev = rb; - rb->prev = NULL; - top_reelbox = rb; - redraw_adapter(rb); - } -} - -static inline int -top_space_p(int rows){ - if(!top_reelbox){ - return rows - 2; - } - return getbegy(top_reelbox->win) - 1; -} - -// Selecting the previous or next adapter (this doesn't apply to an arbitrary -// repositioning): There are two phases to be considered. -// -// 1. There's not enough data to fill the screen. In this case, none will lose -// or gain visibility, but they might be rotated. -// 2. There's a screen's worth, but not much more than that. An adapter might -// be split across the top/bottom boundaries. adapters can be caused to -// lose or gain visibility. -static void -use_next_controller(WINDOW *w){ - int rows,cols,delta; - reelbox *oldrb; - reelbox *rb; - - if(!current_adapter || current_adapter->as->next == current_adapter->as){ - return; - } -// fprintf(stderr,"\nWant next adapter (%s->%s)\n",current_adapter->as->c->name, -// current_adapter->as->next->c->name); - getmaxyx(w,rows,cols); - oldrb = current_adapter; - deselect_adapter_locked(); - // Don't redraw the old interface yet; it might have been moved/hidden - if(current_adapter->next == NULL){ - adapterstate *is = current_adapter->as->next; - - if(is->rb == NULL){ // it's off-screen - is->rb = create_reelbox(is,rows,(rows - 1) - adapter_lines_bounded(is,rows),cols); - assert(is->rb); - current_adapter = is->rb; - delta = -adapter_lines_bounded(is,rows); - if(getbegy(last_reelbox->win) + getmaxy(last_reelbox->win) >= rows - 1){ - --delta; - } - push_adapters_above(NULL,rows,cols,delta); - if((current_adapter->prev = last_reelbox) == NULL){ - top_reelbox = current_adapter; - }else{ - last_reelbox->next = current_adapter; - } - current_adapter->next = NULL; - last_reelbox = current_adapter; - if( (delta = top_space_p(rows)) ){ - pull_adapters_up(NULL,rows,cols,delta); - } - redraw_adapter(is->rb); - return; - } - current_adapter = is->rb; // it's at the top - }else{ - current_adapter = current_adapter->next; // it's below us - } - rb = current_adapter; - // If the newly-selected adapter is wholly visible, we'll not need - // change visibility of any adapters. If it's above us, we'll need - // rotate the adapters 1 unit, moving all. Otherwise, none change - // position. Redraw all affected adapters. - if(adapter_wholly_visible_p(rows, rb)){ -// fprintf(stderr, "[%s] is VISIBLE\n", rb->as->c->name); // current_adapter - if(rb->scrline > oldrb->scrline){ // new is below old - redraw_adapter(oldrb); - redraw_adapter(rb); - }else{ // we were at the bottom (rotate) - if(top_reelbox->next){ - top_reelbox->next->prev = NULL; - top_reelbox = top_reelbox->next; - }else{ - top_reelbox = last_reelbox; - } - push_adapters_above(rb,rows,cols,-getmaxy(rb->win) - 1); - if(last_reelbox){ - rb->scrline = last_reelbox->scrline + getmaxy(last_reelbox->win) + 1; - }else{ - rb->scrline = 0; - } - rb->prev = last_reelbox; - last_reelbox->next = rb; - rb->next = NULL; - last_reelbox = rb; - move_adapter_generic(rb,rows,cols,rb->scrline - getbegy(rb->win)); - } - }else{ // new is partially visible... - if(rb->scrline > oldrb->scrline){ // ...at the bottom -// fprintf(stderr, "rb->as->c->name [%s] is PART-VISIBLE-BOTTOM\n", -// rb->as->c->name); // current_adapter - adapterstate *is = current_adapter->as; - delta = getmaxy(rb->win) - adapter_lines_bounded(is,rows); - rb->scrline = rows - (adapter_lines_bounded(is,rows) + 1); - push_adapters_above(rb,rows,cols,delta); - move_adapter_generic(rb,rows,cols,getbegy(rb->win) - rb->scrline); - wresize(rb->win,adapter_lines_bounded(rb->as,rows),PAD_COLS(cols)); - replace_panel(rb->panel,rb->win); - redraw_adapter(rb); - }else{ // ...at the top (rotate) -// fprintf(stderr, "rb->as->c->name [%s] is PART-VISIBLE-TOP\n", -// rb->as->c->name); // current_adapter - assert(top_reelbox == rb); - rb->scrline = rows - 1 - adapter_lines_bounded(rb->as,rows); - top_reelbox->next->prev = NULL; - top_reelbox = top_reelbox->next; - delta = -adapter_lines_bounded(rb->as,rows); - if(getbegy(last_reelbox->win) + getmaxy(last_reelbox->win) >= (rows - 1)){ - --delta; - } - push_adapters_above(NULL,rows,cols,delta); - rb->next = NULL; - if( (rb->prev = last_reelbox) ){ - last_reelbox->next = rb; - }else{ - top_reelbox = rb; - } - last_reelbox = rb; - move_adapter_generic(rb,rows,cols,rb->scrline); - wresize(rb->win,adapter_lines_bounded(rb->as,rows),PAD_COLS(cols)); - replace_panel(rb->panel,rb->win); - redraw_adapter(rb); - } - } - if( (delta = top_space_p(rows)) ){ - pull_adapters_up(NULL,rows,cols,delta); - } -} - -static void -use_prev_zone(blockobj *b){ - if(b->zone){ - b->zone = b->zone->prev; - } -} - -static void -use_next_zone(blockobj *b){ - if(b->zone){ - b->zone = b->zone->next; - } -} - -static void -use_prev_controller(WINDOW *w){ - reelbox *oldrb,*rb; - int rows,cols; - - if(!current_adapter || current_adapter->as->next == current_adapter->as){ - return; - } - getmaxyx(w,rows,cols); - oldrb = current_adapter; - deselect_adapter_locked(); - // Don't redraw the old adapter yet; it might have been moved/hidden - if(current_adapter->prev){ - current_adapter = current_adapter->prev; - }else{ - adapterstate *as = current_adapter->as->prev; - - if(as->rb){ - current_adapter = as->rb; - }else{ - as->rb = create_reelbox(as,rows,0,cols); - assert(as); - current_adapter = as->rb; - push_adapters_below(NULL,rows,cols,adapter_lines_bounded(as,rows) + 1); - if((current_adapter->next = top_reelbox) == NULL){ - last_reelbox = current_adapter; - }else{ - top_reelbox->prev = current_adapter; - } - current_adapter->prev = NULL; - top_reelbox = current_adapter; - redraw_adapter(current_adapter); - return; - } - } - rb = current_adapter; - // If the newly-selected adapter is wholly visible, we'll not need - // change visibility of any adapters. If it's below us, we'll need - // rotate the adapters 1 unit, moving all. Otherwise, none need change - // position. Redraw all affected adapters. - if(adapter_wholly_visible_p(rows,rb)){ - if(rb->scrline < oldrb->scrline){ // new is above old - redraw_adapter(oldrb); - redraw_adapter(rb); - }else{ // we were at the top - // Selecting the previous adapter is simpler -- we - // take one from the bottom, and stick it in row 1. - if(last_reelbox->prev){ - last_reelbox->prev->next = NULL; - last_reelbox = last_reelbox->prev; - }else{ - last_reelbox = top_reelbox; - } - pull_adapters_down(rb,rows,cols,getmaxy(rb->win) + 1); - rb->scrline = 0; - rb->next = top_reelbox; - top_reelbox->prev = rb; - rb->prev = NULL; - top_reelbox = rb; - move_adapter_generic(rb,rows,cols,getbegy(rb->win) - rb->scrline); - } - }else{ // partially visible... - adapterstate *is = current_adapter->as; - - if(rb->scrline < oldrb->scrline){ // ... at the top - rb->scrline = 0; - push_adapters_below(rb,rows,cols,-(getmaxy(rb->win) - adapter_lines_bounded(is,rows))); - wresize(rb->win,adapter_lines_bounded(rb->as,rows),PAD_COLS(cols)); - replace_panel(rb->panel,rb->win); - redraw_adapter(rb); - }else{ // at the bottom - if(last_reelbox->prev){ - last_reelbox->prev->next = NULL; - last_reelbox = last_reelbox->prev; - }else{ - last_reelbox = top_reelbox; - } - push_adapters_below(NULL,rows,cols,adapter_lines_bounded(is,rows) + 1); - rb->scrline = 0; - if( (rb->next = top_reelbox) ){ - top_reelbox->prev = rb; - }else{ - last_reelbox = rb; - } - rb->prev = NULL; - top_reelbox = rb; - move_adapter_generic(rb,rows,cols,getbegy(rb->win) - rb->scrline); - wresize(rb->win,adapter_lines_bounded(rb->as,rows),PAD_COLS(cols)); - replace_panel(rb->panel,rb->win); - redraw_adapter(rb); - } - } -} - -static void -use_prev_device(void){ - reelbox *rb; - int delta; - - if((rb = current_adapter) == NULL){ - return; - } - if(rb->selected == NULL || rb->selected->prev == NULL){ - if(rb->prev){ - locked_diag("Press PageUp to go to the previous adapter"); - } - return; - } - delta = -device_lines(rb->as->expansion,rb->selected->prev); - if(rb->selline + delta <= 1){ // FIXME verify - delta = 1 - rb->selline; - } - select_adapter_dev(rb,rb->selected->prev,delta); -} - -static void -use_next_device(void){ - reelbox *rb; - int delta; - - if((rb = current_adapter) == NULL){ - return; - } - if(rb->selected == NULL || rb->selected->next == NULL){ - if(rb->next){ - locked_diag("Press PageDown to go to the next adapter"); - } - return; - } - delta = device_lines(rb->as->expansion,rb->selected); - if(rb->selline + delta + device_lines(rb->as->expansion,rb->selected->next) >= getmaxy(rb->win) - 1){ - delta = (getmaxy(rb->win) - 1 - device_lines(rb->as->expansion,rb->selected->next)) - - rb->selline; - } - select_adapter_dev(rb,rb->selected->next,delta); -} - -static const int DIAGROWS = 14; - -// Used after shutting down on error, which will clean the screen. This takes -// the last few diagnostics and prints them, unmutilated, to stderr. -static int -dump_diags(void){ - logent l[10]; - int y, r; - - y = sizeof(l) / sizeof(*l); - if((y = get_logs(y, l)) < 0){ - return -1; - } - for(r = 0 ; r < y ; ++r){ - char tbuf[27]; - - if(l[r].msg == NULL){ - break; - } - ctime_r(&l[r].when, tbuf); - fprintf(stderr, "%s %s", tbuf, l[r].msg); - free(l[r].msg); - } - return 0; -} - -static int -update_diags(struct panel_state *ps){ - WINDOW *w = panel_window(ps->p); - logent l[DIAGROWS]; - int y,x,r; - - getmaxyx(w,y,x); - y = getmaxy(w) - 2; - assert(x > 26 + START_COL * 2); // see ctime_r(3) - if((y = get_logs(y,l)) < 0){ - return -1; - } - wattrset(w,SUBDISPLAY_ATTR); - for(r = 0 ; r < y ; ++r){ - char *c,tbuf[x]; - struct tm tm; - size_t tb; - int p; - - if(l[r].msg == NULL){ - break; - } - if(localtime_r(&l[r].when,&tm) == NULL){ - break; - } - if(strftime(tbuf,sizeof(tbuf),"%F %T",&tm) == 0){ - break;; - } - tb = sizeof(tbuf) / sizeof(*tbuf) - strlen(tbuf); - p = snprintf(tbuf + strlen(tbuf),tb," %-*.*s", - (int)tb - 2,(int)tb - 2,l[r].msg); - if(p < 0 || (unsigned)p >= tb){ - tbuf[sizeof(tbuf) / sizeof(*tbuf) - 1] = '\0'; - } - if( (c = strchr(tbuf,'\n')) ){ - *c = '\0'; - } - c = tbuf; - while((c = strchr(tbuf,'\b')) || (c = strchr(tbuf,'\t'))){ - *c = ' '; - } - mvwprintw(w,y - r,START_COL,"%-*.*s",x - 2,x - 2,tbuf); - free(l[r].msg); - } - return 0; -} - -static int -display_diags(WINDOW *mainw,struct panel_state *ps){ - memset(ps,0,sizeof(*ps)); - if(new_display_panel(mainw,ps,DIAGROWS,0,L"press 'D' to dismiss diagnostics" - ,NULL,PBORDER_COLOR)){ - goto err; - } - if(update_diags(ps)){ - goto err; - } - return OK; - -err: - if(ps->p){ - WINDOW *psw = panel_window(ps->p); - - hide_panel(ps->p); - del_panel(ps->p); - delwin(psw); - } - memset(ps,0,sizeof(*ps)); - return ERR; -} - -static const int DETAILROWS = 7; // FIXME make it dynamic based on selections - -static int -display_details(WINDOW *mainw,struct panel_state *ps){ - memset(ps,0,sizeof(*ps)); - if(new_display_panel(mainw,ps,DETAILROWS,78,L"press 'v' to dismiss details" - ,NULL,PBORDER_COLOR)){ - goto err; - } - if(current_adapter){ - if(update_details(panel_window(ps->p))){ - goto err; - } - } - return 0; - -err: - if(ps->p){ - WINDOW *psw = panel_window(ps->p); - - hide_panel(ps->p); - del_panel(ps->p); - delwin(psw); - } - memset(ps,0,sizeof(*ps)); - return ERR; -} - -static int -display_help(WINDOW *mainw,struct panel_state *ps){ - static const int helprows = sizeof(helps) / sizeof(*helps) - 1 + - sizeof(helps_block) / sizeof(*helps_block) - 1 + - sizeof(helps_target) / sizeof(*helps_target) - 1; // NULL != row - unsigned helpcols; - - helpcols = max_helpstr_len(helps); - if(max_helpstr_len(helps_target) > helpcols){ - helpcols = max_helpstr_len(helps_target); - } - if(max_helpstr_len(helps_block) > helpcols){ - helpcols = max_helpstr_len(helps_block); - } - helpcols += 2; // spacing + borders - memset(ps,0,sizeof(*ps)); - if(new_display_panel(mainw,ps,helprows,helpcols,L"press 'H' to dismiss help", - L"https://nick-black.com/dankwiki/index.php/Growlight", - PBORDER_COLOR)){ - goto err; - } - if(helpstrs(panel_window(ps->p))){ - goto err; - } - return OK; - -err: - if(ps->p){ - WINDOW *psw = panel_window(ps->p); - - hide_panel(ps->p); - del_panel(ps->p); - delwin(psw); - } - memset(ps,0,sizeof(*ps)); - return ERR; -} - -#define ENVROWS 10 -#define COLORSPERROW 32 - -static int -env_details(WINDOW *hw,int rows){ - const int col = START_COL; - const int row = 1; - int z,srows,scols,cols; - - wattrset(hw,SUBDISPLAY_ATTR); - getmaxyx(stdscr,srows,scols); - if((z = rows) >= ENVROWS){ - z = ENVROWS - 1; - } - cols = getmaxx(hw); - switch(z){ // Intentional fallthroughs all the way to 0 - case (ENVROWS - 1):{ - while(z > 1){ - int c0,c1; - - mvwhline(hw,row + z,1,' ',cols - 2); - c0 = (z - 2) * COLORSPERROW; - c1 = c0 + (COLORSPERROW - 1); - mvwprintw(hw,row + z,col,"0x%02x%lc0x%02x: ",c0,L'–',c1); - while(c0 <= c1){ - if(c0 < COLORS){ - wattrset(hw,COLOR_PAIR(c0)); - wprintw(hw,"X"); - }else{ - wattrset(hw,SUBDISPLAY_ATTR); - wprintw(hw," "); - } - ++c0; - } - --z; - wattrset(hw,SUBDISPLAY_ATTR); - } - } /* intentional fallthrough */ - case 1:{ - mvwhline(hw,row + z,1,' ',cols - 2); - mvwprintw(hw,row + z,col,"Colors (pairs): %u (%u) Geom: %dx%d Palette: %s", - COLORS,COLOR_PAIRS,srows,scols, - can_change_color() ? "dynamic" : "fixed"); - --z; - } /* intentional fallthrough */ - case 0:{ - const char *lang = getenv("LANG"); - const char *term = getenv("TERM"); - - mvwhline(hw,row + z,1,' ',cols - 2); - lang = lang ? lang : "Undefined"; - mvwprintw(hw,row + z,col,"LANG: %-21s TERM: %s ESCDELAY: %d",lang,term,ESCDELAY); - --z; - break; - }default:{ - return ERR; - } - } - return OK; -} - -static void -detail_mounts(WINDOW *w,int *row,int maxy,const device *d){ - char buf[PREFIXSTRLEN + 1],b[256]; - int cols = getmaxx(w),r; - unsigned z; - - assert(d->mnt.count == d->mntops.count); - for(z = 0 ; z < d->mnt.count ; ++z){ - if(*row == maxy){ - return; - } - if(growlight_target && !strncmp(d->mnt.list[z],growlight_target,strlen(growlight_target))){ - continue; - } - mvwhline(w,*row,START_COL,' ',cols - 2); - mvwprintw(w,*row,START_COL,"%-*.*s %-5.5s %-36.36s " PREFIXFMT " %-*.*s", - FSLABELSIZ,FSLABELSIZ,d->label ? d->label : "n/a", - d->mnttype, - d->uuid ? d->uuid : "n/a", - qprefix(d->mntsize,1,buf,0), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), - d->name); - if(++*row == maxy){ - return; - } - wattroff(w,A_BOLD); - if((r = snprintf(b,sizeof(b)," %s %s",d->mnt.list[z],d->mntops.list[z])) >= (int)sizeof(b)){ - b[sizeof(b) - 1] = '\0'; - } - mvwhline(w,*row,START_COL,' ',cols - 2); - mvwprintw(w,*row,START_COL,"%-*.*s",cols - 2,cols - 2,b); - wattron(w,A_BOLD); - ++*row; - } -} - -static void -detail_targets(WINDOW *w,int *row,int both,const device *d){ - char buf[PREFIXSTRLEN + 1],b[256]; // FIXME uhhhh - int cols = getmaxx(w),r; - unsigned z; - - if(growlight_target == NULL){ - return; - } - for(z = 0 ; z < d->mnt.count ; ++z){ - if(strncmp(d->mnt.list[z],growlight_target,strlen(growlight_target))){ - continue; - } - mvwhline(w,*row,START_COL,' ',cols - 2); - mvwprintw(w,*row,START_COL,"%-*.*s %-5.5s %-36.36s " PREFIXFMT " %-*.*s", - FSLABELSIZ,FSLABELSIZ,d->label ? d->label : "n/a", - d->mnttype, - d->uuid ? d->uuid : "n/a", - qprefix(d->mntsize,1,buf,0), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), - d->name); - ++*row; - if(!both){ - return; - } - wattroff(w,A_BOLD); - if((r = snprintf(b,sizeof(b)," %s %s",d->mnt.list[z],d->mntops.list[z])) >= (int)sizeof(b)){ - b[sizeof(b) - 1] = '\0'; - } - mvwhline(w,*row,START_COL,' ',cols - 2); - mvwprintw(w,*row,START_COL,"%-*.*s",cols - 2,cols - 2,b); - wattron(w,A_BOLD); - ++*row; - break; // FIXME no space currently - } -} - -static int -map_details(WINDOW *hw){ - const controller *c; - int y,rows,cols; - char *fstab; - - cols = getmaxx(hw); - rows = getmaxy(hw) - 1; - y = 1; - if(growlight_target){ - int blockout; - - wattrset(hw,A_BOLD|COLOR_PAIR(PHEADING_COLOR)); - mvwprintw(hw,y,1,"Operating in target mode (%s)",growlight_target); - if( (blockout = cols - getcurx(hw) - 1) ){ - wprintw(hw,"%*.*s",blockout,blockout,""); - } - ++y; - } - wattrset(hw,A_BOLD|COLOR_PAIR(FORMTEXT_COLOR)); - // First we list the target fstab, and then the targets - // FIXME this is probably multibyte input and needs be handled as such - if( (fstab = dump_targets()) ){ - unsigned pos,linestart; - - pos = 0; - linestart = 0; - while(fstab[pos]){ - if(fstab[pos] == '\n'){ - fstab[pos] = '\0'; - if(pos != linestart){ - mvwprintw(hw,y,1,"%-*.*s",cols - 2,cols - 2,fstab + linestart); - if(++y >= rows){ - return 0; - } - } - linestart = pos + 1; - }else if(fstab[pos] == '\t'){ - fstab[pos] = ' '; - } - ++pos; - } - if(pos != linestart){ - mvwprintw(hw,y,1,"%-*.*s",cols - 2,cols - 2,fstab + linestart); - if(++y >= rows){ - return 0; - } - } - free(fstab); - } - wattrset(hw,A_BOLD|COLOR_PAIR(SUBDISPLAY_COLOR)); - mvwhline(hw,y,1,' ',cols - 2); - mvwprintw(hw,y,1,"%-*.*s %-5.5s %-36.36s " PREFIXFMT " %s", - FSLABELSIZ,FSLABELSIZ,"Label", - "Type","UUID","Bytes","Device"); - if(++y >= rows){ - return 0; - } - wattrset(hw,A_BOLD|COLOR_PAIR(FORMTEXT_COLOR)); - for(c = get_controllers() ; c ; c = c->next){ - const device *d; - - for(d = c->blockdevs ; d ; d = d->next){ - const device *p; - - detail_targets(hw,&y,y + 1 < rows,d); - if(y >= rows){ - return 0; - } - for(p = d->parts ; p ; p = p->next){ - detail_targets(hw,&y,y + 1 < rows,p); - if(y >= rows){ - return 0; - } - } - } - } - // Now list the existing maps, a superset of the targets - wattrset(hw,A_BOLD|COLOR_PAIR(SUBDISPLAY_COLOR)); - for(c = get_controllers() ; c ; c = c->next){ - const device *d; - - for(d = c->blockdevs ; d ; d = d->next){ - const device *p; - - detail_mounts(hw,&y,rows - y,d); - if(y >= rows){ - return 0; - } - for(p = d->parts ; p ; p = p->next){ - detail_mounts(hw,&y,rows - y,p); - if(y >= rows){ - return 0; - } - } - } - } - - while(y < rows){ - mvwhline(hw,y++,1,' ',cols - 2); - } - return 0; -} - -static int -display_enviroment(WINDOW *mainw,struct panel_state *ps){ - memset(ps,0,sizeof(*ps)); - if(new_display_panel(mainw,ps,ENVROWS,78,L"press 'e' to dismiss display" - ,NULL,PBORDER_COLOR)){ - goto err; - } - if(env_details(panel_window(ps->p),getmaxy(panel_window(ps->p)) - 1)){ - goto err; - } - return OK; - -err: - if(ps->p){ - WINDOW *psw = panel_window(ps->p); - - hide_panel(ps->p); - del_panel(ps->p); - delwin(psw); - } - memset(ps,0,sizeof(*ps)); - return ERR; -} - -static int -display_maps(WINDOW *mainw,struct panel_state *ps){ - // FIXME compute based off number of maps + targets - unsigned rows = getmaxy(mainw) - 15; - - memset(ps,0,sizeof(*ps)); - if(new_display_panel(mainw,ps,rows,0,L"press 'E' to dismiss display" - ,NULL,PBORDER_COLOR)){ - goto err; - } - if(map_details(panel_window(ps->p))){ - goto err; - } - return OK; - -err: - if(ps->p){ - WINDOW *psw = panel_window(ps->p); - - hide_panel(ps->p); - del_panel(ps->p); - delwin(psw); - } - memset(ps,0,sizeof(*ps)); - return ERR; -} - -static void -toggle_panel(WINDOW *w,struct panel_state *ps,int (*psfxn)(WINDOW *,struct panel_state *)){ - if(ps->p){ - hide_panel_locked(ps); - active = NULL; - }else{ - hide_panel_locked(active); - active = ((psfxn(w,ps) == OK) ? ps : NULL); - } -} - - -static unsigned -node_lines(int e,const blockobj *l){ - unsigned lns; - - if(e == EXPANSION_NONE){ - return 0; - } - lns = 1; - if(l->d->size){ - lns += 2; - } - return lns; -} - -// Recompute lns values for all nodes, and return the number of lines of -// output available above and below the current selection. If there is no -// current selection, the return value ought not be ascribed meaning. O(N) on -// the number of drives, not just those visible -- unacceptable! FIXME -static void -recompute_lines(adapterstate *is,int *before,int *after){ - blockobj *l; - int newsel; - - *after = -1; - *before = 0; - newsel = 0; - for(l = is->bobjs ; l ; l = l->next){ - unsigned lns; - - lns = node_lines(is->expansion,l); - if(l == is->rb->selected){ - *before = newsel; - *after = lns ? lns - 1 : 0; - }else if(*after >= 0){ - *after += lns; - }else{ - newsel += lns; - } - } -} - -// When we expand or collapse, we want the current selection to contain above -// it approximately the same proportion of the entire adapter. That is, if -// we're at the top, we ought remain so; if we're at the bottom, we ought -// remain so; if we fill the entire screen before and after the operation, we -// oughtn't move more than a few rows at the most. -// -// oldsel: old line of the selection, within the window -// oldrows: old number of rows in the iface -// newrows: new number of rows in the iface -// oldlines: number of lines selection used to occupy -static void -recompute_selection(adapterstate *is,int oldsel,int oldrows,int newrows){ - int newsel,bef,aft; - - if(newrows == oldrows){ - return; - } - // Calculate the maximum new line -- we can't leave space at the top or - // bottom, so we can't be after the true number of lines of output that - // precede us, or before the true number that follow us. - recompute_lines(is,&bef,&aft); - if(bef < 0 || aft < 0){ - return; - } - if(bef + aft + 1 <= newrows - 3){ // should never be less than, surely - is->rb->selline = bef + 2; - return; - } - // Account for lost/restored lines within the selection. Negative means - // we shrank, positive means we grew, 0 stayed the same. - // Calculate the new target line for the selection - newsel = oldsel * newrows / oldrows; - if(oldsel * newrows % oldrows >= oldrows / 2){ - ++newsel; - } - // If we have a full screen's worth after us, we can go anywhere - if(newsel > bef){ - newsel = bef; - } - /*wstatus_locked(stdscr,"newsel: %d bef: %d aft: %d oldsel: %d maxy: %d", - newsel,bef,aft,oldsel,getmaxy(is->rb->win)); - update_panels(); - doupdate();*/ - if(newsel + aft <= getmaxy(is->rb->win) - 3){ - newsel = getmaxy(is->rb->win) - aft - 3; - } - if(newsel + (int)node_lines(is->expansion,is->rb->selected) >= getmaxy(is->rb->win) - 2){ - newsel = getmaxy(is->rb->win) - 1 - node_lines(is->expansion,is->rb->selected); - } - /*wstatus_locked(stdscr,"newsel: %d bef: %d aft: %d oldsel: %d maxy: %d", - newsel,bef,aft,oldsel,getmaxy(is->rb->win)); - update_panels(); - doupdate();*/ - if(newsel){ - is->rb->selline = newsel; - } -} - -static int -expand_adapter_locked(void){ - adapterstate *is; - int old,oldrows; - - if(!current_adapter){ - return 0; - } - is = current_adapter->as; - if(is->expansion == EXPANSION_FULL){ - return 0; - } - ++is->expansion; - old = current_adapter->selline; - oldrows = getmaxy(current_adapter->win); - resize_adapter(current_adapter); - recompute_selection(is,old,oldrows,getmaxy(current_adapter->win)); - redraw_adapter(current_adapter); - return 0; -} - -static int -collapse_adapter_locked(void){ - adapterstate *is; - int old,oldrows; - - if(!current_adapter){ - return 0; - } - is = current_adapter->as; - if(is->expansion == EXPANSION_NONE){ - return 0; - } - --is->expansion; - old = current_adapter->selline; - oldrows = getmaxy(current_adapter->win); - resize_adapter(current_adapter); - recompute_selection(is,old,oldrows,getmaxy(current_adapter->win)); - redraw_adapter(current_adapter); - return 0; -} - -static int -select_adapter(void){ - reelbox *rb; - - if((rb = current_adapter) == NULL){ - return -1; - } - if(rb->selected){ - // locked_diag("Already browsing [%s]", rb->as->c->ident); - return 0; - } - if(rb->as->bobjs == NULL){ - return -1; - } - assert(rb->selline == -1); - return select_adapter_dev(rb, rb->as->bobjs, 2); -} - -static void -enslave_disk(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("A block device must be selected"); - return; - } - // FIXME enslave it -} - -static void -liberate_disk(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("A block device must be selected"); - return; - } - // FIXME liberate it -} - -static int -approvedp(const char *op){ - if(strcasecmp(op,"do it") == 0){ - return 1; - } - return 0; -} - -static void -remove_ptable_confirm(const char *op){ - if(op && approvedp(op)){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition table removal requires selection of a block device"); - return; - } - if(b->d->layout != LAYOUT_NONE){ - locked_diag("%s is not partitionable",b->d->name); - return; - } - if(b->d->blkdev.pttable == NULL){ - locked_diag("%s has no partition table",b->d->name); - return; - } - wipe_ptable(b->d,NULL); - return; - } - locked_diag("partition table removal was cancelled"); -} - -static void -remove_ptable(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition table removal requires selection of a block device"); - return; - } - if(b->d->layout != LAYOUT_NONE){ - locked_diag("%s is not partitionable",b->d->name); - return; - } - if(blockobj_unpartitionedp(b)){ - locked_diag("%s has no partition table",b->d->name); - return; - } - confirm_operation("remove the partition table",remove_ptable_confirm); -} - -static struct form_option * -pttype_table(int *count){ - struct form_option *fo = NULL,*tmp; - pttable_type *types; - int z; - - if((types = get_ptable_types(count)) == NULL){ - return NULL; - } - for(z = 0 ; z < *count ; ++z){ - char *key,*desc; - - if((key = strdup(types[z].name)) == NULL){ - goto err; - } - if((desc = strdup(types[z].desc)) == NULL){ - free(key); - goto err; - } - if((tmp = realloc(fo,sizeof(*fo) * (*count + 1))) == NULL){ - free(key); - free(desc); - goto err; - } - fo = tmp; - fo[z].option = key; - fo[z].desc = desc; - } - return fo; - -err: - while(z--){ - free(fo[z].option); - free(fo[z].desc); - } - free(fo); - *count = 0; - return NULL; -} - -static void -make_ptable(void){ - struct form_option *ops_ptype; - int opcount; - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition table creation requires selection of a block device"); - return; - } - if(!partition_table_makeablep(b)){ - return; - } - if((ops_ptype = pttype_table(&opcount)) == NULL){ - return; - } - raise_form("select a table type",pttype_callback,ops_ptype,opcount,-1, - PTTYPE_TEXT); -} - -static void -new_filesystem(void){ - blockobj *b = get_selected_blockobj(); - struct form_option *ops_fs; - int opcount,defidx; - - if(b == NULL){ - locked_diag("A block device must be selected"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(selected_emptyp()){ - locked_diag("Selected region of %s is empty space",b->d->name); - return; - } - if(!selected_mkfs_safe_p()){ - return; - } - if((ops_fs = fs_table(&opcount,NULL,&defidx)) == NULL){ - return; - } - raise_form("select a filesystem type",fs_callback,ops_fs,opcount, - defidx,FSTYPE_TEXT); - return; -} - -static void -kill_filesystem_confirm(const char *op){ - if(op && approvedp(op)){ - blockobj *b; - device *d; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Filesystem wipe requires a selected block device"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(selected_emptyp()){ - locked_diag("Filesystems cannot be wiped from empty space"); - return; - } - if(selected_unpartitionedp()){ - d = b->d; - }else{ - assert(selected_partitionp()); - d = b->zone->p; - } - // FIXME splash screen - if(wipe_filesystem(d)){ - return; - } - redraw_adapter(current_adapter); - locked_diag("Wiped filesystem on %s",d->name); - return; - } - locked_diag("filesystem wipe was cancelled"); -} - -static void -kill_filesystem(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Filesystem wipe requires a selected block device"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(selected_emptyp()){ - locked_diag("Filesystems cannot be wiped from empty space"); - return; - } - if(b->zone){ - if(b->zone->p && !b->zone->p->mnttype){ - locked_diag("No filesystem signature on %s\n",b->zone->p->name); - }else if(b->zone->p->mnt.count){ - locked_diag("Filesystem on %s is mounted. Use 'O'/'T' to unmount.\n",b->zone->p->name); - }else{ - confirm_operation("wipe the filesystem signature",kill_filesystem_confirm); - } - }else if(!b->zone){ - if(!b->d->mnttype){ - locked_diag("No filesystem signature on %s\n",b->d->name); - }else if(b->d->mnt.count){ - locked_diag("Filesystem on %s is mounted. Use 'O'/'T' to unmount.\n",b->d->name); - }else{ - confirm_operation("wipe the filesystem signature",kill_filesystem_confirm); - } - }else{ - confirm_operation("wipe the filesystem signature",kill_filesystem_confirm); - } -} - -static const struct form_option dos_flags[] = { - { - .option = "0x80", - .desc = "Bootable", - }, -}; - -static const struct form_option gpt_flags[] = { - { // protects OEM partitions from being overwritten by windows - .option = "0x0000000000000001", // 2^0, 1 - .desc = "System partition", - },{ - .option = "0x0000000000000002", // 2^1, 2 - .desc = "Hide from EFI", - },{ - .option = "0x0000000000000004", // 2^2, 4 - .desc = "Legacy BIOS bootable", - },{ // readonly for EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 - .option = "0x1000000000000000", // 2^60 - .desc = "Read-only", - },{ - .option = "0x2000000000000000", // 2^61 - .desc = "Shadow copy", - },{ // hidden for EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 - .option = "0x4000000000000000", // 2^62 - .desc = "Hidden", - },{ // no default drive letter for EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 - .option = "0x8000000000000000", // 2^63 - .desc = "Inhibit automounting", - }, -}; - -static struct form_option * -flag_table(int *count,const char *match,int *defidx,char ***selarray,int *selections, - const struct form_option *flags,unsigned fcount){ - struct form_option *fo = NULL; - int z = 0; - - *count = 0; - *defidx = -1; - if((*count = fcount) == 0){ - goto err; - } - if((fo = malloc(sizeof(*fo) * *count)) == NULL){ - goto err; - } - while(z < *count){ - const char *key = flags[z].option; - - if((fo[z].desc = strdup(flags[z].desc)) == NULL){ - goto err; - } - if((fo[z].option = strdup(key)) == NULL){ - free(fo[z].desc); - goto err; - } - if(match && strcmp(match,fo[z].option) == 0){ - int zz; - - *defidx = z; - for(zz = 0 ; selections && zz < *selections ; ++zz){ - if(strcmp(key,(*selarray)[zz]) == 0){ - free((*selarray)[zz]); - (*selarray)[zz] = NULL; - if(zz < *selections - 1){ - memmove(&(*selarray)[zz],&(*selarray)[zz + 1],sizeof(**selarray) * (*selections - 1 - zz)); - } - --*selections; - zz = -1; - break; - } - } - if(zz >= *selections){ - typeof(*selarray) tmp; - - if((tmp = realloc(*selarray,sizeof(*selarray) * (*selections + 1))) == NULL){ - free(fo[zz].option); - free(fo[zz].desc); - goto err; - } - *selarray = tmp; - (*selarray)[*selections] = strdup(match); - ++*selections; - } - } - ++z; - } - *defidx = (*defidx + 1) % *count; - return fo; - -err: - while(z--){ - free(fo[z].option); - free(fo[z].desc); - } - free(fo); - return NULL; -} - -static void -do_partflag(char **selarray,int selections){ - unsigned long long flags; - device *d; - int z; - - if(!selected_partitionp()){ - locked_diag("Selected object is not a partition"); - return; - } - d = get_selected_blockobj()->zone->p; - flags = 0; - for(z = 0 ; z < selections ; ++z){ - char *eptr = selarray[z]; - unsigned long long ul; - - errno = 0; - ul = strtoull(selarray[z],&eptr,16); - assert(ul && (ul < ULLONG_MAX || errno != ERANGE) && !*eptr); - flags |= ul; - } - if(partition_set_flags(d,flags)){ - return; - } -} - -static void -partflag_callback(const char *fn,char **selarray,int selections,int scrollp){ - struct form_option *flags_agg; - int opcount,defidx; - - if(fn == NULL){ - // FIXME free selections - return; - } - if(strcmp(fn,"") == 0){ - do_partflag(selarray,selections); - // FIXME free - return; - } - if((flags_agg = flag_table(&opcount,fn,&defidx,&selarray,&selections, - gpt_flags,sizeof(gpt_flags) / sizeof(*gpt_flags))) == NULL){ - // FIXME free - return; - } - raise_checkform("set GPT partition flags",partflag_callback,flags_agg, - opcount,defidx,selarray,selections,PARTFLAG_TEXT,scrollp); -} - -static void -dos_partflag_callback(const char *fn,char **selarray,int selections,int scrollp){ - struct form_option *flags_agg; - int opcount,defidx; - - if(fn == NULL){ - // FIXME free selections - return; - } - if(strcmp(fn,"") == 0){ - do_partflag(selarray,selections); - // FIXME free - return; - } - if((flags_agg = flag_table(&opcount,fn,&defidx,&selarray,&selections, - dos_flags,sizeof(dos_flags) / sizeof(*dos_flags))) == NULL){ - // FIXME free - return; - } - raise_checkform("set DOS partition flags",dos_partflag_callback,flags_agg, - opcount,defidx,selarray,selections,PARTFLAG_TEXT,scrollp); -} - -static int -flag_to_selections(uint64_t flags,char ***selarray,int *selections, - const struct form_option *ops,unsigned opcount){ - assert(selarray && selections); - assert(!*selarray && !*selections); - while(opcount--){ - unsigned long long ul; - char *eptr; - - ul = strtoull(ops[opcount].option,&eptr,16); - assert(ul && (ul < ULLONG_MAX || errno != ERANGE) && !*eptr); - if(flags & ul){ - typeof(*selarray) tmp; - - if((tmp = realloc(*selarray,sizeof(*selarray) * (*selections + 1))) == NULL){ - // FIXME backfree - return -1; - } - *selarray = tmp; - (*selarray)[*selections] = strdup(ops[opcount].option); - ++*selections; - } - } - return 0; -} - -static void -set_partition_attrs(void){ - struct form_option *flags_agg; - char **selarray = NULL; - int selections = 0; - int opcount,defidx; - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition modification requires selection of a partition"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(!selected_partitionp()){ - locked_diag("Selected object is not a partition"); - return; - } - // FIXME need to initialize widget based off current flags - if(strcmp("gpt",b->d->blkdev.pttable) == 0){ - if(flag_to_selections(b->zone->p->partdev.flags,&selarray,&selections, - gpt_flags,sizeof(gpt_flags) / sizeof(*gpt_flags))){ - return; - } - if((flags_agg = flag_table(&opcount,NULL,&defidx,&selarray,&selections, - gpt_flags,sizeof(gpt_flags) / sizeof(*gpt_flags))) == NULL){ - // FIXME free selarray - return; - } - raise_checkform("set GPT partition flags",partflag_callback,flags_agg, - opcount,defidx,selarray,selections,PARTFLAG_TEXT,0); - }else if(strcmp("dos",b->d->blkdev.pttable) == 0 || - strcmp("msdos",b->d->blkdev.pttable) == 0){ - - if(flag_to_selections(b->zone->p->partdev.flags,&selarray,&selections, - dos_flags,sizeof(dos_flags) / sizeof(*dos_flags))){ - return; - } - if((flags_agg = flag_table(&opcount,NULL,&defidx,&selarray,&selections, - dos_flags,sizeof(dos_flags) / sizeof(*dos_flags))) == NULL){ - return; - } - raise_checkform("set DOS partition flags",dos_partflag_callback,flags_agg, - opcount,defidx,selarray,selections,PARTFLAG_TEXT,0); - }else{ - assert(0); - } -} - -static inline int -fsck_suitable_p(const device *d){ - if(d->mnt.count){ - locked_diag("Will not fsck mounted filesystem on %s",d->name); - return 0; - } - if(d->mnttype == NULL){ - locked_diag("No filesystem found on %s",d->name); - return 0; - } - return 1; -} - -static void -fsck_partition(void){ - blockobj *b; - device *d; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition check requires selection of a partition"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(selected_emptyp()){ - locked_diag("Selected object is not a partition"); - return; - } - if(selected_unpartitionedp()){ - d = b->d; - }else{ - assert(selected_unpartitionedp()); - d = b->zone->p; - } - if(fsck_suitable_p(d)){ - if(check_partition(d) == 0){ - locked_diag("Validated filesystem on %s",d->name); - } - } -} - -static void -delete_partition_confirm(const char *op){ - if(op && approvedp(op)){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition deletion requires selection of a partition"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(selected_unpartitionedp()){ - locked_diag("Space is already unpartitioned"); - return; - } - if(selected_emptyp()){ - locked_diag("Cannot remove empty space; partition it instead"); - return; - } - if(wipe_partition(b->zone->p)){ - return; - } - redraw_adapter(current_adapter); - return; - } - locked_diag("partition deletion was cancelled"); -} - -static void -delete_partition(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Partition deletion requires selection of a partition"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(selected_unpartitionedp()){ - locked_diag("Space is already unpartitioned"); - return; - } - if(selected_emptyp()){ - locked_diag("Cannot remove empty space; partition it instead"); - return; - } - if(b->zone->p->mnttype){ - locked_diag("%s has a valid filesystem signature. Wipe it with 'w'.",b->zone->p->name); - return; - } - confirm_operation("delete the partition",delete_partition_confirm); -} - -static void -wipe_mbr_confirm(const char *op){ - blockobj *b; - - if(!op || !approvedp(op)){ - locked_diag("master boot record wipe was cancelled"); - return; - } - if((b = get_selected_blockobj()) == NULL){ - locked_diag("MBR wipe requires selection of a block device"); - return; - } - if(blockobj_unloadedp(b)){ - locked_diag("Media is unloaded on %s\n",b->d->name); - return; - } - wipe_dosmbr(b->d); -} - -static void -wipe_mbr(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("MBR wipe requires selection of a block device"); - return; - } - if(blockobj_unloadedp(b)){ - locked_diag("Media is unloaded on %s\n",b->d->name); - return; - } - confirm_operation("wipe the mbr",wipe_mbr_confirm); -} - -static void -badblock_do_internal(void){ - struct panel_state *ps; - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Block check requires selection of a block device"); - return; - } - ps = show_splash(L"Performing block check..."); - badblock_scan(b->d,0); // FIXME allow destructive badblock check - if(ps){ - kill_splash(ps); - } -} - -static void -badblock_check(void){ - badblock_do_internal(); -} - -static void -mountpoint_callback(const char *path){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a filesystem to mount"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(path == NULL){ - locked_diag("User cancelled mount operation"); - return; - } - if(selected_unpartitionedp()){ - mmount(b->d,path,0,NULL); - }else{ - assert(selected_partitionp()); - mmount(b->zone->p,path,0,NULL); - } -} - -static void -mount_filesystem(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a filesystem to mount"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(!selected_unpartitionedp()){ - if(selected_emptyp()){ - locked_diag("Cannot mount unused space"); - return; - } - if(b->zone->p->mnttype == NULL){ - locked_diag("No filesystem detected on %s",b->zone->p->name); - return; - } - if(fstype_swap_p(b->zone->p->mnttype)){ - if(swapondev(b->zone->p) == 0){ - redraw_adapter(current_adapter); - } - return; - } - }else{ - if(b->d->mnttype == NULL){ - locked_diag("No filesystem detected on %s",b->d->name); - return; - } - if(fstype_swap_p(b->d->mnttype)){ - if(swapondev(b->d) == 0){ - redraw_adapter(current_adapter); - } - return; - } - } - raise_str_form("enter mountpount",mountpoint_callback,"/",MOUNT_TEXT); -} - -static void -numount_target(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a filesystem to mount"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(!selected_unpartitionedp()){ - if(selected_emptyp()){ - locked_diag("Cannot unmount unused space"); - return; - } - if(!targeted_p(b->zone->p)){ - locked_diag("Block device %s is not a target",b->zone->p->name); - return; - } - if(unmount(b->zone->p,NULL)){ - return; - } - redraw_adapter(current_adapter); - return; - }else{ - if(!targeted_p(b->d)){ - locked_diag("Block device %s is not a target",b->d->name); - return; - } - if(unmount(b->d,NULL)){ - return; - } - redraw_adapter(current_adapter); - return; - } -} - -static int -biosboot(void){ - blockobj *b; - device *d; - - if(!target_mode_p()){ - locked_diag("Not in target mode"); - return -1; - } - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a block device to boot"); - return -1; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return -1; - } - if(selected_unpartitionedp()){ - locked_diag("BIOS cannot boot from unpartitioned %s",b->d->name); - return -1; - } - if(b->zone->p){ - if(b->zone->p->layout != LAYOUT_PARTITION){ - locked_diag("Cannot boot from unused space"); - return -1; - } - d = b->zone->p; - }else{ - d = b->d; - } - if(!targeted_p(d)){ - locked_diag("Block device %s is not a target",d->name); - return -1; - } - // Do not enforce a check against the path for '/'; it can be in /boot - if(finalize_target()){ - return -1; - } - if(prepare_bios_boot(d)){ - return -1; - } - locked_diag("Successfully prepared BIOS boot"); - return 0; -} - -static int -uefiboot(void){ - blockobj *b; - device *d; - - if(!target_mode_p()){ - locked_diag("Not in target mode"); - return -1; - } - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a block device to boot"); - return -1; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return -1; - } - if(selected_unpartitionedp()){ - locked_diag("UEFI cannot boot from unpartitioned %s",b->d->name); - return -1; - } - if(b->zone->p){ - if(b->zone->p->layout != LAYOUT_PARTITION){ - locked_diag("Cannot boot from unused space"); - return -1; - } - d = b->zone->p; - }else{ - d = b->d; - } - if(!targeted_p(d)){ - locked_diag("Block device %s is not a target",d->name); - return -1; - } - // Do not enforce a check against the path for '/'; it can be in /boot - if(finalize_target()){ - return -1; - } - if(prepare_uefi_boot(d)){ - return -1; - } - locked_diag("Successfully prepared UEFI boot"); - return 0; -} - -static void -nmount_target(void){ - blockobj *b; - - if(!target_mode_p()){ - locked_diag("Not in target mode"); - return; - } - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a filesystem to mount"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(!selected_unpartitionedp()){ - if(selected_emptyp()){ - locked_diag("Cannot mount unused space"); - return; - } - if(targeted_p(b->zone->p)){ - locked_diag("%s is already a target",b->zone->p->name); - return; - } - if(b->zone->p->mnttype == NULL){ - locked_diag("No filesystem detected on %s",b->zone->p->name); - return; - } - }else{ - if(targeted_p(b->d)){ - locked_diag("%s is already a target",b->d->name); - return; - } - if(b->d->mnttype == NULL){ - locked_diag("No filesystem detected on %s",b->d->name); - return; - } - } - raise_str_form("enter target mountpount",targpoint_callback,"/", - TARG_TEXT); -} - -static void -umount_filesystem(void){ - blockobj *b; - int r; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Must select a filesystem to unmount"); - return; - } - if(selected_unloadedp()){ - locked_diag("Media is not loaded on %s",b->d->name); - return; - } - if(!selected_unpartitionedp()){ - if(selected_emptyp()){ - locked_diag("Cannot unmount unused space"); - return; - } - if(fstype_swap_p(b->zone->p->mnttype)){ - r = swapoffdev(b->zone->p); - }else{ - r = unmount(b->zone->p,NULL); - } - }else{ - if(fstype_swap_p(b->d->mnttype)){ - r = swapoffdev(b->d); - }else{ - r = unmount(b->d,NULL); - } - } - if(!r){ - redraw_adapter(current_adapter); - } -} - -static void -remove_last_bufchar(char *buf){ - char *killem = buf; - mbstate_t mb; - size_t m; - - memset(&mb,0,sizeof(mb)); - while( (m = mbrlen(buf,strlen(buf),&mb)) ){ - if(m == (size_t)-1 || m == (size_t)-2){ - break; - } - killem = buf; - buf += m; - } - *killem = '\0'; -} - -// We received input while a modal freeform string input form was active. -// Divert it from the typical UI, and handle it according to the form. -static void -handle_actform_string_input(int ch){ - struct form_state *fs = actform; - void (*cb)(const char *); - - cb = actform->fxn; - switch(ch){ - case 21: // CTRL+u, clear input line FIXME - lock_ncurses(); - fs->inp.buffer[0] = '\0'; - form_string_options(fs); - unlock_ncurses(); - break; - case '\r': case '\n': case KEY_ENTER:{ - char *str; - - lock_ncurses(); - str = strdup(actform->inp.buffer); - assert(NULL != str); - free_form(actform); - actform = NULL; - curs_set(0); - cb(str); - free(str); - unlock_ncurses(); - break; - }case KEY_ESC:{ - lock_ncurses(); - free_form(actform); - actform = NULL; - curs_set(0); - cb(NULL); - unlock_ncurses(); - break; - }case KEY_BACKSPACE:{ - lock_ncurses(); - remove_last_bufchar(fs->inp.buffer); - form_string_options(fs); - unlock_ncurses(); - break; - }default:{ - char *tmp; - - if(ch >= 256 || !isgraph(ch)){ - diag("please %s, or cancel",actform->boxstr); - } - lock_ncurses(); - if((tmp = realloc(fs->inp.buffer,strlen(fs->inp.buffer) + 2)) == NULL){ - locked_diag("Couldn't allocate input buffer (%s?)",strerror(errno)); - unlock_ncurses(); - return; - } - fs->inp.buffer = tmp; - fs->inp.buffer[strlen(fs->inp.buffer) + 1] = '\0'; - fs->inp.buffer[strlen(fs->inp.buffer)] = (unsigned char)ch; - form_string_options(fs); - unlock_ncurses(); - } } -} - -// We received input while a modal subwindow was active. Divert it from the -// typical UI, and handle it according to the subwindow. If we are not -// interested in the input, return it for further use. Otherwise, return 0 to -// indicate intercept. -static int -handle_subwindow_input(int ch){ - /*switch(ch){ - default: - locked_diag("FIXME handle subwindow input"); - }*/ - return ch; -} - -static void -handle_actform_splash_input(void){ - lock_ncurses(); - free_form(actform); - actform = NULL; - curs_set(0); - unlock_ncurses(); -} - -// We received input while a modal form was active. Divert it from the typical -// UI, and handle it according to the form. Returning non-zero quits the -// program, and should pretty much only indicate that 'q' was pressed. -static int -handle_actform_input(int ch){ - struct form_state *fs = actform; - void (*mcb)(const char *,char **,int,int); - void (*cb)(const char *); - - if(fs->formtype == FORM_STRING_INPUT){ - handle_actform_string_input(ch); - return 0; - }else if(fs->formtype == FORM_SPLASH_PROMPT){ - handle_actform_splash_input(); - return 0; - }else if(fs->formtype == FORM_MULTISELECT || fs->formtype == FORM_CHECKBOXEN){ - mcb = actform->mcb; - cb = NULL; - }else{ - mcb = NULL; - cb = actform->fxn; - } - switch(ch){ - case 12: // CTRL+L FIXME - lock_ncurses(); - wrefresh(curscr); - unlock_ncurses(); - break; - case ' ': case '\r': case '\n': case KEY_ENTER:{ - int op,selections,scrolloff; - char **selarray; - char *optstr; - - lock_ncurses(); - op = fs->idx; - optstr = strdup(fs->ops[op].option); - assert(NULL != optstr); - selarray = fs->selarray; - selections = fs->selections; - scrolloff = fs->scrolloff; - fs->selarray = NULL; - free_form(actform); - actform = NULL; - setup_colors(); - if(mcb){ - mcb(optstr,selarray,selections,scrolloff); - }else{ - cb(optstr); - } - free(optstr); - unlock_ncurses(); - break; - }case KEY_ESC:{ - lock_ncurses(); - if(fs->formtype == FORM_MULTISELECT || fs->formtype == FORM_CHECKBOXEN){ - int scrolloff = fs->scrolloff; - free_form(actform); - actform = NULL; - mcb(NULL,NULL,0,scrolloff); - }else{ - free_form(actform); - actform = NULL; - cb(NULL); - } - unlock_ncurses(); - break; - }case KEY_UP: case 'k':{ - lock_ncurses(); - if(fs->idx == fs->scrolloff){ - if(--fs->scrolloff < 0){ - fs->scrolloff = fs->opcount - 1; - } - } - if(--fs->idx < 0){ - fs->idx = fs->opcount - 1; - } - if(fs->formtype == FORM_MULTISELECT){ - multiform_options(fs); - }else if(fs->formtype == FORM_CHECKBOXEN){ - check_options(fs); - }else{ - form_options(fs); - } - unlock_ncurses(); - break; - }case KEY_DOWN: case 'j':{ - lock_ncurses(); - int maxz; - maxz = getmaxy(panel_window(fs->p)) - 5 >= fs->opcount - 1 ? fs->opcount - 1 : getmaxy(panel_window(fs->p)) - 5; - if(fs->idx == (fs->scrolloff + maxz) % fs->opcount){ - if(++fs->scrolloff >= fs->opcount){ - fs->scrolloff = 0; - } - } - if(++fs->idx >= fs->opcount){ - fs->idx = 0; - } - if(fs->formtype == FORM_MULTISELECT){ - multiform_options(fs); - }else if(fs->formtype == FORM_CHECKBOXEN){ - check_options(fs); - }else{ - form_options(fs); - } - unlock_ncurses(); - break; - }case 'q':{ - return 'q'; - }case 'C':{ - int selections,scrolloff; - char **selarray; - - lock_ncurses(); - if(fs->formtype == FORM_MULTISELECT || fs->formtype == FORM_CHECKBOXEN){ - selarray = fs->selarray; - selections = fs->selections; - scrolloff = fs->scrolloff; - fs->selarray = NULL; - free_form(actform); - actform = NULL; - mcb("",selarray,selections,scrolloff); - unlock_ncurses(); - break; - } - unlock_ncurses(); - } /* intentional fallthrough */ - default:{ - diag("please %s, or cancel",actform->boxstr); - break; - } - } - return 0; -} - -static void -destroy_aggregate_confirm(const char *op){ - blockobj *b; - - if(!op || !approvedp(op)){ - locked_diag("aggregate destruction was cancelled"); - return; - } - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Aggregate destruction requires selection of an aggregate"); - return; - } - if(b->d->layout == LAYOUT_NONE || b->d->layout == LAYOUT_PARTITION){ - locked_diag("%s is not an aggregate",b->d->name); - }else if(b->d->layout == LAYOUT_ZPOOL){ - destroy_zpool(b->d); - }else if(b->d->layout == LAYOUT_MDADM){ - destroy_mdadm(b->d); - }else if(b->d->layout == LAYOUT_DM){ - locked_diag("Not yet implemented FIXME"); // FIXME - }else{ - locked_diag("Unknown layout type %d on %s",b->d->layout,b->d->name); - } -} - -static void -untargeted_exit_confirm(const char *op){ - if(!op || !approvedp(op)){ - locked_diag("exit cancelled"); - return; - } - shutdown_cycle(); -} - -static void -destroy_aggregate(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Aggregate destruction requires selection of an aggregate"); - return; - } - if(b->d->layout == LAYOUT_NONE || b->d->layout == LAYOUT_PARTITION){ - locked_diag("%s is not an aggregate",b->d->name); - return; - } - confirm_operation("destroy the aggregate",destroy_aggregate_confirm); -} - -static void -modify_aggregate(void){ - blockobj *b; - - if((b = get_selected_blockobj()) == NULL){ - locked_diag("Aggregate modification requires selection of an aggregate"); - return; - } - if(b->d->layout == LAYOUT_NONE || b->d->layout == LAYOUT_PARTITION){ - locked_diag("%s is not an aggregate",b->d->name); - return; - } - locked_diag("Aggregate modification not yet implemented FIXME"); -} - -static void -search_callback(const char *term){ - if(term == NULL){ - locked_diag("Search was cancelled"); - return; - } - locked_diag("Search not yet implemented FIXME"); -} - -static void -start_search(void){ - raise_str_form("start typing an identifier",search_callback,NULL, - SEARCH_TEXT); -} - -static void -loop_callback(const char *term){ - if(term == NULL){ - locked_diag("Loop device setup cancelled"); - return; - } - locked_diag("Looping not yet implemented FIXME"); -} - -static void -configure_loop_dev(void){ - raise_str_form("Select a file to loop",loop_callback,NULL, - LOOP_TEXT); -} - -static void -set_label(void){ - device *d; - - if((d = selected_filesystem()) == NULL){ - locked_diag("No filesystem is selected"); - return; - } - if(!fstype_named_p(d->mnttype)){ - locked_diag("%s does not support labels",d->mnttype); - return; - } - // FIXME - locked_diag("FIXME not yet implemented"); -} - -static void -set_uuid(void){ - device *d; - - if((d = selected_filesystem()) == NULL){ - locked_diag("No filesystem is selected"); - return; - } - if(!fstype_uuid_p(d->mnttype)){ - locked_diag("%s does not support UUIDs",d->mnttype); - return; - } - // FIXME - locked_diag("FIXME not yet implemented"); -} - -static void -do_setup_target(const char *token){ - if(token == NULL){ - locked_diag("Targeting was cancelled"); - return; - } - if(token[0] != '/'){ - locked_diag("Target must be an absolute path"); - return; - } - if(target_mode_p()){ - locked_diag("Already have a target at %s",growlight_target); - return; - } - if(set_target(token)){ - return; - } - locked_diag("Now targeting %s",token); -} - -static void -setup_target(void){ - if(target_mode_p()){ - locked_diag("Already have a target at %s",growlight_target); - return; - } - raise_str_form("enter target path",do_setup_target,"/target",TARGET_TEXT); -} - -static void -unset_target(void){ - if(!target_mode_p()){ - locked_diag("Not in target mode"); - return; - } - if(set_target(NULL)){ - return; - } - locked_diag("Successfully left target mode"); -} - -static void -handle_ncurses_input(WINDOW *w){ - int ch,r; - - while((ch = getch()) != ERR){ - if(ch == 12){ // CTRL+L FIXME - lock_ncurses(); - wrefresh(curscr); - unlock_ncurses(); - continue; - } - if(actform){ - if((ch = handle_actform_input(ch)) == ERR){ - break; - } - if(ch == 0){ - continue; - } - } - if(active){ - if((ch = handle_subwindow_input(ch)) == ERR){ - return; - } - if(ch == 0){ // intercepted - continue; - } - } - switch(ch){ - case 'H':{ - lock_ncurses(); - toggle_panel(w,&help,display_help); - unlock_ncurses(); - break; - } - case 'D':{ - lock_ncurses(); - toggle_panel(w,&diags,display_diags); - unlock_ncurses(); - break; - } - case 'v':{ - lock_ncurses(); - toggle_panel(w,&details,display_details); - unlock_ncurses(); - break; - } - case 'e':{ - lock_ncurses(); - toggle_panel(w,&environment,display_enviroment); - unlock_ncurses(); - break; - } - case 'E':{ - lock_ncurses(); - toggle_panel(w,&maps,display_maps); - unlock_ncurses(); - break; - } - case '+': - lock_ncurses(); - expand_adapter_locked(); - unlock_ncurses(); - break; - case '-':{ - lock_ncurses(); - collapse_adapter_locked(); - unlock_ncurses(); - break; - } - case KEY_RIGHT: case 'l':{ - lock_ncurses(); - if(selection_active()){ - use_next_zone(current_adapter->selected); - } - redraw_adapter(current_adapter); - unlock_ncurses(); - break; - } - case KEY_LEFT: case 'h':{ - lock_ncurses(); - if(selection_active()){ - use_prev_zone(current_adapter->selected); - } - redraw_adapter(current_adapter); - unlock_ncurses(); - break; - } - case KEY_UP: case 'k':{ - lock_ncurses(); - use_prev_device(); - unlock_ncurses(); - break; - } - case KEY_DOWN: case 'j':{ - lock_ncurses(); - use_next_device(); - unlock_ncurses(); - break; - } - case KEY_PPAGE:{ - int sel; - lock_ncurses(); - sel = selection_active(); - deselect_adapter_locked(); - use_prev_controller(w); - if(sel){ - select_adapter(); - } - unlock_ncurses(); - break; - } - case KEY_NPAGE:{ - int sel; - lock_ncurses(); -// fprintf(stderr, "-------------- BEGIN PgDown ---------------\n"); - sel = selection_active(); - deselect_adapter_locked(); - use_next_controller(w); - if(sel){ - select_adapter(); - } -// fprintf(stderr, "--------------- END PgDown ----------------\n"); - unlock_ncurses(); - break; - } - case 'm':{ - lock_ncurses(); - make_ptable(); - unlock_ncurses(); - break; - } - case 'r':{ - lock_ncurses(); - remove_ptable(); - unlock_ncurses(); - break; - } - case 'W':{ - lock_ncurses(); - wipe_mbr(); - unlock_ncurses(); - break; - } - case 'B':{ - lock_ncurses(); - badblock_check(); - unlock_ncurses(); - break; - } - case 'n':{ - lock_ncurses(); - new_partition(); - unlock_ncurses(); - break; - } - case 'd':{ - lock_ncurses(); - delete_partition(); - unlock_ncurses(); - break; - } - case 'F':{ - lock_ncurses(); - fsck_partition(); - unlock_ncurses(); - break; - } - case 'U':{ - lock_ncurses(); - set_uuid(); - unlock_ncurses(); - break; - } - case 'L':{ - lock_ncurses(); - set_label(); - unlock_ncurses(); - break; - } - case 's':{ - lock_ncurses(); - set_partition_attrs(); - unlock_ncurses(); - break; - } - case 'M':{ - lock_ncurses(); - new_filesystem(); - unlock_ncurses(); - break; - } - case 'w':{ - lock_ncurses(); - kill_filesystem(); - unlock_ncurses(); - break; - } - case 'o':{ - lock_ncurses(); - mount_filesystem(); - unlock_ncurses(); - break; - } - case 'O':{ - lock_ncurses(); - umount_filesystem(); - unlock_ncurses(); - break; - } - case 't':{ - lock_ncurses(); - nmount_target(); - unlock_ncurses(); - break; - } - case 'T':{ - lock_ncurses(); - numount_target(); - unlock_ncurses(); - break; - } - case 'b':{ - lock_ncurses(); - enslave_disk(); - unlock_ncurses(); - break; - } - case 'f':{ - lock_ncurses(); - liberate_disk(); - unlock_ncurses(); - break; - } - case 'i':{ - lock_ncurses(); - setup_target(); - unlock_ncurses(); - break; - } - case '/':{ - lock_ncurses(); - start_search(); - unlock_ncurses(); - break; - } - case 'p':{ - lock_ncurses(); - configure_loop_dev(); - unlock_ncurses(); - break; - } - case 'I':{ - lock_ncurses(); - unset_target(); - unlock_ncurses(); - break; - } - case 'A': - lock_ncurses(); - if(actform){ - locked_diag("An input dialog is already active"); - }else{ - raise_aggregate_form(); - } - unlock_ncurses(); - break; - case 'z': - lock_ncurses(); - modify_aggregate(); - unlock_ncurses(); - break; - case 'Z': - lock_ncurses(); - destroy_aggregate(); - unlock_ncurses(); - break; -// Finalization commands - case '*': - lock_ncurses(); - if((r = uefiboot()) == 0){ - locked_diag("Successfully finalized target /etc/fstab"); - } - unlock_ncurses(); - if(r == 0){ - return; - } - break; - case '#': - lock_ncurses(); - if((r = biosboot()) == 0){ - locked_diag("Successfully finalized target /etc/fstab"); - } - unlock_ncurses(); - if(r == 0){ - return; - } - break; - case '@': - lock_ncurses(); - if((r = finalize_target()) == 0){ - locked_diag("Successfully finalized target /etc/fstab"); - } - unlock_ncurses(); - if(r == 0){ - return; - } - break; - case 'q': - if(!growlight_target){ - return; - }else if(finalized){ - return; - } - confirm_operation("exit without finalizing a target",untargeted_exit_confirm); - break; - default:{ - const char *hstr = !help.p ? " ('H' for help)" : ""; - // diag() locks/unlocks, and calls screen_update() - if(isprint(ch)){ - diag("unknown command '%c'%s",ch,hstr); - }else{ - diag("unknown scancode %d%s",ch,hstr); - } - break; - } - } - } - diag("Error reading from console, aborting"); -} - -static adapterstate * -create_adapter_state(controller *a){ - adapterstate *as; - - if( (as = malloc(sizeof(*as))) ){ - memset(as,0,sizeof(*as)); - as->c = a; - as->expansion = EXPANSION_MAX; - // next, prev, rb are managed by caller - } - return as; -} - -static void -free_adapter_state(adapterstate *as){ - if(as){ - blockobj *b; - - while( (b = as->bobjs) ){ - as->bobjs = b->next; - free(b); - } - free(as); - } -} - -static void * -adapter_callback(controller *a,void *state){ - adapterstate *as; - reelbox *rb; - - lock_ncurses_growlight(); - if((as = state) == NULL){ - if(a->blockdevs){ - if( (state = as = create_adapter_state(a)) ){ - int newrb,rows,cols; - - getmaxyx(stdscr,rows,cols); - if( (newrb = bottom_space_p(rows)) ){ - newrb = rows - newrb; - if((rb = create_reelbox(as,rows,newrb,cols)) == NULL){ - free_adapter_state(as); - unlock_ncurses_growlight(); - return NULL; - } - if(last_reelbox){ - // set up the adapter list entries - as->next = last_reelbox->as->next; - as->next->prev = as; - as->prev = last_reelbox->as; - last_reelbox->as->next = as; - // and also the rb list entries - if( (rb->next = last_reelbox->next) ){ - rb->next->prev = rb; - } - rb->prev = last_reelbox; - last_reelbox->next = rb; - }else{ - as->prev = as->next = as; - rb->next = rb->prev = NULL; - top_reelbox = rb; - current_adapter = rb; - } - last_reelbox = rb; - }else{ // insert it after the last visible one, no rb - as->next = top_reelbox->as; - top_reelbox->as->prev->next = as; - as->prev = top_reelbox->as->prev; - top_reelbox->as->prev = as; - as->rb = NULL; - rb = NULL; - } - ++count_adapters; - draw_main_window(stdscr); - }else{ - rb = NULL; - } - }else{ - rb = NULL; - } - }else{ - rb = as->rb; - } - if(rb){ - //resize_adapter(rb); - redraw_adapter(rb); - } - unlock_ncurses_growlight(); - return as; -} - -static void -free_zchain(zobj **z){ - zobj *zt,*zstart; - - if((zstart = *z) == NULL){ - return; - } - do{ - zt = *z; - *z = (*z)->next; - free(zt); - }while( (*z != zstart) ); - *z = NULL; -} - -// b->zone == NULL: -// d->layout == LAYOUT_NONE: -// d->blkdev.unloaded: device unloaded or inaccessible -// d->blkdev.pttable == NULL: no partitioning table -// d->layout == * ??? FIXME -// b->zone->p == NULL: empty space -// b->zone->p: partition -static void -update_blockobj(blockobj *b,device *d){ - zobj *z,*lastz,*firstchoice; - uintmax_t sector; - int zonesel = -1; // -1 for no choice (b->zone == NULL on entry) - int zones; - device *p; - - if(blockobj_unloadedp(b)){ - free_zchain(&b->zchain); - b->zone = NULL; - return; - } - // Remember the zone we had selected, though it might disappear, or - // change index due to zones appearing prior to it. - if(b->zone){ - zonesel = b->zone->zoneno; - } - z = NULL; - zones = 0; - if((d->layout == LAYOUT_NONE && d->blkdev.pttable == NULL) || - (d->layout == LAYOUT_MDADM && d->mddev.pttable == NULL) || - (d->layout == LAYOUT_DM && d->dmdev.pttable == NULL)){ - sector = d->size / d->logsec + 1; - }else{ - if( (sector = first_usable_sector(d)) ){ - if((z = create_zobj(z, zones, zones, sector - 1, NULL, REP_METADATA)) == NULL){ - goto err; - } - ++zones; - } - } - for(p = d->parts ; p ; p = p->next){ - if(sector != p->partdev.fsector){ - if((z = create_zobj(z, zones, sector, p->partdev.fsector - 1, NULL, REP_EMPTY)) == NULL){ - goto err; - } - ++zones; - } - if((z = create_zobj(z, zones, p->partdev.fsector, p->partdev.lsector, p, L'\0')) == NULL){ - goto err; - } - ++zones; - sector = p->partdev.lsector + 1; - } - if(d->logsec && d->size){ - if(sector < d->size / d->logsec){ - if(sector < last_usable_sector(d) + 1){ - if((z = create_zobj(z, zones, sector, last_usable_sector(d), NULL, REP_EMPTY)) == NULL){ - goto err; - } - ++zones; - sector = last_usable_sector(d); - } - if(sector < d->size / d->logsec){ - if((z = create_zobj(z, zones, sector, d->size / d->logsec - 1, NULL, REP_METADATA)) == NULL){ - goto err; - } - ++zones; - sector = d->size / d->logsec; - } - } - } - b->zone = NULL; - free_zchain(&b->zchain); - firstchoice = NULL; - if(zonesel >= zones){ - zonesel = zones ? zones - 1 : 0; - } - if( (lastz = z) ){ - z->following = 0; - // If we hadn't selected one before, select the first - // empty space (where we can make a partition) - while(z->prev){ - if((zonesel == z->zoneno) || - (zonesel == -1 && !z->p && z->rep == REP_EMPTY)){ - b->zone = z; - }else if(z->zoneno){ - firstchoice = z; - } - z->prev->following = z->following + 1; - z = z->prev; - } - if((zonesel == z->zoneno) || (zonesel == -1 && !z->p && z->rep == REP_EMPTY)){ - b->zone = z; - } - z->prev = lastz; - lastz->next = z; - } - if(b->zone == NULL){ - if((b->zone = firstchoice) == NULL){ - b->zone = z; - } - } - b->zchain = z; - return; - -err: - while( (lastz = z) ){ - z = z->prev; - free(lastz); - } - assert(0); // FIXME -} - -static blockobj * -create_blockobj(device *d){ - blockobj *b; - - if( (b = malloc(sizeof(*b))) ){ - memset(b,0,sizeof(*b)); - b->d = d; - update_blockobj(b,d); - } - return b; -} - -static void * -block_callback(device *d,void *v){ - adapterstate *as; - blockobj *b; - - if(d->layout == LAYOUT_PARTITION){ - return NULL; // FIXME ought be an assert; this shouldn't happen - } - lock_ncurses_growlight(); -// fprintf(stderr, "---------begin block event on %s\n", d->name); - if((as = d->c->uistate) == NULL){ -// fprintf(stderr, "MAKE THAT INVISIBLE block event on %s\n!", d->name); - if((as = d->c->uistate = adapter_callback(d->c,NULL)) == NULL){ - return NULL; - } - } -// if(as->rb){ fprintf(stderr, "we're on line %d\n", as->rb->scrline); } - if((b = v) == NULL){ - if( (b = create_blockobj(d)) ){ - if(as->devs == 0){ - b->prev = b->next = NULL; - as->bobjs = b; - }else{ - b->next = as->bobjs; - b->prev = NULL; - as->bobjs->prev = b; - as->bobjs = b; - } - ++as->devs; - } - }else{ - update_blockobj(b,d); - } - if(as->rb){ - int old,oldrows; - - old = as->rb->selline; - oldrows = getmaxy(as->rb->win); -// fprintf(stderr, "into resize_adapter line %d hidden %d\n", as->rb->scrline, panel_hidden(as->rb->panel)); - resize_adapter(as->rb); -// fprintf(stderr, "into recompute_selection line %d hidden %d\n", as->rb->scrline, panel_hidden(as->rb->panel)); - recompute_selection(as,old,oldrows,getmaxy(as->rb->win)); - if(current_adapter == as->rb){ - if(b->prev == NULL && b->next == NULL){ - select_adapter(); - } - } -// fprintf(stderr, "into redraw_adapter line %d hidden %d\n", as->rb->scrline, panel_hidden(as->rb->panel)); - redraw_adapter(as->rb); - } -// fprintf(stderr, "---------end block event on %s\n", d->name); - unlock_ncurses_growlight(); - return b; -} - -static void -block_free(void *cv,void *bv){ - adapterstate *as = cv; - blockobj *bo = bv; - reelbox *rb; - - lock_ncurses_growlight(); - if( (rb = as->rb) ){ - if(bo == rb->selected){ - if(bo->prev){ - select_adapter_dev(rb,bo->prev,-1); - }else if(bo->next){ - select_adapter_dev(rb,bo->next,1); - }else{ - select_adapter_dev(rb,NULL,0); - } - } - } - free_zchain(&bo->zchain); - if(bo->prev){ - bo->prev->next = bo->next; - } - if(bo->next){ - bo->next->prev = bo->prev; - } - if(as->bobjs == bo){ - as->bobjs = bo->next; - } - --as->devs; - free(bo); - if(as->rb){ - int old,oldrows; - - old = as->rb->selline; - oldrows = getmaxy(rb->win); - resize_adapter(as->rb); - recompute_selection(as,old,oldrows,getmaxy(rb->win)); - redraw_adapter(as->rb); - } - unlock_ncurses_growlight(); -} - -static void -adapter_free(void *cv){ - adapterstate *as = cv; - reelbox *rb = rb; - - lock_ncurses_growlight(); - as->prev->next = as->next; - as->next->prev = as->prev; - if( (rb = as->rb) ){ - int delta = getmaxy(rb->win) + 1,scrrows,scrcols; - -// fprintf(stderr,"Removing iface at %d\n",rb->scrline); - assert(werase(rb->win) == OK); - assert(hide_panel(rb->panel) == OK); - getmaxyx(stdscr,scrrows,scrcols); - if(rb->next){ - rb->next->prev = rb->prev; - }else{ - last_reelbox = rb->prev; - } - if(rb->prev){ - rb->prev->next = rb->next; - }else{ - top_reelbox = rb->next; - } - as->next->prev = as->prev; - as->prev->next = as->next; - if(rb == current_adapter){ - // FIXME need do all the stuff we do in _next_/_prev_ - if((current_adapter = rb->next) == NULL){ - current_adapter = rb->prev; - } - pull_adapters_up(rb,scrrows,scrcols,delta); - // give the details window to new current_iface - if(details.p){ - if(current_adapter == NULL){ - hide_panel_locked(&details); - active = NULL; - } - } - }else if(rb->scrline > current_adapter->scrline){ - pull_adapters_up(rb,scrrows,scrcols,delta); - }else{ // pull them down; removed is above current_adapter - int ts; - - pull_adapters_down(rb,scrrows,scrcols,delta); - if( (ts = top_space_p(scrrows)) ){ - pull_adapters_up(NULL,scrrows,scrcols,ts); - } - } - free_reelbox(rb); - }else{ - as->next->prev = as->prev; - as->prev->next = as->next; - } - free_adapter_state(as); // clears subentries - --count_adapters; - draw_main_window(stdscr); // Update the device count - unlock_ncurses_growlight(); -} - -static void -vdiag(const char *fmt,va_list v){ - lock_ncurses_growlight(); - locked_vdiag(fmt,v); - unlock_ncurses_growlight(); -} - -static void -shutdown_cycle(void){ - struct panel_state *ps; - WINDOW *w = stdscr; - - diag("User-initiated shutdown\n"); - ps = show_splash(L"Shutting down..."); - if(growlight_stop()){ - kill_splash(ps); - ncurses_cleanup(&w); - dump_diags(); - exit(EXIT_FAILURE); - } - kill_splash(ps); - if(ncurses_cleanup(&w)){ - dump_diags(); - exit(EXIT_FAILURE); - } - exit(EXIT_SUCCESS); -}; - -static void raise_info_form(const char *str,const char *text){ - struct form_state *fs; - int lineguess; - WINDOW *fsw; - int cols; - int x,y; - - assert(str && text); - if(actform){ - locked_diag("An input dialog is already active"); - return; - } - if((fs = create_form(str,NULL,FORM_SPLASH_PROMPT,0)) == NULL){ - return; - } - fs->longop = strlen(str); - cols = fs->longop; // FIXME? 40 for input currently - getmaxyx(stdscr,y,x); - assert(x >= cols + 3); - assert(y >= 3); - // It could be more than this due to line breaking, so add a fudge - // factor of 2...FIXME - lineguess = 2; // yuck - lineguess += strlen(text) / (x - 2) + 1; - if((fsw = newwin(3,cols + START_COL * 2,FORM_Y_OFFSET + lineguess,x - cols - 3)) == NULL){ - locked_diag("Couldn't create form window, uh-oh"); - free_form(fs); - return; - } - if((fs->p = new_panel(fsw)) == NULL){ - locked_diag("Couldn't create form panel, uh-oh"); - delwin(fsw); - free_form(fs); - return; - } - assert(top_panel(fs->p) != ERR); - wattroff(fsw,A_BOLD); - wcolor_set(fsw,FORMBORDER_COLOR,NULL); - bevel(fsw); - wattron(fsw,A_BOLD); - mvwprintw(fsw,1,START_COL,"%-*.*s",cols,cols,str); - form_string_options(fs); - actform = fs; - fs->extext = raise_form_explication(stdscr,text,20); - form_colors(); - screen_update(); -} - -static void -boxinfo(const char *text,...){ - va_list v; - char *buf; - int max; - - max = BUFSIZ; - if((buf = malloc(max)) == NULL){ - lock_ncurses_growlight(); - locked_diag("Couldn't display boxinfo"); - unlock_ncurses_growlight(); - return; - } - va_start(v,text); - if(vsnprintf(buf,max,text,v) >= max){ - buf[max - 1] = '\0'; - } - lock_ncurses_growlight(); - raise_info_form("Press any key to continue...",buf); - unlock_ncurses_growlight(); - va_end(v); -} - -int main(int argc,char * const *argv){ - const glightui ui = { - .vdiag = vdiag, - .boxinfo = boxinfo, - .adapter_event = adapter_callback, - .block_event = block_callback, - .adapter_free = adapter_free, - .block_free = block_free, - }; - WINDOW *w; - struct panel_state *ps; - int showhelp = 1; - - if(setlocale(LC_ALL,"") == NULL){ - fprintf(stderr,"Warning: couldn't load locale\n"); - //return EXIT_FAILURE; - } - if((w = ncurses_setup()) == NULL){ - return EXIT_FAILURE; - } - ps = show_splash(L"Initializing..."); - if(growlight_init(argc,argv,&ui,&showhelp)){ - kill_splash(ps); - ncurses_cleanup(&w); - dump_diags(); - return EXIT_FAILURE; - } - lock_growlight(); - kill_splash(ps); - if(showhelp){ - toggle_panel(w,&help,display_help); - screen_update(); - } - unlock_growlight(); - handle_ncurses_input(w); - shutdown_cycle(); // calls exit() on all paths -} diff --git a/src/ncurses.h b/src/ncurses.h deleted file mode 100644 index 6b390b43..00000000 --- a/src/ncurses.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef GROWLIGHT_SRC_UI_NCURSES -#define GROWLIGHT_SRC_UI_NCURSES - -#ifdef __cplusplus -extern "C" { -#endif - -#include "config.h" - -#if defined(HAVE_NCURSESW_H) || defined(HAVE_NCURSESW) -#include -#include -#else -#ifdef HAVE_NCURSESW_CURSES_H -#include -#include -#else -#error "Couldn't find working cursesw headers" -#endif -#endif - -struct form_option; -struct panel_state; - -void locked_diag(const char *,...); - -// Scrolling single select form -void raise_form(const char *,void (*)(const char *),struct form_option *, - int,int,const char *); - -// Single-entry string entry form with command-line editing -void raise_str_form(const char *,void (*)(const char *), - const char *,const char *); - -// Multiselect form with side panel -void raise_multiform(const char *,void (*)(const char *,char **,int,int), - struct form_option *,int,int,int,char **,int,const char *,int); - -struct panel_state *show_splash(const wchar_t *); -void kill_splash(struct panel_state *); - -// get protection against bad arguments to mvwprintw()... -extern int mvwprintw(WINDOW *,int,int,const char *,...) - __attribute__ ((format (printf,4,5))); - -// get protection against bad arguments to wprintw()... -extern int wprintw(WINDOW *,const char *,...) - __attribute__ ((format (printf,2,3))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/ui-aggregate.c b/src/ui-aggregate.c deleted file mode 100644 index ab0b6177..00000000 --- a/src/ui-aggregate.c +++ /dev/null @@ -1,397 +0,0 @@ -#include -#include -#include - -#include "ncurses.h" -#include "growlight.h" -#include "aggregate.h" -#include "ui-aggregate.h" - -static const char AGGCOMP_TEXT[] = -"Bind devices to the new aggregate. To be eligible, a device must either be " -"unpartitioned, or be a partition having the appropriate component type. The " -"device furthermore must not have a valid filesystem signature."; - -static const char AGGTYPE_TEXT[] = -"What kind of aggregate do you hope to create?"; - -static const char AGGNAME_TEXT[] = -"The chosen name will be the primary means by which the system makes use of " -"this new aggregate, so choose wisely, and plan for the future!"; - -typedef enum { - FORM_SELECT, // form_option[] - FORM_STRING_INPUT, // form_input -} form_enum; - -struct form_option { - char *option; // option key (the string passed to cb) - char *desc; // longer description -}; - -struct form_input { - const char *prompt; // short prompt. currently aliases boxstr - char *longprompt; // longer prompt, not currently used - char *buffer; // input buffer, initialized to "" -}; - -struct form_state { - PANEL *p; - int ysize; // number of lines of *text* (not win) - void (*fxn)(const char *); // callback once form is done - int idx; // selection index, [0..ysize) - int longop; // length of longest op - char *boxstr; // string for box label - form_enum formtype; // type of form - union { - struct { - struct form_option *ops;// form_option array for *this instance* - int scrolloff; // scroll offset - int opcount; // total number of ops - }; - struct form_input inp; // form_input state for this instance - }; -}; - -static char *pending_aggname; -static char *pending_aggtype; - -static void -destroy_agg_forms(void){ - free(pending_aggtype); - pending_aggtype = NULL; - free(pending_aggname); - pending_aggname = NULL; -} - -static struct form_option * -agg_table(int *count,const char *match,int *defidx){ - const aggregate_type *types; - struct form_option *fo; - int z; - - *defidx = -1; - if((types = get_aggregate_types(count)) == NULL){ - return NULL; - } - if((fo = malloc(sizeof(*fo) * *count)) == NULL){ - return NULL; - } - for(z = 0 ; z < *count ; ++z){ - char *key,*desc; - - if((key = strdup(types[z].name)) == NULL){ - goto err; - } - if(match){ - if(strcmp(key,match) == 0){ - *defidx = z; - } - }else{ - if(aggregate_default_p(key)){ - *defidx = z; - } - } - if((desc = strdup(types[z].desc)) == NULL){ - free(key); - goto err; - } - fo[z].option = key; - fo[z].desc = desc; - } - return fo; - -err: - while(z--){ - free(fo[z].option); - free(fo[z].desc); - } - free(fo); - *count = 0; - return NULL; -} - -// On success, we must free input desc (hence it not being const) -static char * -prefix_desc_with_size(const device *d,char *desc){ - char s[BPREFIXSTRLEN],*uni; - size_t sz; - - bprefix(d->size, 1, s, 1); - // Might be a bit overspacious due to full BPREFIXSTRLEN, but who cares - sz = (sizeof(s) / sizeof(*s)) + strlen(desc) + 5; // '(' 'B' ')' ' ' '\0' - if((uni = malloc(sz)) == NULL){ - return NULL; - } - if((unsigned)snprintf(uni,sz,"("BPREFIXFMT"B) %s",s,desc) >= sz){ - free(uni); - return NULL; - } - free(desc); - return uni; -} - -static struct form_option * -grow_component_table(const device *d,int *count,const char *match,int *defidx, - char ***selarray,int *selections,struct form_option *fo){ - struct form_option *tmp; - char *key,*desc; - int z; - - if((key = strdup(d->name)) == NULL){ - return NULL; - } - if(match){ - if(strcmp(key,match) == 0){ - *defidx = *count; - for(z = 0 ; z < *selections ; ++z){ - if(strcmp(key,(*selarray)[z]) == 0){ - free((*selarray)[z]); - (*selarray)[z] = NULL; - if(z < *selections - 1){ - memmove(&(*selarray)[z],&(*selarray)[z + 1],sizeof(**selarray) * (*selections - 1 - z)); - } - --*selections; - z = -1; - break; - } - } - if(z >= *selections){ - typeof(*selarray) stmp; - - if((stmp = realloc(*selarray,sizeof(**selarray) * (*selections + 1))) == NULL){ - free(key); - return NULL; - } - *selarray = stmp; - (*selarray)[*selections] = strdup(match); - ++*selections; - } - } - } - if((desc = strdup(d->bypath ? d->bypath : - d->byid ? d->byid : - (d->layout == LAYOUT_NONE && d->blkdev.serial) ? - d->blkdev.serial : - d->name)) == NULL){ - free(key); - return NULL; - } - if((desc = prefix_desc_with_size(d,desc)) == NULL){ // free()s old desc - free(key); - free(desc); - return NULL; - } - if((tmp = realloc(fo,sizeof(*fo) * (*count + 1))) == NULL){ - free(key); - free(desc); - return NULL; - } - fo = tmp; - for(z = 0 ; z < *count ; ++z){ - if(strcmp(desc,fo[z].desc) > 0){ - memmove(&fo[z + 1],&fo[z],sizeof(*fo) * (*count - z)); - break; - } - } - fo[z].option = key; - fo[z].desc = desc; - ++*count; - return fo; -} - -static struct form_option * -component_table(const aggregate_type *at,int *count,const char *match,int *defidx, - char ***selarray,int *selections){ - struct form_option *fo = NULL,*tmp; - const controller *c; - - *count = 0; - *defidx = -1; - for(c = get_controllers() ; c ; c = c->next){ - const device *d; - - for(d = c->blockdevs ; d ; d = d->next){ - const device *p; - - if(device_aggregablep(d)){ - if((tmp = grow_component_table(d,count,match,defidx,selarray,selections,fo)) == NULL){ - goto err; - } - fo = tmp; - } - for(p = d->parts ; p ; p = p->next){ - if(device_aggregablep(p)){ - if((tmp = grow_component_table(p,count,match,defidx,selarray,selections,fo)) == NULL){ - goto err; - } - fo = tmp; - } - } - } - } - if(at->maxfaulted){ - device fauxd; - - memset(&fauxd,0,sizeof(fauxd)); - strncpy(fauxd.name,"missing",sizeof(fauxd.name)); - fauxd.bypath = "force construction of degraded array"; - if((tmp = grow_component_table(&fauxd,count,match,defidx,selarray,selections,fo)) == NULL){ - goto err; - } - fo = tmp; - } - *defidx = *count ? (*defidx + 1) % *count : -1; - return fo; - -err: - // FIXME free up selarray? - while(*count--){ - free(fo[*count].option); - free(fo[*count].desc); - } - free(fo); - return NULL; -} - -static void agg_callback(const char *); -static void aggname_callback(const char *); - -static void -do_agg(const aggregate_type *at,char * const *selarray,int selections){ - struct panel_state *ps; - int r; - - if(at->makeagg == NULL){ - locked_diag("FIXME %s creation is not yet implemented",pending_aggtype); - return; - } - - ps = show_splash(L"Creating aggregate..."); - r = at->makeagg(pending_aggname,selarray,selections); - if(ps){ - kill_splash(ps); - } - if(r == 0){ - locked_diag("Successfully created %s",pending_aggtype); - } -} - -static void -aggcomp_callback(const char *fn,char **selarray,int selections,int scrollp){ - struct form_option *comps_agg; - const aggregate_type *at; - int opcount,defidx; - - assert(selections >= 0); - if(fn == NULL){ - raise_str_form("enter aggregate name",aggname_callback, - pending_aggname,AGGNAME_TEXT); - return; - } - if((at = get_aggregate(pending_aggtype)) == NULL){ - destroy_agg_forms(); - return; - } - if(strcmp(fn,"") == 0){ - if((unsigned)selections >= at->mindisks){ - do_agg(at,selarray,selections); - destroy_agg_forms(); - return; - } - } - if((comps_agg = component_table(at,&opcount,fn,&defidx,&selarray,&selections)) == NULL){ - struct form_option *ops_agg; - - if( (ops_agg = agg_table(&opcount,pending_aggtype,&defidx)) ){ - raise_form("select an aggregate type",agg_callback,ops_agg, - opcount,defidx,AGGTYPE_TEXT); - }else{ - destroy_agg_forms(); - } - locked_diag("insufficiently many available devices for %s",pending_aggtype); - return; - } - raise_multiform("select aggregate components",aggcomp_callback,comps_agg, - opcount,defidx,at->mindisks,selarray,selections,AGGCOMP_TEXT,scrollp); - if((unsigned)selections < at->mindisks){ - locked_diag("%s needs at least %d devices",pending_aggtype,at->mindisks); - }else{ - locked_diag("%s device requirement (%d) satisfied",pending_aggtype,at->mindisks); - } -} - -static void -aggname_callback(const char *fn){ - struct form_option *comps_agg; - const aggregate_type *at; - int selections = 0; - int opcount,defidx; - char **selarray; - - if(fn == NULL){ - struct form_option *ops_agg; - - if( (ops_agg = agg_table(&opcount,pending_aggtype,&defidx)) ){ - raise_form("select an aggregate type",agg_callback,ops_agg, - opcount,defidx,AGGTYPE_TEXT); - } - return; - } - if((pending_aggname = strdup(fn)) == NULL){ - destroy_agg_forms(); - return; - } - if((at = get_aggregate(pending_aggtype)) == NULL){ - destroy_agg_forms(); - return; - } - selarray = NULL; - if((comps_agg = component_table(at,&opcount,NULL,&defidx,&selarray,&selections)) == NULL){ - struct form_option *ops_agg; - - if( (ops_agg = agg_table(&opcount,pending_aggtype,&defidx)) ){ - raise_form("select an aggregate type",agg_callback,ops_agg, - opcount,defidx,AGGTYPE_TEXT); - }else{ - destroy_agg_forms(); - } - locked_diag("insufficiently many available devices for %s",pending_aggtype); - return; - } - raise_multiform("select aggregate components",aggcomp_callback,comps_agg, - opcount,defidx,at->mindisks,selarray,selections,AGGCOMP_TEXT,0); -} - -static void -agg_callback(const char *fn){ - const aggregate_type *at; - - if(fn == NULL){ - locked_diag("aggregate creation was cancelled"); - return; - } - if((at = get_aggregate(fn)) == NULL){ - destroy_agg_forms(); - return; - } - if((pending_aggtype = strdup(fn)) == NULL){ - destroy_agg_forms(); - return; - } - raise_str_form("enter aggregate name",aggname_callback,at->defname, - AGGNAME_TEXT); -} - -int raise_aggregate_form(void){ - struct form_option *ops_agg; - int opcount,defidx; - - if((ops_agg = agg_table(&opcount,pending_aggtype,&defidx)) == NULL){ - destroy_agg_forms(); - return -1; - } - raise_form("select an aggregate type",agg_callback,ops_agg,opcount, - defidx,AGGTYPE_TEXT); - return 0; -} diff --git a/src/ui-aggregate.h b/src/ui-aggregate.h deleted file mode 100644 index 88edde18..00000000 --- a/src/ui-aggregate.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef GROWLIGHT_SRC_UI_AGGREGATE -#define GROWLIGHT_SRC_UI_AGGREGATE - -#ifdef __cplusplus -extern "C" { -#endif - -int raise_aggregate_form(void); - -#ifdef __cplusplus -} -#endif - -#endif From c421c48ee6506182014675a736615fd7a0637281 Mon Sep 17 00:00:00 2001 From: nick black Date: Fri, 10 Apr 2020 14:15:08 -0400 Subject: [PATCH 09/30] notcurses: adapt to 1.2.7 --- configure.ac | 2 +- src/notcurses.c | 4 ++-- src/notui-aggregate.c | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index b6593384..0fe4f937 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ AC_CHECK_LIB(pci, pci_get_dev, [have_libpci=yes], LIBS+=" -lpci" if test "x$notcurses" = "xtrue" ; then - PKG_CHECK_MODULES([notcurses], [notcurses >= 1.2.1]) + PKG_CHECK_MODULES([notcurses], [notcurses >= 1.2.7]) notcurses_CFLAGS+=" $notcurses_CFLAGS" notcurses_LIBS+=" $notcurses_LIBS" fi diff --git a/src/notcurses.c b/src/notcurses.c index e461ba3e..125aa3ff 100644 --- a/src/notcurses.c +++ b/src/notcurses.c @@ -4994,7 +4994,7 @@ handle_actform_input(wchar_t ch){ switch(ch){ case 12: // CTRL+L FIXME lock_notcurses(); - notcurses_refresh(NC); + notcurses_refresh(NC, NULL, NULL); unlock_notcurses(); break; case ' ': case '\r': case '\n': case NCKEY_ENTER:{ @@ -5279,7 +5279,7 @@ handle_ncurses_input(struct ncplane* w){ while((ch = notcurses_getc_blocking(NC, &ni)) != (char32_t)-1){ if(ch == 12){ // CTRL+L FIXME lock_notcurses(); - notcurses_refresh(NC); + notcurses_refresh(NC, NULL, NULL); unlock_notcurses(); continue; } diff --git a/src/notui-aggregate.c b/src/notui-aggregate.c index 02d77343..95be4a3b 100644 --- a/src/notui-aggregate.c +++ b/src/notui-aggregate.c @@ -385,13 +385,12 @@ agg_callback(const char *fn){ int raise_aggregate_form(void){ struct form_option *ops_agg; - int opcount,defidx; + int opcount, defidx; - if((ops_agg = agg_table(&opcount,pending_aggtype,&defidx)) == NULL){ + if((ops_agg = agg_table(&opcount, pending_aggtype, &defidx)) == NULL){ destroy_agg_forms(); return -1; } - raise_form("select an aggregate type",agg_callback,ops_agg,opcount, - defidx,AGGTYPE_TEXT); + raise_form("select an aggregate type", agg_callback, ops_agg, opcount, defidx, AGGTYPE_TEXT); return 0; } From eccb4eaa5eef724ffe2e94d1f6fbde67e7b26cac Mon Sep 17 00:00:00 2001 From: nick black Date: Fri, 10 Apr 2020 15:39:16 -0400 Subject: [PATCH 10/30] prep for 1.2.3, bump notcurses dep to 1.2.7 --- README.md | 5 +++-- configure.ac | 2 +- debian/changelog | 4 ++-- debian/control | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a4f991a5..3a36c24c 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ https://nick-black.com/dankwiki/index.php/Growlight Dependencies: - - notcurses 1.1.6+ + - notcurses 1.2.7+ - libudev 175+ - - libblkid 2.20.1+ + - libblkid 2.20.1 + - libpci 3.1.9+ - libpciaccess 0.13.1+ - libdevmapper 1.02.74+ diff --git a/configure.ac b/configure.ac index 0fe4f937..812edcba 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.61]) -AC_INIT([growlight], [1.2.2], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) +AC_INIT([growlight], [1.2.3], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([-Wall foreign dist-xz no-dist-gzip std-options subdir-objects nostdinc]) AC_CONFIG_HEADER([src/config.h]) diff --git a/debian/changelog b/debian/changelog index 8c6580f0..f77c0a94 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ -growlight (1.2.2-1) unstable; urgency=medium +growlight (1.2.3-1) unstable; urgency=medium * Debian policy 4.5.0 * Update copyrights - -- Nick Black Thu, 20 Feb 2020 06:12:54 -0500 + -- Nick Black Fri, 10 Apr 2020 15:31:59 -0400 diff --git a/debian/control b/debian/control index f91dfd91..034eb0a9 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Build-Depends: libcryptsetup-dev, libcunit1-ncurses-dev, libdevmapper-dev, - libnotcurses-dev (>= 1.2.1), + libnotcurses-dev (>= 1.2.7), libpci-dev, libpciaccess-dev, libreadline-dev, From 8e3268e85c519683cfa1446266fe02c829ebfce8 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 18 Apr 2020 04:26:49 -0400 Subject: [PATCH 11/30] drone: don't update debian installs --- .drone.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 61c00b12..705294e5 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,12 +5,10 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-02-17a + image: dankamongmen/unstable_builder:2020-04-18a commands: - apt-get update - - apt-get -y install devscripts git-buildpackage - export LANG=en_US.UTF-8 - - mk-build-deps --install -t'apt-get -y' - autoreconf -fis - ./configure - make @@ -22,11 +20,9 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-02-17a + image: dankamongmen/focal:2020-04-05a commands: - apt-get update - - apt-get -y install devscripts git-buildpackage equivs - - mk-build-deps --install -t'apt-get -y' - export LANG=en_US.UTF-8 - autoreconf -fis - ./configure From 169ca357862c6260f2b79b736662f00f8ec88e00 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 18 Apr 2020 04:57:07 -0400 Subject: [PATCH 12/30] drone: use new builders --- .drone.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 705294e5..8c3c0afb 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-04-18a + image: dankamongmen/unstable_builder:2020-04-18c commands: - apt-get update - export LANG=en_US.UTF-8 @@ -20,7 +20,7 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-04-05a + image: dankamongmen/focal:2020-04-18b commands: - apt-get update - export LANG=en_US.UTF-8 From 3b27419c5300d4104fc0deb5489553709f9bea27 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 18 Apr 2020 05:02:14 -0400 Subject: [PATCH 13/30] drone: use newest builders --- .drone.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.drone.yml b/.drone.yml index 8c3c0afb..df121291 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,9 +5,8 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-04-18c + image: dankamongmen/unstable_builder:2020-04-18e commands: - - apt-get update - export LANG=en_US.UTF-8 - autoreconf -fis - ./configure @@ -20,10 +19,10 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-04-18b + image: dankamongmen/focal:2020-04-18c commands: - - apt-get update - export LANG=en_US.UTF-8 + - DEBIAN_FRONTEND=noninteractive apt-get --yes install autoconf-archive xsltproc - autoreconf -fis - ./configure - make From b7bb4f7e6bea2d6fb2b4aa9818e941267ff15787 Mon Sep 17 00:00:00 2001 From: nick black Date: Tue, 21 Apr 2020 02:51:19 -0400 Subject: [PATCH 14/30] drone: use newest builders --- .drone.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.drone.yml b/.drone.yml index df121291..c6a00c7c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-04-18e + image: dankamongmen/unstable_builder:2020-04-20a commands: - export LANG=en_US.UTF-8 - autoreconf -fis @@ -19,10 +19,9 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-04-18c + image: dankamongmen/focal:2020-04-20a commands: - export LANG=en_US.UTF-8 - - DEBIAN_FRONTEND=noninteractive apt-get --yes install autoconf-archive xsltproc - autoreconf -fis - ./configure - make From 629273a78a4a49e7d508d207c2c14362a0da08ca Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 22 Apr 2020 15:09:09 -0400 Subject: [PATCH 15/30] Adapt to notcurses 1.3.2 --- README.md | 2 +- configure.ac | 2 +- debian/control | 2 +- src/notcurses.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3a36c24c..3891d280 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ https://nick-black.com/dankwiki/index.php/Growlight Dependencies: - - notcurses 1.2.7+ + - notcurses 1.3.2+ - libudev 175+ - libblkid 2.20.1 diff --git a/configure.ac b/configure.ac index 812edcba..8b939f2b 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ AC_CHECK_LIB(pci, pci_get_dev, [have_libpci=yes], LIBS+=" -lpci" if test "x$notcurses" = "xtrue" ; then - PKG_CHECK_MODULES([notcurses], [notcurses >= 1.2.7]) + PKG_CHECK_MODULES([notcurses], [notcurses >= 1.3.2]) notcurses_CFLAGS+=" $notcurses_CFLAGS" notcurses_LIBS+=" $notcurses_LIBS" fi diff --git a/debian/control b/debian/control index 034eb0a9..f62d6eb1 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Build-Depends: libcryptsetup-dev, libcunit1-ncurses-dev, libdevmapper-dev, - libnotcurses-dev (>= 1.2.7), + libnotcurses-dev (>= 1.3.2), libpci-dev, libpciaccess-dev, libreadline-dev, diff --git a/src/notcurses.c b/src/notcurses.c index 125aa3ff..2e417e39 100644 --- a/src/notcurses.c +++ b/src/notcurses.c @@ -741,7 +741,7 @@ cwprintw(struct ncplane* n, const char* fmt, ...){ static int cwbkgd(struct ncplane* nc){ - return ncplane_set_base(nc, 0, 0, " "); + return ncplane_set_base(nc, " ", 0, 0); } static void From af635ce05c5611060d5f25b501b29754ddf3e50c Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 22 Apr 2020 15:09:46 -0400 Subject: [PATCH 16/30] prep for 1.2.4 --- configure.ac | 2 +- debian/changelog | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 8b939f2b..dfe0d327 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.61]) -AC_INIT([growlight], [1.2.3], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) +AC_INIT([growlight], [1.2.4], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([-Wall foreign dist-xz no-dist-gzip std-options subdir-objects nostdinc]) AC_CONFIG_HEADER([src/config.h]) diff --git a/debian/changelog b/debian/changelog index f77c0a94..eab68518 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -growlight (1.2.3-1) unstable; urgency=medium +growlight (1.2.4-1) unstable; urgency=medium * Debian policy 4.5.0 * Update copyrights From 8634be84c4d1a9ea8a6ce6d96bf313b407574d05 Mon Sep 17 00:00:00 2001 From: nick black Date: Fri, 24 Apr 2020 05:04:00 -0400 Subject: [PATCH 17/30] remove unused cunit dep --- Makefile.am | 7 ------- README.md | 1 - configure.ac | 3 --- debian/control | 1 - test/growlight.c | 39 --------------------------------------- 5 files changed, 51 deletions(-) delete mode 100644 test/growlight.c diff --git a/Makefile.am b/Makefile.am index 3e34c70f..a51065b4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,9 +26,6 @@ AM_CPPFLAGS=-D_GNU_SOURCE bin_PROGRAMS=growlight-readline bin_PROGRAMS+=growlight -bin_PROGRAMS+=growlight-test - -TESTS=growlight-test common_SOURCES=src/growlight.c src/growlight.h src/mbr.c src/mbr.h \ src/libblkid.c src/libblkid.h src/apm.c src/apm.h src/ssd.h src/ssd.c \ @@ -51,10 +48,6 @@ growlight_SOURCES=$(common_SOURCES) growlight_SOURCES+=src/notcurses.c src/notcurses.h src/notui-aggregate.h src/notui-aggregate.c growlight_LDADD=@notcurses_LIBS@ -growlight_test_SOURCES=$(common_SOURCES) -growlight_test_SOURCES+=test/growlight.c -growlight_test_LDADD=$(CUNIT_LIBS) - #XSLTARGS=--nonet /usr/share/xml/docbook/stylesheet/docbook-xsl XSLTARGS=http://docbook.sourceforge.net/release/xsl/current diff --git a/README.md b/README.md index 3a36c24c..16b9cdc1 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ Build-only dependencies: - docbook-xsl (tested with 4.5) - autotools (tested with 1.11) - pkg-config (tested with 0.29) - - cunit (tested with 2.1) - autoconf-archive (tested with 2018+) Building from a git checkout: diff --git a/configure.ac b/configure.ac index 812edcba..968a096d 100644 --- a/configure.ac +++ b/configure.ac @@ -73,9 +73,6 @@ AX_LIB_READLINE AC_CHECK_LIB([readline], [main], [have_readline=yes], [AC_MSG_ERROR([Cannot find libreadline.])]) -# CUnit (unit testing) -PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes]) - # Remaining dependencies are needed by all binaries. AC_CHECK_LIB(pciaccess, pci_system_init, [have_pciaccess=yes], [AC_MSG_ERROR([Cannot find libpciaccess.])]) diff --git a/debian/control b/debian/control index 034eb0a9..bd3527c5 100644 --- a/debian/control +++ b/debian/control @@ -8,7 +8,6 @@ Build-Depends: libatasmart-dev, libblkid-dev, libcryptsetup-dev, - libcunit1-ncurses-dev, libdevmapper-dev, libnotcurses-dev (>= 1.2.7), libpci-dev, diff --git a/test/growlight.c b/test/growlight.c deleted file mode 100644 index 01eba32f..00000000 --- a/test/growlight.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -static int -init_suite(void) { - return 0; -} - -static int -clean_suite(void) { - return 0; -} - -int main() { - unsigned failures; - CU_pSuite suite; - if(CUE_SUCCESS != CU_initialize_registry()){ - fprintf(stderr, "Couldn't initialize CUnit (%d)\n", CU_get_error()); - exit(EXIT_FAILURE); - } - if((suite = CU_add_suite(__FILE__, init_suite, clean_suite)) == NULL){ - fprintf(stderr, "Couldn't add CUnit suite %s (%d)\n", - __FILE__, CU_get_error()); - exit(EXIT_FAILURE); - } - CU_basic_set_mode(CU_BRM_VERBOSE); - if(CU_basic_run_tests()){ - fprintf(stderr, "Error %d running CUnit tests\n", CU_get_error()); - exit(EXIT_FAILURE); - } - failures = CU_get_number_of_failures(); - if(failures){ - fprintf(stderr, "Returning %d after %u test failure\n", - EXIT_FAILURE, failures); - exit(EXIT_FAILURE); - } - CU_cleanup_registry(); - return CU_get_error(); -} From e0144b680e2650760ba8b18d093ea5bb2c8c682e Mon Sep 17 00:00:00 2001 From: nick black Date: Fri, 24 Apr 2020 05:06:57 -0400 Subject: [PATCH 18/30] drone: purge 'make test' --- .drone.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index c6a00c7c..31c21b67 100644 --- a/.drone.yml +++ b/.drone.yml @@ -11,7 +11,6 @@ steps: - autoreconf -fis - ./configure - make - - make test --- kind: pipeline type: docker @@ -25,4 +24,3 @@ steps: - autoreconf -fis - ./configure - make - - make test From 505a3e43c6309e3fc66a9c16d171b7f538ec1b4c Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 29 Apr 2020 03:35:07 -0400 Subject: [PATCH 19/30] drone: newest unstable_builder --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 31c21b67..f1db38e6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-04-20a + image: dankamongmen/unstable_builder:2020-04-29a commands: - export LANG=en_US.UTF-8 - autoreconf -fis From e0436ec445378f85470a9ae5654286d6ab82f34b Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 13 May 2020 10:52:38 -0400 Subject: [PATCH 20/30] ui: use PREFIXCOLUMNS from notcurses --- README.md | 2 +- debian/control | 2 +- src/notcurses.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1f3002c4..34672092 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ https://nick-black.com/dankwiki/index.php/Growlight Dependencies: - - notcurses 1.3.2+ + - notcurses 1.4.2+ - libudev 175+ - libblkid 2.20.1 diff --git a/debian/control b/debian/control index 462a5bc8..f9fe4df1 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Build-Depends: libblkid-dev, libcryptsetup-dev, libdevmapper-dev, - libnotcurses-dev (>= 1.3.2), + libnotcurses-dev (>= 1.4.2), libpci-dev, libpciaccess-dev, libreadline-dev, diff --git a/src/notcurses.c b/src/notcurses.c index 2e417e39..41abe7e4 100644 --- a/src/notcurses.c +++ b/src/notcurses.c @@ -3627,8 +3627,8 @@ detail_mounts(struct ncplane* w, int* row, int maxy, const device* d){ d->mnttype, d->uuid ? d->uuid : "n/a", qprefix(d->mntsize, 1, buf, 0), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), + cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), + cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), d->name); if(++*row == maxy){ return; @@ -3664,8 +3664,8 @@ detail_targets(struct ncplane* w, int* row, int both, const device* d){ d->mnttype, d->uuid ? d->uuid : "n/a", qprefix(d->mntsize, 1, buf, 0), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), - cols - (FSLABELSIZ + 47 + PREFIXSTRLEN), + cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), + cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), d->name); ++*row; if(!both){ From cd44ea31e45d7015d58192f79869b620a53d0ed9 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 13 May 2020 11:05:03 -0400 Subject: [PATCH 21/30] configure.ac: require notcurses 1.4.3 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f7794241..21f38402 100644 --- a/configure.ac +++ b/configure.ac @@ -83,7 +83,7 @@ AC_CHECK_LIB(pci, pci_get_dev, [have_libpci=yes], LIBS+=" -lpci" if test "x$notcurses" = "xtrue" ; then - PKG_CHECK_MODULES([notcurses], [notcurses >= 1.3.2]) + PKG_CHECK_MODULES([notcurses], [notcurses >= 1.4.2]) notcurses_CFLAGS+=" $notcurses_CFLAGS" notcurses_LIBS+=" $notcurses_LIBS" fi From 1287b8063ed47a06ae3177bfc8bf2af521bd53f4 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 23 May 2020 18:50:30 -0400 Subject: [PATCH 22/30] drone: update to new builders --- .drone.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index f1db38e6..ea5f3d42 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-04-29a + image: dankamongmen/unstable_builder:2020-05-23a commands: - export LANG=en_US.UTF-8 - autoreconf -fis @@ -18,7 +18,7 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-04-20a + image: dankamongmen/focal:2020-05-23a commands: - export LANG=en_US.UTF-8 - autoreconf -fis From 60c53fc0f42ed38825905b46f9cb5fb80711257f Mon Sep 17 00:00:00 2001 From: Nick Black Date: Sun, 24 May 2020 14:40:03 -0400 Subject: [PATCH 23/30] Build on newest drone dockers (#80) * drone: focal/debian new builder --- .drone.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index ea5f3d42..b9580bb4 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-05-23a + image: dankamongmen/unstable_builder:2020-05-23b commands: - export LANG=en_US.UTF-8 - autoreconf -fis @@ -18,7 +18,7 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-05-23a + image: dankamongmen/focal:2020-05-23b commands: - export LANG=en_US.UTF-8 - autoreconf -fis From d22cbcc638603ed7014d9b22251547d271d6a7e7 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 27 May 2020 11:41:28 -0400 Subject: [PATCH 24/30] readline: update to new ncmetric() from notcurses 1.4.3 --- configure.ac | 2 +- debian/control | 2 +- src/readline.c | 122 +++++++++++++++++++++++++------------------------ 3 files changed, 65 insertions(+), 61 deletions(-) diff --git a/configure.ac b/configure.ac index 21f38402..ad8b7026 100644 --- a/configure.ac +++ b/configure.ac @@ -83,7 +83,7 @@ AC_CHECK_LIB(pci, pci_get_dev, [have_libpci=yes], LIBS+=" -lpci" if test "x$notcurses" = "xtrue" ; then - PKG_CHECK_MODULES([notcurses], [notcurses >= 1.4.2]) + PKG_CHECK_MODULES([notcurses], [notcurses >= 1.4.3]) notcurses_CFLAGS+=" $notcurses_CFLAGS" notcurses_LIBS+=" $notcurses_LIBS" fi diff --git a/debian/control b/debian/control index f9fe4df1..e2d6deee 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Build-Depends: libblkid-dev, libcryptsetup-dev, libdevmapper-dev, - libnotcurses-dev (>= 1.4.2), + libnotcurses-dev (>= 1.4.3), libpci-dev, libpciaccess-dev, libreadline-dev, diff --git a/src/readline.c b/src/readline.c index 1856c8f3..2ea8d0c4 100644 --- a/src/readline.c +++ b/src/readline.c @@ -272,16 +272,15 @@ static int print_dev_mplex(const device *,int,int); static int print_mounts(const device *d){ char buf[PREFIXSTRLEN + 1]; - int r = 0,rr; + int r = 0, rr; unsigned z; for(z = 0 ; z < d->mnt.count ; ++z){ - r += rr = printf("%-*.*s %-5.5s %-36.36s %-6.6s " PREFIXFMT "\n %s %s\n", + const char *size = d->mntsize ? qprefix(d->mntsize, 1, buf, 0) : ""; + r += rr = printf("%-*.*s %-5.5s %-36.36s %-6.6s %*s\n %s %s\n", FSLABELSIZ,FSLABELSIZ,d->label ? d->label : "n/a", - d->mnttype, - d->uuid ? d->uuid : "n/a", d->name, - d->mntsize ? qprefix(d->mntsize,1,buf,0) : "", - d->mnt.list[z],d->mntops.list[z]); + d->mnttype, d->uuid ? d->uuid : "n/a", d->name, + PREFIXFMT(size), d->mnt.list[z], d->mntops.list[z]); if(rr < 0){ return -1; } @@ -292,15 +291,14 @@ print_mounts(const device *d){ static int print_swap(const device *p){ char buf[PREFIXSTRLEN + 1]; - int r = 0,rr; + int r = 0, rr; assert(p->mnttype); - r += rr = printf("%-*.*s %-5.5s %-36.36s %-6.6s " PREFIXFMT, + qprefix(p->mntsize, 1, buf, 0), + r += rr = printf("%-*.*s %-5.5s %-36.36s %-6.6s %*s", FSLABELSIZ,FSLABELSIZ,p->label ? p->label : "n/a", - p->mnttype, - p->uuid ? p->uuid : "n/a", - qprefix(p->mntsize,1,buf,0), - p->name); + p->mnttype, p->uuid ? p->uuid : "n/a", + p->name, PREFIXFMT(buf)); if(rr < 0){ return -1; } @@ -364,10 +362,11 @@ print_partition(const device *p, int descend){ int r = 0, rr; use_terminfo_color(COLOR_BLUE, 1); - r += rr = printf("%-10.10s %-36.36s " PREFIXFMT " %-3.3s %ls\n", + qprefix(p->size, 1, buf, 0); + r += rr = printf("%-10.10s %-36.36s %*s %-3.3s %ls\n", p->name, p->partdev.uuid ? p->partdev.uuid : "n/a", - qprefix(p->size, 1, buf, 0), + PREFIXFMT(buf), partrole_str(p->partdev.ptype, p->partdev.flags), p->partdev.pname ? p->partdev.pname : L"n/a"); if(rr < 0){ @@ -431,11 +430,12 @@ print_drive(const device *d,int descend){ }else{ use_terminfo_color(COLOR_MAGENTA,1); // virtual } - r += rr = printf("%-10.10s %-16.16s %4.4s " PREFIXFMT " %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", + qprefix(d->size, 1, buf, 0); + r += rr = printf("%-10.10s %-16.16s %4.4s %*s %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", d->name, d->model ? d->model : "n/a", d->revision ? d->revision : "n/a", - qprefix(d->size,1,buf,0), + PREFIXFMT(buf), d->physsec, d->blkdev.unloaded ? L'U' : d->blkdev.removable ? L'R' : @@ -456,12 +456,13 @@ print_drive(const device *d,int descend){ ); break; }case LAYOUT_MDADM:{ - use_terminfo_color(COLOR_YELLOW,1); - r += rr = printf("%-10.10s %-16.16s %4.4s " PREFIXFMT " %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", + use_terminfo_color(COLOR_YELLOW, 1); + qprefix(d->size, 1, buf, 0); + r += rr = printf("%-10.10s %-16.16s %4.4s %*s %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", d->name, d->model ? d->model : "n/a", d->revision ? d->revision : "n/a", - qprefix(d->size,1,buf,0), + PREFIXFMT(buf), d->physsec, L'V', L'M', L'.', d->roflag ? L'r' : L'.', L'.', d->mddev.pttable ? d->mddev.pttable : "none", @@ -470,12 +471,13 @@ print_drive(const device *d,int descend){ ); break; }case LAYOUT_DM:{ - use_terminfo_color(COLOR_YELLOW,1); - r += rr = printf("%-10.10s %-16.16s %4.4s " PREFIXFMT " %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", + use_terminfo_color(COLOR_YELLOW, 1); + qprefix(d->size, 1, buf, 0); + r += rr = printf("%-10.10s %-16.16s %4.4s %*s %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", d->name, d->model ? d->model : "n/a", d->revision ? d->revision : "n/a", - qprefix(d->size,1,buf,0), + PREFIXFMT(buf), d->physsec, L'V', L'D', L'.', d->roflag ? L'r' : L'.', L'.', "n/a", @@ -484,12 +486,13 @@ print_drive(const device *d,int descend){ ); break; }case LAYOUT_ZPOOL:{ - use_terminfo_color(COLOR_RED,1); - r += rr = printf("%-10.10s %-16.16s %4ju " PREFIXFMT " %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", + use_terminfo_color(COLOR_RED, 1); + qprefix(d->size, 1, buf, 0); + r += rr = printf("%-10.10s %-16.16s %4ju %*s %4uB %lc%lc%lc%lc%lc %-6.6s%-16.16s %-4.4s\n", d->name, d->model ? d->model : "n/a", (uintmax_t)d->zpool.zpoolver, - qprefix(d->size,1,buf,0), + PREFIXFMT(buf), d->physsec, L'V', L'Z', L'.', d->roflag ? L'r' : L'.', L'.', "spa", @@ -548,11 +551,11 @@ print_zpool(const device *d,int descend){ if(d->layout != LAYOUT_ZPOOL){ return 0; } - r += rr = printf("%-10.10s %-36.36s " PREFIXFMT " %4uB ZFS%2ju %5lu %-6.6s\n", + qprefix(d->size, 1, buf, 0); + r += rr = printf("%-10.10s %-36.36s %*s %4uB ZFS%2ju %5lu %-6.6s\n", d->name, d->uuid ? d->uuid : "n/a", - qprefix(d->size,1,buf,0), - d->physsec, d->zpool.zpoolver, + PREFIXFMT(buf), d->physsec, d->zpool.zpoolver, d->zpool.disks,d->zpool.level ? d->zpool.level : "n/a" ); if(rr < 0){ @@ -574,12 +577,12 @@ print_dm(const device *d,int prefix,int descend){ return 0; } use_terminfo_color(COLOR_YELLOW,1); - r += rr = printf("%-*.*s%-10.10s %-36.36s " PREFIXFMT " %4uB %-6.6s%5lu %-6.6s\n", + qprefix(d->size, 1, buf, 0); + r += rr = printf("%-*.*s%-10.10s %-36.36s %*s %4uB %-6.6s%5lu %-6.6s\n", prefix,prefix,"", d->name, d->uuid ? d->uuid : "n/a", - qprefix(d->size,1,buf,0), - d->physsec, "n/a", + PREFIXFMT(buf), d->physsec, "n/a", d->dmdev.disks,d->dmdev.level ? d->dmdev.level : "n/a" ); if(rr < 0){ @@ -624,14 +627,15 @@ print_mdadm(const device *d,int prefix,int descend){ if(d->layout != LAYOUT_MDADM){ return 0; } - use_terminfo_color(COLOR_YELLOW,1); - r += rr = printf("%-*.*s%-10.10s %-36.36s " PREFIXFMT " %4uB %-6.6s%5lu %-6.6s\n", + use_terminfo_color(COLOR_YELLOW, 1); + qprefix(d->size, 1, buf, 0); + r += rr = printf("%-*.*s%-10.10s %-36.36s %*s %4uB %-6.6s%5lu %-6.6s\n", prefix,prefix,"", d->name, d->uuid ? d->uuid : "n/a", - qprefix(d->size,1,buf,0), + PREFIXFMT(buf), d->physsec, "n/a", - d->mddev.disks,d->mddev.level ? d->mddev.level : "n/a"); + d->mddev.disks, d->mddev.level ? d->mddev.level : "n/a"); if(rr < 0){ return -1; } @@ -836,8 +840,8 @@ zpool(wchar_t * const *args,const char *arghelp){ } return 0; } - printf("%-10.10s %-36.36s " PREFIXFMT " %5.5s %-6.6s%-6.6s%-6.6s\n", - "Device","UUID","Bytes","AShft","Fmt","Disks","Level"); + printf("%-10.10s %-36.36s %*s %5.5s %-6.6s%-6.6s%-6.6s\n", + "Device", "UUID", PREFIXFMT("Bytes"), "AShft", "Fmt", "Disks", "Level"); if(walk_devices(print_zpool,descend)){ return -1; } @@ -872,7 +876,7 @@ dm(wchar_t * const *args,const char *arghelp){ return 0; } /* - printf("%-10.10s %-36.36s " PREFIXFMT " %5.5s %-6.6s%-6.6s%-6.6s\n", + printf("%-10.10s %-36.36s %*s %5.5s %-6.6s%-6.6s%-6.6s\n", "Device","UUID","Bytes","PSect","Table","Disks","Level"); if(walk_devices(print_zpool,descend)){ return -1; @@ -899,8 +903,8 @@ mdadm(wchar_t * const *args,const char *arghelp){ usage(args,arghelp); return -1; } - printf("%-10.10s %-36.36s " PREFIXFMT " %5.5s %-6.6s%-6.6s%-6.6s\n", - "Device","UUID","Bytes","PSect","Table","Disks","Level"); + printf("%-10.10s %-36.36s %*s %5.5s %-6.6s%-6.6s%-6.6s\n", + "Device","UUID", PREFIXFMT("Bytes"), "PSect","Table","Disks","Level"); for(c = get_controllers() ; c ; c = c->next){ device *d; @@ -962,8 +966,8 @@ static inline int blockdev_dump(int descend){ const controller *c; - printf("%-10.10s %-16.16s %4.4s " PREFIXFMT " %5.5s Flags %-6.6s%-16.16s %-4.4s\n", - "Device","Model","Rev","Bytes","PSect","Table","WWN","PHY"); + printf("%-10.10s %-16.16s %4.4s %*s %5.5s Flags %-6.6s%-16.16s %-4.4s\n", + "Device","Model","Rev", PREFIXFMT("Bytes"),"PSect","Table","WWN","PHY"); for(c = get_controllers() ; c ; c = c->next){ const device *d; @@ -1145,7 +1149,7 @@ print_partition_types(void){ const ptype *pt; for(pt = ptypes ; pt->name ; ++pt){ - if(printf("%04x %-37.37s",pt->code,pt->name) < 0){ + if(printf("%04x %-37.37s", pt->code, pt->name) < 0){ return -1; } // FIXME if all zeros, don't print gpt guid @@ -1350,8 +1354,8 @@ partition(wchar_t * const *args,const char *arghelp){ usage(args,arghelp); return -1; } - printf("%-10.10s %-36.36s " PREFIXFMT " %-4.4s %s\n", - "Partition","UUID","Bytes","Role","Name"); + printf("%-10.10s %-36.36s %*s %-4.4s %s\n", + "Partition","UUID", PREFIXFMT("Bytes"), "Role", "Name"); for(c = get_controllers() ; c ; c = c->next){ const device *d; @@ -1373,9 +1377,9 @@ mounts(wchar_t * const *args,const char *arghelp){ const controller *c; ZERO_ARG_CHECK(args,arghelp); - printf("%-*.*s %-5.5s %-36.36s %s " PREFIXFMT "\n", + printf("%-*.*s %-5.5s %-36.36s %s %*s\n", FSLABELSIZ,FSLABELSIZ,"Label", - "Type","UUID","Device","Bytes"); + "Type","UUID","Device", PREFIXFMT("Bytes")); for(c = get_controllers() ; c ; c = c->next){ const device *d; @@ -1458,11 +1462,11 @@ print_swaps(const device *d,int descend){ if(d->swapprio == SWAP_INVALID){ return 0; } - r += rr = printf("%-*.*s %-5d %-36.36s %s " PREFIXFMT "\n", + qprefix(d->mntsize,1,buf,0); + r += rr = printf("%-*.*s %-5d %-36.36s %s %*s\n", FSLABELSIZ,FSLABELSIZ,d->label ? d->label : "n/a", d->swapprio,d->uuid ? d->uuid : "n/a", - d->name, - qprefix(d->mntsize,1,buf,0)); + d->name, PREFIXFMT(buf)); if(rr < 0){ return -1; } @@ -1471,9 +1475,9 @@ print_swaps(const device *d,int descend){ static inline int fs_dump(int descend){ - printf("%-*.*s %-5.5s %-36.36s %s " PREFIXFMT "\n", - FSLABELSIZ,FSLABELSIZ,"Label", - "Type","UUID","Device","Bytes"); + printf("%-*.*s %-5.5s %-36.36s %s %*s\n", + FSLABELSIZ, FSLABELSIZ, "Label", + "Type", "UUID", "Device", PREFIXFMT("Bytes")); if(walk_devices(print_fs,descend)){ return -1; } @@ -1574,11 +1578,11 @@ static int swap(wchar_t * const *args,const char *arghelp){ device *d; if(!args[1]){ - if(printf("%-*.*s %-5.5s %-36.36s %s " PREFIXFMT "\n",FSLABELSIZ,FSLABELSIZ, - "Label","Prio","UUID","Device","Bytes") < 0){ + if(printf("%-*.*s %-5.5s %-36.36s %s %*s\n", FSLABELSIZ, FSLABELSIZ, + "Label", "Prio", "UUID", "Device", PREFIXFMT("Bytes")) < 0){ return -1; } - if(walk_devices(print_swaps,0)){ + if(walk_devices(print_swaps, 0)){ return -1; } return 0; @@ -1587,16 +1591,16 @@ swap(wchar_t * const *args,const char *arghelp){ if((d = lookup_wdevice(args[2])) == NULL){ return -1; } - if(wcscmp(args[1],L"on") == 0){ + if(wcscmp(args[1], L"on") == 0){ if(swapondev(d)){ return -1; } - }else if(wcscmp(args[1],L"off") == 0){ + }else if(wcscmp(args[1], L"off") == 0){ if(swapoffdev(d)){ return -1; } }else{ - usage(args,arghelp); + usage(args, arghelp); return -1; } return 0; From 30fa87d10897fe558a0f7d391b9ff950cddd40d0 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 27 May 2020 11:54:34 -0400 Subject: [PATCH 25/30] drone: use new builders with notcurses 1.4.3 --- .drone.yml | 4 ++-- src/notcurses.c | 56 ++++++++++++++++++++++++------------------- src/notui-aggregate.c | 2 +- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/.drone.yml b/.drone.yml index b9580bb4..5c836c79 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: debian-unstable steps: - name: debian-build - image: dankamongmen/unstable_builder:2020-05-23b + image: dankamongmen/unstable_builder:2020-05-27a commands: - export LANG=en_US.UTF-8 - autoreconf -fis @@ -18,7 +18,7 @@ name: ubuntu-focal steps: - name: ubuntu-build - image: dankamongmen/focal:2020-05-23b + image: dankamongmen/focal:2020-05-27a commands: - export LANG=en_US.UTF-8 - autoreconf -fis diff --git a/src/notcurses.c b/src/notcurses.c index 41abe7e4..3554cfbc 100644 --- a/src/notcurses.c +++ b/src/notcurses.c @@ -718,7 +718,7 @@ cmvwhline(struct ncplane* nc, int y, int x, const char* ch, int n){ return 0; } -static int +static int __attribute__ ((format (printf, 4, 5))) cmvwprintw(struct ncplane* n, int y, int x, const char* fmt, ...){ if(ncplane_cursor_move_yx(n, y, x)){ return -1; @@ -730,7 +730,7 @@ cmvwprintw(struct ncplane* n, int y, int x, const char* fmt, ...){ return ret; } -static int +static int __attribute__ ((format (printf, 2, 3))) cwprintw(struct ncplane* n, const char* fmt, ...){ va_list va; va_start(va, fmt); @@ -1148,11 +1148,12 @@ case LAYOUT_NONE: }else if(selected){ cwattron(n, NCSTYLE_REVERSE); } - cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", + qprefix(bo->d->size, 1, buf, 0); + cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s %*s %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, bo->d->model ? bo->d->model : "n/a", bo->d->revision ? bo->d->revision : "n/a", - qprefix(bo->d->size, 1, buf, 0), + PREFIXFMT(buf), bo->d->physsec, bo->d->blkdev.pttable ? bo->d->blkdev.pttable : "none", bo->d->blkdev.wwn ? bo->d->blkdev.wwn : "n/a", @@ -1182,11 +1183,12 @@ case LAYOUT_MDADM: }else if(selected){ cwattron(n, NCSTYLE_REVERSE); } - cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", + qprefix(bo->d->size, 1, buf, 0); + cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s %*s %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, bo->d->model ? bo->d->model : "n/a", bo->d->revision ? bo->d->revision : "n/a", - qprefix(bo->d->size, 1, buf, 0), + PREFIXFMT(buf), bo->d->physsec, bo->d->mddev.pttable ? bo->d->mddev.pttable : "none", bo->d->mddev.mdname ? bo->d->mddev.mdname : "n/a", @@ -1209,11 +1211,12 @@ case LAYOUT_DM: }else if(selected){ cwattron(n, NCSTYLE_REVERSE); } - cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", + qprefix(bo->d->size, 1, buf, 0); + cmvwprintw(n, line, 1, "%11.11s %-16.16s %4.4s %*s %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, bo->d->model ? bo->d->model : "n/a", bo->d->revision ? bo->d->revision : "n/a", - qprefix(bo->d->size, 1, buf, 0), + PREFIXFMT(buf), bo->d->physsec, bo->d->dmdev.pttable ? bo->d->dmdev.pttable : "none", bo->d->dmdev.dmname ? bo->d->dmdev.dmname : "n/a", @@ -1237,11 +1240,12 @@ case LAYOUT_ZPOOL: }else if(selected){ cwattron(n, NCSTYLE_REVERSE); } - cmvwprintw(n, line, 1, "%11.11s %-16.16s %4ju " PREFIXFMT " %4uB %-6.6s%-16.16s %4.4s %-*.*s", + qprefix(bo->d->size, 1, buf, 0); + cmvwprintw(n, line, 1, "%11.11s %-16.16s %4ju %*s %4uB %-6.6s%-16.16s %4.4s %-*.*s", bo->d->name, bo->d->model ? bo->d->model : "n/a", (uintmax_t)bo->d->zpool.zpoolver, - qprefix(bo->d->size, 1, buf, 0), + PREFIXFMT(buf), bo->d->physsec, "spa", "n/a", // FIXME @@ -3049,9 +3053,9 @@ detail_fs(struct ncplane* hw, const device* d, int row){ char buf[BPREFIXSTRLEN + 1]; ncplane_styles_off(hw, NCSTYLE_BOLD); - cmvwprintw(hw, row, START_COL, BPREFIXFMT "%c ", - d->mntsize ? bprefix(d->mntsize, 1, buf, 1) : "", - d->mntsize ? 'B' : ' '); + const char *size = d->mntsize ? bprefix(d->mntsize, 1, buf, 1) : ""; + cmvwprintw(hw, row, START_COL, "%*s%c ", + BPREFIXFMT(size), d->mntsize ? 'B' : ' '); ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "%s%s", d->label ? "" : "unlabeled ", d->mnttype); if(d->label){ @@ -3220,9 +3224,9 @@ update_details(struct ncplane* hw){ if(blockobj_unpartitionedp(b)){ char ubuf[BPREFIXSTRLEN + 1]; + bprefix(d->size, 1, ubuf, 1); ncplane_styles_off(hw, NCSTYLE_BOLD); - cmvwprintw(hw, 6, START_COL, BPREFIXFMT "B ", - bprefix(d->size, 1, ubuf, 1)); + cmvwprintw(hw, 6, START_COL, "%*sB ", BPREFIXFMT(ubuf)); ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "%s", "unpartitioned media"); detail_fs(hw, b->d, 7); @@ -3236,9 +3240,9 @@ update_details(struct ncplane* hw){ assert(b->zone->p->layout == LAYOUT_PARTITION); bprefix(b->zone->p->partdev.alignment, 1, align, 1); // FIXME limit length! + bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1),1, zbuf, 1); ncplane_styles_off(hw, NCSTYLE_BOLD); - cmvwprintw(hw, 6, START_COL, BPREFIXFMT "B ", - bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1), 1, zbuf, 1)); + cmvwprintw(hw, 6, START_COL, "%*sB ", BPREFIXFMT(zbuf)); ncplane_styles_on(hw, NCSTYLE_BOLD); cwprintw(hw, "P%lc%lc ", subscript((b->zone->p->partdev.pnumber % 100 / 10)), subscript((b->zone->p->partdev.pnumber % 10))); @@ -3269,8 +3273,8 @@ update_details(struct ncplane* hw){ // but not until we implement zones in core (bug 252) // or we'll need recreate alignment() etc here ncplane_styles_off(hw, NCSTYLE_BOLD); - cmvwprintw(hw, 6, START_COL, BPREFIXFMT "B ", - bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1), 1, zbuf, 1)); + bprefix(d->logsec * (b->zone->lsector - b->zone->fsector + 1), 1, zbuf, 1); + cmvwprintw(hw, 6, START_COL, "%*sB ", BPREFIXFMT(zbuf)); ncplane_styles_on(hw, NCSTYLE_BOLD); ncplane_styles_off(hw, NCSTYLE_BOLD); cwprintw(hw, "%ju", b->zone->fsector); @@ -3622,11 +3626,12 @@ detail_mounts(struct ncplane* w, int* row, int maxy, const device* d){ continue; } cmvwhline(w, *row, START_COL, " ", cols - 2); - cmvwprintw(w, *row, START_COL, "%-*.*s %-5.5s %-36.36s " PREFIXFMT " %-*.*s", + qprefix(d->mntsize, 1, buf, 0); + cmvwprintw(w, *row, START_COL, "%-*.*s %-5.5s %-36.36s %*s %-*.*s", FSLABELSIZ, FSLABELSIZ, d->label ? d->label : "n/a", d->mnttype, d->uuid ? d->uuid : "n/a", - qprefix(d->mntsize, 1, buf, 0), + PREFIXFMT(buf), cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), d->name); @@ -3659,11 +3664,12 @@ detail_targets(struct ncplane* w, int* row, int both, const device* d){ continue; } cmvwhline(w, *row, START_COL, " ", cols - 2); - cmvwprintw(w, *row, START_COL, "%-*.*s %-5.5s %-36.36s " PREFIXFMT " %-*.*s", + qprefix(d->mntsize, 1, buf, 0); + cmvwprintw(w, *row, START_COL, "%-*.*s %-5.5s %-36.36s %*s %-*.*s", FSLABELSIZ, FSLABELSIZ, d->label ? d->label : "n/a", d->mnttype, d->uuid ? d->uuid : "n/a", - qprefix(d->mntsize, 1, buf, 0), + PREFIXFMT(buf), cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), cols - (FSLABELSIZ + 47 + PREFIXCOLUMNS), d->name); @@ -3736,9 +3742,9 @@ map_details(struct ncplane *hw){ } cwattrset(hw, NCSTYLE_BOLD|SUBDISPLAY_COLOR); cmvwhline(hw, y, 1, " ", cols - 2); - cmvwprintw(hw, y, 1, "%-*.*s %-5.5s %-36.36s " PREFIXFMT " %s", + cmvwprintw(hw, y, 1, "%-*.*s %-5.5s %-36.36s %*s %s", FSLABELSIZ, FSLABELSIZ, "Label", - "Type", "UUID", "Bytes", "Device"); + "Type", "UUID", PREFIXFMT("Bytes"), "Device"); if(++y >= rows){ return 0; } diff --git a/src/notui-aggregate.c b/src/notui-aggregate.c index 95be4a3b..64f2d000 100644 --- a/src/notui-aggregate.c +++ b/src/notui-aggregate.c @@ -123,7 +123,7 @@ prefix_desc_with_size(const device *d,char *desc){ if((uni = malloc(sz)) == NULL){ return NULL; } - if((unsigned)snprintf(uni,sz,"("BPREFIXFMT"B) %s",s,desc) >= sz){ + if((unsigned)snprintf(uni,sz,"(%*sB) %s", BPREFIXFMT(s), desc) >= sz){ free(uni); return NULL; } From 26c067ca8a162e36ff02ef7cb1817669e37cf985 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 27 May 2020 19:52:39 -0400 Subject: [PATCH 26/30] v1.2.5 --- configure.ac | 2 +- debian/changelog | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index ad8b7026..1b387303 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.61]) -AC_INIT([growlight], [1.2.4], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) +AC_INIT([growlight], [1.2.5], [dankamongmen@gmail.com], [growlight], [https://nick-black.com/dankwiki/index.php/Growlight]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE([-Wall foreign dist-xz no-dist-gzip std-options subdir-objects nostdinc]) AC_CONFIG_HEADER([src/config.h]) diff --git a/debian/changelog b/debian/changelog index eab68518..17e2bb0f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,5 @@ -growlight (1.2.4-1) unstable; urgency=medium +growlight (1.2.5-1) unstable; urgency=medium - * Debian policy 4.5.0 - * Update copyrights + * New upstream version - -- Nick Black Fri, 10 Apr 2020 15:31:59 -0400 + -- Nick Black Wed, 27 May 2020 19:52:13 -0400 From c7a4070091203bdcb430ce33f1ffa992f58e81db Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 28 May 2020 14:51:25 -0400 Subject: [PATCH 27/30] declare debian policy 4.5.0.2 compliance --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index e2d6deee..b3834a3a 100644 --- a/debian/control +++ b/debian/control @@ -19,7 +19,7 @@ Build-Depends: pkg-config, xsltproc, Section: utils -Standards-Version: 4.5.0 +Standards-Version: 4.5.0.2 Rules-Requires-Root: no Homepage: https://nick-black.com/dankwiki/index.php/Growlight Vcs-Browser: https://github.com/dankamongmen/growlight From b69edbe169899a59de7b8a228091149aa86bb584 Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 18 Jun 2020 06:40:50 -0400 Subject: [PATCH 28/30] debian: compat level 13 --- debian/compat | 1 - debian/control | 33 ++++++++++++++++----------------- debian/watch | 7 ------- 3 files changed, 16 insertions(+), 25 deletions(-) delete mode 100644 debian/compat diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 48082f72..00000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -12 diff --git a/debian/control b/debian/control index b3834a3a..7646129d 100644 --- a/debian/control +++ b/debian/control @@ -1,23 +1,22 @@ Source: growlight Priority: optional Maintainer: Nick Black -Build-Depends: - autoconf-archive, - debhelper (>= 12), - docbook-xsl, - libatasmart-dev, - libblkid-dev, - libcryptsetup-dev, - libdevmapper-dev, - libnotcurses-dev (>= 1.4.3), - libpci-dev, - libpciaccess-dev, - libreadline-dev, - libssl-dev, - libudev-dev, - libzfslinux-dev (>= 0.8.0), - pkg-config, - xsltproc, +Build-Depends: autoconf-archive, + debhelper (>= 13), + docbook-xsl, + libatasmart-dev, + libblkid-dev, + libcryptsetup-dev, + libdevmapper-dev, + libnotcurses-dev (>= 1.4.3), + libpci-dev, + libpciaccess-dev, + libreadline-dev, + libssl-dev, + libudev-dev, + libzfslinux-dev (>= 0.8.0), + pkg-config, + xsltproc Section: utils Standards-Version: 4.5.0.2 Rules-Requires-Root: no diff --git a/debian/watch b/debian/watch index c72796a5..759e5160 100644 --- a/debian/watch +++ b/debian/watch @@ -1,11 +1,4 @@ -# Example watch control file for uscan -# Rename this file to "watch" and then you can run the "uscan" command -# to check for upstream updates and more. -# See uscan(1) for format - -# Compulsory line, this is a version 4 file version=4 - opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%growlight-$1.tar.gz%" \ https://github.com/dankamongmen/growlight/tags \ (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate From d8fc853c814d7650cbe760badb23482aed084bb6 Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 18 Jun 2020 07:20:17 -0400 Subject: [PATCH 29/30] debian: pass --disable-zfs --- debian/rules | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/debian/rules b/debian/rules index e1c367c1..915e1237 100755 --- a/debian/rules +++ b/debian/rules @@ -1,25 +1,10 @@ #!/usr/bin/make -f -# See debhelper(7) (uncomment to enable) -# output every command that modifies files on the build system. -#export DH_VERBOSE = 1 - - -# see FEATURE AREAS in dpkg-buildflags(1) -#export DEB_BUILD_MAINT_OPTIONS = hardening=+all - -# see ENVIRONMENT in dpkg-buildflags(1) -# package maintainers to append CFLAGS -#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic -# package maintainers to append LDFLAGS -#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed %: dh $@ - -# dh_make generated override targets -# This is example for Cmake (See https://bugs.debian.org/641051 ) -#override_dh_auto_configure: -# dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) - +override_dh_auto_configure: + dh_auto_configure -- --disable-zfs From c0888da96673df610ac5794ed1ac7775b0dc6c7f Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 18 Jun 2020 08:01:36 -0400 Subject: [PATCH 30/30] Makefile.am: switch to --nonet for docbook #24 --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index a51065b4..ac09a0e7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,8 +48,8 @@ growlight_SOURCES=$(common_SOURCES) growlight_SOURCES+=src/notcurses.c src/notcurses.h src/notui-aggregate.h src/notui-aggregate.c growlight_LDADD=@notcurses_LIBS@ -#XSLTARGS=--nonet /usr/share/xml/docbook/stylesheet/docbook-xsl -XSLTARGS=http://docbook.sourceforge.net/release/xsl/current +XSLTARGS=--nonet /usr/share/xml/docbook/stylesheet/docbook-xsl +#XSLTARGS=http://docbook.sourceforge.net/release/xsl/current $(dist_man_MANS): %.8: $(doc_DIR)/man/man8/%.xml $(doc_DIR)/@PACKAGE_NAME@.ent $(XSLTPROC) --path $(doc_DIR) -o $@ $(XSLTARGS)/manpages/docbook.xsl $<