// SPDX-License-Identifier: GPL-3.0-or-later #include "apps_plugin.h" #if defined(__FreeBSD__) static inline bool read_proc_pid_status_per_os(struct pid_stat *p, void *ptr) { struct kinfo_proc *proc_info = (struct kinfo_proc *)ptr; p->uid = proc_info->ki_uid; p->gid = proc_info->ki_groups[0]; p->status_vmsize = proc_info->ki_size / 1024; // in KiB p->status_vmrss = proc_info->ki_rssize * pagesize / 1024; // in KiB // TODO: what about shared and swap memory on FreeBSD? return true; } #endif #ifdef __APPLE__ static inline bool read_proc_pid_status_per_os(struct pid_stat *p, void *ptr) { struct pid_info *pi = ptr; p->uid = pi->bsdinfo.pbi_uid; p->gid = pi->bsdinfo.pbi_gid; p->status_vmsize = pi->taskinfo.pti_virtual_size / 1024; // Convert bytes to KiB p->status_vmrss = pi->taskinfo.pti_resident_size / 1024; // Convert bytes to KiB // p->status_vmswap = rusageinfo.ri_swapins + rusageinfo.ri_swapouts; // This is not directly available, consider an alternative representation p->status_voluntary_ctxt_switches = pi->taskinfo.pti_csw; // p->status_nonvoluntary_ctxt_switches = taskinfo.pti_nivcsw; return true; } #endif // __APPLE__ #if !defined(__FreeBSD__) && !defined(__APPLE__) struct arl_callback_ptr { struct pid_stat *p; procfile *ff; size_t line; }; void arl_callback_status_uid(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 5)) return; //const char *real_uid = procfile_lineword(aptr->ff, aptr->line, 1); const char *effective_uid = procfile_lineword(aptr->ff, aptr->line, 2); //const char *saved_uid = procfile_lineword(aptr->ff, aptr->line, 3); //const char *filesystem_uid = procfile_lineword(aptr->ff, aptr->line, 4); if(likely(effective_uid && *effective_uid)) aptr->p->uid = (uid_t)str2l(effective_uid); } void arl_callback_status_gid(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 5)) return; //const char *real_gid = procfile_lineword(aptr->ff, aptr->line, 1); const char *effective_gid = procfile_lineword(aptr->ff, aptr->line, 2); //const char *saved_gid = procfile_lineword(aptr->ff, aptr->line, 3); //const char *filesystem_gid = procfile_lineword(aptr->ff, aptr->line, 4); if(likely(effective_gid && *effective_gid)) aptr->p->gid = (uid_t)str2l(effective_gid); } void arl_callback_status_vmsize(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; aptr->p->status_vmsize = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); } void arl_callback_status_vmswap(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; aptr->p->status_vmswap = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); } void arl_callback_status_vmrss(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; aptr->p->status_vmrss = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); } void arl_callback_status_rssfile(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; aptr->p->status_rssfile = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); } void arl_callback_status_rssshmem(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 3)) return; aptr->p->status_rssshmem = str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1)); } void arl_callback_status_voluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return; struct pid_stat *p = aptr->p; pid_incremental_rate(stat, p->status_voluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1))); } void arl_callback_status_nonvoluntary_ctxt_switches(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; (void)value; struct arl_callback_ptr *aptr = (struct arl_callback_ptr *)dst; if(unlikely(procfile_linewords(aptr->ff, aptr->line) < 2)) return; struct pid_stat *p = aptr->p; pid_incremental_rate(stat, p->status_nonvoluntary_ctxt_switches, str2kernel_uint_t(procfile_lineword(aptr->ff, aptr->line, 1))); } static inline bool read_proc_pid_status_per_os(struct pid_stat *p, void *ptr __maybe_unused) { static struct arl_callback_ptr arl_ptr; static procfile *ff = NULL; if(unlikely(!p->status_arl)) { p->status_arl = arl_create("/proc/pid/status", NULL, 60); arl_expect_custom(p->status_arl, "Uid", arl_callback_status_uid, &arl_ptr); arl_expect_custom(p->status_arl, "Gid", arl_callback_status_gid, &arl_ptr); arl_expect_custom(p->status_arl, "VmSize", arl_callback_status_vmsize, &arl_ptr); arl_expect_custom(p->status_arl, "VmRSS", arl_callback_status_vmrss, &arl_ptr); arl_expect_custom(p->status_arl, "RssFile", arl_callback_status_rssfile, &arl_ptr); arl_expect_custom(p->status_arl, "RssShmem", arl_callback_status_rssshmem, &arl_ptr); arl_expect_custom(p->status_arl, "VmSwap", arl_callback_status_vmswap, &arl_ptr); arl_expect_custom(p->status_arl, "voluntary_ctxt_switches", arl_callback_status_voluntary_ctxt_switches, &arl_ptr); arl_expect_custom(p->status_arl, "nonvoluntary_ctxt_switches", arl_callback_status_nonvoluntary_ctxt_switches, &arl_ptr); } if(unlikely(!p->status_filename)) { char filename[FILENAME_MAX + 1]; snprintfz(filename, FILENAME_MAX, "%s/proc/%d/status", netdata_configured_host_prefix, p->pid); p->status_filename = strdupz(filename); } ff = procfile_reopen(ff, p->status_filename, (!ff)?" \t:,-()/":NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); if(unlikely(!ff)) return false; ff = procfile_readall(ff); if(unlikely(!ff)) return false; calls_counter++; // let ARL use this pid arl_ptr.p = p; arl_ptr.ff = ff; size_t lines = procfile_lines(ff), l; arl_begin(p->status_arl); for(l = 0; l < lines ;l++) { // debug_log("CHECK: line %zu of %zu, key '%s' = '%s'", l, lines, procfile_lineword(ff, l, 0), procfile_lineword(ff, l, 1)); arl_ptr.line = l; if(unlikely(arl_check(p->status_arl, procfile_lineword(ff, l, 0), procfile_lineword(ff, l, 1)))) break; } p->status_vmshared = p->status_rssfile + p->status_rssshmem; // debug_log("%s uid %d, gid %d, VmSize %zu, VmRSS %zu, RssFile %zu, RssShmem %zu, shared %zu", p->comm, (int)p->uid, (int)p->gid, p->status_vmsize, p->status_vmrss, p->status_rssfile, p->status_rssshmem, p->status_vmshared); return true; } #endif // !__FreeBSD__ !__APPLE__ int read_proc_pid_status(struct pid_stat *p, void *ptr) { p->status_vmsize = 0; p->status_vmrss = 0; p->status_vmshared = 0; p->status_rssfile = 0; p->status_rssshmem = 0; p->status_vmswap = 0; p->status_voluntary_ctxt_switches = 0; p->status_nonvoluntary_ctxt_switches = 0; return read_proc_pid_status_per_os(p, ptr) ? 1 : 0; }