/* Copyright 2010 Myhailo Danylenko
*
* This file is part of mcabber-uptime
*
* mcabber-uptime is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <glib.h>
#include <gmodule.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <mcabber/modules.h>
#include <mcabber/logprint.h>
#include <mcabber/commands.h>
#include <mcabber/settings.h>
#include "config.h"
#define DESCRIPTION ( "Shows mcabber uptime\nRecognizes option uptime_hz (at load time)." )
module_info_t info_uptime_experimental = {
.branch = "experimental",
.api = 15,
.version = PROJECT_VERSION,
.description = DESCRIPTION,
.requires = NULL,
.init = NULL,
.uninit = NULL,
.next = NULL,
};
module_info_t info_uptime = {
.branch = "dev",
.api = 13,
.version = PROJECT_VERSION,
.description = DESCRIPTION,
.requires = NULL,
.init = NULL,
.uninit = NULL,
.next = &info_uptime_experimental,
};
time_t starttime = 0;
void do_uptime (char *arg)
{
GString *line = g_string_new (NULL);
guint seconds = time (NULL) - starttime;
guint minutes = seconds / 60;
guint hours = minutes / 60;
guint days = hours / 24;
seconds %= 60;
minutes %= 60;
hours %= 24;
if (days)
g_string_append_printf (line, " %u days", days);
if (hours)
g_string_append_printf (line, " %u hours", hours);
if (minutes)
g_string_append_printf (line, " %u minutes", minutes);
if (seconds)
g_string_append_printf (line, " %u seconds", seconds);
scr_log_print (LPRINT_NORMAL, "Uptime: %s.", line -> len ? line -> str : " 0 seconds");
g_string_free (line, TRUE);
}
gchar *g_module_check_init (GModule *module)
{
if (settings_opt_get_int ("uptime_use_proc")) {
long long unsigned int mstime = 0;
long long unsigned int kbtime = 0;
GError *error = NULL;
GString *line;
GIOChannel *channel = g_io_channel_new_file ("/proc/self/stat", "r", &error);
if (!channel)
return "Cannot open own stats for reading";
g_io_channel_set_close_on_unref (channel, TRUE);
line = g_string_new (NULL);
if (g_io_channel_read_line_string (channel, line, NULL, &error) != G_IO_STATUS_NORMAL) {
if (error) {
scr_log_print (LPRINT_DEBUG, "uptime: Own stats reading error: %s.", error -> message);
g_error_free (error);
}
g_io_channel_unref (channel);
g_string_free (line, TRUE);
return "Error reading own stats";
}
g_io_channel_unref (channel);
gchar *p = strrchr (line -> str, ')'); // end of command
if (!p) {
g_string_free (line, TRUE);
return "Missing ) in own stats";
}
while (*p && isspace (*p)) p++;
while (*p && isalpha (*p)) p++; // state (%c)
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // ppid (this and next are %d)
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // pgrp
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // session
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // tty_nr
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // tpgid
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // flags (this and all next - %u)
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // minflt
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // cminflt
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // majflt
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // cmajflt
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // utime
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // stime
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // cutime (this and next next are %d)
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // cstime
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // priority
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // nice
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // num_threads
while (*p && isspace (*p)) p++;
while (*p && isdigit (*p)) p++; // itrealvalue
while (*p && isspace (*p)) p++;
char *u = p;
while (*u && isdigit (*u)) u++;
*u = '\0';
if (!sscanf (p, "%llu", &mstime)) {
scr_log_print (LPRINT_LOGNORM, "uptime: now at %u/%u, remaining string: %s.", p - line -> str, line -> len, p);
g_string_free (line, TRUE);
return "Malformed own start time.";
}
channel = g_io_channel_new_file ("/proc/stat", "r", &error);
if (!channel) {
g_string_free (line, TRUE);
return "Cannot open system stats for reading";
}
g_io_channel_set_close_on_unref (channel, TRUE);
while (TRUE) {
GIOStatus ret = g_io_channel_read_line_string (channel, line, NULL, &error);
if (ret != G_IO_STATUS_NORMAL) {
if (error) {
scr_log_print (LPRINT_DEBUG, "uptime: System stats reading error: %s.", error -> message);
g_error_free (error);
}
g_io_channel_unref (channel);
g_string_free (line, TRUE);
return "Error reading system stats.";
}
if (sscanf (line -> str, "btime %llu", &kbtime))
break;
}
g_io_channel_unref (channel);
g_string_free (line, TRUE);
guint hz = settings_opt_get_int ("uptime_hz");
if (!hz)
hz = 100;
starttime = kbtime + (mstime / hz);
} else
starttime = time (NULL);
cmd_add ("uptime", "", 0, 0, do_uptime, NULL);
return NULL;
}
void g_module_unload (GModule *module)
{
cmd_del ("uptime");
}
/* The End */