Mercurial > dovecot > core-2.2
view src/plugins/stats/mail-stats-fill.c @ 22944:666f2182826f
plugins/old-stats: Add old-stats preinit() which opens mail stats io.
author | Sergey Kitov <sergey.kitov@open-xchange.com> |
---|---|
date | Fri, 09 Mar 2018 15:17:29 +0200 |
parents | ce305d3d9b52 |
children | 12c7ddbeae92 |
line wrap: on
line source
/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "time-util.h" #include "restrict-access.h" #include "stats-plugin.h" #include "mail-stats.h" #include <sys/resource.h> #define PROC_IO_PATH "/proc/self/io" static bool proc_io_disabled = FALSE; static int proc_io_fd = -1; static int process_io_buffer_parse(const char *buf, struct mail_stats *stats) { const char *const *tmp; tmp = t_strsplit(buf, "\n"); for (; *tmp != NULL; tmp++) { if (strncmp(*tmp, "rchar: ", 7) == 0) { if (str_to_uint64(*tmp + 7, &stats->read_bytes) < 0) return -1; } else if (strncmp(*tmp, "wchar: ", 7) == 0) { if (str_to_uint64(*tmp + 7, &stats->write_bytes) < 0) return -1; } else if (strncmp(*tmp, "syscr: ", 7) == 0) { if (str_to_uint32(*tmp + 7, &stats->read_count) < 0) return -1; } else if (strncmp(*tmp, "syscw: ", 7) == 0) { if (str_to_uint32(*tmp + 7, &stats->write_count) < 0) return -1; } } return 0; } static int process_io_open(void) { uid_t uid; if (proc_io_fd != -1) return proc_io_fd; if (proc_io_disabled) return -1; bool dumpable = restrict_access_get_dumpable(); if (!dumpable) restrict_access_set_dumpable(TRUE); proc_io_fd = open(PROC_IO_PATH, O_RDONLY); if (proc_io_fd == -1 && errno == EACCES) { /* kludge: if we're running with permissions temporarily dropped, get them temporarily back so we can open /proc/self/io. */ uid = geteuid(); if (seteuid(0) == 0) { proc_io_fd = open(PROC_IO_PATH, O_RDONLY); if (seteuid(uid) < 0) { /* oops, this is bad */ i_fatal("stats: seteuid(%s) failed", dec2str(uid)); } } errno = EACCES; } if (!dumpable) restrict_access_set_dumpable(FALSE); if (proc_io_fd == -1) { if (errno != ENOENT) i_error("open(%s) failed: %m", PROC_IO_PATH); proc_io_disabled = TRUE; return -1; } return proc_io_fd; } static void process_read_io_stats(struct mail_stats *stats) { char buf[1024]; int fd, ret; if ((fd = process_io_open()) == -1) return; ret = pread(fd, buf, sizeof(buf), 0); if (ret <= 0) { if (ret == -1) i_error("read(%s) failed: %m", PROC_IO_PATH); else i_error("read(%s) returned EOF", PROC_IO_PATH); } else if (ret == sizeof(buf)) { /* just shouldn't happen.. */ i_error("%s is larger than expected", PROC_IO_PATH); proc_io_disabled = TRUE; } else { buf[ret] = '\0'; T_BEGIN { if (process_io_buffer_parse(buf, stats) < 0) { i_error("Invalid input in file %s", PROC_IO_PATH); proc_io_disabled = TRUE; } } T_END; } } static void user_trans_stats_get(struct stats_user *suser, struct mail_stats *dest_r) { struct stats_transaction_context *strans; mail_stats_add_transaction(dest_r, &suser->finished_transaction_stats); for (strans = suser->transactions; strans != NULL; strans = strans->next) mail_stats_add_transaction(dest_r, &strans->trans->stats); } void mail_stats_fill(struct stats_user *suser, struct mail_stats *stats_r) { static bool getrusage_broken = FALSE; static struct rusage prev_usage; struct rusage usage; i_zero(stats_r); /* cputime */ if (getrusage(RUSAGE_SELF, &usage) < 0) { if (!getrusage_broken) { i_error("getrusage() failed: %m"); getrusage_broken = TRUE; } usage = prev_usage; } else if (timeval_diff_usecs(&usage.ru_stime, &prev_usage.ru_stime) < 0) { /* This seems to be a Linux bug. */ usage.ru_stime = prev_usage.ru_stime; } prev_usage = usage; stats_r->user_cpu = usage.ru_utime; stats_r->sys_cpu = usage.ru_stime; stats_r->min_faults = usage.ru_minflt; stats_r->maj_faults = usage.ru_majflt; stats_r->vol_cs = usage.ru_nvcsw; stats_r->invol_cs = usage.ru_nivcsw; stats_r->disk_input = (unsigned long long)usage.ru_inblock * 512ULL; stats_r->disk_output = (unsigned long long)usage.ru_oublock * 512ULL; (void)gettimeofday(&stats_r->clock_time, NULL); process_read_io_stats(stats_r); user_trans_stats_get(suser, stats_r); } void mail_stats_global_preinit(void) { (void)process_io_open(); } void mail_stats_fill_global_deinit(void) { if (proc_io_fd != -1) i_close_fd(&proc_io_fd); }