]> arthur.barton.de Git - netdata.git/commitdiff
cleanup
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sat, 10 May 2014 14:30:47 +0000 (17:30 +0300)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sat, 10 May 2014 14:30:47 +0000 (17:30 +0300)
Makefile
apps_plugin.c
netdata.c
netdata.start
plugins.d/tc-qos-helper.sh

index 6136630e8748d072cc7693ad33b9d6bbf9665d88..3db02ca369bac778bd1aecdf8b082262b9153313 100755 (executable)
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,27 @@
 \r
+CONFIG_DIR = "conf.d"\r
+LOG_DIR = "log"\r
+PLUGINS_DIR = "plugins.d"\r
+\r
+COMMON_FLAGS = -DCONFIG_DIR='$(CONFIG_DIR)' -DLOG_DIR='$(LOG_DIR)' -DPLUGINS_DIR='$(PLUGINS_DIR)'\r
+\r
 ifdef debug\r
-CFLAGS=-Wall -Wextra -ggdb\r
+CFLAGS = $(COMMON_FLAGS) -Wall -Wextra -ggdb\r
 else\r
-CFLAGS=-Wall -Wextra -O3\r
+CFLAGS = $(COMMON_FLAGS) -Wall -Wextra -O3\r
 endif\r
 \r
-all: netdata plugins\r
+all: setuid\r
+\r
+bin: netdata plugins\r
+\r
+setuid: bin\r
+       @echo\r
+       @echo " >>> apps.plugin requires root access to access files in /proc"\r
+       @echo " >>> Please authorize it!"\r
+       @echo\r
+       sudo chown root plugins.d/apps.plugin\r
+       sudo chmod 4775 plugins.d/apps.plugin\r
 \r
 netdata: netdata.c\r
        $(CC) $(CFLAGS) -o netdata netdata.c -lpthread -lz\r
@@ -14,15 +30,11 @@ plugins: plugins.d/apps.plugin
 \r
 plugins.d/apps.plugin: apps_plugin.c\r
        $(CC) $(CFLAGS) -o plugins.d/apps.plugin apps_plugin.c\r
-       @echo\r
-       @echo "apps.plugin requires root access to access files in /proc"\r
-       @echo "Please authorize it."\r
-       sudo chown root plugins.d/apps.plugin\r
-       sudo chmod 4775 plugins.d/apps.plugin\r
 \r
 clean:\r
        rm -f *.o netdata plugins.d/apps.plugin core\r
 \r
 getconf:\r
+       wget -O conf.d/netdata.conf.new "http://localhost:19999/netdata.conf"\r
        mv conf.d/netdata.conf conf.d/netdata.conf.old\r
-       wget -O conf.d/netdata.conf "http://localhost:19999/netdata.conf"\r
+       mv conf.d/netdata.conf.new conf.d/netdata.conf\r
index b79b4f326f6f844f8f8c71ff8714c704f65212c3..a48c08166640716b66b8c77f8d83a1dbfdd57f1e 100755 (executable)
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <time.h>\r
-#include <unistd.h>\r
-#include <sys/types.h>\r
-#include <sys/time.h>\r
-#include <sys/wait.h>\r
-\r
-#include <sys/resource.h>\r
-#include <sys/stat.h>\r
-\r
-#include <errno.h>\r
-#include <stdarg.h>\r
-#include <locale.h>\r
-#include <ctype.h>\r
-#include <fcntl.h>\r
-\r
-#include <malloc.h>\r
-#include <inttypes.h>\r
-#include <dirent.h>\r
-#include <arpa/inet.h>\r
-\r
-#define MAX_COMPARE_NAME 15\r
-#define MAX_NAME 100\r
-\r
-\r
-unsigned long long Hertz = 1;\r
-\r
-long processors = 1;\r
-long pid_max = 32768;\r
-int debug = 0;\r
-\r
-struct wanted {\r
-       char compare[MAX_COMPARE_NAME + 1];\r
-       char id[MAX_NAME + 1];\r
-       char name[MAX_NAME + 1];\r
-\r
-       unsigned long long minflt;\r
-       unsigned long long cminflt;\r
-       unsigned long long majflt;\r
-       unsigned long long cmajflt;\r
-       unsigned long long utime;\r
-       unsigned long long stime;\r
-       unsigned long long cutime;\r
-       unsigned long long cstime;\r
-       unsigned long long num_threads;\r
-       unsigned long long rss;\r
-\r
-       unsigned long long fix_minflt;\r
-       unsigned long long fix_cminflt;\r
-       unsigned long long fix_majflt;\r
-       unsigned long long fix_cmajflt;\r
-       unsigned long long fix_utime;\r
-       unsigned long long fix_stime;\r
-       unsigned long long fix_cutime;\r
-       unsigned long long fix_cstime;\r
-\r
-       unsigned long long statm_size;\r
-       unsigned long long statm_resident;\r
-       unsigned long long statm_share;\r
-       unsigned long long statm_text;\r
-       unsigned long long statm_lib;\r
-       unsigned long long statm_data;\r
-       unsigned long long statm_dirty;\r
-\r
-       unsigned long long io_logical_bytes_read;\r
-       unsigned long long io_logical_bytes_written;\r
-       unsigned long long io_read_calls;\r
-       unsigned long long io_write_calls;\r
-       unsigned long long io_storage_bytes_read;\r
-       unsigned long long io_storage_bytes_written;\r
-       unsigned long long io_cancelled_write_bytes;\r
-\r
-       unsigned long long fix_io_logical_bytes_read;\r
-       unsigned long long fix_io_logical_bytes_written;\r
-       unsigned long long fix_io_read_calls;\r
-       unsigned long long fix_io_write_calls;\r
-       unsigned long long fix_io_storage_bytes_read;\r
-       unsigned long long fix_io_storage_bytes_written;\r
-       unsigned long long fix_io_cancelled_write_bytes;\r
-\r
-       unsigned long processes;        // how many processes have been merged to this\r
-       int exposed;                            // if set, we have sent this to netdata\r
-\r
-       struct wanted *target;  // the one that will be reported to netdata\r
-       struct wanted *next;\r
-} *wanted_root = NULL, *default_target = NULL;\r
-\r
-int update_every = 1;\r
-unsigned long long file_counter = 0;\r
-\r
-struct wanted *get_wanted(const char *id, struct wanted *target)\r
-{\r
-       struct wanted *w;\r
-       for(w = wanted_root ; w ; w = w->next)\r
-               if(strncmp(id, w->id, MAX_NAME) == 0) return w;\r
-       \r
-       w = calloc(sizeof(struct wanted), 1);\r
-       if(!w) {\r
-               fprintf(stderr, "Cannot allocate %lu bytes of memory\n", sizeof(struct wanted));\r
-               return NULL;\r
-       }\r
-\r
-       strncpy(w->id, id, MAX_NAME);\r
-       strncpy(w->name, id, MAX_NAME);\r
-       strncpy(w->compare, id, MAX_COMPARE_NAME);\r
-       w->target = target;\r
-\r
-       w->next = wanted_root;\r
-       wanted_root = w;\r
-\r
-       if(debug) fprintf(stderr, "Adding hook for process '%s', compare '%s' on target '%s'\n", w->id, w->compare, w->target?w->target->id:"");\r
-\r
-       return w;\r
-}\r
-\r
-void parse_args(int argc, char **argv)\r
-{\r
-       int i = 1;\r
-\r
-       debug = 0;\r
-       if(i < argc && strcmp(argv[i], "debug") == 0) {\r
-               debug = 1;\r
-               i++;\r
-       }\r
-\r
-       if(i < argc) {\r
-               update_every = atoi(argv[i++]);\r
-               if(update_every == 0) {\r
-                       i = 1;\r
-                       update_every = 1;\r
-               }\r
-       }\r
-\r
-       for(; i < argc ; i++) {\r
-               struct wanted *w = NULL;\r
-               char *s = argv[i];\r
-               char *t;\r
-\r
-               while((t = strsep(&s, " "))) {\r
-                       if(w && strcmp(t, "as") == 0 && s && *s) {\r
-                               strncpy(w->name, s, MAX_NAME);\r
-                               if(debug) fprintf(stderr, "Setting dimension name to '%s' on target '%s'\n", w->name, w->id);\r
-                               break;\r
-                       }\r
-\r
-                       struct wanted *n = get_wanted(t, w);\r
-                       if(!w) w = n;\r
-               }\r
-       }\r
-\r
-       default_target = get_wanted("all_other_processes", NULL);\r
-       strncpy(default_target->name, "other", MAX_NAME);\r
-}\r
-\r
-// see: man proc\r
-struct pid_stat {\r
-       int32_t pid;\r
-       char comm[MAX_COMPARE_NAME + 1];\r
-       char state;\r
-       int32_t ppid;\r
-       int32_t pgrp;\r
-       int32_t session;\r
-       int32_t tty_nr;\r
-       int32_t tpgid;\r
-       uint64_t flags;\r
-       unsigned long long minflt;\r
-       unsigned long long cminflt;\r
-       unsigned long long majflt;\r
-       unsigned long long cmajflt;\r
-       unsigned long long utime;\r
-       unsigned long long stime;\r
-       unsigned long long cutime;\r
-       unsigned long long cstime;\r
-       int64_t priority;\r
-       int64_t nice;\r
-       int32_t num_threads;\r
-       int64_t itrealvalue;\r
-       unsigned long long starttime;\r
-       unsigned long long vsize;\r
-       unsigned long long rss;\r
-       unsigned long long rsslim;\r
-       unsigned long long starcode;\r
-       unsigned long long endcode;\r
-       unsigned long long startstack;\r
-       unsigned long long kstkesp;\r
-       unsigned long long kstkeip;\r
-       uint64_t signal;\r
-       uint64_t blocked;\r
-       uint64_t sigignore;\r
-       uint64_t sigcatch;\r
-       uint64_t wchan;\r
-       uint64_t nswap;\r
-       uint64_t cnswap;\r
-       int32_t exit_signal;\r
-       int32_t processor;\r
-       uint32_t rt_priority;\r
-       uint32_t policy;\r
-       unsigned long long delayacct_blkio_ticks;\r
-       uint64_t guest_time;\r
-       int64_t cguest_time;\r
-\r
-       unsigned long long statm_size;\r
-       unsigned long long statm_resident;\r
-       unsigned long long statm_share;\r
-       unsigned long long statm_text;\r
-       unsigned long long statm_lib;\r
-       unsigned long long statm_data;\r
-       unsigned long long statm_dirty;\r
-\r
-       unsigned long long io_logical_bytes_read;\r
-       unsigned long long io_logical_bytes_written;\r
-       unsigned long long io_read_calls;\r
-       unsigned long long io_write_calls;\r
-       unsigned long long io_storage_bytes_read;\r
-       unsigned long long io_storage_bytes_written;\r
-       unsigned long long io_cancelled_write_bytes;\r
-\r
-/*     unsigned long long old_utime;\r
-       unsigned long long old_stime;\r
-       unsigned long long old_minflt;\r
-       unsigned long long old_majflt;\r
-\r
-       unsigned long long old_cutime;\r
-       unsigned long long old_cstime;\r
-       unsigned long long old_cminflt;\r
-       unsigned long long old_cmajflt;\r
-\r
-       unsigned long long fix_cutime;\r
-       unsigned long long fix_cstime;\r
-       unsigned long long fix_cminflt;\r
-       unsigned long long fix_cmajflt;\r
-\r
-       unsigned long long diff_cutime;\r
-       unsigned long long diff_cstime;\r
-       unsigned long long diff_cminflt;\r
-       unsigned long long diff_cmajflt;\r
-*/\r
-\r
-       int childs;     // number of processes directly referencing this\r
-       int updated;\r
-       int merged;\r
-       int new_entry;\r
-       struct wanted *target;\r
-       struct pid_stat *parent;\r
-       struct pid_stat *prev;\r
-       struct pid_stat *next;\r
-} *root = NULL;\r
-\r
-struct pid_stat **all_pids;\r
-\r
-#define PROC_BUFFER 4096\r
-\r
-struct pid_stat *get_entry(pid_t pid)\r
-{\r
-       if(all_pids[pid]) {\r
-               all_pids[pid]->new_entry = 0;\r
-               return all_pids[pid];\r
-       }\r
-\r
-       all_pids[pid] = calloc(sizeof(struct pid_stat), 1);\r
-       if(!all_pids[pid]) {\r
-               fprintf(stderr, "Cannot allocate %lu bytes of memory", sizeof(struct pid_stat));\r
-               return NULL;\r
-       }\r
-\r
-       if(root) root->prev = all_pids[pid];\r
-       all_pids[pid]->next = root;\r
-       root = all_pids[pid];\r
-\r
-       all_pids[pid]->new_entry = 1;\r
-\r
-       return all_pids[pid];\r
-}\r
-\r
-void del_entry(pid_t pid)\r
-{\r
-       if(!all_pids[pid]) return;\r
-\r
-       if(debug) fprintf(stderr, "Process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);\r
-\r
-       if(root == all_pids[pid]) root = all_pids[pid]->next;\r
-       if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;\r
-       if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;\r
-\r
-       free(all_pids[pid]);\r
-       all_pids[pid] = NULL;\r
-}\r
-\r
-int update_from_proc(void)\r
-{\r
-       static long count_open_errors = 0;\r
-\r
-       char buffer[PROC_BUFFER + 1];\r
-       char name[PROC_BUFFER + 1];\r
-       char filename[FILENAME_MAX+1];\r
-       DIR *dir = opendir("/proc");\r
-       if(!dir) return 0;\r
-\r
-       struct dirent *file = NULL;\r
-       struct pid_stat *p = NULL;\r
-\r
-       // mark them all as un-updated\r
-       for(p = root; p ; p = p->next) {\r
-               p->parent = NULL;\r
-               p->updated = 0;\r
-               p->childs = 0;\r
-               p->merged = 0;\r
-               p->new_entry = 0;\r
-       }\r
-\r
-       while((file = readdir(dir))) {\r
-               char *endptr = file->d_name;\r
-               pid_t pid = strtoul(file->d_name, &endptr, 10);\r
-               if(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0') continue;\r
-\r
-\r
-               // --------------------------------------------------------------------\r
-               // /proc/<pid>/stat\r
-\r
-               snprintf(filename, FILENAME_MAX, "/proc/%s/stat", file->d_name);\r
-               int fd = open(filename, O_RDONLY);\r
-               if(fd == -1) {\r
-                       if(errno != ENOENT && errno != ESRCH) {\r
-                               if(!count_open_errors) fprintf(stderr, "Cannot open file '%s' for reading (%d, %s).\n", filename, errno, strerror(errno));\r
-                               count_open_errors++;\r
-                       }\r
-                       continue;\r
-               }\r
-               file_counter++;\r
-\r
-               int bytes = read(fd, buffer, PROC_BUFFER);\r
-               close(fd);\r
-\r
-               if(bytes == -1) {\r
-                       fprintf(stderr, "Cannot read from file '%s' (%s).\n", filename, strerror(errno));\r
-                       continue;\r
-               }\r
-\r
-               if(bytes < 10) continue;\r
-               buffer[bytes] = '\0';\r
-               if(debug) fprintf(stderr, "READ stat: %s", buffer);\r
-\r
-               p = get_entry(pid);\r
-               if(!p) continue;\r
-\r
-               int parsed = sscanf(buffer,\r
-                       "%d (%[^)]) %c"                                         // pid, comm, state\r
-                       " %d %d %d %d %d"                                       // ppid, pgrp, session, tty_nr, tpgid\r
-                       " %lu %llu %llu %llu %llu"                      // flags, minflt, cminflt, majflt, cmajflt\r
-                       " %llu %llu %llu %llu"                          // utime, stime, cutime, cstime\r
-                       " %ld %ld"                                                      // priority, nice\r
-                       " %d"                                                           // num_threads\r
-                       " %ld"                                                          // itrealvalue\r
-                       " %llu"                                                         // starttime\r
-                       " %llu"                                                         // vsize\r
-                       " %llu"                                                         // rss\r
-                       " %llu %llu %llu %llu %llu %llu"        // rsslim, starcode, endcode, startstack, kstkesp, kstkeip\r
-                       " %lu %lu %lu %lu"                                      // signal, blocked, sigignore, sigcatch\r
-                       " %lu %lu %lu"                                          // wchan, nswap, cnswap\r
-                       " %d %d"                                                        // exit_signal, processor\r
-                       " %u %u"                                                        // rt_priority, policy\r
-                       " %llu %lu %ld"\r
-                       , &p->pid, name, &p->state\r
-                       , &p->ppid, &p->pgrp, &p->session, &p->tty_nr, &p->tpgid\r
-                       , &p->flags, &p->minflt, &p->cminflt, &p->majflt, &p->cmajflt\r
-                       , &p->utime, &p->stime, &p->cutime, &p->cstime\r
-                       , &p->priority, &p->nice\r
-                       , &p->num_threads\r
-                       , &p->itrealvalue\r
-                       , &p->starttime\r
-                       , &p->vsize\r
-                       , &p->rss\r
-                       , &p->rsslim, &p->starcode, &p->endcode, &p->startstack, &p->kstkesp, &p->kstkeip\r
-                       , &p->signal, &p->blocked, &p->sigignore, &p->sigcatch\r
-                       , &p->wchan, &p->nswap, &p->cnswap\r
-                       , &p->exit_signal, &p->processor\r
-                       , &p->rt_priority, &p->policy\r
-                       , &p->delayacct_blkio_ticks, &p->guest_time, &p->cguest_time\r
-                       );\r
-               strncpy(p->comm, name, MAX_COMPARE_NAME);\r
-               p->comm[MAX_COMPARE_NAME] = '\0';\r
-\r
-               if(debug) fprintf(stderr, "VALUES: %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);\r
-\r
-               if(parsed < 39) fprintf(stderr, "file %s gave %d results (expected 44)\n", filename, parsed);\r
-\r
-               // check if it is wanted\r
-               // we do this only once, the first time this pid is loaded\r
-               if(p->new_entry) {\r
-                       if(debug) fprintf(stderr, "\tJust added %s\n", p->comm);\r
-\r
-                       struct wanted *w;\r
-                       for(w = wanted_root; w ; w = w->next) {\r
-                               // if(debug) fprintf(stderr, "\t\tcomparing '%s' with '%s'\n", w->compare, p->comm);\r
-\r
-                               if(strcmp(w->compare, p->comm) == 0) {\r
-                                       if(w->target) p->target = w->target;\r
-                                       else p->target = w;\r
-\r
-                                       if(debug) fprintf(stderr, "\t\t%s linked to target %s\n", p->comm, p->target->name);\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // just a few checks\r
-               if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0;\r
-\r
-\r
-               // --------------------------------------------------------------------\r
-               // /proc/<pid>/statm\r
-\r
-               snprintf(filename, FILENAME_MAX, "/proc/%s/statm", file->d_name);\r
-               fd = open(filename, O_RDONLY);\r
-               if(fd == -1) {\r
-                       if(errno != ENOENT && errno != ESRCH) {\r
-                               if(!count_open_errors) fprintf(stderr, "Cannot open file '%s' for reading (%d, %s).\n", filename, errno, strerror(errno));\r
-                               count_open_errors++;\r
-                       }\r
-               }\r
-               else {\r
-                       file_counter++;\r
-                       bytes = read(fd, buffer, PROC_BUFFER);\r
-                       close(fd);\r
-\r
-                       if(bytes == -1) {\r
-                               fprintf(stderr, "Cannot read from file '%s' (%s).\n", filename, strerror(errno));\r
-                       }\r
-                       else if(bytes > 10) {\r
-                               buffer[bytes] = '\0';\r
-                               if(debug) fprintf(stderr, "READ statm: %s", buffer);\r
-\r
-                               parsed = sscanf(buffer,\r
-                                       "%llu %llu %llu %llu %llu %llu %llu"\r
-                                       , &p->statm_size\r
-                                       , &p->statm_resident\r
-                                       , &p->statm_share\r
-                                       , &p->statm_text\r
-                                       , &p->statm_lib\r
-                                       , &p->statm_data\r
-                                       , &p->statm_dirty\r
-                                       );\r
-\r
-                               if(parsed < 7) fprintf(stderr, "file %s gave %d results (expected 7)\n", filename, parsed);\r
-                       }\r
-               }\r
-\r
-               // --------------------------------------------------------------------\r
-               // /proc/<pid>/io\r
-\r
-               snprintf(filename, FILENAME_MAX, "/proc/%s/io", file->d_name);\r
-               fd = open(filename, O_RDONLY);\r
-               if(fd == -1) {\r
-                       if(errno != ENOENT && errno != ESRCH) {\r
-                               if(!count_open_errors) fprintf(stderr, "Cannot open file '%s' for reading (%d, %s).\n", filename, errno, strerror(errno));\r
-                               count_open_errors++;\r
-                       }\r
-               }\r
-               else {\r
-                       file_counter++;\r
-                       bytes = read(fd, buffer, PROC_BUFFER);\r
-                       close(fd);\r
-\r
-                       if(bytes == -1) {\r
-                               fprintf(stderr, "Cannot read from file '%s' (%s).\n", filename, strerror(errno));\r
-                       }\r
-                       else if(bytes > 10) {\r
-                               buffer[bytes] = '\0';\r
-                               if(debug) fprintf(stderr, "READ io: %s", buffer);\r
-\r
-                               parsed = sscanf(buffer,\r
-                                       "rchar: %llu\nwchar: %llu\nsyscr: %llu\nsyscw: %llu\nread_bytes: %llu\nwrite_bytes: %llu\ncancelled_write_bytes: %llu"\r
-                                       , &p->io_logical_bytes_read\r
-                                       , &p->io_logical_bytes_written\r
-                                       , &p->io_read_calls\r
-                                       , &p->io_write_calls\r
-                                       , &p->io_storage_bytes_read\r
-                                       , &p->io_storage_bytes_written\r
-                                       , &p->io_cancelled_write_bytes\r
-                                       );\r
-\r
-                               if(parsed < 7) fprintf(stderr, "file %s gave %d results (expected 7)\n", filename, parsed);\r
-                       }\r
-               }\r
-\r
-\r
-               // --------------------------------------------------------------------\r
-               // done!\r
-\r
-               // mark it as updated\r
-               p->updated = 1;\r
-       }\r
-       if(count_open_errors > 1 && count_open_errors > 1000) {\r
-               fprintf(stderr, "file open errors repeated %ld times\n", count_open_errors - 1);\r
-               count_open_errors = 0;\r
-       }\r
-\r
-       closedir(dir);\r
-\r
-       return 1;\r
-}\r
-/*\r
-int walk_down(pid_t pid, int level) {\r
-       struct pid_stat *p = NULL;\r
-       char b[level+3];\r
-       int i, ret = 0;\r
-\r
-       for(i = 0; i < level; i++) b[i] = '\t';\r
-       b[level] = '|';\r
-       b[level+1] = '-';\r
-       b[level+2] = '\0';\r
-\r
-       for(p = root; p ; p = p->next) {\r
-               if(p->ppid == pid) {\r
-                       ret += walk_down(p->pid, level+1);\r
-               }\r
-       }\r
-\r
-       p = all_pids[pid];\r
-       if(p) {\r
-               if(!p->updated) ret += 1;\r
-               if(ret) fprintf(stderr, "%s %s %d [%s, %s] c=%d u=%llu+%llu, s=%llu+%llu, cu=%llu+%llu, cs=%llu+%llu, n=%llu+%llu, j=%llu+%llu, cn=%llu+%llu, cj=%llu+%llu\n"\r
-                       , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->childs\r
-                       , p->utime, p->utime - p->old_utime\r
-                       , p->stime, p->stime - p->old_stime\r
-                       , p->cutime, p->cutime - p->old_cutime\r
-                       , p->cstime, p->cstime - p->old_cstime\r
-                       , p->minflt, p->minflt - p->old_minflt\r
-                       , p->majflt, p->majflt - p->old_majflt\r
-                       , p->cminflt, p->cminflt - p->old_cminflt\r
-                       , p->cmajflt, p->cmajflt - p->old_cmajflt\r
-                       );\r
-       }\r
-\r
-       return ret;\r
-}\r
-*/\r
-\r
-void update_statistics(void)\r
-{\r
-       struct pid_stat *p = NULL;\r
-\r
-       // link all parents and update childs count\r
-       for(p = root; p ; p = p->next) {\r
-               if(p->ppid > 0 && p->ppid <= pid_max && all_pids[p->ppid]) {\r
-                       if(debug) fprintf(stderr, "\tParent of %d %s is %d %s\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);\r
-                       \r
-                       p->parent = all_pids[p->ppid];\r
-                       p->parent->childs++;\r
-               }\r
-               else if(p->ppid != 0) fprintf(stderr, "\t\tWRONG! pid %d %s states parent %d, but the later does not exist.\n", p->pid, p->comm, p->ppid);\r
-       }\r
-\r
-       // find all the procs with 0 childs and merge them to their parents\r
-       // repeat, until nothing more can be done.\r
-       int found = 1;\r
-       while(found) {\r
-               found = 0;\r
-               for(p = root; p ; p = p->next) {\r
-                       // if this process does not have any childs, and\r
-                       // is not already merged, and\r
-                       // its parent has childs waiting to be merged, and\r
-                       // the target of this process and its parent is the same, or the parent does not have a target, or this process does not have a parent\r
-                       // and its parent is not init\r
-                       // then... merge them!\r
-                       if(!p->childs && !p->merged && p->parent && p->parent->childs && (p->target == p->parent->target || !p->parent->target || !p->target) && p->ppid != 1) {\r
-                               p->parent->childs--;\r
-                               p->merged = 1;\r
-\r
-                               // the parent inherits the child's target, if it does not have a target itself\r
-                               if(p->target && !p->parent->target) {\r
-                                       p->parent->target = p->target;\r
-                                       if(debug) fprintf(stderr, "\t\ttarget %s is inherited by %d %s from its child %d %s.\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);\r
-                               }\r
-\r
-                               found++;\r
-                       }\r
-               }\r
-               if(debug) fprintf(stderr, "Merged %d processes\n", found);\r
-       }\r
-\r
-       // give a default target on all top level processes\r
-       // init goes always to default target\r
-       if(all_pids[1]) all_pids[1]->target = default_target;\r
-\r
-       for(p = root; p ; p = p->next) {\r
-               // if the process is not merged itself\r
-               // then is is a top level process\r
-               if(!p->merged && !p->target) p->target = default_target;\r
-\r
-/*             // by the way, update the diffs\r
-               // will be used later for substracting killed process times\r
-               p->diff_cutime = p->utime - p->cutime;\r
-               p->diff_cstime = p->stime - p->cstime;\r
-               p->diff_cminflt = p->minflt - p->cminflt;\r
-               p->diff_cmajflt = p->majflt - p->cmajflt;\r
-*/     }\r
-\r
-       // give a target to all merged child processes\r
-       found = 1;\r
-       while(found) {\r
-               found = 0;\r
-               for(p = root; p ; p = p->next) {\r
-                       if(!p->target && p->merged && p->parent && p->parent->target) {\r
-                               p->target = p->parent->target;\r
-                               found++;\r
-                       }\r
-               }\r
-       }\r
-\r
-/*     // for each killed process, remove its values from the parents\r
-       // sums (we had already added them in a previous loop)\r
-       for(p = root; p ; p = p->next) {\r
-               if(p->updated) continue;\r
-\r
-               fprintf(stderr, "UNMERGING %d %s\n", p->pid, p->comm);\r
-\r
-               unsigned long long diff_utime = p->utime + p->cutime + p->fix_cutime;\r
-               unsigned long long diff_stime = p->stime + p->cstime + p->fix_cstime;\r
-               unsigned long long diff_minflt = p->minflt + p->cminflt + p->fix_cminflt;\r
-               unsigned long long diff_majflt = p->majflt + p->cmajflt + p->fix_cmajflt;\r
-\r
-               struct pid_stat *t = p;\r
-               while((t = t->parent)) {\r
-                       if(!t->updated) continue;\r
-\r
-                       unsigned long long x;\r
-                       if(diff_utime && t->diff_cutime) {\r
-                               x = (t->diff_cutime < diff_utime)?t->diff_cutime:diff_utime;\r
-                               diff_utime -= x;\r
-                               t->diff_cutime -= x;\r
-                               t->fix_cutime += x;\r
-                               fprintf(stderr, "\t cutime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);\r
-                       }\r
-                       if(diff_stime && t->diff_cstime) {\r
-                               x = (t->diff_cstime < diff_stime)?t->diff_cstime:diff_stime;\r
-                               diff_stime -= x;\r
-                               t->diff_cstime -= x;\r
-                               t->fix_cstime += x;\r
-                               fprintf(stderr, "\t cstime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);\r
-                       }\r
-                       if(diff_minflt && t->diff_cminflt) {\r
-                               x = (t->diff_cminflt < diff_minflt)?t->diff_cminflt:diff_minflt;\r
-                               diff_minflt -= x;\r
-                               t->diff_cminflt -= x;\r
-                               t->fix_cminflt += x;\r
-                               fprintf(stderr, "\t cminflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);\r
-                       }\r
-                       if(diff_majflt && t->diff_cmajflt) {\r
-                               x = (t->diff_cmajflt < diff_majflt)?t->diff_cmajflt:diff_majflt;\r
-                               diff_majflt -= x;\r
-                               t->diff_cmajflt -= x;\r
-                               t->fix_cmajflt += x;\r
-                               fprintf(stderr, "\t cmajflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);\r
-                       }\r
-               }\r
-\r
-               if(diff_utime) fprintf(stderr, "\t cannot fix up utime %llu\n", diff_utime);\r
-               if(diff_stime) fprintf(stderr, "\t cannot fix up stime %llu\n", diff_stime);\r
-               if(diff_minflt) fprintf(stderr, "\t cannot fix up minflt %llu\n", diff_minflt);\r
-               if(diff_majflt) fprintf(stderr, "\t cannot fix up majflt %llu\n", diff_majflt);\r
-       }\r
-*/\r
-       // zero all the targets\r
-       struct wanted *w;\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               w->minflt = 0;\r
-               w->majflt = 0;\r
-               w->utime = 0;\r
-               w->stime = 0;\r
-               w->cminflt = 0;\r
-               w->cmajflt = 0;\r
-               w->cutime = 0;\r
-               w->cstime = 0;\r
-               w->num_threads = 0;\r
-               w->rss = 0;\r
-               w->processes = 0;\r
-\r
-               w->statm_size = 0;\r
-               w->statm_resident = 0;\r
-               w->statm_share = 0;\r
-               w->statm_text = 0;\r
-               w->statm_lib = 0;\r
-               w->statm_data = 0;\r
-               w->statm_dirty = 0;\r
-\r
-               w->io_logical_bytes_read = 0;\r
-               w->io_logical_bytes_written = 0;\r
-               w->io_read_calls = 0;\r
-               w->io_write_calls = 0;\r
-               w->io_storage_bytes_read = 0;\r
-               w->io_storage_bytes_written = 0;\r
-               w->io_cancelled_write_bytes = 0;\r
-       }\r
-\r
-/*     walk_down(0, 1);\r
-*/\r
-       // concentrate everything on the targets\r
-       for(p = root; p ; p = p->next) {\r
-               if(!p->target) {\r
-                       fprintf(stderr, "WRONG! pid %d %s was left without a target!\n", p->pid, p->comm);\r
-                       continue;\r
-               }\r
-\r
-               if(p->updated) {\r
-                       p->target->cutime += p->cutime; // - p->fix_cutime;\r
-                       p->target->cstime += p->cstime; // - p->fix_cstime;\r
-                       p->target->cminflt += p->cminflt; // - p->fix_cminflt;\r
-                       p->target->cmajflt += p->cmajflt; // - p->fix_cmajflt;\r
-\r
-                       p->target->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;\r
-                       p->target->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;\r
-                       p->target->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;\r
-                       p->target->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;\r
-\r
-                       p->target->num_threads += p->num_threads;\r
-                       p->target->rss += p->rss;\r
-\r
-                       p->target->statm_size += p->statm_size;\r
-                       p->target->statm_resident += p->statm_resident;\r
-                       p->target->statm_share += p->statm_share;\r
-                       p->target->statm_text += p->statm_text;\r
-                       p->target->statm_lib += p->statm_lib;\r
-                       p->target->statm_data += p->statm_data;\r
-                       p->target->statm_dirty += p->statm_dirty;\r
-\r
-                       p->target->io_logical_bytes_read += p->io_logical_bytes_read;\r
-                       p->target->io_logical_bytes_written += p->io_logical_bytes_written;\r
-                       p->target->io_read_calls += p->io_read_calls;\r
-                       p->target->io_write_calls += p->io_write_calls;\r
-                       p->target->io_storage_bytes_read += p->io_storage_bytes_read;\r
-                       p->target->io_storage_bytes_written += p->io_storage_bytes_written;\r
-                       p->target->io_cancelled_write_bytes += p->io_cancelled_write_bytes;\r
-\r
-                       p->target->processes++;\r
-\r
-                       if(debug) fprintf(stderr, "\tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);\r
-\r
-/*                     if(p->utime - p->old_utime > 100) fprintf(stderr, "BIG CHANGE: %d %s utime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->utime - p->old_utime, p->old_utime, p->utime);\r
-                       if(p->cutime - p->old_cutime > 100) fprintf(stderr, "BIG CHANGE: %d %s cutime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cutime - p->old_cutime, p->old_cutime, p->cutime);\r
-                       if(p->stime - p->old_stime > 100) fprintf(stderr, "BIG CHANGE: %d %s stime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->stime - p->old_stime, p->old_stime, p->stime);\r
-                       if(p->cstime - p->old_cstime > 100) fprintf(stderr, "BIG CHANGE: %d %s cstime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cstime - p->old_cstime, p->old_cstime, p->cstime);\r
-                       if(p->minflt - p->old_minflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s minflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->minflt - p->old_minflt, p->old_minflt, p->minflt);\r
-                       if(p->majflt - p->old_majflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s majflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->majflt - p->old_majflt, p->old_majflt, p->majflt);\r
-                       if(p->cminflt - p->old_cminflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cminflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cminflt - p->old_cminflt, p->old_cminflt, p->cminflt);\r
-                       if(p->cmajflt - p->old_cmajflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cmajflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cmajflt - p->old_cmajflt, p->old_cmajflt, p->cmajflt);\r
-\r
-                       p->old_utime = p->utime;\r
-                       p->old_cutime = p->cutime;\r
-                       p->old_stime = p->stime;\r
-                       p->old_cstime = p->cstime;\r
-                       p->old_minflt = p->minflt;\r
-                       p->old_majflt = p->majflt;\r
-                       p->old_cminflt = p->cminflt;\r
-                       p->old_cmajflt = p->cmajflt;\r
-*/             }\r
-               else {\r
-                       // since the process has exited, the user\r
-                       // will see a drop in our charts, because the incremental\r
-                       // values of this process will not be there\r
-\r
-                       // add them to the fix_* values and they will be added to\r
-                       // the reported values, so that the report goes steady\r
-                       p->target->fix_minflt += p->minflt;\r
-                       p->target->fix_majflt += p->majflt;\r
-                       p->target->fix_utime += p->utime;\r
-                       p->target->fix_stime += p->stime;\r
-                       p->target->fix_cminflt += p->cminflt;\r
-                       p->target->fix_cmajflt += p->cmajflt;\r
-                       p->target->fix_cutime += p->cutime;\r
-                       p->target->fix_cstime += p->cstime;\r
-\r
-                       p->target->fix_io_logical_bytes_read += p->io_logical_bytes_read;\r
-                       p->target->fix_io_logical_bytes_written += p->io_logical_bytes_written;\r
-                       p->target->fix_io_read_calls += p->io_read_calls;\r
-                       p->target->fix_io_write_calls += p->io_write_calls;\r
-                       p->target->fix_io_storage_bytes_read += p->io_storage_bytes_read;\r
-                       p->target->fix_io_storage_bytes_written += p->io_storage_bytes_written;\r
-                       p->target->fix_io_cancelled_write_bytes += p->io_cancelled_write_bytes;\r
-               }\r
-       }\r
-\r
-/*     fprintf(stderr, "\n");\r
-*/\r
-       // cleanup all un-updated processed (exited, killed, etc)\r
-       int c;\r
-       for(p = root, c = 0; p ; c++) {\r
-               if(!p->updated) {\r
-/*                     fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name,  p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);\r
-*/                     \r
-                       pid_t r = p->pid;\r
-                       p = p->next;\r
-                       del_entry(r);\r
-               }\r
-               else p = p->next;\r
-       }\r
-}\r
-\r
-\r
-void show_dimensions(void)\r
-{\r
-       struct wanted *w;\r
-\r
-       fprintf(stdout, "BEGIN apps.cpu\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + w->fix_utime + w->fix_stime);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.cpu_user\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->fix_utime);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.cpu_system\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + w->fix_stime);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.threads\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->num_threads);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.processes\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %lu\n", w->name, w->processes);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.mem\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %lld\n", w->name, (long long)w->statm_resident - (long long)w->statm_share);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.minor_faults\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + w->fix_minflt);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.major_faults\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + w->fix_majflt);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.lreads\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.lwrites\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.preads\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-\r
-       fprintf(stdout, "BEGIN apps.pwrites\n");\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written);\r
-       }\r
-       fprintf(stdout, "END\n");\r
-}\r
-\r
-void show_charts(void)\r
-{\r
-       struct wanted *w;\r
-       int newly_added = 0;\r
-\r
-       for(w = wanted_root ; w ; w = w->next)\r
-               if(!w->exposed && w->processes) {\r
-                       newly_added++;\r
-                       w->exposed = 1;\r
-                       if(debug) fprintf(stderr, "%s just added - regenerating charts.\n", w->name);\r
-               }\r
-\r
-       // nothing more to show\r
-       if(!newly_added) return;\r
-\r
-       // we have something new to show\r
-       // update the charts\r
-       fprintf(stdout, "CHART apps.cpu '' 'Apps CPU Time (%ld%% = %ld core%s)' 'cpu time %%' apps apps stacked 20001 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 100 %llu\n", w->name, Hertz);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.mem '' 'Apps Dedicated Memory (w/o shared)' 'MB' apps apps stacked 20003 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.threads '' 'Apps Threads' 'threads' apps apps stacked 20005 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.processes '' 'Apps Processes' 'processes' apps apps stacked 20004 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.cpu_user '' 'Apps CPU User Time (%ld%% = %ld core%s)' 'cpu time %%' apps none stacked 20020 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 100 %llu\n", w->name, Hertz * processors);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.cpu_system '' 'Apps CPU System Time (%ld%% = %ld core%s)' 'cpu time %%' apps none stacked 20021 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 100 %llu\n", w->name, Hertz * processors);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.major_faults '' 'Apps Major Page Faults (swaps in)' 'page faults/s' apps apps stacked 20010 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w->name);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.minor_faults '' 'Apps Minor Page Faults' 'page faults/s' apps apps stacked 20011 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w->name);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.lreads '' 'Apps Logical Reads' 'kilobytes/s' apps apps stacked 20042 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.lwrites '' 'Apps Logical Writes' 'kilobytes/s' apps apps stacked 20042 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.preads '' 'Apps Reads' 'kilobytes/s' apps apps stacked 20002 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);\r
-       }\r
-\r
-       fprintf(stdout, "CHART apps.pwrites '' 'Apps Writes' 'kilobytes/s' apps apps stacked 20002 %d\n", update_every);\r
-       for (w = wanted_root; w ; w = w->next) {\r
-               if(w->target || (!w->processes && !w->exposed)) continue;\r
-\r
-               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);\r
-       }\r
-}\r
-\r
-unsigned long long get_hertz(void)\r
-{\r
-       unsigned long long hz = 1;\r
-\r
-#ifdef _SC_CLK_TCK\r
-       if((hz = sysconf(_SC_CLK_TCK)) > 0) {\r
-               return hz;\r
-       }\r
-#endif\r
-\r
-#ifdef HZ\r
-       hz = (unsigned long long)HZ;    /* <asm/param.h> */\r
-#else\r
-       /* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */\r
-       hz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;\r
-#endif\r
-\r
-       fprintf(stderr, "Unknown HZ value. Assuming %llu.\n", hz);\r
-       return hz;\r
-}\r
-\r
-long get_processors(void)\r
-{\r
-       char buffer[1025], *s;\r
-       int processors = 0;\r
-\r
-       FILE *fp = fopen("/proc/stat", "r");\r
-       if(!fp) return 1;\r
-\r
-       while((s = fgets(buffer, 1024, fp))) {\r
-               if(strncmp(buffer, "cpu", 3) == 0) processors++;\r
-       }\r
-       fclose(fp);\r
-       processors--;\r
-       if(processors < 1) processors = 1;\r
-       return processors;\r
-}\r
-\r
-long get_pid_max(void)\r
-{\r
-       char buffer[1025], *s;\r
-       long mpid = 32768;\r
-\r
-       FILE *fp = fopen("/proc/sys/kernel/pid_max", "r");\r
-       if(!fp) return 1;\r
-\r
-       s = fgets(buffer, 1024, fp);\r
-       if(s) mpid = atol(buffer);\r
-       fclose(fp);\r
-       if(mpid < 32768) mpid = 32768;\r
-       return mpid;\r
-}\r
-\r
-unsigned long long usecdiff(struct timeval *now, struct timeval *last) {\r
-               return ((((now->tv_sec * 1000000ULL) + now->tv_usec) - ((last->tv_sec * 1000000ULL) + last->tv_usec)));\r
-}\r
-\r
-int main(int argc, char **argv)\r
-{\r
-       Hertz = get_hertz();\r
-       pid_max = get_pid_max();\r
-       processors = get_processors();\r
-\r
-       parse_args(argc, argv);\r
-\r
-       all_pids = calloc(sizeof(struct pid_stat *), pid_max);\r
-       if(!all_pids) {\r
-               fprintf(stderr, "Cannot allocate %lu bytes of memory.\n", sizeof(struct pid_stat *) * pid_max);\r
-               printf("DISABLE\n");\r
-               exit(1);\r
-       }\r
-\r
-       int created_usage_chart = 0;\r
-       struct rusage me, me_last;\r
-       unsigned long long counter = 1;\r
-       unsigned long long usec = 0, susec = 0;\r
-       struct timeval last, now;\r
-       gettimeofday(&last, NULL);\r
-       getrusage(RUSAGE_SELF, &me_last);\r
-\r
-       for(;1; counter++) {\r
-               if(!update_from_proc()) {\r
-                       fprintf(stderr, "Cannot allocate %lu bytes of memory.\n", sizeof(struct pid_stat *) * pid_max);\r
-                       printf("DISABLE\n");\r
-                       exit(1);\r
-               }\r
-\r
-               update_statistics();\r
-               show_charts();          // this is smart enough to show only newly added apps, when needed\r
-               show_dimensions();\r
-\r
-               if(getrusage(RUSAGE_SELF, &me) == 0) {\r
-                       unsigned long long cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec;\r
-                       unsigned long long cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec;\r
-\r
-                       if(!created_usage_chart) {\r
-                               created_usage_chart = 1;\r
-                               fprintf(stdout, "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' netdata netdata stacked 10000 %d\n", update_every);\r
-                               fprintf(stdout, "DIMENSION user '' incremental 1 1000\n");\r
-                               fprintf(stdout, "DIMENSION system '' incremental 1 1000\n");\r
-\r
-                               fprintf(stdout, "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' netdata netdata line 10001 %d\n", update_every);\r
-                               fprintf(stdout, "DIMENSION files '' incremental 1 1\n");\r
-                       }\r
-\r
-                       fprintf(stdout, "BEGIN netdata.apps_cpu\n");\r
-                       fprintf(stdout, "SET user = %llu\n", cpuuser);\r
-                       fprintf(stdout, "SET system = %llu\n", cpusyst);\r
-                       fprintf(stdout, "END\n");\r
-\r
-                       fprintf(stdout, "BEGIN netdata.apps_files\n");\r
-                       fprintf(stdout, "SET files = %llu\n", file_counter);\r
-                       fprintf(stdout, "END\n");\r
-\r
-                       bcopy(&me, &me_last, sizeof(struct rusage));\r
-               }\r
-\r
-               if(debug) fprintf(stderr, "Done Loop No %llu\n", counter);\r
-               // if(counter == 1000) exit(0);\r
-\r
-               gettimeofday(&now, NULL);\r
-\r
-               usec = usecdiff(&now, &last) - susec;\r
-               if(debug) fprintf(stderr, "last loop took %llu usec (worked for %llu, sleeped for %llu).\n", usec + susec, usec, susec);\r
-\r
-               // if the last loop took less than half the time\r
-               // wait the rest of the time\r
-               if(usec < (update_every * 1000000ULL / 2)) susec = (update_every * 1000000ULL) - usec;\r
-               else susec = update_every * 1000000ULL / 2;\r
-\r
-               fflush(NULL);\r
-               usleep(susec);\r
-\r
-               bcopy(&now, &last, sizeof(struct timeval));\r
-       }\r
-}\r
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <sys/resource.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <locale.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <malloc.h>
+#include <inttypes.h>
+#include <dirent.h>
+#include <arpa/inet.h>
+
+#define MAX_COMPARE_NAME 15
+#define MAX_NAME 100
+
+unsigned long long Hertz = 1;
+
+long processors = 1;
+long pid_max = 32768;
+int debug = 0;
+
+struct target {
+       char compare[MAX_COMPARE_NAME + 1];
+       char id[MAX_NAME + 1];
+       char name[MAX_NAME + 1];
+
+       unsigned long long minflt;
+       unsigned long long cminflt;
+       unsigned long long majflt;
+       unsigned long long cmajflt;
+       unsigned long long utime;
+       unsigned long long stime;
+       unsigned long long cutime;
+       unsigned long long cstime;
+       unsigned long long num_threads;
+       unsigned long long rss;
+
+       unsigned long long fix_minflt;
+       unsigned long long fix_cminflt;
+       unsigned long long fix_majflt;
+       unsigned long long fix_cmajflt;
+       unsigned long long fix_utime;
+       unsigned long long fix_stime;
+       unsigned long long fix_cutime;
+       unsigned long long fix_cstime;
+
+       unsigned long long statm_size;
+       unsigned long long statm_resident;
+       unsigned long long statm_share;
+       unsigned long long statm_text;
+       unsigned long long statm_lib;
+       unsigned long long statm_data;
+       unsigned long long statm_dirty;
+
+       unsigned long long io_logical_bytes_read;
+       unsigned long long io_logical_bytes_written;
+       unsigned long long io_read_calls;
+       unsigned long long io_write_calls;
+       unsigned long long io_storage_bytes_read;
+       unsigned long long io_storage_bytes_written;
+       unsigned long long io_cancelled_write_bytes;
+
+       unsigned long long fix_io_logical_bytes_read;
+       unsigned long long fix_io_logical_bytes_written;
+       unsigned long long fix_io_read_calls;
+       unsigned long long fix_io_write_calls;
+       unsigned long long fix_io_storage_bytes_read;
+       unsigned long long fix_io_storage_bytes_written;
+       unsigned long long fix_io_cancelled_write_bytes;
+
+       unsigned long processes;        // how many processes have been merged to this
+       int exposed;                            // if set, we have sent this to netdata
+
+       struct target *target;  // the one that will be reported to netdata
+       struct target *next;
+} *target_root = NULL, *default_target = NULL;
+
+int update_every = 1;
+unsigned long long file_counter = 0;
+
+struct target *get_target(const char *id, struct target *target)
+{
+       struct target *w;
+       for(w = target_root ; w ; w = w->next)
+               if(strncmp(id, w->id, MAX_NAME) == 0) return w;
+       
+       w = calloc(sizeof(struct target), 1);
+       if(!w) {
+               fprintf(stderr, "Cannot allocate %lu bytes of memory\n", sizeof(struct target));
+               return NULL;
+       }
+
+       strncpy(w->id, id, MAX_NAME);
+       strncpy(w->name, id, MAX_NAME);
+       strncpy(w->compare, id, MAX_COMPARE_NAME);
+       w->target = target;
+
+       w->next = target_root;
+       target_root = w;
+
+       if(debug) fprintf(stderr, "Adding hook for process '%s', compare '%s' on target '%s'\n", w->id, w->compare, w->target?w->target->id:"");
+
+       return w;
+}
+
+char *trim(char *s)
+{
+       // skip leading spaces
+       while(*s && isspace(*s)) s++;
+       if(!*s) return NULL;
+
+       // skip tailing spaces
+       int c = strlen(s) - 1;
+       while(c >= 0 && isspace(s[c])) {
+               s[c] = '\0';
+               c--;
+       }
+       if(c < 0) return NULL;
+       if(!*s) return NULL;
+       return s;
+}
+
+int read_process_groups(const char *name)
+{
+       char buffer[4096+1];
+       char filename[FILENAME_MAX + 1];
+
+       snprintf(filename, FILENAME_MAX, "%s/apps_%s.conf", CONFIG_DIR, name);
+
+       if(debug) fprintf(stderr, "Process groups file: '%s'\n", filename);
+       FILE *fp = fopen(filename, "r");
+       if(!fp) {
+               fprintf(stderr, "Cannot open file '%s' (%s)\n", filename, strerror(errno));
+               return 1;
+       }
+
+       long line = 0;
+       while(fgets(buffer, 4096, fp) != NULL) {
+               line++;
+
+               // if(debug) fprintf(stderr, "\tread %s\n", buffer);
+
+               char *s = buffer, *t, *p;
+               s = trim(s);
+               if(!s || !*s || *s == '#') continue;
+
+               if(debug) fprintf(stderr, "\tread %s\n", s);
+
+               // the target name
+               t = strsep(&s, ":");
+               if(t) t = trim(t);
+               if(!t || !*t) continue;
+
+               if(debug) fprintf(stderr, "\t\ttarget %s\n", t);
+
+               struct target *w = NULL;
+               long count = 0;
+
+               // the process names
+               while((p = strsep(&s, " "))) {
+                       p = trim(p);
+                       if(!p || !*p) continue;
+
+                       struct target *n = get_target(p, w);
+                       if(!w) w = n;
+
+                       count++;
+               }
+
+               if(w) strncpy(w->name, t, MAX_NAME);
+               if(!count) fprintf(stderr, "the line %ld on file '%s', for group '%s' does not state any process names.\n", line, filename, t);
+       }
+       fclose(fp);
+
+       default_target = get_target("+p!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
+       strncpy(default_target->name, "other", MAX_NAME);
+
+       return 0;
+}
+
+void parse_args(int argc, char **argv)
+{
+       int i, freq = 0;
+       char *name = NULL;
+
+       for(i = 1; i < argc; i++) {
+               if(!freq) {
+                       int n = atoi(argv[i]);
+                       if(n > 0) {
+                               freq = n;
+                               continue;
+                       }
+               }
+
+               if(strcmp("debug", argv[i]) == 0) {
+                       debug = 1;
+                       continue;
+               }
+
+               if(!name) {
+                       name = argv[i];
+                       continue;
+               }
+
+               fprintf(stderr, "Cannot understand option %s\n", argv[i]);
+               exit(1);
+       }
+
+       if(freq > 0) update_every = freq;
+       if(!name) name = "groups";
+
+       if(read_process_groups(name)) {
+               fprintf(stderr, "Cannot read process groups %s\n", name);
+               exit(1);
+       }
+}
+
+// see: man proc
+struct pid_stat {
+       int32_t pid;
+       char comm[MAX_COMPARE_NAME + 1];
+       char state;
+       int32_t ppid;
+       int32_t pgrp;
+       int32_t session;
+       int32_t tty_nr;
+       int32_t tpgid;
+       uint64_t flags;
+       unsigned long long minflt;
+       unsigned long long cminflt;
+       unsigned long long majflt;
+       unsigned long long cmajflt;
+       unsigned long long utime;
+       unsigned long long stime;
+       unsigned long long cutime;
+       unsigned long long cstime;
+       int64_t priority;
+       int64_t nice;
+       int32_t num_threads;
+       int64_t itrealvalue;
+       unsigned long long starttime;
+       unsigned long long vsize;
+       unsigned long long rss;
+       unsigned long long rsslim;
+       unsigned long long starcode;
+       unsigned long long endcode;
+       unsigned long long startstack;
+       unsigned long long kstkesp;
+       unsigned long long kstkeip;
+       uint64_t signal;
+       uint64_t blocked;
+       uint64_t sigignore;
+       uint64_t sigcatch;
+       uint64_t wchan;
+       uint64_t nswap;
+       uint64_t cnswap;
+       int32_t exit_signal;
+       int32_t processor;
+       uint32_t rt_priority;
+       uint32_t policy;
+       unsigned long long delayacct_blkio_ticks;
+       uint64_t guest_time;
+       int64_t cguest_time;
+
+       unsigned long long statm_size;
+       unsigned long long statm_resident;
+       unsigned long long statm_share;
+       unsigned long long statm_text;
+       unsigned long long statm_lib;
+       unsigned long long statm_data;
+       unsigned long long statm_dirty;
+
+       unsigned long long io_logical_bytes_read;
+       unsigned long long io_logical_bytes_written;
+       unsigned long long io_read_calls;
+       unsigned long long io_write_calls;
+       unsigned long long io_storage_bytes_read;
+       unsigned long long io_storage_bytes_written;
+       unsigned long long io_cancelled_write_bytes;
+
+/*     unsigned long long old_utime;
+       unsigned long long old_stime;
+       unsigned long long old_minflt;
+       unsigned long long old_majflt;
+
+       unsigned long long old_cutime;
+       unsigned long long old_cstime;
+       unsigned long long old_cminflt;
+       unsigned long long old_cmajflt;
+
+       unsigned long long fix_cutime;
+       unsigned long long fix_cstime;
+       unsigned long long fix_cminflt;
+       unsigned long long fix_cmajflt;
+
+       unsigned long long diff_cutime;
+       unsigned long long diff_cstime;
+       unsigned long long diff_cminflt;
+       unsigned long long diff_cmajflt;
+*/
+
+       int childs;     // number of processes directly referencing this
+       int updated;
+       int merged;
+       int new_entry;
+       struct target *target;
+       struct pid_stat *parent;
+       struct pid_stat *prev;
+       struct pid_stat *next;
+} *root = NULL;
+
+struct pid_stat **all_pids;
+
+#define PROC_BUFFER 4096
+
+struct pid_stat *get_entry(pid_t pid)
+{
+       if(all_pids[pid]) {
+               all_pids[pid]->new_entry = 0;
+               return all_pids[pid];
+       }
+
+       all_pids[pid] = calloc(sizeof(struct pid_stat), 1);
+       if(!all_pids[pid]) {
+               fprintf(stderr, "Cannot allocate %lu bytes of memory", sizeof(struct pid_stat));
+               return NULL;
+       }
+
+       if(root) root->prev = all_pids[pid];
+       all_pids[pid]->next = root;
+       root = all_pids[pid];
+
+       all_pids[pid]->new_entry = 1;
+
+       return all_pids[pid];
+}
+
+void del_entry(pid_t pid)
+{
+       if(!all_pids[pid]) return;
+
+       if(debug) fprintf(stderr, "Process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
+
+       if(root == all_pids[pid]) root = all_pids[pid]->next;
+       if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
+       if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
+
+       free(all_pids[pid]);
+       all_pids[pid] = NULL;
+}
+
+int update_from_proc(void)
+{
+       static long count_open_errors = 0;
+
+       char buffer[PROC_BUFFER + 1];
+       char name[PROC_BUFFER + 1];
+       char filename[FILENAME_MAX+1];
+       DIR *dir = opendir("/proc");
+       if(!dir) return 0;
+
+       struct dirent *file = NULL;
+       struct pid_stat *p = NULL;
+
+       // mark them all as un-updated
+       for(p = root; p ; p = p->next) {
+               p->parent = NULL;
+               p->updated = 0;
+               p->childs = 0;
+               p->merged = 0;
+               p->new_entry = 0;
+       }
+
+       while((file = readdir(dir))) {
+               char *endptr = file->d_name;
+               pid_t pid = strtoul(file->d_name, &endptr, 10);
+               if(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0') continue;
+
+
+               // --------------------------------------------------------------------
+               // /proc/<pid>/stat
+
+               snprintf(filename, FILENAME_MAX, "/proc/%s/stat", file->d_name);
+               int fd = open(filename, O_RDONLY);
+               if(fd == -1) {
+                       if(errno != ENOENT && errno != ESRCH) {
+                               if(!count_open_errors) fprintf(stderr, "Cannot open file '%s' for reading (%d, %s).\n", filename, errno, strerror(errno));
+                               count_open_errors++;
+                       }
+                       continue;
+               }
+               file_counter++;
+
+               int bytes = read(fd, buffer, PROC_BUFFER);
+               close(fd);
+
+               if(bytes == -1) {
+                       fprintf(stderr, "Cannot read from file '%s' (%s).\n", filename, strerror(errno));
+                       continue;
+               }
+
+               if(bytes < 10) continue;
+               buffer[bytes] = '\0';
+               if(debug) fprintf(stderr, "READ stat: %s", buffer);
+
+               p = get_entry(pid);
+               if(!p) continue;
+
+               int parsed = sscanf(buffer,
+                       "%d (%[^)]) %c"                                         // pid, comm, state
+                       " %d %d %d %d %d"                                       // ppid, pgrp, session, tty_nr, tpgid
+                       " %lu %llu %llu %llu %llu"                      // flags, minflt, cminflt, majflt, cmajflt
+                       " %llu %llu %llu %llu"                          // utime, stime, cutime, cstime
+                       " %ld %ld"                                                      // priority, nice
+                       " %d"                                                           // num_threads
+                       " %ld"                                                          // itrealvalue
+                       " %llu"                                                         // starttime
+                       " %llu"                                                         // vsize
+                       " %llu"                                                         // rss
+                       " %llu %llu %llu %llu %llu %llu"        // rsslim, starcode, endcode, startstack, kstkesp, kstkeip
+                       " %lu %lu %lu %lu"                                      // signal, blocked, sigignore, sigcatch
+                       " %lu %lu %lu"                                          // wchan, nswap, cnswap
+                       " %d %d"                                                        // exit_signal, processor
+                       " %u %u"                                                        // rt_priority, policy
+                       " %llu %lu %ld"
+                       , &p->pid, name, &p->state
+                       , &p->ppid, &p->pgrp, &p->session, &p->tty_nr, &p->tpgid
+                       , &p->flags, &p->minflt, &p->cminflt, &p->majflt, &p->cmajflt
+                       , &p->utime, &p->stime, &p->cutime, &p->cstime
+                       , &p->priority, &p->nice
+                       , &p->num_threads
+                       , &p->itrealvalue
+                       , &p->starttime
+                       , &p->vsize
+                       , &p->rss
+                       , &p->rsslim, &p->starcode, &p->endcode, &p->startstack, &p->kstkesp, &p->kstkeip
+                       , &p->signal, &p->blocked, &p->sigignore, &p->sigcatch
+                       , &p->wchan, &p->nswap, &p->cnswap
+                       , &p->exit_signal, &p->processor
+                       , &p->rt_priority, &p->policy
+                       , &p->delayacct_blkio_ticks, &p->guest_time, &p->cguest_time
+                       );
+               strncpy(p->comm, name, MAX_COMPARE_NAME);
+               p->comm[MAX_COMPARE_NAME] = '\0';
+
+               if(debug) fprintf(stderr, "VALUES: %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+
+               if(parsed < 39) fprintf(stderr, "file %s gave %d results (expected 44)\n", filename, parsed);
+
+               // check if it is target
+               // we do this only once, the first time this pid is loaded
+               if(p->new_entry) {
+                       if(debug) fprintf(stderr, "\tJust added %s\n", p->comm);
+
+                       struct target *w;
+                       for(w = target_root; w ; w = w->next) {
+                               // if(debug) fprintf(stderr, "\t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
+
+                               if(strcmp(w->compare, p->comm) == 0) {
+                                       if(w->target) p->target = w->target;
+                                       else p->target = w;
+
+                                       if(debug) fprintf(stderr, "\t\t%s linked to target %s\n", p->comm, p->target->name);
+                               }
+                       }
+               }
+
+               // just a few checks
+               if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0;
+
+
+               // --------------------------------------------------------------------
+               // /proc/<pid>/statm
+
+               snprintf(filename, FILENAME_MAX, "/proc/%s/statm", file->d_name);
+               fd = open(filename, O_RDONLY);
+               if(fd == -1) {
+                       if(errno != ENOENT && errno != ESRCH) {
+                               if(!count_open_errors) fprintf(stderr, "Cannot open file '%s' for reading (%d, %s).\n", filename, errno, strerror(errno));
+                               count_open_errors++;
+                       }
+               }
+               else {
+                       file_counter++;
+                       bytes = read(fd, buffer, PROC_BUFFER);
+                       close(fd);
+
+                       if(bytes == -1) {
+                               fprintf(stderr, "Cannot read from file '%s' (%s).\n", filename, strerror(errno));
+                       }
+                       else if(bytes > 10) {
+                               buffer[bytes] = '\0';
+                               if(debug) fprintf(stderr, "READ statm: %s", buffer);
+
+                               parsed = sscanf(buffer,
+                                       "%llu %llu %llu %llu %llu %llu %llu"
+                                       , &p->statm_size
+                                       , &p->statm_resident
+                                       , &p->statm_share
+                                       , &p->statm_text
+                                       , &p->statm_lib
+                                       , &p->statm_data
+                                       , &p->statm_dirty
+                                       );
+
+                               if(parsed < 7) fprintf(stderr, "file %s gave %d results (expected 7)\n", filename, parsed);
+                       }
+               }
+
+               // --------------------------------------------------------------------
+               // /proc/<pid>/io
+
+               snprintf(filename, FILENAME_MAX, "/proc/%s/io", file->d_name);
+               fd = open(filename, O_RDONLY);
+               if(fd == -1) {
+                       if(errno != ENOENT && errno != ESRCH) {
+                               if(!count_open_errors) fprintf(stderr, "Cannot open file '%s' for reading (%d, %s).\n", filename, errno, strerror(errno));
+                               count_open_errors++;
+                       }
+               }
+               else {
+                       file_counter++;
+                       bytes = read(fd, buffer, PROC_BUFFER);
+                       close(fd);
+
+                       if(bytes == -1) {
+                               fprintf(stderr, "Cannot read from file '%s' (%s).\n", filename, strerror(errno));
+                       }
+                       else if(bytes > 10) {
+                               buffer[bytes] = '\0';
+                               if(debug) fprintf(stderr, "READ io: %s", buffer);
+
+                               parsed = sscanf(buffer,
+                                       "rchar: %llu\nwchar: %llu\nsyscr: %llu\nsyscw: %llu\nread_bytes: %llu\nwrite_bytes: %llu\ncancelled_write_bytes: %llu"
+                                       , &p->io_logical_bytes_read
+                                       , &p->io_logical_bytes_written
+                                       , &p->io_read_calls
+                                       , &p->io_write_calls
+                                       , &p->io_storage_bytes_read
+                                       , &p->io_storage_bytes_written
+                                       , &p->io_cancelled_write_bytes
+                                       );
+
+                               if(parsed < 7) fprintf(stderr, "file %s gave %d results (expected 7)\n", filename, parsed);
+                       }
+               }
+
+
+               // --------------------------------------------------------------------
+               // done!
+
+               // mark it as updated
+               p->updated = 1;
+       }
+       if(count_open_errors > 1 && count_open_errors > 1000) {
+               fprintf(stderr, "file open errors repeated %ld times\n", count_open_errors - 1);
+               count_open_errors = 0;
+       }
+
+       closedir(dir);
+
+       return 1;
+}
+/*
+int walk_down(pid_t pid, int level) {
+       struct pid_stat *p = NULL;
+       char b[level+3];
+       int i, ret = 0;
+
+       for(i = 0; i < level; i++) b[i] = '\t';
+       b[level] = '|';
+       b[level+1] = '-';
+       b[level+2] = '\0';
+
+       for(p = root; p ; p = p->next) {
+               if(p->ppid == pid) {
+                       ret += walk_down(p->pid, level+1);
+               }
+       }
+
+       p = all_pids[pid];
+       if(p) {
+               if(!p->updated) ret += 1;
+               if(ret) fprintf(stderr, "%s %s %d [%s, %s] c=%d u=%llu+%llu, s=%llu+%llu, cu=%llu+%llu, cs=%llu+%llu, n=%llu+%llu, j=%llu+%llu, cn=%llu+%llu, cj=%llu+%llu\n"
+                       , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->childs
+                       , p->utime, p->utime - p->old_utime
+                       , p->stime, p->stime - p->old_stime
+                       , p->cutime, p->cutime - p->old_cutime
+                       , p->cstime, p->cstime - p->old_cstime
+                       , p->minflt, p->minflt - p->old_minflt
+                       , p->majflt, p->majflt - p->old_majflt
+                       , p->cminflt, p->cminflt - p->old_cminflt
+                       , p->cmajflt, p->cmajflt - p->old_cmajflt
+                       );
+       }
+
+       return ret;
+}
+*/
+
+void update_statistics(void)
+{
+       struct pid_stat *p = NULL;
+
+       // link all parents and update childs count
+       for(p = root; p ; p = p->next) {
+               if(p->ppid > 0 && p->ppid <= pid_max && all_pids[p->ppid]) {
+                       if(debug) fprintf(stderr, "\tParent of %d %s is %d %s\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);
+                       
+                       p->parent = all_pids[p->ppid];
+                       p->parent->childs++;
+               }
+               else if(p->ppid != 0) fprintf(stderr, "\t\tWRONG! pid %d %s states parent %d, but the later does not exist.\n", p->pid, p->comm, p->ppid);
+       }
+
+       // find all the procs with 0 childs and merge them to their parents
+       // repeat, until nothing more can be done.
+       int found = 1;
+       while(found) {
+               found = 0;
+               for(p = root; p ; p = p->next) {
+                       // if this process does not have any childs, and
+                       // is not already merged, and
+                       // its parent has childs waiting to be merged, and
+                       // the target of this process and its parent is the same, or the parent does not have a target, or this process does not have a parent
+                       // and its parent is not init
+                       // then... merge them!
+                       if(!p->childs && !p->merged && p->parent && p->parent->childs && (p->target == p->parent->target || !p->parent->target || !p->target) && p->ppid != 1) {
+                               p->parent->childs--;
+                               p->merged = 1;
+
+                               // the parent inherits the child's target, if it does not have a target itself
+                               if(p->target && !p->parent->target) {
+                                       p->parent->target = p->target;
+                                       if(debug) fprintf(stderr, "\t\ttarget %s is inherited by %d %s from its child %d %s.\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
+                               }
+
+                               found++;
+                       }
+               }
+               if(debug) fprintf(stderr, "Merged %d processes\n", found);
+       }
+
+       // give a default target on all top level processes
+       // init goes always to default target
+       if(all_pids[1]) all_pids[1]->target = default_target;
+
+       for(p = root; p ; p = p->next) {
+               // if the process is not merged itself
+               // then is is a top level process
+               if(!p->merged && !p->target) p->target = default_target;
+
+/*             // by the way, update the diffs
+               // will be used later for substracting killed process times
+               p->diff_cutime = p->utime - p->cutime;
+               p->diff_cstime = p->stime - p->cstime;
+               p->diff_cminflt = p->minflt - p->cminflt;
+               p->diff_cmajflt = p->majflt - p->cmajflt;
+*/     }
+
+       // give a target to all merged child processes
+       found = 1;
+       while(found) {
+               found = 0;
+               for(p = root; p ; p = p->next) {
+                       if(!p->target && p->merged && p->parent && p->parent->target) {
+                               p->target = p->parent->target;
+                               found++;
+                       }
+               }
+       }
+
+/*     // for each killed process, remove its values from the parents
+       // sums (we had already added them in a previous loop)
+       for(p = root; p ; p = p->next) {
+               if(p->updated) continue;
+
+               fprintf(stderr, "UNMERGING %d %s\n", p->pid, p->comm);
+
+               unsigned long long diff_utime = p->utime + p->cutime + p->fix_cutime;
+               unsigned long long diff_stime = p->stime + p->cstime + p->fix_cstime;
+               unsigned long long diff_minflt = p->minflt + p->cminflt + p->fix_cminflt;
+               unsigned long long diff_majflt = p->majflt + p->cmajflt + p->fix_cmajflt;
+
+               struct pid_stat *t = p;
+               while((t = t->parent)) {
+                       if(!t->updated) continue;
+
+                       unsigned long long x;
+                       if(diff_utime && t->diff_cutime) {
+                               x = (t->diff_cutime < diff_utime)?t->diff_cutime:diff_utime;
+                               diff_utime -= x;
+                               t->diff_cutime -= x;
+                               t->fix_cutime += x;
+                               fprintf(stderr, "\t cutime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
+                       }
+                       if(diff_stime && t->diff_cstime) {
+                               x = (t->diff_cstime < diff_stime)?t->diff_cstime:diff_stime;
+                               diff_stime -= x;
+                               t->diff_cstime -= x;
+                               t->fix_cstime += x;
+                               fprintf(stderr, "\t cstime %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
+                       }
+                       if(diff_minflt && t->diff_cminflt) {
+                               x = (t->diff_cminflt < diff_minflt)?t->diff_cminflt:diff_minflt;
+                               diff_minflt -= x;
+                               t->diff_cminflt -= x;
+                               t->fix_cminflt += x;
+                               fprintf(stderr, "\t cminflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
+                       }
+                       if(diff_majflt && t->diff_cmajflt) {
+                               x = (t->diff_cmajflt < diff_majflt)?t->diff_cmajflt:diff_majflt;
+                               diff_majflt -= x;
+                               t->diff_cmajflt -= x;
+                               t->fix_cmajflt += x;
+                               fprintf(stderr, "\t cmajflt %llu from %d %s %s\n", x, t->pid, t->comm, t->target->name);
+                       }
+               }
+
+               if(diff_utime) fprintf(stderr, "\t cannot fix up utime %llu\n", diff_utime);
+               if(diff_stime) fprintf(stderr, "\t cannot fix up stime %llu\n", diff_stime);
+               if(diff_minflt) fprintf(stderr, "\t cannot fix up minflt %llu\n", diff_minflt);
+               if(diff_majflt) fprintf(stderr, "\t cannot fix up majflt %llu\n", diff_majflt);
+       }
+*/
+       // zero all the targets
+       struct target *w;
+       for (w = target_root; w ; w = w->next) {
+               w->minflt = 0;
+               w->majflt = 0;
+               w->utime = 0;
+               w->stime = 0;
+               w->cminflt = 0;
+               w->cmajflt = 0;
+               w->cutime = 0;
+               w->cstime = 0;
+               w->num_threads = 0;
+               w->rss = 0;
+               w->processes = 0;
+
+               w->statm_size = 0;
+               w->statm_resident = 0;
+               w->statm_share = 0;
+               w->statm_text = 0;
+               w->statm_lib = 0;
+               w->statm_data = 0;
+               w->statm_dirty = 0;
+
+               w->io_logical_bytes_read = 0;
+               w->io_logical_bytes_written = 0;
+               w->io_read_calls = 0;
+               w->io_write_calls = 0;
+               w->io_storage_bytes_read = 0;
+               w->io_storage_bytes_written = 0;
+               w->io_cancelled_write_bytes = 0;
+       }
+
+/*     walk_down(0, 1);
+*/
+       // concentrate everything on the targets
+       for(p = root; p ; p = p->next) {
+               if(!p->target) {
+                       fprintf(stderr, "WRONG! pid %d %s was left without a target!\n", p->pid, p->comm);
+                       continue;
+               }
+
+               if(p->updated) {
+                       p->target->cutime += p->cutime; // - p->fix_cutime;
+                       p->target->cstime += p->cstime; // - p->fix_cstime;
+                       p->target->cminflt += p->cminflt; // - p->fix_cminflt;
+                       p->target->cmajflt += p->cmajflt; // - p->fix_cmajflt;
+
+                       p->target->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;
+                       p->target->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;
+                       p->target->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;
+                       p->target->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;
+
+                       p->target->num_threads += p->num_threads;
+                       p->target->rss += p->rss;
+
+                       p->target->statm_size += p->statm_size;
+                       p->target->statm_resident += p->statm_resident;
+                       p->target->statm_share += p->statm_share;
+                       p->target->statm_text += p->statm_text;
+                       p->target->statm_lib += p->statm_lib;
+                       p->target->statm_data += p->statm_data;
+                       p->target->statm_dirty += p->statm_dirty;
+
+                       p->target->io_logical_bytes_read += p->io_logical_bytes_read;
+                       p->target->io_logical_bytes_written += p->io_logical_bytes_written;
+                       p->target->io_read_calls += p->io_read_calls;
+                       p->target->io_write_calls += p->io_write_calls;
+                       p->target->io_storage_bytes_read += p->io_storage_bytes_read;
+                       p->target->io_storage_bytes_written += p->io_storage_bytes_written;
+                       p->target->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
+
+                       p->target->processes++;
+
+                       if(debug) fprintf(stderr, "\tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+
+/*                     if(p->utime - p->old_utime > 100) fprintf(stderr, "BIG CHANGE: %d %s utime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->utime - p->old_utime, p->old_utime, p->utime);
+                       if(p->cutime - p->old_cutime > 100) fprintf(stderr, "BIG CHANGE: %d %s cutime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cutime - p->old_cutime, p->old_cutime, p->cutime);
+                       if(p->stime - p->old_stime > 100) fprintf(stderr, "BIG CHANGE: %d %s stime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->stime - p->old_stime, p->old_stime, p->stime);
+                       if(p->cstime - p->old_cstime > 100) fprintf(stderr, "BIG CHANGE: %d %s cstime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cstime - p->old_cstime, p->old_cstime, p->cstime);
+                       if(p->minflt - p->old_minflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s minflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->minflt - p->old_minflt, p->old_minflt, p->minflt);
+                       if(p->majflt - p->old_majflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s majflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->majflt - p->old_majflt, p->old_majflt, p->majflt);
+                       if(p->cminflt - p->old_cminflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cminflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cminflt - p->old_cminflt, p->old_cminflt, p->cminflt);
+                       if(p->cmajflt - p->old_cmajflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cmajflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cmajflt - p->old_cmajflt, p->old_cmajflt, p->cmajflt);
+
+                       p->old_utime = p->utime;
+                       p->old_cutime = p->cutime;
+                       p->old_stime = p->stime;
+                       p->old_cstime = p->cstime;
+                       p->old_minflt = p->minflt;
+                       p->old_majflt = p->majflt;
+                       p->old_cminflt = p->cminflt;
+                       p->old_cmajflt = p->cmajflt;
+*/             }
+               else {
+                       // since the process has exited, the user
+                       // will see a drop in our charts, because the incremental
+                       // values of this process will not be there
+
+                       // add them to the fix_* values and they will be added to
+                       // the reported values, so that the report goes steady
+                       p->target->fix_minflt += p->minflt;
+                       p->target->fix_majflt += p->majflt;
+                       p->target->fix_utime += p->utime;
+                       p->target->fix_stime += p->stime;
+                       p->target->fix_cminflt += p->cminflt;
+                       p->target->fix_cmajflt += p->cmajflt;
+                       p->target->fix_cutime += p->cutime;
+                       p->target->fix_cstime += p->cstime;
+
+                       p->target->fix_io_logical_bytes_read += p->io_logical_bytes_read;
+                       p->target->fix_io_logical_bytes_written += p->io_logical_bytes_written;
+                       p->target->fix_io_read_calls += p->io_read_calls;
+                       p->target->fix_io_write_calls += p->io_write_calls;
+                       p->target->fix_io_storage_bytes_read += p->io_storage_bytes_read;
+                       p->target->fix_io_storage_bytes_written += p->io_storage_bytes_written;
+                       p->target->fix_io_cancelled_write_bytes += p->io_cancelled_write_bytes;
+               }
+       }
+
+/*     fprintf(stderr, "\n");
+*/
+       // cleanup all un-updated processed (exited, killed, etc)
+       int c;
+       for(p = root, c = 0; p ; c++) {
+               if(!p->updated) {
+/*                     fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name,  p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+*/                     
+                       pid_t r = p->pid;
+                       p = p->next;
+                       del_entry(r);
+               }
+               else p = p->next;
+       }
+}
+
+
+void show_dimensions(void)
+{
+       struct target *w;
+
+       fprintf(stdout, "BEGIN apps.cpu\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + w->fix_utime + w->fix_stime);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.cpu_user\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->fix_utime);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.cpu_system\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + w->fix_stime);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.threads\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->num_threads);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.processes\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %lu\n", w->name, w->processes);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.mem\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %lld\n", w->name, (long long)w->statm_resident - (long long)w->statm_share);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.minor_faults\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + w->fix_minflt);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.major_faults\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + w->fix_majflt);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.lreads\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.lwrites\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.preads\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read);
+       }
+       fprintf(stdout, "END\n");
+
+       fprintf(stdout, "BEGIN apps.pwrites\n");
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written);
+       }
+       fprintf(stdout, "END\n");
+}
+
+void show_charts(void)
+{
+       struct target *w;
+       int newly_added = 0;
+
+       for(w = target_root ; w ; w = w->next)
+               if(!w->exposed && w->processes) {
+                       newly_added++;
+                       w->exposed = 1;
+                       if(debug) fprintf(stderr, "%s just added - regenerating charts.\n", w->name);
+               }
+
+       // nothing more to show
+       if(!newly_added) return;
+
+       // we have something new to show
+       // update the charts
+       fprintf(stdout, "CHART apps.cpu '' 'Apps CPU Time (%ld%% = %ld core%s)' 'cpu time %%' apps apps stacked 20001 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 100 %llu\n", w->name, Hertz);
+       }
+
+       fprintf(stdout, "CHART apps.mem '' 'Apps Dedicated Memory (w/o shared)' 'MB' apps apps stacked 20003 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
+       }
+
+       fprintf(stdout, "CHART apps.threads '' 'Apps Threads' 'threads' apps apps stacked 20005 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
+       }
+
+       fprintf(stdout, "CHART apps.processes '' 'Apps Processes' 'processes' apps apps stacked 20004 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' absolute 1 1\n", w->name);
+       }
+
+       fprintf(stdout, "CHART apps.cpu_user '' 'Apps CPU User Time (%ld%% = %ld core%s)' 'cpu time %%' apps none stacked 20020 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 100 %llu\n", w->name, Hertz * processors);
+       }
+
+       fprintf(stdout, "CHART apps.cpu_system '' 'Apps CPU System Time (%ld%% = %ld core%s)' 'cpu time %%' apps none stacked 20021 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 100 %llu\n", w->name, Hertz * processors);
+       }
+
+       fprintf(stdout, "CHART apps.major_faults '' 'Apps Major Page Faults (swaps in)' 'page faults/s' apps apps stacked 20010 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w->name);
+       }
+
+       fprintf(stdout, "CHART apps.minor_faults '' 'Apps Minor Page Faults' 'page faults/s' apps apps stacked 20011 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w->name);
+       }
+
+       fprintf(stdout, "CHART apps.lreads '' 'Apps Logical Reads' 'kilobytes/s' apps apps stacked 20042 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);
+       }
+
+       fprintf(stdout, "CHART apps.lwrites '' 'Apps Logical Writes' 'kilobytes/s' apps apps stacked 20042 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);
+       }
+
+       fprintf(stdout, "CHART apps.preads '' 'Apps Reads' 'kilobytes/s' apps apps stacked 20002 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);
+       }
+
+       fprintf(stdout, "CHART apps.pwrites '' 'Apps Writes' 'kilobytes/s' apps apps stacked 20002 %d\n", update_every);
+       for (w = target_root; w ; w = w->next) {
+               if(w->target || (!w->processes && !w->exposed)) continue;
+
+               fprintf(stdout, "DIMENSION %s '' incremental 1 1024\n", w->name);
+       }
+}
+
+unsigned long long get_hertz(void)
+{
+       unsigned long long hz = 1;
+
+#ifdef _SC_CLK_TCK
+       if((hz = sysconf(_SC_CLK_TCK)) > 0) {
+               return hz;
+       }
+#endif
+
+#ifdef HZ
+       hz = (unsigned long long)HZ;    /* <asm/param.h> */
+#else
+       /* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
+       hz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
+#endif
+
+       fprintf(stderr, "Unknown HZ value. Assuming %llu.\n", hz);
+       return hz;
+}
+
+long get_processors(void)
+{
+       char buffer[1025], *s;
+       int processors = 0;
+
+       FILE *fp = fopen("/proc/stat", "r");
+       if(!fp) return 1;
+
+       while((s = fgets(buffer, 1024, fp))) {
+               if(strncmp(buffer, "cpu", 3) == 0) processors++;
+       }
+       fclose(fp);
+       processors--;
+       if(processors < 1) processors = 1;
+       return processors;
+}
+
+long get_pid_max(void)
+{
+       char buffer[1025], *s;
+       long mpid = 32768;
+
+       FILE *fp = fopen("/proc/sys/kernel/pid_max", "r");
+       if(!fp) return 1;
+
+       s = fgets(buffer, 1024, fp);
+       if(s) mpid = atol(buffer);
+       fclose(fp);
+       if(mpid < 32768) mpid = 32768;
+       return mpid;
+}
+
+unsigned long long usecdiff(struct timeval *now, struct timeval *last) {
+               return ((((now->tv_sec * 1000000ULL) + now->tv_usec) - ((last->tv_sec * 1000000ULL) + last->tv_usec)));
+}
+
+int main(int argc, char **argv)
+{
+       Hertz = get_hertz();
+       pid_max = get_pid_max();
+       processors = get_processors();
+
+       parse_args(argc, argv);
+
+       all_pids = calloc(sizeof(struct pid_stat *), pid_max);
+       if(!all_pids) {
+               fprintf(stderr, "Cannot allocate %lu bytes of memory.\n", sizeof(struct pid_stat *) * pid_max);
+               printf("DISABLE\n");
+               exit(1);
+       }
+
+       int created_usage_chart = 0;
+       struct rusage me, me_last;
+       unsigned long long counter = 1;
+       unsigned long long usec = 0, susec = 0;
+       struct timeval last, now;
+       gettimeofday(&last, NULL);
+       getrusage(RUSAGE_SELF, &me_last);
+
+       for(;1; counter++) {
+               if(!update_from_proc()) {
+                       fprintf(stderr, "Cannot allocate %lu bytes of memory.\n", sizeof(struct pid_stat *) * pid_max);
+                       printf("DISABLE\n");
+                       exit(1);
+               }
+
+               update_statistics();
+               show_charts();          // this is smart enough to show only newly added apps, when needed
+               show_dimensions();
+
+               if(getrusage(RUSAGE_SELF, &me) == 0) {
+                       unsigned long long cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec;
+                       unsigned long long cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec;
+
+                       if(!created_usage_chart) {
+                               created_usage_chart = 1;
+                               fprintf(stdout, "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' netdata netdata stacked 10000 %d\n", update_every);
+                               fprintf(stdout, "DIMENSION user '' incremental 1 1000\n");
+                               fprintf(stdout, "DIMENSION system '' incremental 1 1000\n");
+
+                               fprintf(stdout, "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' netdata netdata line 10001 %d\n", update_every);
+                               fprintf(stdout, "DIMENSION files '' incremental 1 1\n");
+                       }
+
+                       fprintf(stdout, "BEGIN netdata.apps_cpu\n");
+                       fprintf(stdout, "SET user = %llu\n", cpuuser);
+                       fprintf(stdout, "SET system = %llu\n", cpusyst);
+                       fprintf(stdout, "END\n");
+
+                       fprintf(stdout, "BEGIN netdata.apps_files\n");
+                       fprintf(stdout, "SET files = %llu\n", file_counter);
+                       fprintf(stdout, "END\n");
+
+                       bcopy(&me, &me_last, sizeof(struct rusage));
+               }
+
+               if(debug) fprintf(stderr, "Done Loop No %llu\n", counter);
+               // if(counter == 1000) exit(0);
+
+               gettimeofday(&now, NULL);
+
+               usec = usecdiff(&now, &last) - susec;
+               if(debug) fprintf(stderr, "last loop took %llu usec (worked for %llu, sleeped for %llu).\n", usec + susec, usec, susec);
+
+               // if the last loop took less than half the time
+               // wait the rest of the time
+               if(usec < (update_every * 1000000ULL / 2)) susec = (update_every * 1000000ULL) - usec;
+               else susec = update_every * 1000000ULL / 2;
+
+               fflush(NULL);
+               usleep(susec);
+
+               bcopy(&now, &last, sizeof(struct timeval));
+       }
+}
index d6f2747230bc42d1b30469468806039b2db99b0d..05f13d1310952d8a3371adc93e1dec24c9112143 100644 (file)
--- a/netdata.c
+++ b/netdata.c
@@ -36,6 +36,9 @@
 #include <inttypes.h>
 #include <dirent.h>
 
+// enabling this will detach the plugins from netdata
+// each plugin will have its own process group
+// #define DETACH_PLUGINS_FROM_NETDATA
 
 #define RRD_TYPE_NET                           "net"
 #define RRD_TYPE_NET_LEN                       strlen(RRD_TYPE_NET)
@@ -227,7 +230,8 @@ void info_int( const char *file, const char *function, const unsigned long line,
        log_date(stderr);
 
        va_start( args, fmt );
-       fprintf(stderr, "INFO (%04lu@%-15.15s): ", line, function);
+       if(debug_flags) fprintf(stderr, "INFO (%04lu@%-15.15s): ", line, function);
+       else            fprintf(stderr, "INFO: ");
        vfprintf( stderr, fmt, args );
        va_end( args );
 
@@ -235,7 +239,7 @@ void info_int( const char *file, const char *function, const unsigned long line,
 
        if(error_log_syslog) {
                va_start( args, fmt );
-               vsyslog(LOG_ERR,  fmt, args );
+               vsyslog(LOG_INFO,  fmt, args );
                va_end( args );
        }
 }
@@ -250,7 +254,8 @@ void error_int( const char *file, const char *function, const unsigned long line
        log_date(stderr);
 
        va_start( args, fmt );
-       fprintf(stderr, "ERROR (%04lu@%-15.15s): ", line, function);
+       if(debug_flags) fprintf(stderr, "ERROR (%04lu@%-15.15s): ", line, function);
+       else            fprintf(stderr, "ERROR: ");
        vfprintf( stderr, fmt, args );
        va_end( args );
 
@@ -277,7 +282,8 @@ void fatal_int( const char *file, const char *function, const unsigned long line
        log_date(stderr);
 
        va_start( args, fmt );
-       fprintf(stderr, "FATAL (%04lu@%-15.15s): ", line, function);
+       if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-15.15s): ", line, function);
+       else            fprintf(stderr, "FATAL: ");
        vfprintf( stderr, fmt, args );
        va_end( args );
 
@@ -367,7 +373,10 @@ FILE *mypopen(const char *command, pid_t *pidptr)
                close(pipefd[PIPE_WRITE]);
        }
 
-/*
+#ifdef DETACH_PLUGINS_FROM_NETDATA
+       // this was an attempt to detach the child and use the suspend mode charts.d
+       // unfortunatelly it does not work as expected.
+
        // fork again to become session leader
        pid = fork();
        if(pid == -1) fprintf(stderr, "Cannot fork again on pid %d\n", getpid());
@@ -385,13 +394,13 @@ FILE *mypopen(const char *command, pid_t *pidptr)
 
        if( setsid() != 0 )
                fprintf(stderr, "Cannot set session id for pid %d (%s)\n", getpid(), strerror(errno));
-*/
-       
-       // ignore all signals
-       for (i = 1 ; i < 65 ;i++) if(i != SIGSEGV) signal(i, SIG_DFL);
 
        fprintf(stdout, "MYPID %d\n", getpid());
        fflush(NULL);
+#endif
+       
+       // ignore all signals
+       for (i = 1 ; i < 65 ;i++) if(i != SIGSEGV) signal(i, SIG_DFL);
 
        fprintf(stderr, "executing command: '%s'\n", command);
        execl("/bin/sh", "sh", "-c", command, NULL);
@@ -400,6 +409,10 @@ FILE *mypopen(const char *command, pid_t *pidptr)
 
 void mypclose(FILE *fp)
 {
+       // this is a very poor implementation of pclose()
+       // the caller should catch SIGCHLD and waitpid() on the exited child
+       // otherwise the child will be a zombie forever
+
        fclose(fp);
 }
 
@@ -515,7 +528,7 @@ int create_listen_socket(int port)
 
 #define CONFIG_MAX_NAME 1024
 #define CONFIG_MAX_VALUE 4096
-#define CONFIG_FILENAME "conf.d/netdata.conf"
+#define CONFIG_FILENAME "netdata.conf"
 #define CONFIG_FILE_LINE_MAX 4096
 
 pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -629,10 +642,10 @@ int load_config(char *filename, int overwrite_used)
 
        char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
 
-       if(!filename) filename = CONFIG_FILENAME;
+       if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
        FILE *fp = fopen(filename, "r");
        if(!fp) {
-               error("Cannot open file '%s'", CONFIG_FILENAME);
+               error("Cannot open file '%s'", CONFIG_DIR "/" CONFIG_FILENAME);
                pthread_mutex_unlock(&config_mutex);
                return 0;
        }
@@ -5369,7 +5382,7 @@ void *proc_main(void *ptr)
 
                        if(!stclients) stclients = rrd_stats_find("netdata.clients");
                        if(!stclients) {
-                               stclients = rrd_stats_create("netdata", "clients", NULL, "netdata", "NetData Web Clients", "clients", 11000, update_every, CHART_TYPE_LINE);
+                               stclients = rrd_stats_create("netdata", "clients", NULL, "netdata", "NetData Web Clients", "connected clients", 11000, update_every, CHART_TYPE_LINE);
 
                                rrd_stats_dimension_add(stclients, "clients",  NULL,  1, 1, RRD_DIMENSION_ABSOLUTE);
                        }
@@ -5382,7 +5395,7 @@ void *proc_main(void *ptr)
 
                        if(!streqs) streqs = rrd_stats_find("netdata.requests");
                        if(!streqs) {
-                               streqs = rrd_stats_create("netdata", "requests", NULL, "netdata", "NetData Web Requests", "requests", 12000, update_every, CHART_TYPE_LINE);
+                               streqs = rrd_stats_create("netdata", "requests", NULL, "netdata", "NetData Web Requests", "requests/s", 12000, update_every, CHART_TYPE_LINE);
 
                                rrd_stats_dimension_add(streqs, "requests",  NULL,  1, 1, RRD_DIMENSION_INCREMENTAL);
                        }
@@ -5614,7 +5627,7 @@ void *tc_main(void *ptr)
                struct tc_device *device = NULL;
                struct tc_class *class = NULL;
 
-               snprintf(buffer, TC_LINE_MAX, "exec %s %d", config_get("plugin:tc", "script to run to get tc values", "plugins.d/tc-qos-helper.sh"), update_every);
+               snprintf(buffer, TC_LINE_MAX, "exec %s %d", config_get("plugin:tc", "script to run to get tc values", PLUGINS_DIR "/tc-qos-helper.sh"), update_every);
                debug(D_TC_LOOP, "executing '%s'", buffer);
                // fp = popen(buffer, "r");
                fp = mypopen(buffer, &tc_child_pid);
@@ -5703,17 +5716,16 @@ void *tc_main(void *ptr)
                                char *path  = strsep(&b, " \n");
                                if(id && *id && path && *path) tc_device_set_class_name(device, id, path);
                        }
+#ifdef DETACH_PLUGINS_FROM_NETDATA
                        else if((strcmp(p, "MYPID") == 0)) {
                                char *id = strsep(&b, " \n");
                                pid_t pid = atol(id);
 
-                               if(pid != tc_child_pid)
-                                       error("tc-qos-helper reports wrong pid %d (expected %d).", pid, tc_child_pid);
-
-                               // tc_child_pid = pid;
+                               if(pid) tc_child_pid = pid;
 
                                debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid);
                        }
+#endif
                }
                mypclose(fp);
 
@@ -5843,8 +5855,10 @@ void *pluginsd_worker_thread(void *arg)
        struct plugind *cd = (struct plugind *)arg;
        char line[PLUGINSD_LINE_MAX + 1];
 
+#ifdef DETACH_PLUGINS_FROM_NETDATA
        unsigned long long usec = 0, susec = 0;
        struct timeval last = {0, 0} , now = {0, 0};
+#endif
 
        while(1) {
                // FILE *fp = popen(cd->cmd, "r");
@@ -6035,26 +6049,20 @@ void *pluginsd_worker_thread(void *arg)
                                }
                                else if(st->debug) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
                        }
-                       else if(!strcmp(s, "MYPID")) {
-                               char *pid_s = qstrsep(&p);
-                               pid_t pid = atol(pid_s);
-
-                               if(pid != cd->pid) {
-                                       error("plugin %s reports wrong pid %d (expected %d). Disabling it.", cd->filename, pid, cd->pid);
-                                       cd->enabled = 0;
-                                       kill(cd->pid, SIGTERM);
-                                       break;
-                               }
-                               // cd->pid = pid;
-
-                               debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
-                       }
                        else if(!strcmp(s, "DISABLE")) {
                                error("PLUGINSD: script '%s' called DISABLE. Disabling it.", cd->fullfilename);
                                cd->enabled = 0;
                                kill(cd->pid, SIGTERM);
                                break;
                        }
+#ifdef DETACH_PLUGINS_FROM_NETDATA
+                       else if(!strcmp(s, "MYPID")) {
+                               char *pid_s = qstrsep(&p);
+                               pid_t pid = atol(pid_s);
+
+                               if(pid) cd->pid = pid;
+                               debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
+                       }
                        else if(!strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE")) {
                                error("PLUGINSD: script '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
 
@@ -6071,12 +6079,13 @@ void *pluginsd_worker_thread(void *arg)
                                        else susec = 100000ULL;
                                }
 
-                               error("PLUGINSD: %s sleeping for %llu. Will kill pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
+                               error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
                                usleep(susec);
                                kill(cd->pid, SIGCONT);
                                bcopy(&now, &last, sizeof(struct timeval));
                                break;
                        }
+#endif
                        else {
                                error("PLUGINSD: script %s is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
                                cd->enabled = 0;
@@ -6105,7 +6114,7 @@ void *pluginsd_worker_thread(void *arg)
 void *pluginsd_main(void *ptr)
 {
        if(ptr) { ; }
-       char *dir_name = config_get("plugins", "plugins directory", "plugins.d");
+       char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
        int automatic_run = config_get_boolean("plugins", "enable running new plugins", 0);
        int scan_frequency = config_get_number("plugins", "check for new plugins every", 60);
        DIR *dir = NULL;
@@ -6158,7 +6167,7 @@ void *pluginsd_main(void *ptr)
                        // allocate a new one, or use the obsolete one
                        if(!cd) {
                                cd = calloc(sizeof(struct plugind), 1);
-                               if(!cd) fatal("Cannot allocate memory for chart.d");
+                               if(!cd) fatal("Cannot allocate memory for plugin.");
 
                                snprintf(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
                                
@@ -6169,43 +6178,6 @@ void *pluginsd_main(void *ptr)
                                cd->update_every = config_get_number(cd->id, "update every", update_every);
 
                                char *def = "";
-                               if(strcmp(cd->id, "plugin:apps") == 0)
-                                       def =
-                                       " 'mplayer vlc xine mediatomb as media'"
-                                       " 'squid squid3 as squid'"
-                                       " 'apache apache2 as apache'"
-                                       " 'mysql mysqld as mysql'"
-                                       " asterisk"
-                                       " 'opensips opensips-mi-pro as opensips'"
-                                       " stund"
-                                       " 'radiusd radiusclient as radius'"
-                                       " 'fail2ban-server as fail2ban'"
-                                       " dovecot"
-                                       " nginx"
-                                       " lighttpd"
-                                       " 'proftpd in.tftpd as ftpd'"
-                                       " 'master as postfix'"
-                                       " 'smbd nmbd winbindd as samba'"
-                                       " 'rpcbind rpc.statd rpc.idmapd rpc.mountd nfsd4 nfsd4_callbacks nfsd nfsiod as nfs'"
-                                       " 'ssh sshd as ssh'"
-                                       " 'gdm X lightdm xdm gnome-session gconfd-2 gnome-terminal gnome-screensaver gnome-settings-daemon pulseaudio as X'"
-                                       " named"
-                                       " 'clamd freshclam as clam'"
-                                       " 'cupsd cups-browsed as cups'"
-                                       " 'ntpq ntpd as ntp'"
-                                       " 'deluge deluged as deluge'"
-                                       " 'vboxwebsrv VBoxXPCOMIPCD VBoxSVC as vbox'"
-                                       " 'ulogd syslogd syslog-ng rsyslogd logrotate as log'"
-                                       " 'snmpd vnstatd smokeping zabbix_agentd monit munin-node mon openhpid as nms'"
-                                       " 'ppp pppd pptpd pptpctrl as ppp'"
-                                       " 'inetd xinetd as inetd'"
-                                       " openvpn"
-                                       " 'cron atd as cron'"
-                                       " 'corosync hs_logd ha_logd stonithd as ha'"
-                                       " 'ipvs_syncmaster ipvs_syncbackup as ipvs'"
-                                       " 'kthreadd as kernel'"
-                                       " netdata"
-                                       ;
                                snprintf(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def));
 
                                // link it
@@ -6523,7 +6495,7 @@ int main(int argc, char **argv)
                else {
                        fprintf(stderr, "Cannot understand option '%s'.\n", argv[i]);
                        fprintf(stderr, "\nUSAGE: %s [-d] [-l LINES_TO_SAVE] [-u UPDATE_TIMER] [-p LISTEN_PORT] [-dl debug log file] [-df debug flags].\n\n", argv[0]);
-                       fprintf(stderr, "  -c CONFIG FILE the configuration file to load. Default: %s.\n", CONFIG_FILENAME);
+                       fprintf(stderr, "  -c CONFIG FILE the configuration file to load. Default: %s.\n", CONFIG_DIR "/" CONFIG_FILENAME);
                        fprintf(stderr, "  -l LINES_TO_SAVE can be from 5 to %d lines in JSON data. Default: %d.\n", HISTORY_MAX, HISTORY);
                        fprintf(stderr, "  -t UPDATE_TIMER can be from 1 to %d seconds. Default: %d.\n", UPDATE_EVERY_MAX, UPDATE_EVERY);
                        fprintf(stderr, "  -p LISTEN_PORT can be from 1 to %d. Default: %d.\n", 65535, LISTEN_PORT);
@@ -6551,7 +6523,7 @@ int main(int argc, char **argv)
 
                // --------------------------------------------------------------------
 
-               output_log_file = config_get("global", "debug log", "log/debug.log");
+               output_log_file = config_get("global", "debug log", LOG_DIR "/debug.log");
                if(strcmp(output_log_file, "syslog") == 0) {
                        output_log_syslog = 1;
                        output_log_file = NULL;
@@ -6565,7 +6537,7 @@ int main(int argc, char **argv)
                // --------------------------------------------------------------------
 
                silent = 0;
-               error_log_file = config_get("global", "error log", "log/error.log");
+               error_log_file = config_get("global", "error log", LOG_DIR "/error.log");
                if(strcmp(error_log_file, "syslog") == 0) {
                        error_log_syslog = 1;
                        error_log_file = NULL;
@@ -6579,7 +6551,7 @@ int main(int argc, char **argv)
 
                // --------------------------------------------------------------------
 
-               access_log_file = config_get("global", "access log", "log/access.log");
+               access_log_file = config_get("global", "access log", LOG_DIR "/access.log");
                if(strcmp(access_log_file, "syslog") == 0) {
                        access_log_syslog = 1;
                        access_log_file = NULL;
@@ -6610,7 +6582,7 @@ int main(int argc, char **argv)
 
                // --------------------------------------------------------------------
 
-               char *user = config_get("global", "run as user", "");
+               char *user = config_get("global", "run as user", (getuid() == 0)?"nobody":"");
                if(*user) {
                        if(become_user(user) != 0) {
                                fprintf(stderr, "Cannot become user %s.\n", user);
index 70b7dea7413acc7b5615df7767e173b2f2b16466..981db9324709995f4f1f583cb1934bbcf319b65b 100755 (executable)
@@ -39,30 +39,18 @@ fi
 
 if [ -f conf.d/netdata.conf ]
 then
-       x="`grep "\[global\]" conf.d/netdata.conf`"
-       if [ -z "$x" ]
+       # find if debug is enabled in the config
+       df=`grep "debug flags = " conf.d/netdata.conf | tail -n 1 | cut -d '=' -f 2 | sed s"/ //g"`
+       if [ -z "$df" -o "$df" = "0x00000000" -o $((df + 1 - 1)) -eq 0 ]
        then
-               # import the old values
-               cat netdata.conf | grep ^NETDATA_CONFIG_ >netdata.conf.tmp
-               . netdata.conf.tmp
-               rm netdata.conf.tmp
-
-               mv netdata.conf netdata.conf.old
-               echo "You are having an old config. Moved to netdata.conf.old. New config is in conf.d/"
+               NETDATA_CONFIG_DEBUG=0
        else
-               # find if debug is enabled in the config
-               df=`grep "debug flags = " conf.d/netdata.conf | tail -n 1 | cut -d '=' -f 2 | sed s"/ //g"`
-               if [ -z "$df" -o "$df" = "0x00000000" -o $((df + 1 - 1)) -eq 0 ]
-               then
-                       NETDATA_CONFIG_DEBUG=0
-               else
-                       NETDATA_CONFIG_DEBUG=1
-               fi
-
-               # find the user to run as
-               NETDATA_CONFIG_USER="`grep 'run as user = ' conf.d/netdata.conf | head -n 1 | cut -d '=' -f 2 | sed s"/ //g"`"
-               NETDATA_CONFIG_WEB_DIR="`grep 'web files directory = ' conf.d/netdata.conf | head -n 1 | cut -d '=' -f 2 | sed -e s"/^ \+//g" -e s"/ \+$//g"`"
+               NETDATA_CONFIG_DEBUG=1
        fi
+
+       # find the user to run as
+       NETDATA_CONFIG_USER="`grep 'run as user = ' conf.d/netdata.conf | head -n 1 | cut -d '=' -f 2 | sed s"/ //g"`"
+       NETDATA_CONFIG_WEB_DIR="`grep 'web files directory = ' conf.d/netdata.conf | head -n 1 | cut -d '=' -f 2 | sed -e s"/^ \+//g" -e s"/ \+$//g"`"
 fi
 
 echo "Compiling netdata (debug=$NETDATA_CONFIG_DEBUG)"
index 3398c685c2e1b5c8d87f75c5ce441cc965094473..c8914c491cae1621e27947d0dd9c429b0e265341 100755 (executable)
@@ -1,9 +1,5 @@
 #!/bin/sh
 
-# let netdata know our PID
-# this is required to kill us when it exits
-echo "MYPID $$"
-
 # default sleep function
 loopsleepms() {
        sleep $1