From 1b805a31720727008b32b1129a167758519fd4db Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Mon, 2 May 2022 16:04:21 +0200 Subject: New upstream version 3.2.0 --- linux/CGroupUtils.c | 26 +++++++++++- linux/LinuxProcess.c | 22 +++++----- linux/LinuxProcessList.c | 83 ++++++++++++++++++++++++------------- linux/Platform.c | 104 +++++++++++++++++++++++++++++++++++++++-------- linux/Platform.h | 4 +- 5 files changed, 182 insertions(+), 57 deletions(-) (limited to 'linux') diff --git a/linux/CGroupUtils.c b/linux/CGroupUtils.c index 6f3b6fe..22cce91 100644 --- a/linux/CGroupUtils.c +++ b/linux/CGroupUtils.c @@ -33,7 +33,7 @@ static bool StrBuf_putc_write(StrBuf_state* p, char c) { } static bool StrBuf_putsn(StrBuf_state* p, StrBuf_putc_t w, const char* s, size_t count) { - while (count--) + for (; count; count--) if (!w(p, *s++)) return false; @@ -66,6 +66,7 @@ static bool CGroup_filterName_internal(const char *cgroup, StrBuf_state* s, StrB const char* str_user_slice = "user.slice"; const char* str_machine_slice = "machine.slice"; const char* str_user_slice_prefix = "/user-"; + const char* str_system_slice_prefix = "/system-"; const char* str_lxc_monitor_legacy = "lxc.monitor"; const char* str_lxc_payload_legacy = "lxc.payload"; @@ -76,6 +77,8 @@ static bool CGroup_filterName_internal(const char *cgroup, StrBuf_state* s, StrB const char* str_nspawn_monitor_label = "/supervisor"; const char* str_nspawn_payload_label = "/payload"; + const char* str_snap_scope_prefix = "snap."; + const char* str_service_suffix = ".service"; const char* str_scope_suffix = ".scope"; @@ -100,6 +103,11 @@ static bool CGroup_filterName_internal(const char *cgroup, StrBuf_state* s, StrB if (!StrBuf_putsz(s, w, "[S]")) return false; + if (String_startsWith(cgroup, str_system_slice_prefix)) { + cgroup = strchrnul(cgroup + 1, '/'); + continue; + } + continue; } @@ -266,6 +274,22 @@ static bool CGroup_filterName_internal(const char *cgroup, StrBuf_state* s, StrB else if (String_startsWith(nextSlash, str_nspawn_payload_label)) cgroup += strlen(str_nspawn_payload_label); + continue; + } else if(Label_checkPrefix(labelStart, scopeNameLen, str_snap_scope_prefix)) { + const char* nextDot = strchrnul(labelStart + strlen(str_snap_scope_prefix), '.'); + + if (!StrBuf_putsz(s, w, "!snap:")) + return false; + + if (nextDot >= labelStart + scopeNameLen) { + nextDot = labelStart + scopeNameLen; + } + + if (!StrBuf_putsn(s, w, labelStart + strlen(str_snap_scope_prefix), nextDot - (labelStart + strlen(str_snap_scope_prefix)))) + return false; + + cgroup = nextSlash; + continue; } diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c index ba2dbd4..299b167 100644 --- a/linux/LinuxProcess.c +++ b/linux/LinuxProcess.c @@ -57,8 +57,8 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { [M_DRS] = { .name = "M_DRS", .title = " DATA ", .description = "Size of the data segment plus stack usage of the process", .flags = 0, .defaultSortDesc = true, }, [M_LRS] = { .name = "M_LRS", .title = " LIB ", .description = "The library size of the process (calculated from memory maps)", .flags = PROCESS_FLAG_LINUX_LRS_FIX, .defaultSortDesc = true, }, [ST_UID] = { .name = "ST_UID", .title = "UID", .description = "User ID of the process owner", .flags = 0, }, - [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, .defaultSortDesc = true, }, - [PERCENT_NORM_CPU] = { .name = "PERCENT_NORM_CPU", .title = "NCPU%", .description = "Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count)", .flags = 0, .defaultSortDesc = true, }, + [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, .defaultSortDesc = true, .autoWidth = true, }, + [PERCENT_NORM_CPU] = { .name = "PERCENT_NORM_CPU", .title = "NCPU%", .description = "Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count)", .flags = 0, .defaultSortDesc = true, .autoWidth = true, }, [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, .defaultSortDesc = true, }, [USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, }, [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, .defaultSortDesc = true, }, @@ -81,8 +81,8 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { [IO_READ_RATE] = { .name = "IO_READ_RATE", .title = " DISK READ ", .description = "The I/O rate of read(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, }, [IO_WRITE_RATE] = { .name = "IO_WRITE_RATE", .title = " DISK WRITE ", .description = "The I/O rate of write(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, }, [IO_RATE] = { .name = "IO_RATE", .title = " DISK R/W ", .description = "Total I/O rate in bytes per second", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, }, - [CGROUP] = { .name = "CGROUP", .title = "CGROUP (raw) ", .description = "Which cgroup the process is in", .flags = PROCESS_FLAG_LINUX_CGROUP, }, - [CCGROUP] = { .name = "CCGROUP", .title = "CGROUP (compressed) ", .description = "Which cgroup the process is in (condensed to essentials)", .flags = PROCESS_FLAG_LINUX_CGROUP, }, + [CGROUP] = { .name = "CGROUP", .title = "CGROUP (raw)", .description = "Which cgroup the process is in", .flags = PROCESS_FLAG_LINUX_CGROUP, .autoWidth = true, }, + [CCGROUP] = { .name = "CCGROUP", .title = "CGROUP (compressed)", .description = "Which cgroup the process is in (condensed to essentials)", .flags = PROCESS_FLAG_LINUX_CGROUP, .autoWidth = true, }, [OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, .defaultSortDesc = true, }, [IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, }, #ifdef HAVE_DELAYACCT @@ -94,7 +94,7 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { [M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, }, [M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, }, [CTXT] = { .name = "CTXT", .title = " CTXT ", .description = "Context switches (incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches)", .flags = PROCESS_FLAG_LINUX_CTXT, .defaultSortDesc = true, }, - [SECATTR] = { .name = "SECATTR", .title = "Security Attribute ", .description = "Security attribute of the process (e.g. SELinux or AppArmor)", .flags = PROCESS_FLAG_LINUX_SECATTR, }, + [SECATTR] = { .name = "SECATTR", .title = "Security Attribute", .description = "Security attribute of the process (e.g. SELinux or AppArmor)", .flags = PROCESS_FLAG_LINUX_SECATTR, .autoWidth = true, }, [PROC_COMM] = { .name = "COMM", .title = "COMM ", .description = "comm string of the process from /proc/[pid]/comm", .flags = 0, }, [PROC_EXE] = { .name = "EXE", .title = "EXE ", .description = "Basename of exe of the process from /proc/[pid]/exe", .flags = 0, }, [CWD] = { .name = "CWD", .title = "CWD ", .description = "The current working directory of the process", .flags = PROCESS_FLAG_CWD, }, @@ -248,8 +248,8 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces #ifdef HAVE_VSERVER case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break; #endif - case CGROUP: xSnprintf(buffer, n, "%-35.35s ", lp->cgroup ? lp->cgroup : "N/A"); break; - case CCGROUP: xSnprintf(buffer, n, "%-35.35s ", lp->cgroup_short ? lp->cgroup_short : (lp->cgroup ? lp->cgroup : "N/A")); break; + case CGROUP: xSnprintf(buffer, n, "%-*.*s ", Process_fieldWidths[CGROUP], Process_fieldWidths[CGROUP], lp->cgroup ? lp->cgroup : "N/A"); break; + case CCGROUP: xSnprintf(buffer, n, "%-*.*s ", Process_fieldWidths[CCGROUP], Process_fieldWidths[CCGROUP], lp->cgroup_short ? lp->cgroup_short : (lp->cgroup ? lp->cgroup : "N/A")); break; case OOM: xSnprintf(buffer, n, "%4u ", lp->oom); break; case IO_PRIORITY: { int klass = IOPriority_class(lp->ioPriority); @@ -270,9 +270,9 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces break; } #ifdef HAVE_DELAYACCT - case PERCENT_CPU_DELAY: Process_printPercentage(lp->cpu_delay_percent, buffer, n, &attr); break; - case PERCENT_IO_DELAY: Process_printPercentage(lp->blkio_delay_percent, buffer, n, &attr); break; - case PERCENT_SWAP_DELAY: Process_printPercentage(lp->swapin_delay_percent, buffer, n, &attr); break; + case PERCENT_CPU_DELAY: Process_printPercentage(lp->cpu_delay_percent, buffer, n, 4, &attr); break; + case PERCENT_IO_DELAY: Process_printPercentage(lp->blkio_delay_percent, buffer, n, 4, &attr); break; + case PERCENT_SWAP_DELAY: Process_printPercentage(lp->swapin_delay_percent, buffer, n, 4, &attr); break; #endif case CTXT: if (lp->ctxt_diff > 1000) { @@ -280,7 +280,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces } xSnprintf(buffer, n, "%5lu ", lp->ctxt_diff); break; - case SECATTR: snprintf(buffer, n, "%-30.30s ", lp->secattr ? lp->secattr : "?"); break; + case SECATTR: snprintf(buffer, n, "%-*.*s ", Process_fieldWidths[SECATTR], Process_fieldWidths[SECATTR], lp->secattr ? lp->secattr : "N/A"); break; case AUTOGROUP_ID: if (lp->autogroup_id != -1) { xSnprintf(buffer, n, "%4ld ", lp->autogroup_id); diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index 3bfe7db..5e18f6d 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -174,21 +174,24 @@ static void LinuxProcessList_updateCPUcount(ProcessList* super) { LinuxProcessList* this = (LinuxProcessList*) super; unsigned int existing = 0, active = 0; - DIR* dir = opendir("/sys/devices/system/cpu"); - if (!dir) { - this->cpuData = xReallocArrayZero(this->cpuData, super->existingCPUs ? (super->existingCPUs + 1) : 0, 2, sizeof(CPUData)); + // Initialize the cpuData array before anything else. + if (!this->cpuData) { + this->cpuData = xCalloc(2, sizeof(CPUData)); this->cpuData[0].online = true; /* average is always "online" */ this->cpuData[1].online = true; super->activeCPUs = 1; super->existingCPUs = 1; - return; } + DIR* dir = opendir("/sys/devices/system/cpu"); + if (!dir) + return; + unsigned int currExisting = super->existingCPUs; const struct dirent* entry; while ((entry = readdir(dir)) != NULL) { - if (entry->d_type != DT_DIR) + if (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN) continue; if (!String_startsWith(entry->d_name, "cpu")) @@ -233,6 +236,10 @@ static void LinuxProcessList_updateCPUcount(ProcessList* super) { closedir(dir); + // return if no CPU is found + if (existing < 1) + return; + #ifdef HAVE_SENSORS_SENSORS_H /* When started with offline CPUs, libsensors does not monitor those, * even when they become online. */ @@ -493,6 +500,8 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, openat_arg_t proc unsigned long long last_read = process->io_read_bytes; unsigned long long last_write = process->io_write_bytes; + unsigned long long time_delta = realtimeMs > process->io_last_scan_time_ms ? realtimeMs - process->io_last_scan_time_ms : 0; + char* buf = buffer; const char* line; while ((line = strsep(&buf, "\n")) != NULL) { @@ -502,7 +511,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, openat_arg_t proc process->io_rchar = strtoull(line + 7, NULL, 10); } else if (String_startsWith(line + 1, "ead_bytes: ")) { process->io_read_bytes = strtoull(line + 12, NULL, 10); - process->io_rate_read_bps = (process->io_read_bytes - last_read) * /*ms to s*/1000 / (realtimeMs - process->io_last_scan_time_ms); + process->io_rate_read_bps = time_delta ? (process->io_read_bytes - last_read) * /*ms to s*/1000. / time_delta : NAN; } break; case 'w': @@ -510,7 +519,7 @@ static void LinuxProcessList_readIoFile(LinuxProcess* process, openat_arg_t proc process->io_wchar = strtoull(line + 7, NULL, 10); } else if (String_startsWith(line + 1, "rite_bytes: ")) { process->io_write_bytes = strtoull(line + 13, NULL, 10); - process->io_rate_write_bps = (process->io_write_bytes - last_write) * /*ms to s*/1000 / (realtimeMs - process->io_last_scan_time_ms); + process->io_rate_write_bps = time_delta ? (process->io_write_bytes - last_write) * /*ms to s*/1000. / time_delta : NAN; } break; case 's': @@ -900,16 +909,27 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, openat_arg_t bool changed = !process->cgroup || !String_eq(process->cgroup, output); + Process_updateFieldWidth(CGROUP, strlen(output)); free_and_xStrdup(&process->cgroup, output); - if (!changed) + if (!changed) { + if(process->cgroup_short) { + Process_updateFieldWidth(CCGROUP, strlen(process->cgroup_short)); + } else { + //CCGROUP is alias to normal CGROUP if shortening fails + Process_updateFieldWidth(CCGROUP, strlen(process->cgroup)); + } return; + } char* cgroup_short = CGroup_filterName(process->cgroup); if (cgroup_short) { + Process_updateFieldWidth(CCGROUP, strlen(cgroup_short)); free_and_xStrdup(&process->cgroup_short, cgroup_short); free(cgroup_short); } else { + //CCGROUP is alias to normal CGROUP if shortening fails + Process_updateFieldWidth(CCGROUP, strlen(process->cgroup)); free(process->cgroup_short); process->cgroup_short = NULL; } @@ -1027,6 +1047,9 @@ static void LinuxProcessList_readSecattrData(LinuxProcess* process, openat_arg_t if (newline) { *newline = '\0'; } + + Process_updateFieldWidth(SECATTR, strlen(buffer)); + if (process->secattr && String_eq(process->secattr, buffer)) { return; } @@ -1370,6 +1393,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ ProcessList* pl = (ProcessList*) this; const struct dirent* entry; const Settings* settings = pl->settings; + const ScreenSettings* ss = settings->ss; #ifdef HAVE_OPENAT int dirFd = openat(parentFd, dirname, O_RDONLY | O_DIRECTORY | O_NOFOLLOW); @@ -1463,7 +1487,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ continue; } - if (settings->flags & PROCESS_FLAG_IO) + if (ss->flags & PROCESS_FLAG_IO) LinuxProcessList_readIoFile(lp, procFd, pl->realtimeMs); if (!LinuxProcessList_readStatmFile(lp, procFd)) @@ -1472,8 +1496,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ { bool prev = proc->usesDeletedLib; - if ((settings->flags & PROCESS_FLAG_LINUX_LRS_FIX) || - (settings->highlightDeletedExe && !proc->procExeDeleted && !proc->isKernelThread && !proc->isUserlandThread)) { + if (!proc->isKernelThread && !proc->isUserlandThread && + ((ss->flags & PROCESS_FLAG_LINUX_LRS_FIX) || (settings->highlightDeletedExe && !proc->procExeDeleted))) { + // Check if we really should recalculate the M_LRS value for this process uint64_t passedTimeInMs = pl->realtimeMs - lp->last_mlrs_calctime; @@ -1481,17 +1506,18 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ if (passedTimeInMs > recheck) { lp->last_mlrs_calctime = pl->realtimeMs; - LinuxProcessList_readMaps(lp, procFd, settings->flags & PROCESS_FLAG_LINUX_LRS_FIX, settings->highlightDeletedExe); + LinuxProcessList_readMaps(lp, procFd, ss->flags & PROCESS_FLAG_LINUX_LRS_FIX, settings->highlightDeletedExe); } } else { /* Copy from process structure in threads and reset if setting got disabled */ proc->usesDeletedLib = (proc->isUserlandThread && parent) ? parent->usesDeletedLib : false; + lp->m_lrs = (proc->isUserlandThread && parent) ? ((const LinuxProcess*)parent)->m_lrs : 0; } proc->mergedCommand.exeChanged |= prev ^ proc->usesDeletedLib; } - if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) { + if ((ss->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) { if (!parent) { // Read smaps file of each process only every second pass to improve performance static int smaps_flag = 0; @@ -1521,7 +1547,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ proc->tty_name = LinuxProcessList_updateTtyDevice(this->ttyDrivers, proc->tty_nr); } - if (settings->flags & PROCESS_FLAG_LINUX_IOPRIO) { + if (ss->flags & PROCESS_FLAG_LINUX_IOPRIO) { LinuxProcess_updateIOPriority(lp); } @@ -1529,6 +1555,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ float percent_cpu = (period < 1E-6) ? 0.0F : ((lp->utime + lp->stime - lasttimes) / period * 100.0); proc->percent_cpu = CLAMP(percent_cpu, 0.0F, activeCPUs * 100.0F); proc->percent_mem = proc->m_resident / (double)(pl->totalMem) * 100.0; + Process_updateCPUFieldWidths(proc->percent_cpu); if (! LinuxProcessList_updateUser(pl, proc, procFd)) goto errorReadingProcess; @@ -1536,13 +1563,13 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ if (!preExisting) { #ifdef HAVE_OPENVZ - if (settings->flags & PROCESS_FLAG_LINUX_OPENVZ) { + if (ss->flags & PROCESS_FLAG_LINUX_OPENVZ) { LinuxProcessList_readOpenVZData(lp, procFd); } #endif #ifdef HAVE_VSERVER - if (settings->flags & PROCESS_FLAG_LINUX_VSERVER) { + if (ss->flags & PROCESS_FLAG_LINUX_VSERVER) { LinuxProcessList_readVServerData(lp, procFd); } #endif @@ -1567,32 +1594,32 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ } #ifdef HAVE_DELAYACCT - if (settings->flags & PROCESS_FLAG_LINUX_DELAYACCT) { + if (ss->flags & PROCESS_FLAG_LINUX_DELAYACCT) { LinuxProcessList_readDelayAcctData(this, lp); } #endif - if (settings->flags & PROCESS_FLAG_LINUX_CGROUP) { + if (ss->flags & PROCESS_FLAG_LINUX_CGROUP) { LinuxProcessList_readCGroupFile(lp, procFd); } - if (settings->flags & PROCESS_FLAG_LINUX_OOM) { + if (ss->flags & PROCESS_FLAG_LINUX_OOM) { LinuxProcessList_readOomData(lp, procFd); } - if (settings->flags & PROCESS_FLAG_LINUX_CTXT) { + if (ss->flags & PROCESS_FLAG_LINUX_CTXT) { LinuxProcessList_readCtxtData(lp, procFd); } - if (settings->flags & PROCESS_FLAG_LINUX_SECATTR) { + if (ss->flags & PROCESS_FLAG_LINUX_SECATTR) { LinuxProcessList_readSecattrData(lp, procFd); } - if (settings->flags & PROCESS_FLAG_CWD) { + if (ss->flags & PROCESS_FLAG_CWD) { LinuxProcessList_readCwd(lp, procFd); } - if ((settings->flags & PROCESS_FLAG_LINUX_AUTOGROUP) && this->haveAutogroup) { + if ((ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP) && this->haveAutogroup) { LinuxProcessList_readAutogroup(lp, procFd); } @@ -1994,7 +2021,7 @@ static inline double LinuxProcessList_scanCPUTime(ProcessList* super) { return period; } -static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) { +static int scanCPUFrequencyFromSysCPUFreq(LinuxProcessList* this) { unsigned int existingCPUs = this->super.existingCPUs; int numCPUsWithFrequency = 0; unsigned long totalFrequency = 0; @@ -2057,7 +2084,7 @@ static int scanCPUFreqencyFromSysCPUFreq(LinuxProcessList* this) { return 0; } -static void scanCPUFreqencyFromCPUinfo(LinuxProcessList* this) { +static void scanCPUFrequencyFromCPUinfo(LinuxProcessList* this) { FILE* file = fopen(PROCCPUINFOFILE, "r"); if (file == NULL) return; @@ -2114,11 +2141,11 @@ static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) { this->cpuData[i].frequency = NAN; } - if (scanCPUFreqencyFromSysCPUFreq(this) == 0) { + if (scanCPUFrequencyFromSysCPUFreq(this) == 0) { return; } - scanCPUFreqencyFromCPUinfo(this); + scanCPUFrequencyFromCPUinfo(this); } void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { @@ -2146,7 +2173,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { return; } - if (settings->flags & PROCESS_FLAG_LINUX_AUTOGROUP) { + if (settings->ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP) { // Refer to sched(7) 'autogroup feature' section // The kernel feature can be enabled/disabled through procfs at // any time, so check for it at the start of each sample - only diff --git a/linux/Platform.c b/linux/Platform.c index 93953e8..775f9ae 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -70,6 +70,10 @@ in the source distribution for its full text. #include "LibSensors.h" #endif +#ifndef O_PATH +#define O_PATH 010000000 // declare for ancient glibc versions +#endif + #ifdef HAVE_LIBCAP enum CapMode { @@ -79,7 +83,22 @@ enum CapMode { }; #endif -const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 }; +bool Running_containerized = false; + +const ScreenDefaults Platform_defaultScreens[] = { + { + .name = "Main", + .columns = "PID USER PRIORITY NICE M_VIRT M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command", + .sortKey = "PERCENT_CPU", + }, + { + .name = "I/O", + .columns = "PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command", + .sortKey = "IO_RATE", + }, +}; + +const unsigned int Platform_numberOfDefaultScreens = ARRAYSIZE(Platform_defaultScreens); const SignalItem Platform_signals[] = { { .name = " 0 Cancel", .number = 0 }, @@ -338,7 +357,7 @@ void Platform_setMemoryValues(Meter* this) { this->values[3] = pl->cachedMem; this->values[4] = pl->availableMem; - if (lpl->zfs.enabled != 0) { + if (lpl->zfs.enabled != 0 && !Running_containerized) { this->values[0] -= lpl->zfs.size; this->values[3] += lpl->zfs.size; } @@ -712,18 +731,47 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) { uint64_t totalFull = 0; uint64_t totalRemain = 0; - struct dirent* dirEntry = NULL; + const struct dirent* dirEntry; while ((dirEntry = readdir(dir))) { const char* entryName = dirEntry->d_name; +#ifdef HAVE_OPENAT + int entryFd = openat(dirfd(dir), entryName, O_DIRECTORY | O_PATH); + if (entryFd < 0) + continue; +#else + char entryFd[4096]; + xSnprintf(entryFd, sizeof(entryFd), SYS_POWERSUPPLY_DIR "/%s", entryName); +#endif + + enum { AC, BAT } type; if (String_startsWith(entryName, "BAT")) { - char buffer[1024] = {0}; - char filePath[256]; - xSnprintf(filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName); + type = BAT; + } else if (String_startsWith(entryName, "AC")) { + type = AC; + } else { + char buffer[32]; + ssize_t ret = xReadfileat(entryFd, "type", buffer, sizeof(buffer)); + if (ret <= 0) + goto next; + + /* drop optional trailing newlines */ + for (char* buf = &buffer[(size_t)ret - 1]; *buf == '\n'; buf--) + *buf = '\0'; + + if (String_eq(buffer, "Battery")) + type = BAT; + else if (String_eq(buffer, "Mains")) + type = AC; + else + goto next; + } - ssize_t r = xReadfile(filePath, buffer, sizeof(buffer)); + if (type == BAT) { + char buffer[1024]; + ssize_t r = xReadfileat(entryFd, "uevent", buffer, sizeof(buffer)); if (r < 0) - continue; + goto next; bool full = false; bool now = false; @@ -765,18 +813,15 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) { if (!now && full && !isnan(capacityLevel)) totalRemain += capacityLevel * fullCharge; - } else if (String_startsWith(entryName, "AC")) { - char buffer[2] = {0}; + } else if (type == AC) { if (*isOnAC != AC_ERROR) - continue; - - char filePath[256]; - xSnprintf(filePath, sizeof(filePath), SYS_POWERSUPPLY_DIR "/%s/online", entryName); + goto next; - ssize_t r = xReadfile(filePath, buffer, sizeof(buffer)); + char buffer[2]; + ssize_t r = xReadfileat(entryFd, "online", buffer, sizeof(buffer)); if (r < 1) { *isOnAC = AC_ERROR; - continue; + goto next; } if (buffer[0] == '0') @@ -784,6 +829,9 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) { else if (buffer[0] == '1') *isOnAC = AC_PRESENT; } + +next: + Compat_openatArgClose(entryFd); } closedir(dir); @@ -971,6 +1019,30 @@ bool Platform_init(void) { LibSensors_init(); #endif + char target[PATH_MAX]; + ssize_t ret = readlink(PROCDIR "/self/ns/pid", target, sizeof(target) - 1); + if (ret > 0) { + target[ret] = '\0'; + + if (!String_eq("pid:[4026531836]", target)) { // magic constant PROC_PID_INIT_INO from include/linux/proc_ns.h#L46 + Running_containerized = true; + return true; // early return + } + } + + FILE* fd = fopen(PROCDIR "/1/mounts", "r"); + if (fd) { + char lineBuffer[256]; + while (fgets(lineBuffer, sizeof(lineBuffer), fd)) { + // detect lxc or overlayfs and guess that this means we are running containerized + if (String_startsWith(lineBuffer, "lxcfs ") || String_startsWith(lineBuffer, "overlay ")) { + Running_containerized = true; + break; + } + } + fclose(fd); + } // if (fd) + return true; } diff --git a/linux/Platform.h b/linux/Platform.h index 2e2fb3e..f2c314f 100644 --- a/linux/Platform.h +++ b/linux/Platform.h @@ -38,7 +38,9 @@ in the source distribution for its full text. #endif -extern const ProcessField Platform_defaultFields[]; +extern const ScreenDefaults Platform_defaultScreens[]; + +extern const unsigned int Platform_numberOfDefaultScreens; extern const SignalItem Platform_signals[]; -- cgit v1.2.3