2
* Copyright (C) Tildeslash Ltd. All rights reserved.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Affero General Public License version 3.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU Affero General Public License
13
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15
* In addition, as a special exception, the copyright holders give
16
* permission to link the code of portions of this program with the
17
* OpenSSL library under certain conditions as described in each
18
* individual source file, and distribute linked combinations
21
* You must obey the GNU Affero General Public License in all respects
22
* for all of the code used other than OpenSSL.
28
The code below was copy-pasted from sysdep_LINUX.c
29
with only hack for HZ #define.
42
#ifdef HAVE_SYS_TYPES_H
43
#include <sys/types.h>
50
#ifdef HAVE_SYS_STAT_H
66
#ifdef TIME_WITH_SYS_TIME
69
#ifdef HAVE_SYS_TIME_H
80
#ifdef HAVE_ASM_PARAM_H
81
#include <asm/param.h>
90
On GNU/Hurd procps usually launched with -c (linux-compatibility switch):
91
http://lists.debian.org/debian-hurd/2012/10/msg00070.html
92
so, sysconf(_SC_CLK_TCK_) is useless here right now...
98
# define HZ sysconf(_SC_CLK_TCK)
106
#include "process_sysdep.h"
110
* System dependent resource gathering code for Linux.
116
/* ----------------------------------------------------------------- Private */
119
#define MEMTOTAL "MemTotal:"
120
#define MEMFREE "MemFree:"
121
#define MEMBUF "Buffers:"
122
#define MEMCACHE "Cached:"
123
#define SWAPTOTAL "SwapTotal:"
124
#define SWAPFREE "SwapFree:"
126
#define NSEC_PER_SEC 1000000000L
128
static unsigned long long old_cpu_user = 0;
129
static unsigned long long old_cpu_syst = 0;
130
static unsigned long long old_cpu_wait = 0;
131
static unsigned long long old_cpu_total = 0;
132
static int page_shift_to_kb = 0;
136
* Get system start time
137
* @return seconds since unix epoch
139
static time_t get_starttime() {
143
if (! read_proc_file(buf, 1024, "uptime", -1, NULL)) {
144
LogError("system statistic error -- cannot get system uptime\n");
148
if (sscanf(buf, "%lf", &up) != 1) {
149
LogError("system statistic error -- invalid uptime\n");
153
return time(NULL) - (time_t)up;
157
/* ------------------------------------------------------------------ Public */
160
int init_process_info_sysdep(void) {
166
if (! read_proc_file(buf, sizeof(buf), "meminfo", -1, NULL))
168
if (! (ptr = strstr(buf, MEMTOTAL))) {
169
DEBUG("system statistic error -- cannot get real memory amount\n");
172
if (sscanf(ptr+strlen(MEMTOTAL), "%ld", &systeminfo.mem_kbyte_max) != 1) {
173
DEBUG("system statistic error -- cannot get real memory amount\n");
177
if ((systeminfo.cpus = sysconf(_SC_NPROCESSORS_CONF)) < 0) {
178
DEBUG("system statistic error -- cannot get cpu count: %s\n", STRERROR);
180
} else if (systeminfo.cpus == 0) {
181
DEBUG("system reports cpu count 0, setting dummy cpu count 1\n");
185
if ((page_size = sysconf(_SC_PAGESIZE)) <= 0) {
186
DEBUG("system statistic error -- cannot get page size: %s\n", STRERROR);
190
for (page_shift = 0; page_size != 1; page_size >>= 1, page_shift++);
191
page_shift_to_kb = page_shift - 10;
198
* Read all processes of the proc files system to initialize
199
* the process tree (sysdep version... but should work for
200
* all procfs based unices)
201
* @param reference reference of ProcessTree
202
* @return treesize>0 if succeeded otherwise =0.
204
int initprocesstree_sysdep(ProcessTree_T ** reference) {
210
char procname[STRLEN];
212
char stat_item_state;
213
long stat_item_cutime = 0;
214
long stat_item_cstime = 0;
215
long stat_item_rss = 0;
217
unsigned long stat_item_utime = 0;
218
unsigned long stat_item_stime = 0;
219
unsigned long long stat_item_starttime = 0ULL;
220
ProcessTree_T *pt = NULL;
224
/* Find all processes in the /proc directory */
225
if ((rv = glob("/proc/[0-9]*", GLOB_ONLYDIR, NULL, &globbuf))) {
226
LogError("system statistic error -- glob failed: %d (%s)\n", rv, STRERROR);
230
treesize = globbuf.gl_pathc;
232
pt = CALLOC(sizeof(ProcessTree_T), treesize);
234
/* Insert data from /proc directory */
235
for (i = 0; i < treesize; i++) {
237
pt[i].pid = atoi(globbuf.gl_pathv[i] + strlen("/proc/"));
239
if (!read_proc_file(buf, sizeof(buf), "stat", pt[i].pid, NULL)) {
240
DEBUG("system statistic error -- cannot read /proc/%d/stat\n", pt[i].pid);
244
pt[i].time = get_float_time();
246
if (!(tmp = strrchr(buf, ')'))) {
247
DEBUG("system statistic error -- file /proc/%d/stat parse error\n", pt[i].pid);
251
if (sscanf(buf, "%*d (%256s", procname) != 1) {
252
DEBUG("system statistic error -- file /proc/%d/stat process name parse error\n", pt[i].pid);
258
/* This implementation is done by using fs/procfs/array.c as a basis
259
* it is also worth looking into the source of the procps utils */
261
"%c %d %*d %*d %*d %*d %*u %*u"
262
"%*u %*u %*u %lu %lu %ld %ld %*d %*d %*d "
263
"%*u %llu %*u %ld %*u %*u %*u %*u %*u "
264
"%*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n",
271
&stat_item_starttime,
272
&stat_item_rss) != 8) {
273
DEBUG("system statistic error -- file /proc/%d/stat parse error\n", pt[i].pid);
277
pt[i].ppid = stat_ppid;
278
pt[i].starttime = get_starttime() + (time_t)(stat_item_starttime / HZ);
280
/* jiffies -> seconds = 1 / HZ
281
* HZ is defined in "asm/param.h" and it is usually 1/100s but on
282
* alpha system it is 1/1024s */
283
pt[i].cputime = ((float)(stat_item_utime + stat_item_stime) * 10.0) / HZ;
284
pt[i].cpu_percent = 0;
286
/* State is Zombie -> then we are a Zombie ... clear or? (-: */
287
if (stat_item_state == 'Z')
288
pt[i].status_flag |= PROCESS_ZOMBIE;
290
if (page_shift_to_kb < 0)
291
pt[i].mem_kbyte = (stat_item_rss >> abs(page_shift_to_kb));
293
pt[i].mem_kbyte = (stat_item_rss << abs(page_shift_to_kb));
295
if (! read_proc_file(buf, sizeof(buf), "cmdline", pt[i].pid, &bytes)) {
296
DEBUG("system statistic error -- cannot read /proc/%d/cmdline\n", pt[i].pid);
299
/* The cmdline file contains argv elements/strings terminated separated by '\0' => join the string: */
300
for (j = 0; j < (bytes - 1); j++)
303
pt[i].cmdline = *buf ? Str_dup(buf) : Str_dup(procname);
314
* This routine returns 'nelem' double precision floats containing
315
* the load averages in 'loadv'; at most 3 values will be returned.
316
* @param loadv destination of the load averages
317
* @param nelem number of averages
318
* @return: 0 if successful, -1 if failed (and all load averages are 0).
320
int getloadavg_sysdep(double *loadv, int nelem) {
321
#ifdef HAVE_GETLOADAVG
322
return getloadavg(loadv, nelem);
326
if (! read_proc_file(buf, sizeof(buf), "loadavg", -1, NULL))
328
if (sscanf(buf, "%lf %lf %lf", &load[0], &load[1], &load[2]) != 3) {
329
DEBUG("system statistic error -- cannot get load average\n");
332
for (int i = 0; i < nelem; i++)
340
* This routine returns kbyte of real memory in use.
341
* @return: TRUE if successful, FALSE if failed
343
int used_system_memory_sysdep(SystemInfo_T *si) {
346
unsigned long mem_free = 0UL;
347
unsigned long buffers = 0UL;
348
unsigned long cached = 0UL;
349
unsigned long swap_total = 0UL;
350
unsigned long swap_free = 0UL;
352
if (! read_proc_file(buf, 1024, "meminfo", -1, NULL)) {
353
LogError("system statistic error -- cannot get real memory free amount\n");
358
if (! (ptr = strstr(buf, MEMFREE)) || sscanf(ptr + strlen(MEMFREE), "%ld", &mem_free) != 1) {
359
LogError("system statistic error -- cannot get real memory free amount\n");
362
if (! (ptr = strstr(buf, MEMBUF)) || sscanf(ptr + strlen(MEMBUF), "%ld", &buffers) != 1)
363
DEBUG("system statistic error -- cannot get real memory buffers amount\n");
364
if (! (ptr = strstr(buf, MEMCACHE)) || sscanf(ptr + strlen(MEMCACHE), "%ld", &cached) != 1)
365
DEBUG("system statistic error -- cannot get real memory cache amount\n");
366
si->total_mem_kbyte = systeminfo.mem_kbyte_max - mem_free - buffers - cached;
369
if (! (ptr = strstr(buf, SWAPTOTAL)) || sscanf(ptr + strlen(SWAPTOTAL), "%ld", &swap_total) != 1) {
370
LogError("system statistic error -- cannot get swap total amount\n");
373
if (! (ptr = strstr(buf, SWAPFREE)) || sscanf(ptr + strlen(SWAPFREE), "%ld", &swap_free) != 1) {
374
LogError("system statistic error -- cannot get swap free amount\n");
377
si->swap_kbyte_max = swap_total;
378
si->total_swap_kbyte = swap_total - swap_free;
383
si->total_mem_kbyte = 0;
384
si->swap_kbyte_max = 0;
390
* This routine returns system/user CPU time in use.
391
* @return: TRUE if successful, FALSE if failed (or not available)
393
int used_system_cpu_sysdep(SystemInfo_T *si) {
395
unsigned long long cpu_total;
396
unsigned long long cpu_user;
397
unsigned long long cpu_nice;
398
unsigned long long cpu_syst;
399
unsigned long long cpu_idle;
400
unsigned long long cpu_wait;
401
unsigned long long cpu_irq;
402
unsigned long long cpu_softirq;
405
if (!read_proc_file(buf, 1024, "stat", -1, NULL)) {
406
LogError("system statistic error -- cannot read /proc/stat\n");
410
rv = sscanf(buf, "cpu %llu %llu %llu %llu %llu %llu %llu",
419
LogError("system statistic error -- cannot read cpu usage\n");
421
} else if (rv == 4) {
422
/* linux 2.4.x doesn't support these values */
428
cpu_total = cpu_user + cpu_nice + cpu_syst + cpu_idle + cpu_wait + cpu_irq + cpu_softirq;
429
cpu_user = cpu_user + cpu_nice;
431
if (old_cpu_total == 0) {
432
si->total_cpu_user_percent = -10;
433
si->total_cpu_syst_percent = -10;
434
si->total_cpu_wait_percent = -10;
436
unsigned long long delta = cpu_total - old_cpu_total;
438
si->total_cpu_user_percent = (int)(1000 * (double)(cpu_user - old_cpu_user) / delta);
439
si->total_cpu_syst_percent = (int)(1000 * (double)(cpu_syst - old_cpu_syst) / delta);
440
si->total_cpu_wait_percent = (int)(1000 * (double)(cpu_wait - old_cpu_wait) / delta);
443
old_cpu_user = cpu_user;
444
old_cpu_syst = cpu_syst;
445
old_cpu_wait = cpu_wait;
446
old_cpu_total = cpu_total;
450
si->total_cpu_user_percent = 0;
451
si->total_cpu_syst_percent = 0;
452
si->total_cpu_wait_percent = 0;