aboutsummaryrefslogtreecommitdiffstats
path: root/linux/Platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/Platform.c')
-rw-r--r--linux/Platform.c387
1 files changed, 289 insertions, 98 deletions
diff --git a/linux/Platform.c b/linux/Platform.c
index dd80ded..05023d5 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -7,14 +7,13 @@ in the source distribution for its full text.
#include "config.h"
-#include "Platform.h"
+#include "linux/Platform.h"
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
@@ -31,40 +30,55 @@ in the source distribution for its full text.
#include "DateTimeMeter.h"
#include "DiskIOMeter.h"
#include "HostnameMeter.h"
-#include "IOPriority.h"
-#include "IOPriorityPanel.h"
-#include "LinuxProcess.h"
-#include "LinuxProcessList.h"
+#include "HugePageMeter.h"
#include "LoadAverageMeter.h"
#include "Macros.h"
#include "MainPanel.h"
#include "Meter.h"
#include "MemoryMeter.h"
+#include "MemorySwapMeter.h"
#include "NetworkIOMeter.h"
#include "Object.h"
#include "Panel.h"
#include "PressureStallMeter.h"
#include "ProcessList.h"
#include "ProvideCurses.h"
-#include "SELinuxMeter.h"
+#include "linux/SELinuxMeter.h"
#include "Settings.h"
#include "SwapMeter.h"
-#include "SystemdMeter.h"
+#include "SysArchMeter.h"
#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "XUtils.h"
-#include "ZramMeter.h"
-#include "ZramStats.h"
-
+#include "linux/IOPriority.h"
+#include "linux/IOPriorityPanel.h"
+#include "linux/LinuxProcess.h"
+#include "linux/LinuxProcessList.h"
+#include "linux/SystemdMeter.h"
+#include "linux/ZramMeter.h"
+#include "linux/ZramStats.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsArcStats.h"
#include "zfs/ZfsCompressedArcMeter.h"
+#ifdef HAVE_LIBCAP
+#include <errno.h>
+#include <sys/capability.h>
+#endif
+
#ifdef HAVE_SENSORS_SENSORS_H
#include "LibSensors.h"
#endif
+#ifdef HAVE_LIBCAP
+enum CapMode {
+ CAP_MODE_OFF,
+ CAP_MODE_BASIC,
+ CAP_MODE_STRICT
+};
+#endif
+
const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
const SignalItem Platform_signals[] = {
@@ -111,36 +125,24 @@ static time_t Platform_Battery_cacheTime;
static double Platform_Battery_cachePercent = NAN;
static ACPresence Platform_Battery_cacheIsOnAC;
-void Platform_init(void) {
- if (access(PROCDIR, R_OK) != 0) {
- fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR);
- exit(1);
- }
-
-#ifdef HAVE_SENSORS_SENSORS_H
- LibSensors_init(NULL);
-#endif
-}
-
-void Platform_done(void) {
-#ifdef HAVE_SENSORS_SENSORS_H
- LibSensors_cleanup();
+#ifdef HAVE_LIBCAP
+static enum CapMode Platform_capabilitiesMode = CAP_MODE_BASIC;
#endif
-}
static Htop_Reaction Platform_actionSetIOPriority(State* st) {
- Panel* panel = st->panel;
+ if (Settings_isReadonly())
+ return HTOP_OK;
- LinuxProcess* p = (LinuxProcess*) Panel_getSelected(panel);
+ const LinuxProcess* p = (const LinuxProcess*) Panel_getSelected((Panel*)st->mainPanel);
if (!p)
return HTOP_OK;
IOPriority ioprio1 = p->ioPriority;
Panel* ioprioPanel = IOPriorityPanel_new(ioprio1);
- void* set = Action_pickFromVector(st, ioprioPanel, 21, true);
+ const void* set = Action_pickFromVector(st, ioprioPanel, 20, true);
if (set) {
IOPriority ioprio2 = IOPriorityPanel_getIOPriority(ioprioPanel);
- bool ok = MainPanel_foreachProcess((MainPanel*)panel, LinuxProcess_setIOPriority, (Arg) { .i = ioprio2 }, NULL);
+ bool ok = MainPanel_foreachProcess(st->mainPanel, LinuxProcess_setIOPriority, (Arg) { .i = ioprio2 }, NULL);
if (!ok) {
beep();
}
@@ -149,8 +151,40 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
}
+static bool Platform_changeAutogroupPriority(MainPanel* panel, int delta) {
+ if (LinuxProcess_isAutogroupEnabled() == false) {
+ beep();
+ return false;
+ }
+ bool anyTagged;
+ bool ok = MainPanel_foreachProcess(panel, LinuxProcess_changeAutogroupPriorityBy, (Arg) { .i = delta }, &anyTagged);
+ if (!ok)
+ beep();
+ return anyTagged;
+}
+
+static Htop_Reaction Platform_actionHigherAutogroupPriority(State* st) {
+ if (Settings_isReadonly())
+ return HTOP_OK;
+
+ bool changed = Platform_changeAutogroupPriority(st->mainPanel, -1);
+ return changed ? HTOP_REFRESH : HTOP_OK;
+}
+
+static Htop_Reaction Platform_actionLowerAutogroupPriority(State* st) {
+ if (Settings_isReadonly())
+ return HTOP_OK;
+
+ bool changed = Platform_changeAutogroupPriority(st->mainPanel, 1);
+ return changed ? HTOP_REFRESH : HTOP_OK;
+}
+
void Platform_setBindings(Htop_Action* keys) {
keys['i'] = Platform_actionSetIOPriority;
+ keys['{'] = Platform_actionLowerAutogroupPriority;
+ keys['}'] = Platform_actionHigherAutogroupPriority;
+ keys[KEY_F(19)] = Platform_actionLowerAutogroupPriority; // Shift-F7
+ keys[KEY_F(20)] = Platform_actionHigherAutogroupPriority; // Shift-F8
}
const MeterClass* const Platform_meterTypes[] = {
@@ -162,6 +196,9 @@ const MeterClass* const Platform_meterTypes[] = {
&LoadMeter_class,
&MemoryMeter_class,
&SwapMeter_class,
+ &MemorySwapMeter_class,
+ &SysArchMeter_class,
+ &HugePageMeter_class,
&TasksMeter_class,
&UptimeMeter_class,
&BatteryMeter_class,
@@ -208,19 +245,25 @@ int Platform_getUptime() {
}
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
- int activeProcs, totalProcs, lastProc;
- *one = 0;
- *five = 0;
- *fifteen = 0;
-
FILE* fd = fopen(PROCDIR "/loadavg", "r");
- if (fd) {
- int total = fscanf(fd, "%32lf %32lf %32lf %32d/%32d %32d", one, five, fifteen,
- &activeProcs, &totalProcs, &lastProc);
- (void) total;
- assert(total == 6);
- fclose(fd);
- }
+ if (!fd)
+ goto err;
+
+ double scanOne, scanFive, scanFifteen;
+ int r = fscanf(fd, "%lf %lf %lf", &scanOne, &scanFive, &scanFifteen);
+ fclose(fd);
+ if (r != 3)
+ goto err;
+
+ *one = scanOne;
+ *five = scanFive;
+ *fifteen = scanFifteen;
+ return;
+
+err:
+ *one = NAN;
+ *five = NAN;
+ *fifteen = NAN;
}
int Platform_getMaxPid() {
@@ -235,12 +278,18 @@ int Platform_getMaxPid() {
return maxPid;
}
-double Platform_setCPUValues(Meter* this, int cpu) {
+double Platform_setCPUValues(Meter* this, unsigned int cpu) {
const LinuxProcessList* pl = (const LinuxProcessList*) this->pl;
- const CPUData* cpuData = &(pl->cpus[cpu]);
+ const CPUData* cpuData = &(pl->cpuData[cpu]);
double total = (double) ( cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod);
double percent;
double* v = this->values;
+
+ if (!cpuData->online) {
+ this->curItems = 0;
+ return NAN;
+ }
+
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
if (this->pl->settings->detailedCPUTime) {
@@ -282,18 +331,16 @@ void Platform_setMemoryValues(Meter* this) {
const ProcessList* pl = this->pl;
const LinuxProcessList* lpl = (const LinuxProcessList*) pl;
- long int usedMem = pl->usedMem;
- long int buffersMem = pl->buffersMem;
- long int cachedMem = pl->cachedMem;
- usedMem -= buffersMem + cachedMem;
- this->total = pl->totalMem;
- this->values[0] = usedMem;
- this->values[1] = buffersMem;
- this->values[2] = cachedMem;
+ this->total = pl->totalMem > lpl->totalHugePageMem ? pl->totalMem - lpl->totalHugePageMem : pl->totalMem;
+ this->values[0] = pl->usedMem > lpl->totalHugePageMem ? pl->usedMem - lpl->totalHugePageMem : pl->usedMem;
+ this->values[1] = pl->buffersMem;
+ this->values[2] = pl->sharedMem;
+ this->values[3] = pl->cachedMem;
+ this->values[4] = pl->availableMem;
if (lpl->zfs.enabled != 0) {
this->values[0] -= lpl->zfs.size;
- this->values[2] += lpl->zfs.size;
+ this->values[3] += lpl->zfs.size;
}
}
@@ -301,6 +348,7 @@ void Platform_setSwapValues(Meter* this) {
const ProcessList* pl = this->pl;
this->total = pl->totalSwap;
this->values[0] = pl->usedSwap;
+ this->values[1] = pl->cachedSwap;
}
void Platform_setZramValues(Meter* this) {
@@ -366,8 +414,8 @@ char* Platform_getProcessEnv(pid_t pid) {
*/
char* Platform_getInodeFilename(pid_t pid, ino_t inode) {
struct stat sb;
- struct dirent *de;
- DIR *dirp;
+ const struct dirent* de;
+ DIR* dirp;
ssize_t len;
int fd;
@@ -495,33 +543,27 @@ bool Platform_getDiskIO(DiskIOData* data) {
if (!fd)
return false;
- unsigned long int read_sum = 0, write_sum = 0, timeSpend_sum = 0;
+ char lastTopDisk[32] = { '\0' };
+
+ unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0;
char lineBuffer[256];
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) {
char diskname[32];
- unsigned long int read_tmp, write_tmp, timeSpend_tmp;
- if (sscanf(lineBuffer, "%*d %*d %31s %*u %*u %lu %*u %*u %*u %lu %*u %*u %lu", diskname, &read_tmp, &write_tmp, &timeSpend_tmp) == 4) {
+ unsigned long long int read_tmp, write_tmp, timeSpend_tmp;
+ if (sscanf(lineBuffer, "%*d %*d %31s %*u %*u %llu %*u %*u %*u %llu %*u %*u %llu", diskname, &read_tmp, &write_tmp, &timeSpend_tmp) == 4) {
if (String_startsWith(diskname, "dm-"))
continue;
- /* only count root disks, e.g. do not count IO from sda and sda1 twice */
- if ((diskname[0] == 's' || diskname[0] == 'h')
- && diskname[1] == 'd'
- && isalpha((unsigned char)diskname[2])
- && isdigit((unsigned char)diskname[3]))
+ if (String_startsWith(diskname, "zram"))
continue;
- /* only count root disks, e.g. do not count IO from mmcblk0 and mmcblk0p1 twice */
- if (diskname[0] == 'm'
- && diskname[1] == 'm'
- && diskname[2] == 'c'
- && diskname[3] == 'b'
- && diskname[4] == 'l'
- && diskname[5] == 'k'
- && isdigit((unsigned char)diskname[6])
- && diskname[7] == 'p')
+ /* only count root disks, e.g. do not count IO from sda and sda1 twice */
+ if (lastTopDisk[0] && String_startsWith(diskname, lastTopDisk))
continue;
+ /* This assumes disks are listed directly before any of their partitions */
+ String_safeStrncpy(lastTopDisk, diskname, sizeof(lastTopDisk));
+
read_sum += read_tmp;
write_sum += write_tmp;
timeSpend_sum += timeSpend_tmp;
@@ -535,42 +577,35 @@ bool Platform_getDiskIO(DiskIOData* data) {
return true;
}
-bool Platform_getNetworkIO(unsigned long int* bytesReceived,
- unsigned long int* packetsReceived,
- unsigned long int* bytesTransmitted,
- unsigned long int* packetsTransmitted) {
+bool Platform_getNetworkIO(NetworkIOData* data) {
FILE* fd = fopen(PROCDIR "/net/dev", "r");
if (!fd)
return false;
- unsigned long int bytesReceivedSum = 0, packetsReceivedSum = 0, bytesTransmittedSum = 0, packetsTransmittedSum = 0;
+ memset(data, 0, sizeof(NetworkIOData));
char lineBuffer[512];
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) {
char interfaceName[32];
- unsigned long int bytesReceivedParsed, packetsReceivedParsed, bytesTransmittedParsed, packetsTransmittedParsed;
- if (sscanf(lineBuffer, "%31s %lu %lu %*u %*u %*u %*u %*u %*u %lu %lu",
+ unsigned long long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted;
+ if (sscanf(lineBuffer, "%31s %llu %llu %*u %*u %*u %*u %*u %*u %llu %llu",
interfaceName,
- &bytesReceivedParsed,
- &packetsReceivedParsed,
- &bytesTransmittedParsed,
- &packetsTransmittedParsed) != 5)
+ &bytesReceived,
+ &packetsReceived,
+ &bytesTransmitted,
+ &packetsTransmitted) != 5)
continue;
if (String_eq(interfaceName, "lo:"))
continue;
- bytesReceivedSum += bytesReceivedParsed;
- packetsReceivedSum += packetsReceivedParsed;
- bytesTransmittedSum += bytesTransmittedParsed;
- packetsTransmittedSum += packetsTransmittedParsed;
+ data->bytesReceived += bytesReceived;
+ data->packetsReceived += packetsReceived;
+ data->bytesTransmitted += bytesTransmitted;
+ data->packetsTransmitted += packetsTransmitted;
}
fclose(fd);
- *bytesReceived = bytesReceivedSum;
- *packetsReceived = packetsReceivedSum;
- *bytesTransmitted = bytesTransmittedSum;
- *packetsTransmitted = packetsTransmittedSum;
return true;
}
@@ -596,11 +631,11 @@ static unsigned long int parseBatInfo(const char* fileName, const unsigned short
memset(batteries, 0, MAX_BATTERIES * sizeof(char*));
while (nBatteries < MAX_BATTERIES) {
- struct dirent* dirEntry = readdir(batteryDir);
+ const struct dirent* dirEntry = readdir(batteryDir);
if (!dirEntry)
break;
- char* entryName = dirEntry->d_name;
+ const char* entryName = dirEntry->d_name;
if (!String_startsWith(entryName, "BAT"))
continue;
@@ -653,7 +688,7 @@ static ACPresence procAcpiCheck(void) {
return AC_ERROR;
for (;;) {
- struct dirent* dirEntry = readdir(dir);
+ const struct dirent* dirEntry = readdir(dir);
if (!dirEntry)
break;
@@ -688,8 +723,7 @@ static ACPresence procAcpiCheck(void) {
break;
}
- if (dir)
- closedir(dir);
+ closedir(dir);
return isOn;
}
@@ -728,7 +762,7 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
unsigned long int totalRemain = 0;
for (;;) {
- struct dirent* dirEntry = readdir(dir);
+ const struct dirent* dirEntry = readdir(dir);
if (!dirEntry)
break;
@@ -753,7 +787,7 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
}
char* buf = buffer;
- char* line = NULL;
+ const char* line;
bool full = false;
bool now = false;
int fullSize = 0;
@@ -852,3 +886,160 @@ void Platform_getBattery(double* percent, ACPresence* isOnAC) {
Platform_Battery_cacheIsOnAC = *isOnAC;
Platform_Battery_cacheTime = now;
}
+
+void Platform_longOptionsUsage(const char* name)
+{
+#ifdef HAVE_LIBCAP
+ printf(
+" --drop-capabilities[=off|basic|strict] Drop Linux capabilities when running as root\n"
+" off - do not drop any capabilities\n"
+" basic (default) - drop all capabilities not needed by %s\n"
+" strict - drop all capabilities except those needed for\n"
+" core functionality\n", name);
+#else
+ (void) name;
+#endif
+}
+
+bool Platform_getLongOption(int opt, int argc, char** argv) {
+#ifndef HAVE_LIBCAP
+ (void) argc;
+ (void) argv;
+#endif
+
+ switch (opt) {
+#ifdef HAVE_LIBCAP
+ case 160: {
+ const char* mode = optarg;
+ if (!mode && optind < argc && argv[optind] != NULL &&
+ (argv[optind][0] != '\0' && argv[optind][0] != '-')) {
+ mode = argv[optind++];
+ }
+
+ if (!mode || String_eq(mode, "basic")) {
+ Platform_capabilitiesMode = CAP_MODE_BASIC;
+ } else if (String_eq(mode, "off")) {
+ Platform_capabilitiesMode = CAP_MODE_OFF;
+ } else if (String_eq(mode, "strict")) {
+ Platform_capabilitiesMode = CAP_MODE_STRICT;
+ } else {
+ fprintf(stderr, "Error: invalid capabilities mode \"%s\".\n", mode);
+ exit(1);
+ }
+ return true;
+ }
+#endif
+
+ default:
+ break;
+ }
+ return false;
+}
+
+#ifdef HAVE_LIBCAP
+static int dropCapabilities(enum CapMode mode) {
+
+ if (mode == CAP_MODE_OFF)
+ return 0;
+
+ /* capabilities we keep to operate */
+ const cap_value_t keepcapsStrict[] = {
+ CAP_DAC_READ_SEARCH,
+ CAP_SYS_PTRACE,
+ };
+ const cap_value_t keepcapsBasic[] = {
+ CAP_DAC_READ_SEARCH, /* read non world-readable process files of other users, like /proc/[pid]/io */
+ CAP_KILL, /* send signals to processes of other users */
+ CAP_SYS_NICE, /* lower process nice value / change nice value for arbitrary processes */
+ CAP_SYS_PTRACE, /* read /proc/[pid]/exe */
+#ifdef HAVE_DELAYACCT
+ CAP_NET_ADMIN, /* communicate over netlink socket for delay accounting */
+#endif
+ };
+ const cap_value_t* const keepcaps = (mode == CAP_MODE_BASIC) ? keepcapsBasic : keepcapsStrict;
+ const size_t ncap = (mode == CAP_MODE_BASIC) ? ARRAYSIZE(keepcapsBasic) : ARRAYSIZE(keepcapsStrict);
+
+ cap_t caps = cap_init();
+ if (caps == NULL) {
+ fprintf(stderr, "Error: can not initialize capabilities: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (cap_clear(caps) < 0) {
+ fprintf(stderr, "Error: can not clear capabilities: %s\n", strerror(errno));
+ cap_free(caps);
+ return -1;
+ }
+
+ cap_t currCaps = cap_get_proc();
+ if (currCaps == NULL) {
+ fprintf(stderr, "Error: can not get current process capabilities: %s\n", strerror(errno));
+ cap_free(caps);
+ return -1;
+ }
+
+ for (size_t i = 0; i < ncap; i++) {
+ if (!CAP_IS_SUPPORTED(keepcaps[i]))
+ continue;
+
+ cap_flag_value_t current;
+ if (cap_get_flag(currCaps, keepcaps[i], CAP_PERMITTED, &current) < 0) {
+ fprintf(stderr, "Error: can not get current value of capability %d: %s\n", keepcaps[i], strerror(errno));
+ cap_free(currCaps);
+ cap_free(caps);
+ return -1;
+ }
+
+ if (current != CAP_SET)
+ continue;
+
+ if (cap_set_flag(caps, CAP_PERMITTED, 1, &keepcaps[i], CAP_SET) < 0) {
+ fprintf(stderr, "Error: can not set permitted capability %d: %s\n", keepcaps[i], strerror(errno));
+ cap_free(currCaps);
+ cap_free(caps);
+ return -1;
+ }
+
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &keepcaps[i], CAP_SET) < 0) {
+ fprintf(stderr, "Error: can not set effective capability %d: %s\n", keepcaps[i], strerror(errno));
+ cap_free(currCaps);
+ cap_free(caps);
+ return -1;
+ }
+ }
+
+ if (cap_set_proc(caps) < 0) {
+ fprintf(stderr, "Error: can not set process capabilities: %s\n", strerror(errno));
+ cap_free(currCaps);
+ cap_free(caps);
+ return -1;
+ }
+
+ cap_free(currCaps);
+ cap_free(caps);
+
+ return 0;
+}
+#endif
+
+void Platform_init(void) {
+#ifdef HAVE_LIBCAP
+ if (dropCapabilities(Platform_capabilitiesMode) < 0)
+ exit(1);
+#endif
+
+ if (access(PROCDIR, R_OK) != 0) {
+ fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR);
+ exit(1);
+ }
+
+#ifdef HAVE_SENSORS_SENSORS_H
+ LibSensors_init();
+#endif
+}
+
+void Platform_done(void) {
+#ifdef HAVE_SENSORS_SENSORS_H
+ LibSensors_cleanup();
+#endif
+}

© 2014-2024 Faster IT GmbH | imprint | privacy policy