uptime.c
changeset 0 3f69962cbbf4
child 1 2b0115cae8b2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uptime.c	Sun Apr 04 15:45:42 2010 +0300
@@ -0,0 +1,201 @@
+
+/* 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 <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         = 12,
+	.version     = PROJECT_VERSION,
+	.description = DESCRIPTION,
+	.requires    = NULL,
+	.init        = NULL,
+	.uninit      = NULL,
+	.next        = NULL,
+};
+
+module_info_t info_uptime = {
+	.branch      = "dev",
+	.api         = 11,
+	.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;
+
+	g_string_truncate (line, 0);
+	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 = 250;
+		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 */