diff --git a/Action.c b/Action.c index 6c387def..6fa26e9b 100644 --- a/Action.c +++ b/Action.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include "AffinityPanel.h" #include "CategoriesPanel.h" #include "CRT.h" +#include "EnvScreen.h" #include "MainPanel.h" #include "OpenFilesScreen.h" #include "Process.h" @@ -404,6 +405,7 @@ static struct { const char* key; const char* info; } helpRight[] = { #if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY) { .key = " a: ", .info = "set CPU affinity" }, #endif + { .key = " e: ", .info = "show process environment" }, { .key = " i: ", .info = "set IO prority" }, { .key = " l: ", .info = "list open files with lsof" }, { .key = " s: ", .info = "trace syscalls with strace" }, @@ -499,6 +501,18 @@ static Htop_Reaction actionTagAllChildren(State* st) { return HTOP_OK; } +static Htop_Reaction actionShowEnvScreen(State* st) { + Process* p = (Process*) Panel_getSelected(st->panel); + if (!p) return HTOP_OK; + EnvScreen* ts = EnvScreen_new(p); + EnvScreen_run(ts); + EnvScreen_delete(ts); + clear(); + CRT_enableDelay(); + return HTOP_REFRESH | HTOP_REDRAW_BAR; +} + + void Action_setBindings(Htop_Action* keys) { keys[KEY_RESIZE] = actionResize; keys['M'] = actionSortByMemory; @@ -548,5 +562,6 @@ void Action_setBindings(Htop_Action* keys) { keys['?'] = actionHelp; keys['U'] = actionUntagAll; keys['c'] = actionTagAllChildren; + keys['e'] = actionShowEnvScreen; } diff --git a/Action.h b/Action.h index 8927ce2f..34fc298f 100644 --- a/Action.h +++ b/Action.h @@ -49,6 +49,7 @@ Htop_Reaction Action_setSortKey(Settings* settings, ProcessField sortKey); // ---------------------------------------- + void Action_setBindings(Htop_Action* keys); diff --git a/EnvScreen.c b/EnvScreen.c new file mode 100644 index 00000000..1076ed0a --- /dev/null +++ b/EnvScreen.c @@ -0,0 +1,196 @@ +#include "EnvScreen.h" + +#include "CRT.h" +#include "IncSet.h" +#include "ListItem.h" +#include "StringUtils.h" + +#include +#include +#include +#include +#include + +/*{ +#include "ProcessList.h" +#include "Panel.h" +#include "FunctionBar.h" + +typedef struct EnvScreen_ { + Process* process; + Panel* display; + FunctionBar* bar; +} EnvScreen; +}*/ + +static const char* EnvScreenFunctions[] = {"Search ", "Filter ", "Refresh", "Done ", NULL}; + +static const char* EnvScreenKeys[] = {"F3", "F4", "F5", "Esc"}; + +static int EnvScreenEvents[] = {KEY_F(3), KEY_F(4), KEY_F(5), 27}; + +EnvScreen* EnvScreen_new(Process* process) { + EnvScreen* this = malloc(sizeof(EnvScreen)); + this->process = process; + FunctionBar* bar = FunctionBar_new(EnvScreenFunctions, EnvScreenKeys, EnvScreenEvents); + this->display = Panel_new(0, 1, COLS, LINES-3, false, Class(ListItem), bar); + return this; +} + +void EnvScreen_delete(EnvScreen* this) { + Panel_delete((Object*)this->display); + free(this); +} + +static void EnvScreen_draw(EnvScreen* this, IncSet* inc) { + attrset(CRT_colors[METER_TEXT]); + mvhline(0, 0, ' ', COLS); + mvprintw(0, 0, "environment of process %d - %s", this->process->pid, this->process->comm); + attrset(CRT_colors[DEFAULT_COLOR]); + Panel_draw(this->display, true); + IncSet_drawBar(inc); +} + +static inline void addLine(const char* line, Vector* lines, Panel* panel, const char* incFilter) { + Vector_add(lines, (Object*) ListItem_new(line, 0)); + if (!incFilter || String_contains_i(line, incFilter)) + Panel_add(panel, (Object*)Vector_get(lines, Vector_size(lines)-1)); +} + +static void EnvScreen_scan(EnvScreen* this, Vector* lines, IncSet* inc) { + Panel* panel = this->display; + int idx = MAX(Panel_getSelectedIndex(panel), 0); + uid_t uid = getuid(); + + Panel_prune(panel); + + if (uid == 0 || uid == this->process->st_uid) { + long argmax = sysconf(_SC_ARG_MAX); + char* buf = malloc(argmax); + size_t bufsz = argmax; + if (buf) { + int mib[3]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = this->process->pid; + bufsz = argmax; + if (sysctl(mib, 3, buf, &bufsz, 0, 0) == 0) { + if (bufsz > sizeof(int)) { + char *p = buf, *endp = buf + bufsz; + int argc = *(int*)p; + p += sizeof(int); + + // skip exe + p = strchr(p, 0)+1; + + // skip padding + while(!*p && p < endp) + ++p; + + // skip argv + for (; argc-- && p < endp; p = strrchr(p, 0)+1) + ; + + // skip padding + while(!*p && p < endp) + ++p; + + for (; *p && p < endp; p = strrchr(p, 0)+1) + addLine(p, lines, panel, IncSet_filter(inc)); + } + else { + addLine("Could not allocate memory.", lines, panel, IncSet_filter(inc)); + } + } + else { + addLine("sysctl(KERN_PROCARGS2) failed.", lines, panel, IncSet_filter(inc)); + } + free(buf); + } + else { + addLine("Out of memory.", lines, panel, IncSet_filter(inc)); + } + } + else { + addLine("Process belongs to different user.", lines, panel, IncSet_filter(inc)); + } + + Vector_insertionSort(lines); + Vector_insertionSort(panel->items); + Panel_setSelected(panel, idx); +} + +void EnvScreen_run(EnvScreen* this) { + Panel* panel = this->display; + Panel_setHeader(panel, " "); + + FunctionBar* bar = panel->defaultBar; + IncSet* inc = IncSet_new(bar); + + Vector* lines = Vector_new(panel->items->type, true, DEFAULT_SIZE); + + EnvScreen_scan(this, lines, inc); + EnvScreen_draw(this, inc); + + bool looping = true; + while (looping) { + + Panel_draw(panel, true); + + if (inc->active) + move(LINES-1, CRT_cursorX); + int ch = getch(); + + if (ch == KEY_MOUSE) { + MEVENT mevent; + int ok = getmouse(&mevent); + if (ok == OK) + if (mevent.y >= panel->y && mevent.y < LINES - 1) { + Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV); + ch = 0; + } if (mevent.y == LINES - 1) + ch = IncSet_synthesizeEvent(inc, mevent.x); + } + + if (inc->active) { + IncSet_handleKey(inc, ch, panel, IncSet_getListItemValue, lines); + continue; + } + + switch(ch) { + case ERR: + continue; + case KEY_F(3): + case '/': + IncSet_activate(inc, INC_SEARCH, panel); + break; + case KEY_F(4): + case '\\': + IncSet_activate(inc, INC_FILTER, panel); + break; + case KEY_F(5): + clear(); + EnvScreen_scan(this, lines, inc); + EnvScreen_draw(this, inc); + break; + case '\014': // Ctrl+L + clear(); + EnvScreen_draw(this, inc); + break; + case 'q': + case 27: + case KEY_F(10): + looping = false; + break; + case KEY_RESIZE: + Panel_resize(panel, COLS, LINES-2); + EnvScreen_draw(this, inc); + break; + default: + Panel_onKey(panel, ch); + } + } + + Vector_delete(lines); + IncSet_delete(inc); +} diff --git a/EnvScreen.h b/EnvScreen.h new file mode 100644 index 00000000..f33f0591 --- /dev/null +++ b/EnvScreen.h @@ -0,0 +1,22 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_EnvScreen +#define HEADER_EnvScreen + +#include "ProcessList.h" +#include "Panel.h" +#include "FunctionBar.h" + +typedef struct EnvScreen_ { + Process* process; + Panel* display; + FunctionBar* bar; +} EnvScreen; + +EnvScreen* EnvScreen_new(Process* process); + +void EnvScreen_delete(EnvScreen* this); + +void EnvScreen_run(EnvScreen* this); + +#endif diff --git a/Makefile.am b/Makefile.am index b54b9a91..2861e10b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,7 @@ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \ TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \ -HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c +HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \ @@ -32,7 +32,8 @@ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h \ TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \ -AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h +AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \ +EnvScreen.h if HTOP_LINUX htop_CFLAGS += -rdynamic diff --git a/Process.h b/Process.h index 841b1291..d856c035 100644 --- a/Process.h +++ b/Process.h @@ -158,6 +158,8 @@ typedef struct ProcessClass_ { #define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K) #define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K) +extern char Process_pidFormat[20]; + void Process_setupColumnWidths(); void Process_humanNumber(RichString* str, unsigned long number, bool coloring);