2006-03-04 18:16:49 +00:00
|
|
|
/*
|
|
|
|
htop - Settings.c
|
2011-05-26 16:35:07 +00:00
|
|
|
(C) 2004-2011 Hisham H. Muhammad
|
2006-03-04 18:16:49 +00:00
|
|
|
Released under the GNU GPL, see the COPYING file
|
|
|
|
in the source distribution for its full text.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Settings.h"
|
2015-03-15 23:29:13 +00:00
|
|
|
#include "Platform.h"
|
2006-03-04 18:16:49 +00:00
|
|
|
|
2015-08-19 16:43:20 +00:00
|
|
|
#include "StringUtils.h"
|
2011-12-26 21:35:57 +00:00
|
|
|
#include "Vector.h"
|
2015-04-09 18:19:31 +00:00
|
|
|
#include "CRT.h"
|
2006-03-04 18:16:49 +00:00
|
|
|
|
2011-12-26 21:35:57 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2006-03-04 18:16:49 +00:00
|
|
|
#define DEFAULT_DELAY 15
|
|
|
|
|
|
|
|
/*{
|
2015-01-22 01:27:31 +00:00
|
|
|
#include "Process.h"
|
2011-12-26 21:35:57 +00:00
|
|
|
#include <stdbool.h>
|
2006-03-04 18:16:49 +00:00
|
|
|
|
2018-04-06 15:41:36 +00:00
|
|
|
typedef struct {
|
|
|
|
const char* name;
|
|
|
|
const char* columns;
|
|
|
|
const char* sortKey;
|
|
|
|
} ScreenDefaults;
|
|
|
|
|
2015-01-22 01:27:31 +00:00
|
|
|
typedef struct {
|
|
|
|
int len;
|
|
|
|
char** names;
|
|
|
|
int* modes;
|
|
|
|
} MeterColumnSettings;
|
2015-01-23 05:08:21 +00:00
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
typedef struct {
|
|
|
|
char* name;
|
|
|
|
ProcessField* fields;
|
|
|
|
int flags;
|
|
|
|
int direction;
|
|
|
|
ProcessField sortKey;
|
|
|
|
bool treeView;
|
|
|
|
} ScreenSettings;
|
|
|
|
|
2006-03-04 18:16:49 +00:00
|
|
|
typedef struct Settings_ {
|
2015-01-22 01:27:31 +00:00
|
|
|
char* filename;
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
MeterColumnSettings meterColumns[2];
|
2015-01-22 01:27:31 +00:00
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
ScreenSettings** screens;
|
|
|
|
unsigned int nScreens;
|
|
|
|
unsigned int ssIndex;
|
|
|
|
ScreenSettings* ss;
|
2018-01-28 01:29:58 +00:00
|
|
|
|
2006-03-04 18:16:49 +00:00
|
|
|
int colorScheme;
|
|
|
|
int delay;
|
2015-01-22 01:27:31 +00:00
|
|
|
|
2015-05-13 18:13:55 +00:00
|
|
|
int cpuCount;
|
2015-01-22 01:27:31 +00:00
|
|
|
|
|
|
|
bool countCPUsFromZero;
|
|
|
|
bool detailedCPUTime;
|
2015-07-29 19:14:29 +00:00
|
|
|
bool showProgramPath;
|
2015-01-22 01:27:31 +00:00
|
|
|
bool hideThreads;
|
|
|
|
bool shadowOtherUsers;
|
|
|
|
bool showThreadNames;
|
|
|
|
bool hideKernelThreads;
|
|
|
|
bool hideUserlandThreads;
|
|
|
|
bool highlightBaseName;
|
|
|
|
bool highlightMegabytes;
|
|
|
|
bool highlightThreads;
|
|
|
|
bool updateProcessNames;
|
|
|
|
bool accountGuestInCPUMeter;
|
|
|
|
bool headerMargin;
|
|
|
|
|
2014-02-27 19:35:22 +00:00
|
|
|
bool changed;
|
2006-03-04 18:16:49 +00:00
|
|
|
} Settings;
|
|
|
|
|
2015-01-22 01:27:31 +00:00
|
|
|
#ifndef Settings_cpuId
|
|
|
|
#define Settings_cpuId(settings, cpu) ((settings)->countCPUsFromZero ? (cpu) : (cpu)+1)
|
|
|
|
#endif
|
|
|
|
|
2006-03-04 18:16:49 +00:00
|
|
|
}*/
|
|
|
|
|
2018-01-28 01:29:58 +00:00
|
|
|
static void writeList(FILE* fd, char** list, int len) {
|
|
|
|
const char* sep = "";
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
fprintf(fd, "%s%s", sep, list[i]);
|
|
|
|
sep = " ";
|
|
|
|
}
|
|
|
|
fprintf(fd, "\n");
|
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
/*
|
|
|
|
|
|
|
|
static char** readQuotedList(char* line) {
|
|
|
|
int n = 0;
|
2018-01-28 01:29:58 +00:00
|
|
|
char** list = xCalloc(sizeof(char*), 1);
|
|
|
|
int start = 0;
|
|
|
|
for (;;) {
|
|
|
|
while (line[start] && line[start] == ' ') {
|
|
|
|
start++;
|
|
|
|
}
|
|
|
|
if (line[start] != '"') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
start++;
|
|
|
|
int close = start;
|
|
|
|
while (line[close] && line[close] != '"') {
|
|
|
|
close++;
|
|
|
|
}
|
|
|
|
int len = close - start;
|
|
|
|
char* item = xMalloc(len + 1);
|
|
|
|
strncpy(item, line + start, len);
|
|
|
|
item[len] = '\0';
|
2018-01-28 06:09:06 +00:00
|
|
|
list[n] = item;
|
|
|
|
n++;
|
|
|
|
list = xRealloc(list, sizeof(char*) * (n + 1));
|
2018-01-28 01:29:58 +00:00
|
|
|
start = close + 1;
|
|
|
|
}
|
2018-01-28 06:09:06 +00:00
|
|
|
list[n] = NULL;
|
2018-01-28 01:29:58 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
static void writeQuotedList(FILE* fd, char** list) {
|
2018-01-28 01:29:58 +00:00
|
|
|
const char* sep = "";
|
2018-01-28 06:09:06 +00:00
|
|
|
for (int i = 0; list[i]; i++) {
|
2018-01-28 01:29:58 +00:00
|
|
|
fprintf(fd, "%s\"%s\"", sep, list[i]);
|
|
|
|
sep = " ";
|
|
|
|
}
|
|
|
|
fprintf(fd, "\n");
|
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
*/
|
|
|
|
|
2006-03-04 18:16:49 +00:00
|
|
|
void Settings_delete(Settings* this) {
|
2015-01-22 01:27:31 +00:00
|
|
|
free(this->filename);
|
2018-01-28 06:09:06 +00:00
|
|
|
for (unsigned int i = 0; i < (sizeof(this->meterColumns)/sizeof(MeterColumnSettings)); i++) {
|
|
|
|
String_freeArray(this->meterColumns[i].names);
|
|
|
|
free(this->meterColumns[i].modes);
|
|
|
|
}
|
|
|
|
if (this->screens) {
|
|
|
|
for (unsigned int i = 0; this->screens[i]; i++) {
|
|
|
|
free(this->screens[i]->name);
|
|
|
|
free(this->screens[i]->fields);
|
|
|
|
}
|
|
|
|
free(this->screens);
|
2015-01-22 01:27:31 +00:00
|
|
|
}
|
2006-03-04 18:16:49 +00:00
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
static void Settings_readMeters(Settings* this, char* line, int side) {
|
2006-03-04 18:16:49 +00:00
|
|
|
char* trim = String_trim(line);
|
2011-08-29 20:45:29 +00:00
|
|
|
int nIds;
|
|
|
|
char** ids = String_split(trim, ' ', &nIds);
|
2006-03-04 18:16:49 +00:00
|
|
|
free(trim);
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[side].names = ids;
|
2006-03-04 18:16:49 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
static void Settings_readMeterModes(Settings* this, char* line, int side) {
|
2006-03-04 18:16:49 +00:00
|
|
|
char* trim = String_trim(line);
|
2011-08-29 20:45:29 +00:00
|
|
|
int nIds;
|
|
|
|
char** ids = String_split(trim, ' ', &nIds);
|
2006-03-04 18:16:49 +00:00
|
|
|
free(trim);
|
2015-01-22 01:27:31 +00:00
|
|
|
int len = 0;
|
2011-08-29 20:45:29 +00:00
|
|
|
for (int i = 0; ids[i]; i++) {
|
2015-01-22 01:27:31 +00:00
|
|
|
len++;
|
|
|
|
}
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[side].len = len;
|
2016-02-02 14:53:02 +00:00
|
|
|
int* modes = xCalloc(len, sizeof(int));
|
2015-01-22 01:27:31 +00:00
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
modes[i] = atoi(ids[i]);
|
2006-03-04 18:16:49 +00:00
|
|
|
}
|
|
|
|
String_freeArray(ids);
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[side].modes = modes;
|
2006-03-04 18:16:49 +00:00
|
|
|
}
|
|
|
|
|
2015-05-13 18:13:55 +00:00
|
|
|
static void Settings_defaultMeters(Settings* this) {
|
2015-01-22 01:27:31 +00:00
|
|
|
int sizes[] = { 3, 3 };
|
2015-05-13 18:13:55 +00:00
|
|
|
if (this->cpuCount > 4) {
|
2015-01-22 01:27:31 +00:00
|
|
|
sizes[1]++;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++) {
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char*));
|
|
|
|
this->meterColumns[i].modes = xCalloc(sizes[i], sizeof(int));
|
|
|
|
this->meterColumns[i].len = sizes[i];
|
2015-01-22 01:27:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int r = 0;
|
2015-05-13 18:13:55 +00:00
|
|
|
if (this->cpuCount > 8) {
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[0].names[0] = xStrdup("LeftCPUs2");
|
|
|
|
this->meterColumns[0].modes[0] = BAR_METERMODE;
|
|
|
|
this->meterColumns[1].names[r] = xStrdup("RightCPUs2");
|
|
|
|
this->meterColumns[1].modes[r++] = BAR_METERMODE;
|
2015-05-13 18:13:55 +00:00
|
|
|
} else if (this->cpuCount > 4) {
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[0].names[0] = xStrdup("LeftCPUs");
|
|
|
|
this->meterColumns[0].modes[0] = BAR_METERMODE;
|
|
|
|
this->meterColumns[1].names[r] = xStrdup("RightCPUs");
|
|
|
|
this->meterColumns[1].modes[r++] = BAR_METERMODE;
|
2014-11-27 20:38:52 +00:00
|
|
|
} else {
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[0].names[0] = xStrdup("AllCPUs");
|
|
|
|
this->meterColumns[0].modes[0] = BAR_METERMODE;
|
2015-01-22 01:27:31 +00:00
|
|
|
}
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[0].names[1] = xStrdup("Memory");
|
|
|
|
this->meterColumns[0].modes[1] = BAR_METERMODE;
|
|
|
|
this->meterColumns[0].names[2] = xStrdup("Swap");
|
|
|
|
this->meterColumns[0].modes[2] = BAR_METERMODE;
|
2015-01-22 01:27:31 +00:00
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
this->meterColumns[1].names[r] = xStrdup("Tasks");
|
|
|
|
this->meterColumns[1].modes[r++] = TEXT_METERMODE;
|
|
|
|
this->meterColumns[1].names[r] = xStrdup("LoadAverage");
|
|
|
|
this->meterColumns[1].modes[r++] = TEXT_METERMODE;
|
|
|
|
this->meterColumns[1].names[r] = xStrdup("Uptime");
|
|
|
|
this->meterColumns[1].modes[r++] = TEXT_METERMODE;
|
2015-01-22 01:27:31 +00:00
|
|
|
}
|
|
|
|
|
2018-01-30 16:21:17 +00:00
|
|
|
static const char* toFieldName(int i) {
|
2018-08-24 19:23:20 +00:00
|
|
|
if (i < 0 || i > LAST_PROCESSFIELD) {
|
|
|
|
return "";
|
|
|
|
}
|
2018-01-30 16:21:17 +00:00
|
|
|
return Process_fields[i].name;
|
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
static int toFieldIndex(const char* str) {
|
|
|
|
if (isdigit(str[0])) {
|
|
|
|
// This "+1" is for compatibility with the older enum format.
|
|
|
|
int id = atoi(str) + 1;
|
2018-01-30 16:21:17 +00:00
|
|
|
if (id < Platform_numberOfFields && toFieldName(id)) {
|
2018-01-28 06:09:06 +00:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int p = 1; p < LAST_PROCESSFIELD; p++) {
|
2018-01-30 16:21:17 +00:00
|
|
|
const char* pName = toFieldName(p);
|
|
|
|
if (pName && strcmp(pName, str) == 0) {
|
2018-01-28 06:09:06 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
2018-01-28 01:29:58 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 01:27:31 +00:00
|
|
|
static void readFields(ProcessField* fields, int* flags, const char* line) {
|
|
|
|
char* trim = String_trim(line);
|
|
|
|
int nIds;
|
|
|
|
char** ids = String_split(trim, ' ', &nIds);
|
|
|
|
free(trim);
|
|
|
|
int i, j;
|
|
|
|
*flags = 0;
|
2015-03-15 23:29:13 +00:00
|
|
|
for (j = 0, i = 0; i < Platform_numberOfFields && ids[i]; i++) {
|
2018-01-28 06:09:06 +00:00
|
|
|
int idx = toFieldIndex(ids[i]);
|
|
|
|
if (idx != -1) {
|
|
|
|
fields[j] = idx;
|
|
|
|
*flags |= Process_fields[idx].flags;
|
2015-01-22 01:27:31 +00:00
|
|
|
j++;
|
|
|
|
}
|
2014-11-27 20:38:52 +00:00
|
|
|
}
|
2016-05-30 15:22:07 +00:00
|
|
|
fields[j] = NULL_PROCESSFIELD;
|
2015-01-22 01:27:31 +00:00
|
|
|
String_freeArray(ids);
|
2014-11-27 20:38:52 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 19:06:53 +00:00
|
|
|
ScreenSettings* Settings_newScreen(Settings* this, const char* name, const char* line) {
|
2018-01-28 06:09:06 +00:00
|
|
|
ScreenSettings* ss = xCalloc(sizeof(ScreenSettings), 1);
|
|
|
|
ss->name = xStrdup(name);
|
|
|
|
ss->fields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
|
|
|
|
ss->flags = 0;
|
|
|
|
ss->direction = 1;
|
|
|
|
ss->treeView = 0;
|
|
|
|
readFields(ss->fields, &(ss->flags), line);
|
|
|
|
this->screens[this->nScreens] = ss;
|
|
|
|
this->nScreens++;
|
|
|
|
this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1));
|
|
|
|
this->screens[this->nScreens] = NULL;
|
2018-01-28 19:06:53 +00:00
|
|
|
return ss;
|
2018-01-28 06:09:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void Settings_defaultScreens(Settings* this) {
|
2018-04-06 15:41:36 +00:00
|
|
|
for (unsigned int i = 0; i < Platform_numberOfDefaultScreens; i++) {
|
|
|
|
ScreenDefaults* defaults = &Platform_defaultScreens[i];
|
|
|
|
Settings_newScreen(this, defaults->name, defaults->columns);
|
2018-08-24 19:23:20 +00:00
|
|
|
this->screens[i]->sortKey = toFieldIndex(defaults->sortKey);
|
2018-04-06 15:41:36 +00:00
|
|
|
}
|
2018-01-28 06:09:06 +00:00
|
|
|
}
|
|
|
|
|
2015-05-13 18:13:55 +00:00
|
|
|
static bool Settings_read(Settings* this, const char* fileName) {
|
2015-12-02 22:42:10 +00:00
|
|
|
FILE* fd;
|
2017-07-26 18:40:55 +00:00
|
|
|
|
|
|
|
CRT_dropPrivileges();
|
2015-12-09 19:34:11 +00:00
|
|
|
fd = fopen(fileName, "r");
|
2017-07-26 18:40:55 +00:00
|
|
|
CRT_restorePrivileges();
|
2011-12-25 20:22:41 +00:00
|
|
|
if (!fd)
|
2006-03-04 18:16:49 +00:00
|
|
|
return false;
|
2011-12-25 20:22:41 +00:00
|
|
|
|
2018-02-18 23:35:23 +00:00
|
|
|
bool didReadMeters = false;
|
|
|
|
bool didReadFields = false;
|
2018-01-28 06:09:06 +00:00
|
|
|
ProcessField* legacyFields = xCalloc(Platform_numberOfFields+1, sizeof(ProcessField));
|
|
|
|
int legacyFlags;
|
|
|
|
bool legacyFieldsRead = false;
|
2016-06-19 21:55:35 +00:00
|
|
|
for (;;) {
|
|
|
|
char* line = String_readLine(fd);
|
|
|
|
if (!line) {
|
|
|
|
break;
|
|
|
|
}
|
2011-08-29 20:45:29 +00:00
|
|
|
int nOptions;
|
2016-06-19 21:55:35 +00:00
|
|
|
char** option = String_split(line, '=', &nOptions);
|
|
|
|
free (line);
|
2011-08-29 20:45:29 +00:00
|
|
|
if (nOptions < 2) {
|
|
|
|
String_freeArray(option);
|
|
|
|
continue;
|
|
|
|
}
|
2006-03-04 18:16:49 +00:00
|
|
|
if (String_eq(option[0], "fields")) {
|
2018-01-28 06:09:06 +00:00
|
|
|
readFields(legacyFields, &legacyFlags, option[1]);
|
|
|
|
legacyFieldsRead = true;
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "hide_threads")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->hideThreads = atoi(option[1]);
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "hide_kernel_threads")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->hideKernelThreads = atoi(option[1]);
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "hide_userland_threads")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->hideUserlandThreads = atoi(option[1]);
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "shadow_other_users")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->shadowOtherUsers = atoi(option[1]);
|
2010-02-25 01:37:31 +00:00
|
|
|
} else if (String_eq(option[0], "show_thread_names")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->showThreadNames = atoi(option[1]);
|
2015-07-29 19:14:29 +00:00
|
|
|
} else if (String_eq(option[0], "show_program_path")) {
|
|
|
|
this->showProgramPath = atoi(option[1]);
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "highlight_base_name")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->highlightBaseName = atoi(option[1]);
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "highlight_megabytes")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->highlightMegabytes = atoi(option[1]);
|
2008-03-08 23:39:48 +00:00
|
|
|
} else if (String_eq(option[0], "highlight_threads")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->highlightThreads = atoi(option[1]);
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "header_margin")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->headerMargin = atoi(option[1]);
|
2006-10-04 14:21:27 +00:00
|
|
|
} else if (String_eq(option[0], "expand_system_time")) {
|
2007-11-09 00:40:59 +00:00
|
|
|
// Compatibility option.
|
2015-01-22 01:27:31 +00:00
|
|
|
this->detailedCPUTime = atoi(option[1]);
|
2007-11-09 00:40:59 +00:00
|
|
|
} else if (String_eq(option[0], "detailed_cpu_time")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->detailedCPUTime = atoi(option[1]);
|
2011-03-22 20:37:08 +00:00
|
|
|
} else if (String_eq(option[0], "cpu_count_from_zero")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->countCPUsFromZero = atoi(option[1]);
|
2012-10-20 00:43:25 +00:00
|
|
|
} else if (String_eq(option[0], "update_process_names")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->updateProcessNames = atoi(option[1]);
|
2013-12-18 02:58:34 +00:00
|
|
|
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->accountGuestInCPUMeter = atoi(option[1]);
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "delay")) {
|
|
|
|
this->delay = atoi(option[1]);
|
|
|
|
} else if (String_eq(option[0], "color_scheme")) {
|
|
|
|
this->colorScheme = atoi(option[1]);
|
2015-04-09 18:44:26 +00:00
|
|
|
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) this->colorScheme = 0;
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "left_meters")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
Settings_readMeters(this, option[1], 0);
|
2018-02-18 23:35:23 +00:00
|
|
|
didReadMeters = true;
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "right_meters")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
Settings_readMeters(this, option[1], 1);
|
2018-02-18 23:35:23 +00:00
|
|
|
didReadMeters = true;
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "left_meter_modes")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
Settings_readMeterModes(this, option[1], 0);
|
2018-02-18 23:35:23 +00:00
|
|
|
didReadMeters = true;
|
2006-03-04 18:16:49 +00:00
|
|
|
} else if (String_eq(option[0], "right_meter_modes")) {
|
2015-01-22 01:27:31 +00:00
|
|
|
Settings_readMeterModes(this, option[1], 1);
|
2018-02-18 23:35:23 +00:00
|
|
|
didReadMeters = true;
|
2018-01-28 06:09:06 +00:00
|
|
|
} else if (strncmp(option[0], "screen:", 7) == 0) {
|
2018-01-28 19:06:53 +00:00
|
|
|
Settings_newScreen(this, option[0] + 7, option[1]);
|
2018-01-28 06:09:06 +00:00
|
|
|
} else if (String_eq(option[0], ".tree_view")) {
|
|
|
|
if (this->nScreens > 0) {
|
|
|
|
this->screens[this->nScreens - 1]->treeView = atoi(option[1]);
|
|
|
|
}
|
|
|
|
} else if (String_eq(option[0], ".sort_direction")) {
|
|
|
|
if (this->nScreens > 0) {
|
|
|
|
this->screens[this->nScreens - 1]->direction = atoi(option[1]);
|
|
|
|
}
|
|
|
|
} else if (String_eq(option[0], ".sort_key")) {
|
|
|
|
if (this->nScreens > 0) {
|
|
|
|
this->screens[this->nScreens - 1]->sortKey = toFieldIndex(option[1]);
|
|
|
|
}
|
2006-03-04 18:16:49 +00:00
|
|
|
}
|
|
|
|
String_freeArray(option);
|
|
|
|
}
|
|
|
|
fclose(fd);
|
2018-01-28 06:09:06 +00:00
|
|
|
if (this->nScreens == 0) {
|
2018-01-28 01:29:58 +00:00
|
|
|
Settings_defaultScreens(this);
|
2018-01-28 06:09:06 +00:00
|
|
|
if (legacyFieldsRead) {
|
|
|
|
free(this->screens[0]->fields);
|
|
|
|
this->screens[0]->fields = legacyFields;
|
|
|
|
this->screens[0]->flags = legacyFlags;
|
|
|
|
}
|
2018-01-28 01:29:58 +00:00
|
|
|
}
|
2018-02-18 23:35:23 +00:00
|
|
|
if (!didReadMeters) {
|
2015-05-13 18:13:55 +00:00
|
|
|
Settings_defaultMeters(this);
|
2006-03-04 18:16:49 +00:00
|
|
|
}
|
2018-02-18 23:35:23 +00:00
|
|
|
return didReadFields;
|
2006-03-04 18:16:49 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
static void writeFields(FILE* fd, ProcessField* fields, bool byName) {
|
2017-07-24 23:36:27 +00:00
|
|
|
const char* sep = "";
|
2015-01-22 01:27:31 +00:00
|
|
|
for (int i = 0; fields[i]; i++) {
|
2018-01-28 06:09:06 +00:00
|
|
|
if (byName) {
|
2018-01-30 16:21:17 +00:00
|
|
|
fprintf(fd, "%s%s", sep, toFieldName(fields[i]));
|
2018-01-28 06:09:06 +00:00
|
|
|
} else {
|
|
|
|
// This " - 1" is for compatibility with the older enum format.
|
|
|
|
fprintf(fd, "%s%d", sep, (int) fields[i] - 1);
|
|
|
|
}
|
2017-07-24 23:36:27 +00:00
|
|
|
sep = " ";
|
2015-01-22 01:27:31 +00:00
|
|
|
}
|
|
|
|
fprintf(fd, "\n");
|
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
static void writeMeters(Settings* this, FILE* fd, int side) {
|
|
|
|
writeList(fd, this->meterColumns[side].names, this->meterColumns[side].len);
|
2015-01-22 01:27:31 +00:00
|
|
|
}
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
static void writeMeterModes(Settings* this, FILE* fd, int side) {
|
2017-07-24 23:36:27 +00:00
|
|
|
const char* sep = "";
|
2018-01-28 06:09:06 +00:00
|
|
|
for (int i = 0; i < this->meterColumns[side].len; i++) {
|
|
|
|
fprintf(fd, "%s%d", sep, this->meterColumns[side].modes[i]);
|
2017-07-24 23:36:27 +00:00
|
|
|
sep = " ";
|
2015-01-22 01:27:31 +00:00
|
|
|
}
|
|
|
|
fprintf(fd, "\n");
|
|
|
|
}
|
|
|
|
|
2006-03-04 18:16:49 +00:00
|
|
|
bool Settings_write(Settings* this) {
|
|
|
|
FILE* fd;
|
2015-12-02 22:42:10 +00:00
|
|
|
|
2017-07-26 18:40:55 +00:00
|
|
|
CRT_dropPrivileges();
|
2015-01-22 01:27:31 +00:00
|
|
|
fd = fopen(this->filename, "w");
|
2017-07-26 18:40:55 +00:00
|
|
|
CRT_restorePrivileges();
|
|
|
|
|
2006-03-04 18:16:49 +00:00
|
|
|
if (fd == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
2011-08-12 16:37:27 +00:00
|
|
|
fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n");
|
2006-03-04 18:16:49 +00:00
|
|
|
fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n");
|
2018-01-28 06:09:06 +00:00
|
|
|
fprintf(fd, "fields="); writeFields(fd, this->screens[0]->fields, false);
|
2015-01-22 01:27:31 +00:00
|
|
|
fprintf(fd, "hide_threads=%d\n", (int) this->hideThreads);
|
|
|
|
fprintf(fd, "hide_kernel_threads=%d\n", (int) this->hideKernelThreads);
|
|
|
|
fprintf(fd, "hide_userland_threads=%d\n", (int) this->hideUserlandThreads);
|
|
|
|
fprintf(fd, "shadow_other_users=%d\n", (int) this->shadowOtherUsers);
|
|
|
|
fprintf(fd, "show_thread_names=%d\n", (int) this->showThreadNames);
|
2015-07-29 19:14:29 +00:00
|
|
|
fprintf(fd, "show_program_path=%d\n", (int) this->showProgramPath);
|
2015-01-22 01:27:31 +00:00
|
|
|
fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName);
|
|
|
|
fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes);
|
|
|
|
fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads);
|
|
|
|
fprintf(fd, "header_margin=%d\n", (int) this->headerMargin);
|
|
|
|
fprintf(fd, "detailed_cpu_time=%d\n", (int) this->detailedCPUTime);
|
|
|
|
fprintf(fd, "cpu_count_from_zero=%d\n", (int) this->countCPUsFromZero);
|
|
|
|
fprintf(fd, "update_process_names=%d\n", (int) this->updateProcessNames);
|
|
|
|
fprintf(fd, "account_guest_in_cpu_meter=%d\n", (int) this->accountGuestInCPUMeter);
|
2006-03-04 18:16:49 +00:00
|
|
|
fprintf(fd, "color_scheme=%d\n", (int) this->colorScheme);
|
|
|
|
fprintf(fd, "delay=%d\n", (int) this->delay);
|
2015-01-22 01:27:31 +00:00
|
|
|
fprintf(fd, "left_meters="); writeMeters(this, fd, 0);
|
|
|
|
fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0);
|
|
|
|
fprintf(fd, "right_meters="); writeMeters(this, fd, 1);
|
|
|
|
fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1);
|
2018-01-28 18:56:55 +00:00
|
|
|
|
|
|
|
// Legacy compatibility with older versions of htop
|
|
|
|
fprintf(fd, "tree_view=%d\n", (int) this->screens[0]->treeView);
|
|
|
|
// This "-1" is for compatibility with the older enum format.
|
|
|
|
fprintf(fd, "sort_key=%d\n", (int) this->screens[0]->sortKey-1);
|
|
|
|
fprintf(fd, "sort_direction=%d\n", (int) this->screens[0]->direction);
|
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
if (this->screens && this->screens[0]) {
|
|
|
|
for (unsigned int i = 0; i < this->nScreens; i++) {
|
|
|
|
ScreenSettings* ss = this->screens[i];
|
|
|
|
fprintf(fd, "screen:%s=", ss->name);
|
|
|
|
writeFields(fd, ss->fields, true);
|
|
|
|
fprintf(fd, ".tree_view=%d\n", (int) ss->treeView);
|
2018-01-30 16:21:17 +00:00
|
|
|
fprintf(fd, ".sort_key=%s\n", toFieldName(ss->sortKey));
|
2018-01-28 06:09:06 +00:00
|
|
|
fprintf(fd, ".sort_direction=%d\n", (int) ss->direction);
|
|
|
|
}
|
2018-01-28 01:29:58 +00:00
|
|
|
}
|
2006-03-04 18:16:49 +00:00
|
|
|
fclose(fd);
|
|
|
|
return true;
|
|
|
|
}
|
2008-03-09 08:58:38 +00:00
|
|
|
|
2015-01-22 01:27:31 +00:00
|
|
|
Settings* Settings_new(int cpuCount) {
|
|
|
|
|
2016-02-02 14:53:02 +00:00
|
|
|
Settings* this = xCalloc(1, sizeof(Settings));
|
2015-01-22 01:27:31 +00:00
|
|
|
|
|
|
|
this->hideThreads = false;
|
|
|
|
this->shadowOtherUsers = false;
|
|
|
|
this->showThreadNames = false;
|
|
|
|
this->hideKernelThreads = false;
|
|
|
|
this->hideUserlandThreads = false;
|
|
|
|
this->highlightBaseName = false;
|
|
|
|
this->highlightMegabytes = false;
|
|
|
|
this->detailedCPUTime = false;
|
|
|
|
this->countCPUsFromZero = false;
|
|
|
|
this->updateProcessNames = false;
|
2015-05-13 18:13:55 +00:00
|
|
|
this->cpuCount = cpuCount;
|
2015-08-12 20:24:41 +00:00
|
|
|
this->showProgramPath = true;
|
2016-01-31 11:07:48 +00:00
|
|
|
this->highlightThreads = true;
|
2015-01-22 01:27:31 +00:00
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
this->screens = xCalloc(sizeof(ScreenSettings*), 1);
|
|
|
|
this->nScreens = 0;
|
2015-01-22 01:27:31 +00:00
|
|
|
|
2011-12-25 20:22:41 +00:00
|
|
|
char* legacyDotfile = NULL;
|
|
|
|
char* rcfile = getenv("HTOPRC");
|
|
|
|
if (rcfile) {
|
2016-02-02 14:53:02 +00:00
|
|
|
this->filename = xStrdup(rcfile);
|
2011-12-25 20:22:41 +00:00
|
|
|
} else {
|
|
|
|
const char* home = getenv("HOME");
|
|
|
|
if (!home) home = "";
|
|
|
|
const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
|
|
|
char* configDir = NULL;
|
|
|
|
char* htopDir = NULL;
|
|
|
|
if (xdgConfigHome) {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->filename = String_cat(xdgConfigHome, "/htop/htoprc");
|
2016-02-02 14:53:02 +00:00
|
|
|
configDir = xStrdup(xdgConfigHome);
|
2011-12-25 20:22:41 +00:00
|
|
|
htopDir = String_cat(xdgConfigHome, "/htop");
|
|
|
|
} else {
|
2015-01-22 01:27:31 +00:00
|
|
|
this->filename = String_cat(home, "/.config/htop/htoprc");
|
2011-12-25 20:22:41 +00:00
|
|
|
configDir = String_cat(home, "/.config");
|
|
|
|
htopDir = String_cat(home, "/.config/htop");
|
|
|
|
}
|
|
|
|
legacyDotfile = String_cat(home, "/.htoprc");
|
2017-07-26 18:40:55 +00:00
|
|
|
|
|
|
|
CRT_dropPrivileges();
|
2014-04-22 23:35:57 +00:00
|
|
|
(void) mkdir(configDir, 0700);
|
|
|
|
(void) mkdir(htopDir, 0700);
|
2011-12-25 20:22:41 +00:00
|
|
|
free(htopDir);
|
|
|
|
free(configDir);
|
2012-03-05 11:12:58 +00:00
|
|
|
struct stat st;
|
2018-02-18 23:42:17 +00:00
|
|
|
int err = lstat(legacyDotfile, &st);
|
|
|
|
if (err || S_ISLNK(st.st_mode)) {
|
2011-12-25 20:22:41 +00:00
|
|
|
free(legacyDotfile);
|
|
|
|
legacyDotfile = NULL;
|
|
|
|
}
|
2017-07-26 18:40:55 +00:00
|
|
|
CRT_restorePrivileges();
|
2011-12-25 20:22:41 +00:00
|
|
|
}
|
2008-03-09 08:58:38 +00:00
|
|
|
this->colorScheme = 0;
|
|
|
|
this->changed = false;
|
|
|
|
this->delay = DEFAULT_DELAY;
|
2018-02-18 23:42:17 +00:00
|
|
|
bool ok = false;
|
|
|
|
if (legacyDotfile) {
|
|
|
|
ok = Settings_read(this, legacyDotfile);
|
|
|
|
if (ok) {
|
2011-12-25 20:22:41 +00:00
|
|
|
// Transition to new location and delete old configuration file
|
|
|
|
if (Settings_write(this))
|
|
|
|
unlink(legacyDotfile);
|
|
|
|
}
|
2018-02-18 23:42:17 +00:00
|
|
|
free(legacyDotfile);
|
|
|
|
}
|
|
|
|
if (!ok) {
|
|
|
|
ok = Settings_read(this, this->filename);
|
|
|
|
}
|
|
|
|
if (!ok) {
|
2008-03-09 08:58:38 +00:00
|
|
|
this->changed = true;
|
|
|
|
// TODO: how to get SYSCONFDIR correctly through Autoconf?
|
|
|
|
char* systemSettings = String_cat(SYSCONFDIR, "/htoprc");
|
2015-05-13 18:13:55 +00:00
|
|
|
ok = Settings_read(this, systemSettings);
|
2008-03-09 08:58:38 +00:00
|
|
|
free(systemSettings);
|
|
|
|
}
|
2018-02-18 23:42:17 +00:00
|
|
|
if (!ok) {
|
|
|
|
Settings_defaultMeters(this);
|
2018-01-28 01:29:58 +00:00
|
|
|
Settings_defaultScreens(this);
|
2018-02-18 23:42:17 +00:00
|
|
|
this->hideKernelThreads = true;
|
|
|
|
this->highlightMegabytes = true;
|
|
|
|
this->highlightThreads = true;
|
|
|
|
this->headerMargin = true;
|
|
|
|
}
|
2018-01-28 06:09:06 +00:00
|
|
|
|
|
|
|
this->ssIndex = 0;
|
|
|
|
this->ss = this->screens[this->ssIndex];
|
|
|
|
|
2008-03-09 08:58:38 +00:00
|
|
|
return this;
|
|
|
|
}
|
2015-01-22 01:27:31 +00:00
|
|
|
|
2018-01-28 06:09:06 +00:00
|
|
|
void ScreenSettings_invertSortOrder(ScreenSettings* this) {
|
2015-01-22 01:27:31 +00:00
|
|
|
if (this->direction == 1)
|
|
|
|
this->direction = -1;
|
|
|
|
else
|
|
|
|
this->direction = 1;
|
|
|
|
}
|