gkrellm-2.3.10/0000755000175000000330000000000013003152151011670 5ustar billsudogkrellm-2.3.10/server/0000755000175000000330000000000012726032565013217 5ustar billsudogkrellm-2.3.10/server/Makefile0000644000175000000330000001324212654236716014665 0ustar billsudoinclude ../common.mk PACKAGE_D ?= gkrellmd SINSTALLDIR ?= $(INSTALLROOT)/bin CFGDIR ?= $(INSTALLROOT)/etc CFGDIRMODE ?= 755 CFGMODE ?= 644 SMANDIR ?= $(INSTALLROOT)/share/man/man1 EXTRAOBJS = ifeq ($(without-libsensors),yes) CONFIGURE_ARGS += --without-libsensors endif ifeq ($(without-libsensors),1) CONFIGURE_ARGS += --without-libsensors endif DUMMY_VAR := $(shell ./configure $(CONFIGURE_ARGS)) HAVE_LIBSENSORS = $(shell grep -c HAVE_LIBSENSORS configure.h) ifeq ($(HAVE_LIBSENSORS),1) SENSORS_LIBS ?= -lsensors endif GKRELLMD_INCLUDES = gkrellmd.h $(SHARED_PATH)/log.h PKG_INCLUDE := $(shell $(PKG_CONFIG) --cflags glib-2.0 gmodule-2.0 gthread-2.0) PKG_LIB := $(shell $(PKG_CONFIG) --libs glib-2.0 gmodule-2.0 gthread-2.0) FLAGS = -O2 $(PKG_INCLUDE) FLAGS += $(GTOP_INCLUDE) $(PTHREAD_INC) -I.. -I$(SHARED_PATH) -DGKRELLM_SERVER LIBS = $(PKG_LIB) LIBS += $(GTOP_LIBS_D) $(SYS_LIBS) $(SENSORS_LIBS) ifeq ($(debug),1) FLAGS += -g endif ifeq ($(debug),yes) FLAGS += -g endif ifeq ($(profile),1) FLAGS += -g -pg endif ifeq ($(profile),yes) FLAGS += -g -pg endif ifeq ($(enable_nls),1) FLAGS += -DENABLE_NLS -DLOCALEDIR=\"$(LOCALEDIR)\" endif ifeq ($(enable_nls),yes) FLAGS += -DENABLE_NLS -DLOCALEDIR=\"$(LOCALEDIR)\" endif ifneq ($(PACKAGE_D),gkrellmd) FLAGS += -DPACKAGE_D=\"$(PACKAGE_D)\" endif ifeq ($(HAVE_GETADDRINFO),1) FLAGS += -DHAVE_GETADDRINFO endif OS_RELEASE=$(shell uname -r) OBJS = main.o monitor.o mail.o plugins.o utils.o sysdeps-unix.o log.o all: gkrellmd$(BINEXT) gkrellmd$(BINEXT): check_env $(OBJS) $(EXTRAOBJS) $(CC) $(OBJS) $(EXTRAOBJS) -o $@ \ $(LDFLAGS) $(LIBS) $(LINK_FLAGS) static: check_env $(OBJS) $(EXTRAOBJS) $(CC) $(OBJS) $(EXTRAOBJS) -o gkrellmd.static -static \ $(LDFLAGS) $(LIBS) $(LINK_FLAGS) freebsd2: $(MAKE) EXTRAOBJS= SYS_LIBS="-lkvm -lmd" gkrellmd freebsd3 freebsd: $(MAKE) EXTRAOBJS= SYS_LIBS="-lkvm -ldevstat -lmd" gkrellmd # Darwin target for systems that still have libkvm darwin: $(MAKE) STRIP= HAVE_GETADDRINFO=1 \ EXTRAOBJS= \ SYS_LIBS="-framework CoreFoundation -framework IOKit -lkvm" \ LINK_FLAGS="-Wl,-bind_at_load" \ gkrellmd # Darwin 9.x and newer (OS X > 10.4) do not have libkvm, build without it darwin9: $(MAKE) STRIP= HAVE_GETADDRINFO=1 \ EXTRAOBJS= \ SYS_LIBS="-framework CoreFoundation -framework IOKit" \ LINK_FLAGS="-Wl,-bind_at_load" \ gkrellmd # Same as darwin9 macosx: darwin9 netbsd1: $(MAKE) EXTRAOBJS= SYS_LIBS="-lkvm" gkrellmd netbsd2: $(MAKE) EXTRAOBJS= SYS_LIBS="-lkvm -pthread" gkrellmd openbsd: $(MAKE) SYS_LIBS="-lkvm -pthread" gkrellmd solaris: ifeq ($(OS_RELEASE),5.8) $(MAKE) CFLAGS="-Wno-implicit-int" \ SYS_LIBS="-lkstat -lkvm -ldevinfo -lsocket -lnsl -lintl" \ LINK_FLAGS="" gkrellmd else $(MAKE) CFLAGS="-Wno-implicit-int" \ SYS_LIBS="-lkstat -lkvm -ldevinfo -lsocket -lnsl" \ LINK_FLAGS="" gkrellmd endif windows: libgkrellmd.a $(MAKE) \ BINEXT=".exe" \ CFLAGS="${CFLAGS} -D_WIN32_WINNT=0x0501 -DWINVER=0x0501 -DWIN32_LEAN_AND_MEAN" \ LINK_FLAGS="-mconsole -Wl,--dynamicbase -Wl,--nxcompat" \ EXTRAOBJS="${EXTRAOBJS} win32-resource.o win32-plugin.o" \ SYS_LIBS="-lws2_32 -lwtsapi32 -lpdh -lnetapi32 -liphlpapi -lintl" \ all install: install_bin install_inc install_man install_bin: $(INSTALL) -d -m $(INSTALLDIRMODE) $(SINSTALLDIR) $(INSTALL) -c $(STRIP) -m $(BINMODE) $(PACKAGE_D)$(BINEXT) $(SINSTALLDIR)/$(PACKAGE_D)$(BINEXT) install_inc: $(INSTALL) -d -m $(INCLUDEDIRMODE) $(INCLUDEDIR)/gkrellm2 $(INSTALL) -c -m $(INCLUDEMODE) $(GKRELLMD_INCLUDES) $(INCLUDEDIR)/gkrellm2 install_man: $(INSTALL) -d -m $(MANDIRMODE) $(SMANDIR) $(INSTALL) -c -m $(MANMODE) ../gkrellmd.1 $(SMANDIR)/$(PACKAGE_D).1 install_cfg: $(INSTALL) -d -m $(CFGDIRMODE) $(CFGDIR) $(INSTALL) -c -m $(CFGMODE) gkrellmd.conf $(CFGDIR)/gkrellmd.conf uninstall: rm -f $(SINSTALLDIR)/$(PACKAGE_D) rm -f $(SMANDIR)/$(PACKAGE_D).1 install_darwin install_darwin9 install_macosx: $(MAKE) install STRIP= install_freebsd: $(MAKE) install chgrp kmem $(SINSTALLDIR)/$(PACKAGE_D) chmod g+s $(SINSTALLDIR)/$(PACKAGE_D) install_netbsd: $(MAKE) SMANDIR="$(INSTALLROOT)/man/man1" install install_openbsd: $(MAKE) install chgrp kmem $(SINSTALLDIR)/$(PACKAGE_D) chmod g+sx $(SINSTALLDIR)/$(PACKAGE_D) install_solaris: $(MAKE) install INSTALL=/usr/ucb/install chgrp sys $(SINSTALLDIR)/$(PACKAGE_D) chmod g+s $(SINSTALLDIR)/$(PACKAGE_D) install_windows: install_inc install_cfg $(MAKE) BINEXT=".exe" install_bin $(INSTALL) -d -m $(LIBDIRMODE) $(LIBDIR) $(INSTALL) -c -m $(BINMODE) libgkrellmd.a $(LIBDIR) clean: $(RM) *.o *~ *.bak configure.h configure.log gkrellmd gkrellmd.exe \ libgkrellmd.a core SYSDEPS = ../src/sysdeps/bsd-common.c ../src/sysdeps/bsd-net-open.c \ ../src/sysdeps/darwin.c \ ../src/sysdeps/freebsd.c ../src/sysdeps/gtop.c \ ../src/sysdeps/linux.c ../src/sysdeps/netbsd.c ../src/sysdeps/dragonfly.c \ ../src/sysdeps/openbsd.c ../src/sysdeps/sensors-common.c \ ../src/sysdeps/solaris.c ../src/sysdeps/win32.c GKRELLMD_H = gkrellmd.h gkrellmd-private.h main.o: main.c $(GKRELLMD_H) monitor.o: monitor.c $(GKRELLMD_H) mail.o: mail.c $(GKRELLMD_H) plugins.o: plugins.c $(GKRELLMD_H) utils.o: utils.c $(GKRELLMD_H) sysdeps-unix.o: sysdeps-unix.c ../src/gkrellm-sysdeps.h $(SYSDEPS) $(GKRELLMD_H) log.o: $(SHARED_PATH)/log.c $(SHARED_PATH)/log.h $(GKRELLMD_H) win32-gui.o: win32-gui.c win32-plugin.o: win32-plugin.c win32-plugin.h $(GKRELLMD_H) win32-resource.o: win32-resource.rc win32-resource.h $(WINDRES) $< -o $@ win32-libgkrellmd.o: win32-libgkrellmd.c win32-plugin.h $(GKRELLMD_H) libgkrellmd.a: win32-libgkrellmd.o $(AR) -cr libgkrellmd.a win32-libgkrellmd.o # Checks if the build environment is ok check_env: $(PKG_CONFIG) --atleast-version=2.32 glib-2.0 gkrellm-2.3.10/server/configure0000755000175000000330000000230712416234015015116 0ustar billsudo#!/bin/sh # Configure some things for gkrellmd when make is run. # This configure is run automatically so no need to run it by hand. # # Copyright (C) 2006-2009 Bill Wilson for i do if [ "$i" = "--without-libsensors" ] then without_libsensors=yes fi done rm -f configure.h configure.log test test.o test.c touch configure.h exec 5>./configure.log CC=${CC-gcc} echo "CC : ${CC}" 1>& 5 echo "CFLAGS: ${CFLAGS}" 1>& 5 if [ "$without_libsensors" != "yes" ] then echo "Checking for libsensors... " 1>& 5 cat << EOF > test.c #include #include int main() { FILE *f; #if SENSORS_API_VERSION < 0x400 /* libsensors 3 code */ FILE *f; f = fopen("/etc/sensors.conf", "r"); if (!f) return 1; if (sensors_init(f) != 0) return 1; fclose(f); return 0; #else /* libsensors 4 code */ if (sensors_init(NULL) != 0) return 1; return 0; #endif } EOF $CC ${CFLAGS} -c test.c -o test.o 2>& 5 $CC test.o -o test -lsensors 2>& 5 if [ -x ./test ] then echo 'Defining HAVE_LIBSENSORS' 1>& 5 echo '#define HAVE_LIBSENSORS 1' >> configure.h else echo "Not found, sensors will not have libsensors support..." 1>& 5 fi fi # end of libsensors check rm -f test test.o test.c exit 0 gkrellm-2.3.10/server/win32-plugin.c0000644000175000000330000000576212417342730015626 0ustar billsudo /* GKrellM Windows Portion | Copyright (C) 2006-2014 Stefan Gehn | | Authors: Stefan Gehn stefan+gkrellm@srcbox.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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 "win32-plugin.h" win32_plugin_callbacks gkrellmd_callbacks; void win32_init_callbacks(void) { /* gkrellmd serve data functions used by builtins and plugins. */ gkrellmd_callbacks.gkrellmd_plugin_serve_setup = gkrellmd_plugin_serve_setup; gkrellmd_callbacks.gkrellmd_need_serve = gkrellmd_need_serve; gkrellmd_callbacks.gkrellmd_set_serve_name = gkrellmd_set_serve_name; gkrellmd_callbacks.gkrellmd_serve_data = gkrellmd_serve_data; gkrellmd_callbacks.gkrellmd_add_serveflag_done = gkrellmd_add_serveflag_done; gkrellmd_callbacks.gkrellmd_check_client_version = gkrellmd_check_client_version; gkrellmd_callbacks.gkrellmd_config_getline = gkrellmd_config_getline; gkrellmd_callbacks.gkrellmd_client_input_connect = gkrellmd_client_input_connect; /* Small set of useful functions duplicated from src/utils.c. | These really should just be in the gkrellm_ namespace for sysdep code | common to gkrellm and gkrellmd, but for convenience, offer them in | both gkrellm_ and gkrellmd_ namespaces. */ gkrellmd_callbacks.gkrellmd_free_glist_and_data = gkrellmd_free_glist_and_data; gkrellmd_callbacks.gkrellmd_getline_from_gstring = gkrellmd_getline_from_gstring; gkrellmd_callbacks.gkrellmd_dup_token = gkrellmd_dup_token; gkrellmd_callbacks.gkrellmd_dup_string = gkrellmd_dup_string; gkrellmd_callbacks.gkrellm_free_glist_and_data = gkrellm_free_glist_and_data; gkrellmd_callbacks.gkrellm_getline_from_gstring = gkrellm_getline_from_gstring; gkrellmd_callbacks.gkrellm_dup_token = gkrellm_dup_token; gkrellmd_callbacks.gkrellm_dup_string = gkrellm_dup_string; /* Plugins should use above data serve functions instead of this. */ gkrellmd_callbacks.gkrellmd_send_to_client = gkrellmd_send_to_client; /* Misc */ gkrellmd_callbacks.gkrellmd_add_mailbox = gkrellmd_add_mailbox; gkrellmd_callbacks.gkrellmd_ticks = gkrellmd_ticks; gkrellmd_callbacks.gkrellmd_get_timer_ticks = gkrellmd_get_timer_ticks; //--------------------------------------------------------------------------- // new since 2.3.2 gkrellmd_callbacks.gkrellm_debugv = gkrellm_debugv; } gkrellm-2.3.10/server/utils.c0000644000175000000330000000777312417341637014541 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #include "gkrellmd.h" #include "gkrellmd-private.h" gboolean gkrellmd_dup_string(gchar **dst, gchar *src) { if (!dst || (!*dst && !src)) return FALSE; if (*dst) { if (src && !strcmp(*dst, src)) return FALSE; g_free(*dst); } *dst = g_strdup(src); return TRUE; } gboolean gkrellm_dup_string(gchar **dst, gchar *src) { return gkrellmd_dup_string(dst, src); } static gboolean any(gchar c, gchar *s) { while (*s) if (c == *s++) return TRUE; return FALSE; } /* Return a duplicated token from a string. "*string" points to the source | string and is updated to point to the string remaining after the | found token. If there is no next token, return an empty dupped string | (not a NULL pointer) and leave *string unchanged. | Unlike strtok(): args are not modified, gkrellm_token() can be used on | constant strings, delimeter identity is not lost, and it's thread safe. | Only the caller's initial string pointer is modified. */ gchar * gkrellmd_dup_token(gchar **string, gchar *delimeters) { gchar *str, *s, *delims; gboolean quoted = FALSE; if (!string || !*string) return g_strdup(""); str = *string; delims = delimeters ? delimeters : " \t\n"; while (any(*str, delims)) ++str; if (*str == '"') { quoted = TRUE; ++str; for (s = str; *s && *s != '"'; ++s) ; } else for (s = str; *s && !any(*s, delims); ++s) ; *string = (quoted && *s) ? s + 1 : s; return g_strndup(str, s - str); } gchar * gkrellm_dup_token(gchar **string, gchar *delimeters) { return gkrellmd_dup_token(string, delimeters); } void gkrellmd_free_glist_and_data(GList **list_head) { GList *list; if (*list_head == NULL) return; /* could use g_list_foreach(*list_head, (G_FUNC)g_free, NULL); */ for (list = *list_head; list; list = list->next) if (list->data) g_free(list->data); g_list_free(*list_head); *list_head = NULL; } void gkrellm_free_glist_and_data(GList **list_head) { gkrellmd_free_glist_and_data(list_head); } /* If there is a line in the gstring ('\n' delimited) copy it to the | line buffer including the newline and erase it from the gstring. */ gboolean gkrellmd_getline_from_gstring(GString **gstring, gchar *line, gint size) { GString *gstr = *gstring; gchar *s; gint len, n; if (gstr && gstr->str && (s = strchr(gstr->str, '\n')) != NULL) { n = len = s - gstr->str + 1; if (n >= size) n = size - 1; /* Truncate the line to fit */ strncpy(line, gstr->str, n); line[n] = '\0'; *gstring = g_string_erase(gstr, 0, len); return TRUE; } return FALSE; } gboolean gkrellm_getline_from_gstring(GString **gstring, gchar *line, gint size) { return gkrellmd_getline_from_gstring(gstring, line, size); } gkrellm-2.3.10/server/sysdeps-unix.c0000644000175000000330000001263512417341637016045 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #include "gkrellmd.h" #include "gkrellmd-private.h" #include "../src/gkrellm-sysdeps.h" #if defined(__linux__) #include "../src/sysdeps/linux.c" #include "../src/sysdeps/sensors-common.c" #endif #if defined(__APPLE__) #include "../src/sysdeps/darwin.c" #include "../src/sysdeps/bsd-common.c" #endif #if defined(__FreeBSD__) #include "../src/sysdeps/freebsd.c" #include "../src/sysdeps/bsd-common.c" #include "../src/sysdeps/sensors-common.c" #endif #if defined(__DragonFly__) #include "../src/sysdeps/dragonfly.c" #include "../src/sysdeps/bsd-common.c" #include "../src/sysdeps/sensors-common.c" #endif #if defined(__NetBSD__) #include "../src/sysdeps/netbsd.c" #include "../src/sysdeps/bsd-net-open.c" #include "../src/sysdeps/bsd-common.c" #include "../src/sysdeps/sensors-common.c" #endif #if defined(__OpenBSD__) #include "../src/sysdeps/openbsd.c" #include "../src/sysdeps/bsd-net-open.c" #include "../src/sysdeps/bsd-common.c" #endif #if defined(__solaris__) #include "../src/sysdeps/solaris.c" #endif #if defined(USE_LIBGTOP) #include "../src/sysdeps/gtop.c" #endif #if defined(WIN32) #include "../src/sysdeps/win32.c" #endif #if !defined(WIN32) #include #endif gchar * gkrellm_sys_get_host_name(void) { static gboolean have_it; static gchar buf[128]; if (!have_it && gethostname(buf, sizeof(buf))) strcpy(buf, "unknown"); have_it = TRUE; return buf; } #if !defined(WIN32) gchar * gkrellm_sys_get_system_name(void) { static gchar *sname; struct utsname utsn; if (!sname && uname(&utsn) > -1) sname = g_strdup_printf("%s %s", utsn.sysname, utsn.release); if (!sname) sname = g_strdup("unknown name"); return sname; } #endif /* Remove embedded "-i2c-" or "-isa-" from lm_sensors chip names so | there can be a chance for config name sysfs compatibility. This function | here in sensors.c is a kludge. Give user configs a chance to get | converted and then move this function to sysdeps/linux.c where it | belongs. | Munge names like w83627hf-isa-0290 to w83627hf-0290 | or w83627hf-i2c-0-0290 to w83627hf-0-0290 */ void gkrellm_sensors_linux_name_fix(gchar *id_name) { #if defined(__linux__) gchar *s; gint len, bus = 0; guint addr = 0; len = strlen(id_name) + 1; if ((s = strstr(id_name, "-i2c-")) != NULL) { sscanf(s + 5, "%d-%x", &bus, &addr); snprintf(s, len - (s - id_name), "-%d-%04x", bus, addr); } else if ((s = strstr(id_name, "-isa-")) != NULL) { *(s + 1) = '0'; memmove(s + 2, s + 4, strlen(s + 4) + 1); } #endif } #ifdef SENSORS_COMMON gint gkrellm_connect_to(gchar *server, gint server_port) { gint fd = -1; #ifdef HAVE_GETADDRINFO gint rv = 0; struct addrinfo hints, *res, *res0; gchar portnumber[6]; #else struct hostent *addr; struct sockaddr_in s; #endif // HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO snprintf (portnumber, sizeof(portnumber), "%d", server_port); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((rv = getaddrinfo(server, portnumber, &hints, &res0)) != 0) return -1; for (res = res0; res; res = res->ai_next) { if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) continue; gkrellm_debug(DEBUG_SENSORS, "\t[gkrellm_connect_to: (%d,%d,%d) %s:%d]\n", res->ai_family, res->ai_socktype, res->ai_protocol, server, server_port); if (connect(fd, res->ai_addr, res->ai_addrlen) >= 0) break; #ifdef WIN32 closesocket(fd); #else close(fd); #endif // WIN32 fd = -1; } freeaddrinfo(res0); #else gkrellm_debug(DEBUG_SENSORS, "\t[gkrellm_connect_to: %s:%d]\n", server, server_port); addr = gethostbyname(server); if (addr) { fd = socket(AF_INET, SOCK_STREAM, 0); if (fd >= 0) { memset(&s, 0, sizeof(s)); memcpy(&s.sin_addr.s_addr, he->h_addr, he->h_length); s.sin_family = AF_INET; s.sin_port = htons(server_port); if (connect(fd, (struct sockaddr *)&s, sizeof (s)) < 0) { #ifdef WIN32 closesocket(fd); #else close(fd); #endif // WIN32 fd = -1; } } } #endif // HAVE_GETADDRINFO if (fd < 0) return -1; return fd; } #endif // SENSORS_COMMON gkrellm-2.3.10/server/gkrellmd.conf0000644000175000000330000001072711616372516015676 0ustar billsudo# Sample config file for the GKrellM server gkrellmd # The server update frequency is independent of and should be less than # the client update frequency. Values may be from 1 to 10 and should be # smaller values to reduce network traffic. # #update-hz 3 # Limit number of simultaneous clients allowed to connect. # #max-clients 2 # Specify a specific network interface to listen on for connections. # By default gkrellmd listens on all available network interfaces. # #address 127.0.0.1 # Specify the port to listen on for connections. # #port 19150 # List of hosts allowed to connect. If no hosts are specified in a # gkrellmd.conf file or on the command line, all hosts will be allowed. # #allow-host localhost #allow-host 127.0.0.1 #allow-host ::1 #allow-host 192.168.0.* # Drop privileges after startup (you must start gkrellmd as root to do it). # NOTE: Option ignored on Windows # #user nobody #group proc # Create a PID file for the running gkrellmd. Default is no PID file. # NOTE: Option ignored on Windows # #pidfile /var/run/gkrellmd.pid # Run in background and detach from the controlling terminal # NOTE: Option ignored on Windows # #detach # Enable writing logging message to the system syslog file # NOTE: On windows this enables logging to the windows event log # #syslog # Time interval between checks for various monitors. If nfs-interval # is <= 0 then gkrellmd will not read data for nfs file system types. # #fs-interval 2 #nfs-interval 16 # The Internet monitor defaults to reading tcp connections once per second. # However, for Linux SMP kernels where reading /proc/net/tcp causes high # cpu usage, the inet-interval may be set to 1-20 seconds to slow down # /proc/net/tcp reads. Or set it to 0 to totally disable the Inet monitor. # Requires at least gkrellmd version 2.1.8. # #inet-interval 1 # If the mbmon daemon is started before gkrellmd with this command: # mbmon -r -P port-number # (the "-r" mbmon tag mode is required) then gkrellmd will monitor mbmon # reported sensors if this is uncommented and the port-numbers match. # #mbmon-port port-number # Configure gkrellm clients to disconnect from a gkrellmd server if # there is an io-timeout seconds interval where the client receives no input # from the server. Use this for conditions where gkrellmd may be # ungracefully terminated such that socket connections are not closed. # Minimum is 2 (less than 2 for no I/O disconnecting and is the default). # Requires at least 2.1.8 versions of both gkrellmd and gkrellm. # #io-timeout 5 # Configure gkrellm clients to attempt automatic reconnects to a # gkrellmd server every reconnect-timeout seconds after a disconnected # state is detected. Disconnected states are created by normal gkrellmd # shutdowns or by an expiring io-timeout. # Minimum is 2 (less than 2 for no automatic reconnecting and is the default). # Requires at least 2.1.8 versions of both gkrellmd and gkrellm. # #reconnect-timeout 5 # Server side local mailbox counts can be sent to gkrellm clients. List here # paths to mbox, MH mail, or Maildir style mailboxes. # Requires at least 2.1.11 versions of both gkrellmd and gkrellm. # NOTE: Option ignored on Windows # #mailbox /var/mail/bill #mailbox ~/Mail/inbox # List of plugins to enable. Use "gkrellmd -plist" to view a list of all # available plugins. Use "gkrellmd -plog" to output a log of the plugin # install process (note: the detach option is ignored when using -plog). # #plugin-enable gkrelltopd #plugin-enable gkrellmwho2d # Configure gkrellmd to send the connect time for a network interface # to all clients to be displayed in the client gkrellm timer button # monitor display. If this is done, the client gkrellm timer button can # still execute commands on the client, but the button will not affect the # timer display. If you want the client timer button to execute commands # on the server, your timer button commands can use ssh. # So set this if your server box has a ppp or ippp connection and you # want to monitor its connect time. #net-timer ppp0 # For debugging purposes, gkrellmd can print out messages on console. # There are several debug areas which can be enabled independently by # summing up the following values: # # system 0x1 # mail 0x10 # net 0x20 # timer 0x40 # sensors 0x80 # sensors 0x100 # (w/o libsensors) # inet 0x800 # battery 0x8000 # # i.e. debug-level 0x51 enables messages for timer, mail and system # #debug level 0x1 gkrellm-2.3.10/server/win32-plugin.h0000644000175000000330000000650212417342750015626 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | 2007-2014 Stefan Gehn | | Author: Stefan Gehn stefan+gkrellm@srcbox.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ */ #ifndef WIN32_PLUGIN_H #define WIN32_PLUGIN_H #include "gkrellmd.h" typedef struct { /* gkrellmd serve data functions used by builtins and plugins. */ void (*gkrellmd_plugin_serve_setup)(GkrellmdMonitor *mon, gchar *name, gchar *line); void (*gkrellmd_need_serve)(GkrellmdMonitor *mon); void (*gkrellmd_set_serve_name)(GkrellmdMonitor *mon, const gchar *name); void (*gkrellmd_serve_data)(GkrellmdMonitor *mon, gchar *line); void (*gkrellmd_add_serveflag_done)(gboolean *); gboolean (*gkrellmd_check_client_version)(GkrellmdMonitor *mon, gint major, gint minor, gint rev); const gchar *(*gkrellmd_config_getline)(GkrellmdMonitor *mon); void (*gkrellmd_client_input_connect)(GkrellmdMonitor *mon, void (*func)(GkrellmdClient *, gchar *)); /* Small set of useful functions duplicated from src/utils.c. | These really should just be in the gkrellm_ namespace for sysdep code | common to gkrellm and gkrellmd, but for convenience, offer them in | both gkrellm_ and gkrellmd_ namespaces. */ void (*gkrellmd_free_glist_and_data)(GList **list_head); gboolean (*gkrellmd_getline_from_gstring)(GString **, gchar *, gint); gchar * (*gkrellmd_dup_token)(gchar **string, gchar *delimeters); gboolean (*gkrellmd_dup_string)(gchar **dst, gchar *src); void (*gkrellm_free_glist_and_data)(GList **list_head); gboolean (*gkrellm_getline_from_gstring)(GString **, gchar *, gint); gchar* (*gkrellm_dup_token)(gchar **string, gchar *delimeters); gboolean (*gkrellm_dup_string)(gchar **dst, gchar *src); /* Plugins should use above data serve functions instead of this. */ gint (*gkrellmd_send_to_client)(GkrellmdClient *client, gchar *buf); /* Misc */ void (*gkrellmd_add_mailbox)(gchar *); GkrellmdTicks * (*gkrellmd_ticks)(void); gint (*gkrellmd_get_timer_ticks)(void); //--------------------------------------------------------------------------- // new since 2.3.2 // gkrellm_debug is not called from libgkrellm, only gkrellm_debugv void (*gkrellm_debugv)(guint debug_level, const gchar *format, va_list arg); } win32_plugin_callbacks; /// part of win32-plugin.c /// extern win32_plugin_callbacks gkrellmd_callbacks; /// \brief initializes \p gkrellmd_callbacks /// Has to be called at gkrellmd startup before loading plugins. /// \note only needed on win32 void win32_init_callbacks(void); #endif // WIN32_PLUGIN_H gkrellm-2.3.10/server/win32-resource.h0000644000175000000330000000006711616372516016162 0ustar billsudo#ifndef IDC_STATIC #define IDC_STATIC (-1) #endif gkrellm-2.3.10/server/plugins.c0000644000175000000330000001636312417341637015055 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #include "gkrellmd.h" #include "gkrellmd-private.h" #if defined(WIN32) #include "win32-plugin.h" #endif #include static GList *plugin_list; GList *gkrellmd_plugin_enable_list; gchar *plugin_install_log; /* ======================================================================= */ /* Plugin interface to gkrellmd. */ static void gkrellmd_plugin_log(gchar *string1, ...) { va_list args; gchar *s, *old_log; if (!string1) return; va_start(args, string1); s = string1; while (s) { old_log = plugin_install_log; if (plugin_install_log) plugin_install_log = g_strconcat(plugin_install_log, s, NULL); else plugin_install_log = g_strconcat(s, NULL); g_free(old_log); s = va_arg(args, gchar *); } va_end(args); } GkrellmdMonitor * gkrellmd_plugin_install(gchar *plugin_name) { GModule *module; GkrellmdMonitor *m; GkrellmdMonitor *(*init_plugin)(); gchar buf[256]; if (!g_module_supported()) return NULL; module = g_module_open(plugin_name, 0); gkrellmd_plugin_log(plugin_name, "\n", NULL); if (! module) { snprintf(buf, sizeof(buf), _("\tError: %s\n"), g_module_error()); gkrellmd_plugin_log(buf, NULL); return NULL; } if (!g_module_symbol(module, "gkrellmd_init_plugin", (gpointer) &init_plugin)) { snprintf(buf, sizeof(buf), _("\tError: %s\n"), g_module_error()); gkrellmd_plugin_log(buf, NULL); g_module_close(module); return NULL; } // mon_tmp.name = g_strdup(plugin_name); // gkrellm_record_state(INIT_MONITOR, &mon_tmp); #if defined(WIN32) { win32_plugin_callbacks ** plugin_cb = NULL; if (!g_module_symbol(module, "cb", (gpointer) &plugin_cb)) { snprintf(buf, sizeof(buf), _("\tError: %s\n"), g_module_error()); gkrellmd_plugin_log(buf, NULL); g_module_close(module); return NULL; } *plugin_cb = &gkrellmd_callbacks; } #endif m = (*init_plugin)(); // g_free(mon_tmp.name); // mon_tmp.name = NULL; // gkrellm_record_state(INTERNAL, NULL); if (m == NULL) { gkrellmd_plugin_log( _("\tOoops! plugin returned NULL, not installng\n"), NULL); g_module_close(module); return NULL; } gkrellmd_plugin_log(_("\tInstalled OK\n"), NULL); if (!m->privat) /* may get set in gkrellm_config_getline() */ { m->privat = g_new0(GkrellmdMonitorPrivate, 1); m->privat->config_list = gkrellmd_plugin_config_list; } m->privat->handle = module; m->privat->path = plugin_name; if (!m->name) m->name = g_path_get_basename(m->privat->path); return m; } static gchar * gkrellmd_string_suffix(gchar *string, gchar *suffix) { gchar *dot; if (string == NULL || suffix == NULL) return NULL; dot = strrchr(string, '.'); if (dot && !strcmp(dot + 1, suffix)) return dot + 1; return NULL; } static gboolean gkrellmd_plugin_enabled(gchar *name) { GList *list; gchar *check, *s; gint len; for (list = gkrellmd_plugin_enable_list; list; list = list->next) { check = (gchar *) list->data; s = strstr(name, check); len = strlen(check); if ( s && s == name && (*(name + len) == '\0' || !strcmp(name + len, ".so")) ) return TRUE; } return FALSE; } static void gkrellmd_plugin_scan(gchar *path) { GDir *dir; gchar *name, *filename; GList *list; GkrellmdMonitor *m = NULL; gchar *s; gboolean exists; /*if (path != NULL) g_print("Searching for plugins in '%s'\n", path);*/ if (!path || !*path || (dir = g_dir_open(path, 0, NULL)) == NULL) return; while ((name = (gchar *) g_dir_read_name(dir)) != NULL) { if (!gkrellmd_string_suffix(name, G_MODULE_SUFFIX)) continue; /* If there's a libtool .la archive, won't want to load this .so */ if ( !gkrellmd_string_suffix(name, "la") && (s = strrchr(name, '.')) != NULL ) { s = g_strndup(name, s - name); filename = g_strconcat(path, G_DIR_SEPARATOR_S, s, ".la", NULL); exists = g_file_test(filename, G_FILE_TEST_EXISTS); g_free(s); g_free(filename); if (exists) continue; } if (_GK.list_plugins) { // TODO: list plugins support on win32 g_message("%s (%s)\n", name, path); continue; } for (list = plugin_list; list; list = list->next) { m = (GkrellmdMonitor *) list->data; s = g_path_get_basename(m->privat->path); exists = !strcmp(s, name); g_free(s); if (exists) break; m = NULL; } s = g_strconcat(path, G_DIR_SEPARATOR_S, name, NULL); if (m) { gkrellmd_plugin_log(_("Ignoring duplicate plugin "), s, "\n", NULL); g_free(s); continue; } if (!gkrellmd_plugin_enabled(name)) { gkrellmd_plugin_log(s, "\n", "\tNot enabled in gkrellmd.conf - skipping\n", NULL); continue; } m = gkrellmd_plugin_install(s); if (m) /* s is saved for use */ plugin_list = g_list_append(plugin_list, m); else g_free(s); } g_dir_close(dir); } GList * gkrellmd_plugins_load(void) { GkrellmdMonitor *m; gchar *path; if (_GK.command_line_plugin) { if ( *_GK.command_line_plugin != '.' && !strchr(_GK.command_line_plugin, G_DIR_SEPARATOR) ) path = g_strconcat(".", G_DIR_SEPARATOR_S, _GK.command_line_plugin, NULL); else path = g_strdup(_GK.command_line_plugin); gkrellmd_plugin_log(_("*** Command line plugin:\n"), NULL); if ((m = gkrellmd_plugin_install(path)) == NULL) g_free(path); else plugin_list = g_list_append(plugin_list, m); gkrellmd_plugin_log("\n", NULL); } path = g_build_filename(_GK.homedir, GKRELLMD_PLUGINS_DIR, NULL); gkrellmd_plugin_scan(path); g_free(path); #if defined(WIN32) gchar *install_path; install_path = g_win32_get_package_installation_directory_of_module(NULL); if (install_path != NULL) { path = g_build_filename(install_path, "lib", "gkrellm2", "plugins-gkrellmd", NULL); gkrellmd_plugin_scan(path); g_free(path); g_free(install_path); } #endif #if defined(GKRELLMD_LOCAL_PLUGINS_DIR) gkrellmd_plugin_scan(GKRELLMD_LOCAL_PLUGINS_DIR); #endif #if defined(GKRELLMD_SYSTEM_PLUGINS_DIR) gkrellmd_plugin_scan(GKRELLMD_SYSTEM_PLUGINS_DIR); #endif return plugin_list; } gkrellm-2.3.10/server/win32-libgkrellmd.c0000644000175000000330000000765512417342674016632 0ustar billsudo /* GKrellM Windows Portion | Copyright (C) 2002 Bill Nalen | 2007-2014 Stefan Gehn | | Authors: Bill Nalen bill@nalens.com | Stefan Gehn stefan+gkrellm@srcbox.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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 "win32-plugin.h" __declspec(dllexport) win32_plugin_callbacks* cb = NULL; /* gkrellmd serve data functions used by builtins and plugins. */ void gkrellmd_plugin_serve_setup(GkrellmdMonitor *mon, gchar *name, gchar *line) {cb->gkrellmd_plugin_serve_setup(mon,name,line);} void gkrellmd_need_serve(GkrellmdMonitor *mon) {cb->gkrellmd_need_serve(mon);} void gkrellmd_set_serve_name(GkrellmdMonitor *mon, const gchar *name) {cb->gkrellmd_set_serve_name(mon,name);} void gkrellmd_serve_data(GkrellmdMonitor *mon, gchar *line) {cb->gkrellmd_serve_data(mon,line);} void gkrellmd_add_serveflag_done(gboolean *done) {cb->gkrellmd_add_serveflag_done(done);} gboolean gkrellmd_check_client_version(GkrellmdMonitor *mon, gint major, gint minor, gint rev) {return cb->gkrellmd_check_client_version(mon,major,minor,rev);} const gchar *gkrellmd_config_getline(GkrellmdMonitor *mon) {return gkrellmd_config_getline(mon);} void gkrellmd_client_input_connect(GkrellmdMonitor *mon, void (*func)(GkrellmdClient *, gchar *)) {cb->gkrellmd_client_input_connect(mon, func);} /* Small set of useful functions duplicated from src/utils.c. | These really should just be in the gkrellm_ namespace for sysdep code | common to gkrellm and gkrellmd, but for convenience, offer them in | both gkrellm_ and gkrellmd_ namespaces. */ void gkrellmd_free_glist_and_data(GList **list_head) {cb->gkrellmd_free_glist_and_data(list_head);} gboolean gkrellmd_getline_from_gstring(GString **str, gchar *ch, gint l) {return cb->gkrellmd_getline_from_gstring(str, ch, l);} gchar *gkrellmd_dup_token(gchar **str, gchar *delim) {return cb->gkrellmd_dup_token(str, delim);} gboolean gkrellmd_dup_string(gchar **dst, gchar *src) {return cb->gkrellmd_dup_string(dst, src);} void gkrellm_free_glist_and_data(GList **list_head) {cb->gkrellm_free_glist_and_data(list_head);} gboolean gkrellm_getline_from_gstring(GString **str, gchar *ch, gint l) {return cb->gkrellm_getline_from_gstring(str, ch, l);} gchar *gkrellm_dup_token(gchar **str, gchar *delim) {return cb->gkrellm_dup_token(str, delim);} gboolean gkrellm_dup_string(gchar **dst, gchar *src) {return cb->gkrellm_dup_string(dst, src);} /* Plugins should use above data serve functions instead of this. */ gint gkrellmd_send_to_client(GkrellmdClient *client, gchar *buf) {return cb->gkrellmd_send_to_client(client, buf);} /* Misc */ void gkrellmd_add_mailbox(gchar *g) {cb->gkrellmd_add_mailbox(g);} GkrellmdTicks * gkrellmd_ticks(void) {return cb->gkrellmd_ticks();} gint gkrellmd_get_timer_ticks(void) {return cb->gkrellmd_get_timer_ticks();} //--------------------------------------------------------------------------- // new since 2.3.2 void gkrellm_debug(guint debug_level, const gchar *format, ...) { va_list arg; va_start(arg, format); cb->gkrellm_debugv(debug_level, format, arg); va_end(arg); } void gkrellm_debugv(guint debug_level, const gchar *format, va_list arg) { cb->gkrellm_debugv(debug_level, format, arg); } gkrellm-2.3.10/server/main.c0000644000175000000330000012424012724321624014305 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #include "gkrellmd.h" #include "gkrellmd-private.h" #include "log-private.h" #if !defined(WIN32) #include #endif // !WIN32 // win32 defines addrinfo but only supports getaddrinfo call on winxp or newer #if !defined(HAVE_GETADDRINFO) && !defined(WIN32) struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif // !HAVE_GETADDRINFO #if !defined(IPV6_V6ONLY) && defined(IPV6_BINDV6ONLY) #define IPV6_V6ONLY IPV6_BINDV6ONLY #endif struct GkrellmdConfig _GK; GkrellmdTicks GK; GList *gkrellmd_client_list, *gkrellmd_plugin_config_list; static GList *allow_host_list; #if !defined(WIN32) static gboolean detach_flag; struct { uid_t uid; uid_t gid; } drop_privs = { 0, 0 }; #endif /* !defined(WIN32) */ #if defined(WIN32) /* Flag that determines if gkrellmd was started as a console app (FALSE) or as a service (TRUE) */ static gboolean service_is_one = FALSE; // Flag that is TRUE while gkrellmd should stay in its main loop static gboolean service_running = FALSE; // Unique name for the installed windows service (do not translate!) static wchar_t* service_name = L"gkrellmd"; // User visible name for the installed windows service static wchar_t* service_display_name = L"GKrellM Daemon"; /* Current service status if running as a service, may be stopped or running (pausing is not supported) */ static SERVICE_STATUS service_status; /* Handle that allows changing the service status. Main use is to stop the running service. */ static SERVICE_STATUS_HANDLE service_status_handle = 0; /* Handle to our event log source. The Windows Event Log is used as a replacement for syslog-logging. */ static HANDLE h_event_log = NULL; #endif /* defined(WIN32) */ static gboolean gkrellmd_syslog_init() { #if defined(WIN32) h_event_log = RegisterEventSourceW(NULL, service_name); if (h_event_log == NULL) { g_warning("Cannot register event source for logging into Windows Event Log.\n"); return FALSE; } #else // Unix needs no logging initialization #endif return TRUE; } static gboolean gkrellmd_syslog_cleanup() { #if defined(WIN32) if (h_event_log) DeregisterEventSource(h_event_log); h_event_log = NULL; #else // Unix needs no further logging cleanup #endif return TRUE; } static void gkrellmd_syslog_log(GLogLevelFlags log_level, const gchar *message) { #if defined(WIN32) WORD event_type; const char *p_buf[1]; // Abort if event source is missing if (h_event_log == NULL) return; event_type = EVENTLOG_INFORMATION_TYPE; if (log_level & G_LOG_LEVEL_WARNING) event_type = EVENTLOG_WARNING_TYPE; if (log_level & G_LOG_LEVEL_CRITICAL || log_level & G_LOG_LEVEL_ERROR) event_type = EVENTLOG_ERROR_TYPE; p_buf[0] = message; ReportEventA( h_event_log, // Event source handle (HANDLE) event_type, // Event type (WORD) 0, // Event category (WORD) 0, // Event identifier (DWORD) NULL, // user security identifier (PSID) 1, // Number of substitution strings (WORD) 0, // Data Size (DWORD) p_buf, // Pointer to strings NULL // Pointer to Data ); #else int facility_priority; // default to info and override with other states if they are more important facility_priority = LOG_MAKEPRI(LOG_DAEMON, LOG_INFO); if (log_level & G_LOG_LEVEL_DEBUG) facility_priority = LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG); if (log_level & G_LOG_LEVEL_WARNING) facility_priority = LOG_MAKEPRI(LOG_DAEMON, LOG_WARNING); if (log_level & G_LOG_LEVEL_ERROR) facility_priority = LOG_MAKEPRI(LOG_DAEMON, LOG_ERR); if (log_level & G_LOG_LEVEL_CRITICAL) facility_priority = LOG_MAKEPRI(LOG_DAEMON, LOG_CRIT); syslog(facility_priority, "%s", message); #endif // defined(WIN32) } // gkrellmd_syslog_log() static void make_pidfile(void) { #if !defined(WIN32) FILE *f; if (!_GK.pidfile) return; f = fopen(_GK.pidfile, "w"); if (f) { fprintf(f, "%d\n", getpid()); fclose(f); } else g_warning("Can't create pidfile %s\n", _GK.pidfile); #endif } static void remove_pidfile(void) { #if !defined(WIN32) if (_GK.pidfile) unlink(_GK.pidfile); #endif } static void gkrellmd_cleanup() { gkrellm_sys_main_cleanup(); gkrellm_log_cleanup(); remove_pidfile(); } static void cb_sigterm(gint sig) { g_message("GKrellM Daemon %d.%d.%d%s: Exiting normally\n", GKRELLMD_VERSION_MAJOR, GKRELLMD_VERSION_MINOR, GKRELLMD_VERSION_REV, GKRELLMD_EXTRAVERSION); gkrellmd_cleanup(); exit(0); } gint gkrellmd_send_to_client(GkrellmdClient *client, gchar *buf) { gint n; if (!client->alive) return 0; #if defined(MSG_NOSIGNAL) n = send(client->fd, buf, strlen(buf), MSG_NOSIGNAL); #else n = send(client->fd, buf, strlen(buf), 0); #endif if (n < 0 && errno == EPIPE) { if (_GK.verbose) g_print("Write on closed pipe to host %s\n", client->hostname); client->alive = FALSE; } return n; } #if 0 static gint getline(gint fd, gchar *buf, gint len) { fd_set read_fds; struct timeval tv; gchar *s; gint result, n; FD_ZERO(&read_fds); FD_SET(fd, &read_fds); tv.tv_usec = 0; tv.tv_sec = 15; s = buf; *s = '\0'; for (n = 0; n < len - 1; ++n) { result = select(fd + 1, &read_fds, NULL, NULL, &tv); if (result <= 0 || read(fd, s, 1) != 1) break; if (*s == '\n') { *s = '\0'; break; } *++s = '\0'; } return n; } #endif #ifdef HAVE_GETADDRINFO static gboolean is_valid_reverse(char *addr, char *host, sa_family_t family) { struct addrinfo hints, *res, *r; int error, good; char addrbuf[NI_MAXHOST]; /* Reject numeric addresses */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(host, NULL, &hints, &res) == 0) { freeaddrinfo(res); return 0; } /* Check for spoof */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if (getaddrinfo(host, NULL, &hints, &res) != 0) return 0; good = 0; for (r = res; good == 0 && r; r = r->ai_next) { error = getnameinfo(r->ai_addr, r->ai_addrlen, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); if (error == 0 && strcmp(addr, addrbuf) == 0) { good = 1; break; } } freeaddrinfo(res); return good; } #endif /* Check for CIDR match. */ static gboolean cidr_match(struct sockaddr *sa, socklen_t salen, char *allowed) { #ifdef HAVE_GETADDRINFO struct addrinfo hints, *res; union { struct sockaddr_storage ss; struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr sa; } ss; char *buf; char *p, *ep; guchar *addr, *pat; uint32_t mask; int plen; #if defined(INET6) int i; #endif gboolean result; buf = g_strdup(allowed); plen = -1; if ((p = strchr(buf, '/')) != NULL) { errno = 0; plen = strtoul(p + 1, &ep, 10); if (errno != 0 || ep == NULL || *ep != '\0' || plen < 0) { g_free(buf); return FALSE; } *p = '\0'; allowed = buf; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; result = getaddrinfo(allowed, NULL, &hints, &res); g_free(buf); if (result != 0) return FALSE; memcpy(&ss, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); if (sa->sa_family != ss.sa.sa_family) return FALSE; switch (sa->sa_family) { #if defined(INET6) case AF_INET6: if (plen < 0) plen = 128; if (plen > 128) return FALSE; if (ss.sin6.sin6_scope_id != 0 && ss.sin6.sin6_scope_id != ((struct sockaddr_in6 *)sa)->sin6_scope_id) return FALSE; addr = (guchar *)&((struct sockaddr_in6 *)sa)->sin6_addr; pat = (guchar *)&ss.sin6.sin6_addr; i = 0; while (plen > 0) { if (plen < 32) { mask = htonl(~(0xffffffff >> plen)); if ((*(uint32_t *)&addr[i] & mask) != (*(uint32_t *)&pat[i] & mask)) return FALSE; break; } if (*(uint32_t *)&addr[i] != *(uint32_t *)&pat[i]) return FALSE; i += 4; plen -= 32; } break; #endif case AF_INET: if (plen < 0) plen = 32; if (plen > 32) return FALSE; addr = (guchar *)&((struct sockaddr_in *)sa)->sin_addr; pat = (guchar *)&ss.sin.sin_addr; mask = htonl(~(0xffffffff >> plen)); if ((*(uint32_t *)addr & mask) != (*(uint32_t *)pat & mask)) return FALSE; break; default: return FALSE; } return TRUE; #else return FALSE; #endif } static gboolean allow_host(GkrellmdClient *client, struct sockaddr *sa, socklen_t salen) { GList *list; #ifdef HAVE_GETADDRINFO int error; char hostbuf[NI_MAXHOST], addrbuf[NI_MAXHOST]; #else struct hostent *hostent; #endif gchar buf[128]; gchar *hostname = NULL, *addr = NULL; gchar *s, *allowed; #ifdef HAVE_GETADDRINFO error = getnameinfo(sa, salen, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); if (error == 0) { addr = addrbuf; error = getnameinfo(sa, salen, hostbuf, sizeof(hostbuf), NULL, 0, NI_NAMEREQD); if (error == 0 && is_valid_reverse(addrbuf, hostbuf, sa->sa_family)) hostname = hostbuf; } #else hostent = gethostbyaddr((gchar *)&((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr), AF_INET); if (hostent) hostname = hostent->h_name; addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); #endif client->hostname = g_strdup(hostname ? hostname : addr); if (!allow_host_list) return TRUE; for (list = allow_host_list; list; list = list->next) { allowed = (gchar *) list->data; if ( (hostname && !strcmp(hostname, allowed)) || (addr && !strcmp(addr, allowed)) || !strcmp("ALL", allowed) ) return TRUE; if (addr && cidr_match(sa, salen, allowed)) return TRUE; /* Check for simple IPv4 subnet match. Worry later about ranges and | other hosts_access type patterns. */ if ( addr && (s = strrchr(allowed, (int) '.')) != NULL && *(s + 1) == '*' && *(s + 2) == '\0' && !strncmp(addr, allowed, (gint) (s - allowed + 1)) ) return TRUE; } snprintf(buf, sizeof(buf), _("Connection not allowed from %s\n"), hostname ? hostname : addr); g_warning("%s", buf); gkrellmd_send_to_client(client, "\n"); gkrellmd_send_to_client(client, buf); return FALSE; } /* client sends line: gkrellm x.y.z */ static GkrellmdClient * accept_client(gint fd, struct sockaddr *sa, socklen_t salen) { GkrellmdClient *client; gchar buf[64], name[32]; gboolean client_limit; gint err; client = g_new0(GkrellmdClient, 1); client->fd = fd; client->alive = TRUE; client_limit = (g_list_length(gkrellmd_client_list) >= _GK.max_clients); if (!allow_host(client, sa, salen) || client_limit) { if (client_limit) { g_message(_("Too many clients, rejecting %s\n"), client->hostname); gkrellmd_send_to_client(client, "\nClient limit exceeded.\n"); } g_free(client->hostname); g_free(client); return NULL; } err = recv(fd, buf, sizeof(buf), 0); if (err > 0) buf[err] = '\0'; else buf[0] = '\0'; //getline(fd, buf, sizeof(buf)); if (_GK.verbose) g_print(_("connect string from client: %s\n"), buf); if ( sscanf(buf, "%31s %d.%d.%d", name, &client->major_version, &client->minor_version, &client->rev_version) == 4 && !strcmp(name, "gkrellm") ) { gkrellmd_client_list = g_list_append(gkrellmd_client_list, client); return client; } g_warning(_("Bad connect line from %s: %s\n"), client->hostname, buf); gkrellmd_send_to_client(client, "\nBad connect string!"); g_free(client->hostname); g_free(client); return NULL; } static void remove_client(gint fd) { GList *list; GkrellmdClient *client; for (list = gkrellmd_client_list; list; list = list->next) { client = (GkrellmdClient *) list->data; if (client->fd == fd) { g_message(_("Removing client %s\n"), client->hostname); #if defined(WIN32) closesocket(fd); #else close(fd); #endif g_free(client->hostname); g_free(client); gkrellmd_client_list = g_list_remove(gkrellmd_client_list, client); break; } } } static gint parse_config(gchar *config, gchar *arg) { if (!strcmp(config, "clear-hosts") || !strcmp(config, "c")) { gkrellm_free_glist_and_data(&allow_host_list); return 0; } if (!strcmp(config, "syslog")) { gkrellm_log_register(gkrellmd_syslog_log, gkrellmd_syslog_init, gkrellmd_syslog_cleanup); return 0; } #if !defined(WIN32) if (!strcmp(config, "detach") || !strcmp(config, "d")) { detach_flag = TRUE; return 0; } #endif // All following options take one argument that should be passed in arg if (!arg || !*arg) return -1; if (!strcmp(config, "update-hz") || !strcmp(config, "u")) _GK.update_HZ = atoi(arg); else if (!strcmp(config, "port") || !strcmp(config, "P")) _GK.server_port = atoi(arg); else if (!strcmp(config, "address") || !strcmp(config, "A")) _GK.server_address = g_strdup(arg); else if (!strcmp(config, "max-clients") || !strcmp(config, "m")) _GK.max_clients = atoi(arg); else if (!strcmp(config, "allow-host") || !strcmp(config, "a")) allow_host_list = g_list_append(allow_host_list, g_strdup(arg)); else if (!strcmp(config, "plugin-enable") || !strcmp(config, "pe")) gkrellmd_plugin_enable_list = g_list_append(gkrellmd_plugin_enable_list, g_strdup(arg)); else if (!strcmp(config, "plugin") || !strcmp(config, "p")) _GK.command_line_plugin = g_strdup(arg); else if (!strcmp(config, "io-timeout")) _GK.io_timeout = atoi(arg); else if (!strcmp(config, "reconnect-timeout")) _GK.reconnect_timeout = atoi(arg); else if (!strcmp(config, "fs-interval")) _GK.fs_interval = atoi(arg); else if (!strcmp(config, "nfs-interval")) _GK.nfs_interval = atoi(arg); else if (!strcmp(config, "inet-interval")) _GK.inet_interval = atoi(arg); else if (!strcmp(config, "mbmon-port")) _GK.mbmon_port = atoi(arg); else if (!strcmp(config, "net-timer")) _GK.net_timer = g_strdup(arg); else if (!strcmp(config, "debug-level") || !strcmp(config, "debug")) { _GK.debug_level = (gint) strtoul(arg, NULL, 0); if (_GK.debug_level > 0) g_print("Set debug-level to 0x%x\n", _GK.debug_level); } else if (!strcmp(config, "logfile")) gkrellm_log_set_filename(arg); #if !defined(WIN32) else if (!strcmp(config, "pidfile")) _GK.pidfile = g_strdup(arg); else if (!strcmp(config, "mailbox")) gkrellmd_add_mailbox(arg); else if (!strcmp(config, "user") || !strcmp(config, "U")) { struct passwd *tmp; if ((tmp = getpwnam(arg)) != (struct passwd*) 0) drop_privs.uid = tmp->pw_uid; else return -1; } else if (!strcmp(config, "group") || !strcmp(config, "G")) { struct group *tmp; if ((tmp = getgrnam(arg)) != (struct group*) 0) drop_privs.gid = tmp->gr_gid; else return -1; } #endif else return -1; return 1; } static void load_config(gchar *path) { FILE *f; PluginConfigRec *cfg; gchar buf[128+32+2], config[32], arg[128]; gchar *s, *plugin_config_block = NULL; //g_print("Trying to load config from file '%s'\n", path); f = g_fopen(path, "r"); if (!f) return; while (fgets(buf, sizeof(buf), f)) { if (!buf[0] || buf[0] == '#') continue; if (buf[0] == '[' || buf[0] == '<') { if (buf[1] == '/') { g_free(plugin_config_block); plugin_config_block = NULL; } else { if ( (s = strchr(buf, ']')) != NULL || (s = strchr(buf, '>')) != NULL ) *s = '\0'; plugin_config_block = g_strdup(&buf[1]); } continue; } if (plugin_config_block) { cfg = g_new0(PluginConfigRec, 1); cfg->name = g_strdup(plugin_config_block); if ((s = strchr(buf, '\n')) != NULL) *s = '\0'; cfg->line = g_strdup(buf); gkrellmd_plugin_config_list = g_list_append(gkrellmd_plugin_config_list, cfg); } else /* main gkrellmd config line */ { arg[0] = '\0'; sscanf(buf, "%31s %127s", config, arg); parse_config(config, arg); } } fclose(f); } const gchar * gkrellmd_config_getline(GkrellmdMonitor *mon) { GList *list; PluginConfigRec *cfg; if (!mon->privat) { mon->privat = g_new0(GkrellmdMonitorPrivate, 1); mon->privat->config_list = gkrellmd_plugin_config_list; } for (list = mon->privat->config_list; list; list = list->next) { cfg = (PluginConfigRec *) list->data; if (!strcmp(cfg->name, mon->name)) { mon->privat->config_list = list->next; return cfg->line; } } return NULL; } static void read_config(void) { gchar *path; #if defined(WIN32) gchar *install_path; #endif _GK.update_HZ = 3; _GK.debug_level = 0; _GK.max_clients = 2; _GK.server_port = GKRELLMD_SERVER_PORT; _GK.fs_interval = 2; _GK.nfs_interval = 16; _GK.inet_interval = 1; #if defined(GKRELLMD_SYS_ETC) path = g_build_filename(GKRELLMD_SYS_ETC, GKRELLMD_CONFIG, NULL); load_config(path); g_free(path); #endif #if defined(GKRELLMD_LOCAL_ETC) path = g_build_filename(GKRELLMD_LOCAL_ETC, GKRELLMD_CONFIG, NULL); load_config(path); g_free(path); #endif // on windows also load config from INSTALLDIR/etc/gkrellmd.conf #if defined(WIN32) install_path = g_win32_get_package_installation_directory_of_module(NULL); if (install_path != NULL) { path = g_build_filename(install_path, "etc", GKRELLMD_CONFIG, NULL); load_config(path); g_free(path); g_free(install_path); } #endif _GK.homedir = (gchar *) g_get_home_dir(); if (_GK.homedir == NULL) _GK.homedir = "."; // FIXME: doesn't look right to me path = g_build_filename(_GK.homedir, GKRELLMD_USER_CONFIG, NULL); load_config(path); g_free(path); } static void usage(void) { #if defined(WIN32) g_print(_("usage: gkrellmd command [options]\n")); g_print(_("commands:\n")); g_print(_(" --console run gkrellmd on console (not as a service)\n")); g_print(_(" --install install gkrellmd service and exit\n")); g_print(_(" --uninstall uninstall gkrellmd service and exit\n")); g_print(_(" -h, --help display this help and exit\n")); g_print(_(" -v, --version output version information and exit\n")); g_print(_("options (only for command '--console'):\n")); g_print(_(" -u, --update-hz F Monitor update frequency\n")); g_print(_(" -m, --max-clients N Number of simultaneous clients\n")); g_print(_(" -A, --address A Address of network interface to listen on\n")); g_print(_(" -P, --port P Server port to listen on\n")); g_print(_(" -a, --allow-host host Allow connections from specified hosts\n")); g_print(_(" -c, --clear-hosts Clears the current list of allowed hosts\n")); g_print(_(" --io-timeout N Close connection after N seconds of no I/O\n")); g_print(_(" --reconnect-timeout N Try to connect every N seconds after\n" " a disconnect\n")); g_print(_(" -p, --plugin name Enable a command line plugin\n")); g_print(_(" -pe, --plugin-enable name Enable an installed plugin\n")); g_print(_(" --plist List plugins and exit\n")); g_print(_(" --plog Print plugin install log\n")); g_print( " --logfile path Enable logging to a file\n"); g_print( " --syslog Enable logging to syslog\n"); g_print(_(" -V, --verbose increases the verbosity of gkrellmd\n")); g_print(_(" -debug, --debug-level n Turn debugging on for selective code sections.\n")); #else g_print(_("usage: gkrellmd [options]\n")); g_print(_("options:\n")); g_print(_(" -u, --update-hz F Monitor update frequency\n")); g_print(_(" -m, --max-clients N Number of simultaneous clients\n")); g_print(_(" -A, --address A Address of network interface to listen on\n")); g_print(_(" -P, --port P Server port to listen on\n")); g_print(_(" -a, --allow-host host Allow connections from specified hosts\n")); g_print(_(" -c, --clear-hosts Clears the current list of allowed hosts\n")); g_print(_(" --io-timeout N Close connection after N seconds of no I/O\n")); g_print(_(" --reconnect-timeout N Try to connect every N seconds after\n" " a disconnect\n")); g_print(_(" --mailbox path Send local mailbox counts to gkrellm clients.\n")); g_print(_(" -d, --detach Run in background and detach from terminal\n")); g_print(_(" -U, --user username Change to this username after startup\n")); g_print(_(" -G, --group groupname Change to this group after startup\n")); g_print(_(" -p, --plugin name Enable a command line plugin\n")); g_print(_(" -pe, --plugin-enable name Enable an installed plugin\n")); g_print(_(" --plist List plugins and exit\n")); g_print(_(" --plog Print plugin install log\n")); g_print( " --logfile path Enable logging to a file\n"); g_print( " --syslog Enable logging to the system syslog file\n"); g_print(_(" --pidfile path Create a PID file\n")); g_print(_(" -V, --verbose increases the verbosity of gkrellmd\n")); g_print(_(" -h, --help display this help and exit\n")); g_print(_(" -v, --version output version information and exit\n")); g_print(_(" -debug, --debug-level n Turn debugging on for selective code sections.\n")); #endif } static void get_args(gint argc, gchar **argv) { gchar *s; gint i, r; for (i = 1; i < argc; ++i) { s = argv[i]; if (*s == '-') { ++s; if (*s == '-') ++s; } if (!strcmp(s, "verbose") || !strcmp(s, "V")) _GK.verbose += 1; else if (!strcmp(s, "plist")) _GK.list_plugins = TRUE; else if (!strcmp(s, "plog")) _GK.log_plugins = TRUE; #if !defined(WIN32) else if (!strcmp(s, "without-libsensors")) _GK.without_libsensors = TRUE; #endif /* !WIN32 */ else if ( i < argc && ((r = parse_config(s, (i < argc - 1) ? argv[i+1] : NULL)) >= 0) ) { i += r; } else { g_print(_("Bad arg: %s\n"), argv[i]); usage(); exit(0); } } // for() } static int * socksetup(int af) { struct addrinfo hints, *res, *r; gint maxs, *s, *socks; #ifndef HAVE_GETADDRINFO struct sockaddr_in sin; #else gchar portnumber[6]; gint error; #endif memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; #ifdef HAVE_GETADDRINFO hints.ai_flags = AI_PASSIVE; hints.ai_family = af; snprintf(portnumber, sizeof(portnumber), "%d", _GK.server_port); if (!_GK.server_address || strlen(_GK.server_address) == 0) { error = getaddrinfo(NULL, portnumber, &hints, &res); } else { error = getaddrinfo(_GK.server_address, portnumber, &hints, &res); } if (error) { g_warning("gkrellmd %s\n", gai_strerror(error)); return NULL; } #else /* Set up the address structure for the listen socket and bind the | listen address to the socket. */ hints.ai_family = PF_INET; hints.ai_addrlen = sizeof(struct sockaddr_in); hints.ai_next = NULL; hints.ai_addr = (struct sockaddr *) &sin; sin.sin_family = PF_INET; if (!_GK.server_address || strlen(_GK.server_address) == 0) { sin.sin_addr.s_addr = INADDR_ANY; } else { sin.sin_addr.s_addr = inet_addr(_GK.server_address); } sin.sin_port = htons(_GK.server_port); res = &hints; #endif /* count max number of sockets we may open */ for (maxs = 0, r = res; r; r = r->ai_next, maxs++) ; socks = malloc((maxs + 1) * sizeof(int)); if (!socks) { g_warning("Could not allocate memory for sockets\n"); return NULL; } *socks = 0; /* num of sockets counter at start of array */ s = socks + 1; for (r = res; r; r = r->ai_next) { *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); if (*s < 0) continue; /* SO_REUSEADDR flag allows the server to restart immediately */ if (1) { #if defined(WIN32) const char on = 1; #else const int on = 1; #endif if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { g_warning("gkrellmd: setsockopt (SO_REUSEADDR) failed\n"); #if defined(WIN32) closesocket(*s); #else close(*s); #endif continue; } #ifdef IP_FREEBIND if (setsockopt(*s, SOL_IP, IP_FREEBIND, &on, sizeof(on)) < 0) { g_warning("gkrellmd: setsockopt (IP_FREEBIND) failed\n"); } #endif } #ifdef IPV6_V6ONLY if (r->ai_family == AF_INET6) { const int on = 1; if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { g_warning("gkrellmd: setsockopt (IPV6_V6ONLY) failed\n"); #if defined(WIN32) closesocket(*s); #else close(*s); #endif continue; } } #endif if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { #if defined(WIN32) closesocket(*s); #else close(*s); #endif continue; } (*socks)++; s++; } #ifdef HAVE_GETADDRINFO if (res) freeaddrinfo(res); #endif if (*socks == 0) { g_warning("Could not bind to any socket\n"); free(socks); return NULL; } return socks; } #if !defined(WIN32) /* XXX: Recent glibc seems to have daemon(), too. */ #if defined(BSD4_4) #define HAVE_DAEMON #endif #if !defined(HAVE_DAEMON) && !defined(WIN32) && !defined(__solaris__) #include #endif #if !defined(_PATH_DEVNULL) #define _PATH_DEVNULL "/dev/null" #endif static gboolean detach_from_terminal(void) { #if !defined(HAVE_DAEMON) gint i, fd; #endif /* HAVE_DAEMON */ if (getppid() == 1) /* already a daemon */ return TRUE; #if defined(HAVE_DAEMON) if (daemon(0, 0)) { g_warning("Detach failed: %s\n", strerror(errno)); return FALSE; } #else i = fork(); if (i > 0) exit(0); if (i < 0 || setsid() == -1) /* new session process group */ { g_warning("Detach failed: %s\n", strerror(errno)); return FALSE; } if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) close(fd); } if (chdir("/") != 0) { g_warning("Detach failed in chdir(\"/\"): %s\n", strerror(errno)); return FALSE; } #endif /* HAVE_DAEMON */ // signal(SIGCHLD, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGHUP, SIG_IGN); #if !defined(MSG_NOSIGNAL) signal(SIGPIPE, SIG_IGN); #endif /* MSG_NOSIGNAL */ return TRUE; } #endif /* !defined(WIN32) */ static void drop_privileges(void) { #if !defined(WIN32) if (drop_privs.gid > (uid_t)0) { (void) setgroups((size_t)0, (gid_t*)0); (void) setgid(drop_privs.gid); } if (drop_privs.uid > (uid_t)0) (void) setuid(drop_privs.uid); #endif } static gint gkrellmd_run(gint argc, gchar **argv) { union { #ifdef HAVE_GETADDRINFO struct sockaddr_storage ss; #else struct sockaddr_in ss; #endif struct sockaddr_in sin; struct sockaddr sa; } client_addr; fd_set read_fds, test_fds; struct timeval tv; GkrellmdClient *client; size_t addr_len; gint fd, server_fd, client_fd, i; #if defined(WIN32) gulong nbytes; #else gint nbytes; #endif /* defined(WIN32) */ gint max_fd = -1; gint listen_fds = 0; gint interval, result; read_config(); get_args(argc, argv); // first message that might get logged g_message("Starting GKrellM Daemon %d.%d.%d%s\n", GKRELLMD_VERSION_MAJOR, GKRELLMD_VERSION_MINOR, GKRELLMD_VERSION_REV, GKRELLMD_EXTRAVERSION); if (_GK.verbose) g_print("update_HZ=%d\n", _GK.update_HZ); #if defined(WIN32) if (!service_is_one) { signal(SIGTERM, cb_sigterm); signal(SIGINT, cb_sigterm); } #else if ( detach_flag && !_GK.log_plugins && !_GK.list_plugins && _GK.debug_level == 0 ) { if (detach_from_terminal() == FALSE) return 1; } else { signal(SIGTERM, cb_sigterm); signal(SIGQUIT, cb_sigterm); signal(SIGTSTP, SIG_IGN); signal(SIGINT, cb_sigterm); } #endif /* defined(WIN32) */ make_pidfile(); gkrellm_sys_main_init(); drop_privileges(); _GK.start_time = time(0); if (_GK.update_HZ < 1 || _GK.update_HZ > 10) _GK.update_HZ = 3; if (_GK.fs_interval < 1 || _GK.fs_interval > 1000) _GK.fs_interval = 2; if (_GK.nfs_interval > 10000) _GK.nfs_interval = 16; if (_GK.inet_interval > 20) _GK.inet_interval = 20; gkrellmd_load_monitors(); _GK.server_fd = socksetup(PF_UNSPEC); if (_GK.server_fd == NULL) { g_warning("socket() failed: %s\n", strerror(errno)); gkrellmd_cleanup(); return 1; } /* Listen on the socket so a client gkrellm can connect. */ FD_ZERO(&read_fds); for (i = 1; i <= _GK.server_fd[0]; ++i) { if (listen(_GK.server_fd[i], 5) == -1) { #if defined(WIN32) closesocket(_GK.server_fd[i]); #else close(_GK.server_fd[i]); #endif continue; } ++listen_fds; FD_SET(_GK.server_fd[i], &read_fds); if (max_fd < _GK.server_fd[i]) max_fd = _GK.server_fd[i]; } if (listen_fds <= 0) { g_warning("listen() failed: %s\n", strerror(errno)); gkrellmd_cleanup(); return 1; } interval = 1000000 / _GK.update_HZ; gkrellm_debug(DEBUG_SERVER, "Entering main event loop\n"); // main event loop #if defined(WIN32) /* endless loop if: - we're a service and our service_running flag is TRUE - we're a console-app (--console argument passed at startup */ while(service_running == TRUE || service_is_one == FALSE) #else while(1) #endif { test_fds = read_fds; addr_len = sizeof(client_addr.ss); tv.tv_usec = interval; tv.tv_sec = 0; result = select(max_fd + 1, &test_fds, NULL, NULL, &tv); if (result == -1) { if (errno == EINTR) continue; g_warning("select() failed: %s\n", strerror(errno)); gkrellmd_cleanup(); return 1; } #if 0 /* BUG, result is 0 when test_fds has a set fd!! */ if (result == 0) { gkrellmd_update_monitors(); continue; } #endif for (fd = 0; fd <= max_fd; ++fd) { if (!FD_ISSET(fd, &test_fds)) continue; server_fd = -1; for (i = 1; i <= _GK.server_fd[0]; ++i) { if (fd == _GK.server_fd[i]) { server_fd = fd; break; } } if (server_fd >= 0) { gkrellm_debug(DEBUG_SERVER, "Calling accept() for new client connection\n"); client_fd = accept(server_fd, &client_addr.sa, (socklen_t *) (void *)&addr_len); if (client_fd == -1) { g_warning("accept() failed: %s\n", strerror(errno)); gkrellmd_cleanup(); return 1; } if (client_fd > max_fd) max_fd = client_fd; client = accept_client(client_fd, &client_addr.sa, addr_len); if (!client) { #if defined(WIN32) closesocket(client_fd); #else shutdown(client_fd, SHUT_WR); close(client_fd); #endif continue; } FD_SET(client_fd, &read_fds); gkrellmd_serve_setup(client); g_message(_("Accepted client %s:%u\n"), client->hostname, ntohs(client_addr.sin.sin_port)); } else { gkrellm_debug(DEBUG_SERVER, "Reading data from client connection\n"); #if defined(WIN32) ioctlsocket(fd, FIONREAD, &nbytes); #else ioctl(fd, FIONREAD, &nbytes); #endif if (nbytes == 0) { remove_client(fd); FD_CLR(fd, &read_fds); } else gkrellmd_client_read(fd, nbytes); } } gkrellmd_update_monitors(); } // while(1) return 0; } // gkrellmd_main() #if defined(WIN32) static void service_update_status(DWORD newState) { service_status.dwCurrentState = newState; SetServiceStatus(service_status_handle, &service_status); } void WINAPI service_control_handler(DWORD controlCode) { switch (controlCode) { case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: service_update_status(SERVICE_STOP_PENDING); service_running = FALSE; return; default: break; } } void WINAPI service_main(DWORD argc, WCHAR* argv[]) { gchar **argv_utf8; DWORD i; /* Init service status */ service_status.dwServiceType = SERVICE_WIN32; service_status.dwCurrentState = SERVICE_STOPPED; service_status.dwControlsAccepted = 0; service_status.dwWin32ExitCode = NO_ERROR; service_status.dwServiceSpecificExitCode = NO_ERROR; service_status.dwCheckPoint = 0; service_status.dwWaitHint = 0; service_status_handle = RegisterServiceCtrlHandlerW(service_name, service_control_handler); if (service_status_handle) { // convert all strings in argv pointer array from utf16 to utf8 argv_utf8 = g_malloc(argc * sizeof(gchar *)); for (i = 0; i < argc; i++) argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); // service is starting service_update_status(SERVICE_START_PENDING); // service is running service_status.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); service_update_status(SERVICE_RUNNING); service_running = TRUE; // gkrellmd_main returns on error or as soon as // service_running is FALSE (see service_control_handler()) gkrellmd_run(argc, argv_utf8); // service was stopped service_update_status(SERVICE_STOP_PENDING); // services are not stopped via process signals so we have to // clean up like in cb_sigterm() but without calling exit()! g_message("GKrellM Daemon %d.%d.%d%s: Exiting normally\n", GKRELLMD_VERSION_MAJOR, GKRELLMD_VERSION_MINOR, GKRELLMD_VERSION_REV, GKRELLMD_EXTRAVERSION); gkrellmd_cleanup(); // free all strings in pointer array and free the array itself for (i = 0; i < argc; i++) g_free(argv_utf8[i]); g_free(argv_utf8); // service is now stopped service_status.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); service_update_status(SERVICE_STOPPED); // process is automatically terminated by windows now } } void service_run() { SERVICE_TABLE_ENTRYW service_table[] = { {service_name, service_main}, { 0, 0 } }; service_is_one = TRUE; // Blocking system call, will return if service is not needed anymore StartServiceCtrlDispatcherW(service_table); } static gboolean service_wait_for_stop(SC_HANDLE serviceHandle) { static const gulong waitTimeoutSec = 30; SERVICE_STATUS status; GTimer *waitTimer = NULL; gboolean ret = FALSE; if (!QueryServiceStatus(serviceHandle, &status)) { g_warning("Could not query status of %ls (%ld)\n", service_display_name, GetLastError()); return FALSE; } waitTimer = g_timer_new(); /* create and start */ while (status.dwCurrentState == SERVICE_STOP_PENDING) { g_usleep(status.dwWaitHint * 1000); if (!QueryServiceStatus(serviceHandle, &status)) { g_warning("Could not query status of %ls (%ld)\n", service_display_name, GetLastError()); ret = FALSE; break; } if (status.dwCurrentState == SERVICE_STOPPED) { ret = TRUE; break; } if (g_timer_elapsed(waitTimer, NULL) > waitTimeoutSec) { g_warning("Stopping %ls timed out\n", service_display_name); ret = FALSE; break; } } /*while*/ g_timer_destroy(waitTimer); return ret; } static gboolean service_stop(SC_HANDLE serviceHandle) { SERVICE_STATUS svcStatus; if (!QueryServiceStatus(serviceHandle, &svcStatus)) { g_warning("Could not query status of %ls (%ld)\n", service_display_name, GetLastError()); return FALSE; } /* service not running at all, just return that stopping worked out */ if (svcStatus.dwCurrentState == SERVICE_STOPPED) { g_print(_("%ls already stopped\n"), service_display_name); return TRUE; } /* service already stopping, just wait for its exit */ if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) { return service_wait_for_stop(serviceHandle); } /* Service is running, let's stop it */ if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &svcStatus)) { g_warning(_("Could not stop %ls (%ld)\n"), service_display_name, GetLastError()); return FALSE; } // Wait for the service to stop. if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) { return service_wait_for_stop(serviceHandle); } return TRUE; } static gboolean service_install() { WCHAR path[_MAX_PATH + 1]; SC_HANDLE scmHandle; SC_HANDLE svcHandle; DWORD err; g_print(_("Installing %ls...\n"), service_display_name); if (GetModuleFileNameW(0, path, sizeof(path)/sizeof(path[0])) < 1) { g_warning("Could not determine path to gkrellmd service binary, error 0x%ld\n", GetLastError()); return FALSE; } scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE); if (!scmHandle) { err = GetLastError(); if (err == ERROR_ACCESS_DENIED) g_warning("Could not connect to service manager, access denied\n"); else g_warning("Could not connect to service manager, error 0x%lXd\n", err); return FALSE; } svcHandle = CreateServiceW(scmHandle, service_name, service_display_name, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path, 0, 0, 0, 0, 0); if (!svcHandle) { err = GetLastError(); if (err == ERROR_ACCESS_DENIED) g_warning("Could not install %ls, access denied\n", service_display_name); else if (err == ERROR_SERVICE_EXISTS || err == ERROR_DUPLICATE_SERVICE_NAME) g_warning("Could not install %ls, a service of the same name already exists\n", service_display_name); else g_warning("Could not install %ls, error 0x%lX\n", service_display_name, err); CloseServiceHandle(scmHandle); return FALSE; } else { g_print(_("%ls has been installed.\n"), service_display_name); } g_print(_("Starting %ls...\n"), service_display_name); if (!StartServiceW(svcHandle, 0, NULL)) { err = GetLastError(); if (err == ERROR_ACCESS_DENIED) g_warning("Could not start %ls, access denied\n", service_display_name); else g_warning("Could not start %ls, error 0x%lX\n", service_display_name, err); } else { g_print(_("%ls has been started.\n"), service_display_name); } CloseServiceHandle(svcHandle); CloseServiceHandle(scmHandle); return TRUE; } /* service_install() */ static gboolean service_uninstall() { SC_HANDLE scmHandle; SC_HANDLE svcHandle; BOOL delRet = FALSE; gchar *errmsg; g_print(_("Uninstalling %ls...\n"), service_display_name); scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (!scmHandle) { errmsg = g_win32_error_message(GetLastError()); g_warning("Could not connect to service manager: %s\n", errmsg); g_free(errmsg); return FALSE; } svcHandle = OpenServiceW(scmHandle, service_name, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE); if (!svcHandle) { errmsg = g_win32_error_message(GetLastError()); g_warning("Could not open %ls: %s\n", service_display_name, errmsg); g_free(errmsg); } else { // handle to gkrellm service acquired, now stop and uninstall it if (service_stop(svcHandle)) { delRet = DeleteService(svcHandle); if (!delRet) { errmsg = g_win32_error_message(GetLastError()); g_warning("Could not uninstall %ls: %s\n", service_display_name, errmsg); g_free(errmsg); } else { g_print(_("%ls has been uninstalled.\n"), service_display_name); } } CloseServiceHandle(svcHandle); } CloseServiceHandle(scmHandle); return delRet ? TRUE : FALSE; } /* service_uninstall() */ #endif /* defined(WIN32) */ GkrellmdTicks * gkrellmd_ticks(void) { return &GK; } gint gkrellmd_get_timer_ticks(void) { return GK.timer_ticks; } int main(int argc, char* argv[]) { int i; char *opt; #ifdef ENABLE_NLS #ifdef LOCALEDIR #if defined(WIN32) gchar *install_path; gchar *locale_dir; // Prepend app install path to locale dir install_path = g_win32_get_package_installation_directory_of_module(NULL); if (install_path != NULL) { locale_dir = g_build_filename(install_path, LOCALEDIR, NULL); bindtextdomain(PACKAGE_D, locale_dir); g_free(locale_dir); g_free(install_path); } #else bindtextdomain(PACKAGE_D, LOCALEDIR); #endif /* !WIN32 */ #endif /* LOCALEDIR */ textdomain(PACKAGE_D); bind_textdomain_codeset(PACKAGE_D, "UTF-8"); #endif /* ENABLE_NLS */ // Init logging-chain gkrellm_log_init(); /* Parse arguments for actions that exit gkrellmd immediately */ for (i = 1; i < argc; ++i) { opt = argv[i]; if (*opt == '-') { ++opt; if (*opt == '-') ++opt; } if (!strcmp(opt, "help") || !strcmp(opt, "h")) { usage(); return 0; } else if (!strcmp(opt, "version") || !strcmp(opt, "v")) { g_print("gkrellmd %d.%d.%d%s\n", GKRELLMD_VERSION_MAJOR, GKRELLMD_VERSION_MINOR, GKRELLMD_VERSION_REV, GKRELLMD_EXTRAVERSION); return 0; } #if defined(WIN32) else if (!strcmp(opt, "install")) { return (service_install() ? 1 : 0); } else if (!strcmp(opt, "uninstall")) { return (service_uninstall() ? 1 : 0); } else if (!strcmp(opt, "console")) { /* Special case for windows: run gkrellmd on console and not as a service. This is helpful for debugging purposes. */ int retVal; int newArgc = 0; char **newArgv = malloc((argc - 1) * sizeof(char *)); int j; for (j = 0; j < argc; ++j) { /* filter out option "--console" */ if (j == i) continue; newArgv[newArgc++] = argv[j]; } retVal = gkrellmd_run(newArgc, newArgv); free(newArgv); return retVal; } #endif /* defined(WIN32) */ } #if defined(WIN32) // win32: register service and wait for the service to be started/stopped service_run(); return 0; #else // Unix: just enter main loop return gkrellmd_run(argc, argv); #endif } gkrellm-2.3.10/server/mail.c0000644000175000000330000004133312417341637014311 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #include "gkrellmd.h" #include "gkrellmd-private.h" #if !defined(WIN32) #define MBOX_MBOX 0 #define MBOX_MAILDIR 1 #define MBOX_MH_DIR 2 typedef struct { gchar *path; gchar *homedir_path; gint mboxtype; gboolean (*check_func)(); gint mail_count; gint new_mail_count; gint old_mail_count; gint prev_mail_count, prev_new_mail_count; time_t last_mtime; off_t last_size; gboolean is_internal; /* Internal mail message (ie: localmachine) */ gboolean changed; } Mailbox; static GList *mailbox_list; static gint mail_check_timeout = 5; /* Seconds */ static gboolean unseen_is_new = TRUE; /* Accessed but unread */ static gboolean mail_need_serve; /* Look at a From line to see if it is valid, lines look like: | From sending_address dayofweek month dayofmonth timeofday year | eg: From billw@gkrellm.net Fri Oct 22 13:52:49 2010 */ static gint is_From_line(Mailbox *mbox, gchar *buf) { gchar sender[512]; gint dayofmonth = 0; if (strncmp(buf, "From ", 5)) return FALSE; /* In case sending address missing, look for a day of month | number in field 3 or 4 (0 based). */ sender[0] = '\0'; if (sscanf(buf, "%*s %*s %*s %d", &dayofmonth) != 1) { if (sscanf(buf, "%*s %511s %*s %*s %d", sender, &dayofmonth) != 2) return FALSE; } if (dayofmonth < 1 || dayofmonth > 31) return FALSE; if (strcmp(sender, "MAILER-DAEMON") == 0) mbox->is_internal = TRUE; return TRUE; } /* Check if this is a Content-Type-line. If it contains a boundary | field, copy boundary string to buffer (including two leading and | trailing dashes marking the end of a multipart mail) and return | true. Otherwise, return false. */ static gint is_multipart_mail(gchar *buf, gchar *separator) { gchar *fieldstart; gchar *sepstart; gint seplen; if (strncmp(buf, "Content-Type: ", 14) != 0) return FALSE; if (strncmp(&buf[14], "multipart/", 10) != 0) return FALSE; fieldstart = &buf[14]; while (*fieldstart!=0) { while (*fieldstart!=0 && *fieldstart!=';') fieldstart++; if (*fieldstart==';') fieldstart++; while (*fieldstart!=0 && *fieldstart==' ') fieldstart++; if (strncmp(fieldstart, "boundary=", 9) == 0) { sepstart = fieldstart + 9; if (sepstart[0]=='"') { sepstart++; seplen = 0; while (sepstart[seplen]!='"' && sepstart[seplen]>=32) seplen++; } else { seplen = 0; while (sepstart[seplen]!=';' && sepstart[seplen]>32) seplen++; } strcpy(separator,"--"); strncpy(&separator[2],sepstart,seplen); strcpy(&separator[seplen+2],"--"); return TRUE; } } return FALSE; } static gboolean mh_sequences_new_count(Mailbox *mbox) { FILE *f; gchar buf[1024]; gchar *path, *tok; gint n0, n1; path = g_strconcat(mbox->path, G_DIR_SEPARATOR_S, ".mh_sequences", NULL); f = fopen(path, "r"); g_free(path); if (!f) return FALSE; while (fgets(buf, sizeof(buf), f)) { /* Look for unseen sequence like "unseen: 4 7-9 23" */ if (strncmp(buf, "unseen:", 7)) continue; tok = strtok(buf, " \t\n"); while ((tok = strtok(NULL, " \t\n")) != NULL) { if (sscanf(tok, "%d-%d", &n0, &n1) == 2) mbox->new_mail_count += n1 - n0 + 1; else mbox->new_mail_count++; } break; } fclose(f); return TRUE; } /* Sylpheed procmsg.h enums MSG_NEW as (1 << 0) and MSG_UNREAD as (1 << 1) | And procmsg_write_flags() in Sylpheeds procmsg.c writes a mail record as | a pair of ints with msgnum first followed by flags. */ #define SYLPHEED_MSG_NEW 1 #define SYLPHEED_MSG_UNREAD 2 #define SYLPHEED_MARK_VERSION 2 static gboolean sylpheed_mark_new_count(Mailbox *mbox) { FILE *f; gchar *path; gint msgnum, flags, ver, mark_files = 0; path = g_strconcat(mbox->path, G_DIR_SEPARATOR_S, ".sylpheed_mark", NULL); f = fopen(path, "rb"); g_free(path); if (!f) return FALSE; if ( fread(&ver, sizeof(ver), 1, f) == 1 && SYLPHEED_MARK_VERSION == ver ) { while ( fread(&msgnum, sizeof(msgnum), 1, f) == 1 && fread(&flags, sizeof(flags), 1, f) == 1 ) { if ( (flags & SYLPHEED_MSG_NEW) || ((flags & SYLPHEED_MSG_UNREAD) && unseen_is_new) ) mbox->new_mail_count += 1; ++mark_files; } if (mark_files < mbox->mail_count) mbox->new_mail_count += mbox->mail_count - mark_files; } fclose(f); return TRUE; } /* Check a mh directory for mail. The way that messages are marked as new | depends on the MUA being using. Only .mh_sequences and .sylpheed_mark | are currently checked, otherwise all mail found is considered new mail. */ static gboolean check_mh_dir(Mailbox *mbox) { GDir *dir; gchar *name; mbox->mail_count = mbox->new_mail_count = 0; if ((dir = g_dir_open(mbox->path, 0, NULL)) == NULL) return FALSE; while ((name = (gchar *) g_dir_read_name(dir)) != NULL) { /* Files starting with a digit are messages. */ if (isdigit((unsigned char)name[0])) mbox->mail_count++; } g_dir_close(dir); /* Some MH dir clients use .mh_sequences, others such as mutt or gnus | do not. For mixed cases, it's a user option to ignore .mh_sequences. | Sylpheed uses .sylpheed_mark. */ if ( !mh_sequences_new_count(mbox) && !sylpheed_mark_new_count(mbox) ) mbox->new_mail_count = mbox->mail_count; return TRUE; } /* A maildir has new, cur, and tmp subdirectories. Any file in new | or cur that does not begin with a '.' is a mail message. It is | suggested that messages begin with the output of time() (9 digits) | but while mutt and qmail use this standard, procmail does not. | maildir(5) says: | It is a good idea for readers to skip all filenames in | new and cur starting with a dot. Other than this, | readers should not attempt to parse filenames. | So check_maildir() simply looks for files in new and cur. | But if unseen_is_new flag is set, look for ":2,*S" file suffix where | the 'S' indicates the mail is seen. | See http://cr.yp.to/proto/maildir.html */ static gboolean check_maildir(Mailbox *mbox) { gchar path[256], *s; gchar *name; GDir *dir; mbox->new_mail_count = 0; snprintf(path, sizeof(path), "%s%cnew", mbox->path, G_DIR_SEPARATOR); if ((dir = g_dir_open(path, 0, NULL)) != NULL) { while ((name = (gchar *) g_dir_read_name(dir)) != NULL) mbox->new_mail_count++; g_dir_close(dir); } mbox->mail_count = mbox->new_mail_count; snprintf(path, sizeof(path), "%s%ccur", mbox->path, G_DIR_SEPARATOR); if ((dir = g_dir_open(path, 0, NULL)) != NULL) { while ((name = (gchar *) g_dir_read_name(dir)) != NULL) { mbox->mail_count++; if ( unseen_is_new && ( (s = strchr(name, ':')) == NULL || !strchr(s, 'S') ) ) mbox->new_mail_count++; } g_dir_close(dir); } if (_GK.debug_level & DEBUG_MAIL) g_print(_("mdir %s total=%d old=%d new=%d\n"), mbox->path, mbox->mail_count, mbox->old_mail_count, mbox->new_mail_count); return TRUE; } /* Count total mail and old mail in a mailbox. Old mail can be read | with a Status: R0, or can be accessed and not read with Status: O | So, new mail will be the diff - note that unread mail is not | necessarily new mail. According to stat() man page: | st_atime is changed by mknod(), utime(), read(), write(), truncate() | st_mtime is changed by mknod(), utime(), write() | But, new mail arriving (writing mailbox) sets st_mtime while reading | the mailbox (mail program reading) sets st_atime. So the test | st_atime > st_mtime is testing if mbox has been read since last new mail. | Mail readers may restore st_mtime after writting status. | And Netscape mail does status with X-Mozilla-Status: xxxS | where S is bitwise or of status flags: | 1: read 2: replied 4: marked 8: deleted | | Evolution uses status with X-Evolution: 00000000-xxxx where xxxx status is | a bitfield in hexadecimal (see enum _CamelMessageFlags in evolution/camel | source) and most importantly CAMEL_MESSAGE_SEEN = 1<<4. */ /* test if buf is a status for standard mail, mozilla or evolution */ static gboolean is_status(gchar *buf) { if (buf[0] != 'S' && buf[0] != 'X') return FALSE; if ( !strncmp(buf, "Status:", 7) /* Standard mail clients */ || !strncmp(buf, "X-Mozilla-Status:", 17) /* Netscape */ || !strncmp(buf, "X-Evolution:", 12) /* Mozilla */ ) return TRUE; else return FALSE; } static gboolean status_is_old(gchar *buf) { gchar c; int tmp; /* Standard mail clients */ if ( !strncmp(buf, "Status:", 7) && (strchr(buf, 'R') || (!unseen_is_new && strchr(buf, 'O'))) ) return TRUE; /* Netscape */ if (!strncmp(buf, "X-Mozilla-Status:", 17)) { c = buf[21]; if (c < '8') /* Not deleted */ c -= '0'; if (c >= '8' || (c & 0x1)) return TRUE; } /* Evolution */ if (!strncmp(buf, "X-Evolution:", 12)) { sscanf(buf+22, "%04x", &tmp); if (tmp & (1<<4)) return TRUE; } return FALSE; } /* test if a mail is marked as deleted | Evolution uses status with X-Evolution: 00000000-xxxx where xxxx status is | a bitfield in hexadecimal (see enum _CamelMessageFlags in evolution/camel source) | and most importantly CAMEL_MESSAGE_DELETED = 1<<1. */ static gboolean status_is_deleted(gchar *buf) { gint tmp; /* Standard mail clients if ( !strncmp(buf, "Status:", 7) ) */ /* Netscape if (!strncmp(buf, "X-Mozilla-Status:", 17)) */ /* Evolution */ if (!strncmp(buf, "X-Evolution:", 12)) { sscanf(buf+22, "%04x", &tmp); if (tmp & (1<<1)) return TRUE; /* Junk is not explicitly marked as deleted but is shown as if | where in evolution */ if (tmp & (1<<7)) return TRUE; } return FALSE; } static gboolean check_mbox(Mailbox *mbox) { FILE *f; struct utimbuf ut; struct stat s; gchar buf[1024]; gchar mpart_sep[1024]; gint in_header = FALSE; gint marked_read = FALSE; gint is_multipart = FALSE; if (stat(mbox->path, &s) != 0) { mbox->mail_count = mbox->old_mail_count = mbox->new_mail_count = 0; mbox->last_mtime = 0; mbox->last_size = 0; gkrellm_debug(DEBUG_MAIL, "check_mbox can't stat(%s): %s\n", mbox->path, g_strerror(errno)); return FALSE; } /* If the mailboxes have been modified since last check, count | the new/total messages. */ if ( s.st_mtime != mbox->last_mtime || s.st_size != mbox->last_size ) { if ((f = fopen(mbox->path, "r")) == NULL) { gkrellm_debug(DEBUG_MAIL, "check_mbox can't fopen(%s): %s\n", mbox->path, g_strerror(errno)); return FALSE; } mbox->mail_count = 0; mbox->old_mail_count = 0; while(fgets(buf, sizeof(buf), f)) { if (is_multipart && !in_header) { /* Skip to last line of multipart mail */ if (strncmp(buf,mpart_sep,strlen(mpart_sep))==0) is_multipart = FALSE; } else if (buf[0] == '\n') { in_header = FALSE; mbox->is_internal = FALSE; } else if (is_From_line(mbox, buf)) { mbox->mail_count += 1; in_header = TRUE; marked_read = FALSE; } else if (in_header && is_status(buf)) { if (status_is_old(buf) && !marked_read) { mbox->old_mail_count += 1; marked_read = TRUE; } if (status_is_deleted(buf)) { if (marked_read) mbox->old_mail_count -= 1; mbox->mail_count -= 1; } } else if (in_header && mbox->is_internal) { if (strncmp(buf, "From: Mail System Internal Data", 31) == 0) { in_header = FALSE; mbox->mail_count -= 1; mbox->is_internal = FALSE; } } else if (in_header && is_multipart_mail(buf,mpart_sep)) { is_multipart = TRUE; } } fclose(f); /* Restore the mbox stat times for other mail checking programs and | so the (st_atime > st_mtime) animation override below will work. */ ut.actime = s.st_atime; ut.modtime = s.st_mtime; utime(mbox->path, &ut); mbox->last_mtime = s.st_mtime; mbox->last_size = s.st_size; if (_GK.debug_level & DEBUG_MAIL) g_print("mbox read <%s> total=%d old=%d\n", mbox->path, mbox->mail_count, mbox->old_mail_count); } /* If mbox has been accessed since last modify a MUA has probably read | the mbox. */ mbox->new_mail_count = mbox->mail_count - mbox->old_mail_count; if (s.st_atime > s.st_mtime) { mbox->prev_new_mail_count = mbox->new_mail_count; } return TRUE; } static void update_mail(GkrellmdMonitor *mon, gboolean force) { Mailbox *mbox; GList *list; static gint second_count; if ( (!GK.second_tick || (++second_count % mail_check_timeout) != 0) && !force ) return; for (list = mailbox_list; list; list = list->next) { mbox = (Mailbox *) list->data; if (mbox->check_func) (*mbox->check_func)(mbox); if ( mbox->prev_mail_count != mbox->mail_count || mbox->prev_new_mail_count != mbox->new_mail_count ) { mbox->changed = TRUE; mail_need_serve = TRUE; gkrellmd_need_serve(mon); } mbox->prev_mail_count = mbox->mail_count; mbox->prev_new_mail_count = mbox->new_mail_count; } } static void get_local_mboxtype(Mailbox *mbox) { gchar *path; if (*(mbox->path) == '~') { mbox->homedir_path = mbox->path; mbox->path = g_strdup_printf("%s%s", g_get_home_dir(), mbox->homedir_path + 1); } if (g_file_test(mbox->path, G_FILE_TEST_IS_DIR)) { path = g_build_path(G_DIR_SEPARATOR_S, mbox->path, "new", NULL); if (g_file_test(path, G_FILE_TEST_IS_DIR)) mbox->mboxtype = MBOX_MAILDIR; else mbox->mboxtype = MBOX_MH_DIR; g_free(path); } else mbox->mboxtype = MBOX_MBOX; } void gkrellmd_add_mailbox(gchar *path) { Mailbox *mbox; if (!path || !*path) return; mbox = g_new0(Mailbox, 1); mbox->path = g_strdup(path); get_local_mboxtype(mbox); if (mbox->mboxtype == MBOX_MAILDIR) mbox->check_func = check_maildir; else if (mbox->mboxtype == MBOX_MH_DIR) mbox->check_func = check_mh_dir; else mbox->check_func = check_mbox; mailbox_list = g_list_append(mailbox_list, mbox); gkrellmd_add_serveflag_done(&mbox->changed); } /* ============================================================= */ static void serve_mail_data(GkrellmdMonitor *mon, gboolean first_serve) { Mailbox *mbox; GList *list; gchar *line; if ((!mail_need_serve && !first_serve) || !mailbox_list) return; gkrellmd_set_serve_name(mon, "mail"); for (list = mailbox_list; list; list = list->next) { mbox = (Mailbox *) list->data; if (mbox->changed || first_serve) { line = g_strdup_printf("%s %d %d\n", mbox->homedir_path ? mbox->homedir_path : mbox->path, mbox->mail_count, mbox->new_mail_count); gkrellmd_serve_data(mon, line); g_free(line); } } } static void serve_mail_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; GList *list; Mailbox *mbox; gchar *line; gkrellmd_send_to_client(client, "\n"); for (list = mailbox_list; list; list = list->next) { mbox = (Mailbox *) list->data; line = g_strdup_printf("%s\n", mbox->homedir_path ? mbox->homedir_path : mbox->path); gkrellmd_send_to_client(client, line); g_free(line); } } static GkrellmdMonitor mail_monitor = { "mail", update_mail, serve_mail_data, serve_mail_setup }; GkrellmdMonitor * gkrellmd_init_mail_monitor(void) { gkrellmd_add_serveflag_done(&mail_need_serve); return &mail_monitor; } #else /* defined(WIN32) */ GkrellmdMonitor * gkrellmd_init_mail_monitor(void) { return NULL; } void gkrellmd_add_mailbox(gchar *path) { } #endif void gkrellm_mail_local_unsupported(void) { /* WIN32 only calls this and it is taken care of by above #if */ } GThread * gkrellm_mail_get_active_thread(void) { return NULL; } gkrellm-2.3.10/server/gkrellmd.h0000644000175000000330000001543513001775424015174 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #ifndef GKRELLMD_H #define GKRELLMD_H #include "log.h" #include #include #include #include #include #include #include #include #if (defined(__sun) && defined(__SVR4)) || defined(SOLARIS_8) #define __solaris__ #endif #if !defined(WIN32) #include #include #include #include #include #include #include #include #include #include #if defined(__solaris__) #include #endif /* defined(__solaris__) */ #include #include #else #include #include typedef int sa_family_t; // WIN32 uses int for ai_family; #include // defines uint32_t #endif /* !defined(WIN32) */ #include #include #include #include #include #if !defined(PACKAGE_D) #define PACKAGE_D "gkrellmd" #endif /* Internationalization support. */ #if defined (ENABLE_NLS) #include # undef _ # define _(String) dgettext(PACKAGE_D,String) # if defined(gettext_noop) # define N_(String) gettext_noop(String) # else # define N_(String) (String) # endif /* gettext_noop */ #else # define _(String) (String) # define N_(String) (String) # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,String) (String) # define dcgettext(Domain,String,Type) (String) # define bindtextdomain(Domain,Directory) (Domain) #endif /* ENABLE_NLS */ /* ------------------------------------------------------------------- */ #define GKRELLMD_VERSION_MAJOR 2 #define GKRELLMD_VERSION_MINOR 3 #define GKRELLMD_VERSION_REV 10 #define GKRELLMD_EXTRAVERSION "" //#define GKRELLMD_EXTRAVERSION "-pre1" #define GKRELLMD_CHECK_VERSION(major,minor,rev) \ (GKRELLMD_VERSION_MAJOR > (major) || \ (GKRELLMD_VERSION_MAJOR == (major) && GKRELLMD_VERSION_MINOR > (minor)) || \ (GKRELLMD_VERSION_MAJOR == (major) && GKRELLMD_VERSION_MINOR == (minor) && \ GKRELLMD_VERSION_REV >= (rev))) #define GKRELLMD_CONFIG "gkrellmd.conf" #if defined(WIN32) // no dot in front of config-filename on win32 #define GKRELLMD_USER_CONFIG GKRELLMD_CONFIG #else #define GKRELLMD_USER_CONFIG ".gkrellmd.conf" #endif #define GKRELLMD_PLUGINS_DIR ".gkrellm2/plugins-gkrellmd" #if !defined(WIN32) #define GKRELLMD_LOCAL_PLUGINS_DIR "/usr/local/lib/gkrellm2/plugins-gkrellmd" #if !defined(GKRELLMD_SYSTEM_PLUGINS_DIR) #define GKRELLMD_SYSTEM_PLUGINS_DIR "/usr/lib/gkrellm2/plugins-gkrellmd" #endif #define GKRELLMD_SYS_ETC "/etc" #define GKRELLMD_LOCAL_ETC "/usr/local/etc" #endif // !defined(WIN32) typedef struct _GkrellmdClient { gint major_version, minor_version, rev_version; gchar *hostname; gint fd; gboolean served, alive, last_client; gboolean feature_subdisk; GString *input_gstring; void (*input_func)(struct _GkrellmdClient *, gchar *); } GkrellmdClient; typedef struct { gint timer_ticks, second_tick, two_second_tick, five_second_tick, ten_second_tick, minute_tick; } GkrellmdTicks; extern GkrellmdTicks GK; typedef struct { gboolean need_serve; const gchar *serve_name; gboolean serve_name_sent; GString *serve_gstring; GkrellmdClient *client; GList *config_list; gboolean is_plugin; void *handle; gchar *path; void (*client_input_func)(GkrellmdClient *, gchar *); } GkrellmdMonitorPrivate; typedef struct _GkrellmdMonitor { gchar *name; void (*update_monitor)(struct _GkrellmdMonitor *mon, gboolean first_update); void (*serve_data)(struct _GkrellmdMonitor *mon, gboolean first_serve); void (*serve_setup)(struct _GkrellmdMonitor *mon); GkrellmdMonitorPrivate *privat; } GkrellmdMonitor; /* gkrellmd serve data functions used by builtins and plugins. */ void gkrellmd_plugin_serve_setup(GkrellmdMonitor *mon, gchar *name, gchar *line); void gkrellmd_need_serve(GkrellmdMonitor *mon); void gkrellmd_set_serve_name(GkrellmdMonitor *mon, const gchar *name); void gkrellmd_serve_data(GkrellmdMonitor *mon, gchar *line); void gkrellmd_add_serveflag_done(gboolean *); gboolean gkrellmd_check_client_version(GkrellmdMonitor *mon, gint major, gint minor, gint rev); const gchar *gkrellmd_config_getline(GkrellmdMonitor *mon); void gkrellmd_client_input_connect(GkrellmdMonitor *mon, void (*func)(GkrellmdClient *, gchar *)); /* Small set of useful functions duplicated from src/utils.c. | These really should just be in the gkrellm_ namespace for sysdep code | common to gkrellm and gkrellmd, but for convenience, offer them in | both gkrellm_ and gkrellmd_ namespaces. */ void gkrellmd_free_glist_and_data(GList **list_head); gboolean gkrellmd_getline_from_gstring(GString **, gchar *, gint); gchar *gkrellmd_dup_token(gchar **string, gchar *delimeters); gboolean gkrellmd_dup_string(gchar **dst, gchar *src); void gkrellm_free_glist_and_data(GList **list_head); gboolean gkrellm_getline_from_gstring(GString **, gchar *, gint); gchar *gkrellm_dup_token(gchar **string, gchar *delimeters); gboolean gkrellm_dup_string(gchar **dst, gchar *src); /* Plugins should use above data serve functions instead of this. */ gint gkrellmd_send_to_client(GkrellmdClient *client, gchar *buf); /* Misc */ void gkrellmd_add_mailbox(gchar *); GkrellmdTicks *gkrellmd_ticks(void); gint gkrellmd_get_timer_ticks(void); #endif // GKRELLMD_H gkrellm-2.3.10/server/win32-resource.rc0000644000175000000330000000164113001777073016333 0ustar billsudo// Generated by ResEdit 1.4.3 // Copyright (C) 2006-2008 // http://www.resedit.net #include "win32-resource.h" #include "windows.h" // // Version Information resources // LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 1 VERSIONINFO FILEVERSION 2,3,10,0 PRODUCTVERSION 0,0,0,0 FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "" VALUE "FileDescription", "GKrellM Daemon" VALUE "FileVersion", "2.3.10" VALUE "InternalName", "gkrellmd" VALUE "LegalCopyright", "Copyright (C) 1999-2016 Bill Wilson" VALUE "OriginalFilename", "gkrellmd.exe" VALUE "ProductName", "GKrellM" VALUE "ProductVersion", "2.3.10" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 1033, 1200 END END gkrellm-2.3.10/server/gkrellmd-private.h0000644000175000000330000000776012654236716016657 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #include "configure.h" #include "../src/gkrellm-sysdeps.h" #if defined(WIN32) // Enable getaddrinfo on win32 if we target win xp or newer #if _WIN32_WINNT > 0x0500 #define HAVE_GETADDRINFO 1 #endif #endif #if defined(__linux__) #define HAVE_GETADDRINFO 1 #endif #if defined(__DragonFly__) #define HAVE_GETADDRINFO 1 #endif #if defined(__FreeBSD__) #include #if __FreeBSD_version >= 400000 #define HAVE_GETADDRINFO 1 #endif #endif #if defined(__OpenBSD__) #define HAVE_GETADDRINFO 1 #endif #if defined(__NetBSD__) #define HAVE_GETADDRINFO 1 #include # if __NetBSD_Version__ <= 105010000 # define sa_family_t unsigned char # endif #endif #if defined(__solaris__) # include # if defined(NC_INET6) # define HAVE_GETADDRINFO 1 # endif #endif #if defined(__APPLE__) # ifndef socklen_t # define socklen_t int # endif #define HAVE_GETADDRINFO 1 #endif #ifndef NI_WITHSCOPEID #define NI_WITHSCOPEID 0 #endif #if !defined(__FreeBSD__) && !defined(__linux__) && !defined(__NetBSD__) \ && !defined(__OpenBSD__) && !defined(__solaris__) && !defined(WIN32) \ && !defined(__APPLE__) && !defined(__DragonFly__) #define USE_LIBGTOP #endif #define DEBUG_SYSDEP 0x1 #define DEBUG_SERVER 0x2 #define DEBUG_MAIL 0x10 #define DEBUG_NET 0x20 #define DEBUG_TIMER 0x40 #define DEBUG_SENSORS 0x80 #define DEBUG_NO_LIBSENSORS 0x100 #define DEBUG_INET 0x800 #define DEBUG_BATTERY 0x8000 #define SENSOR_TEMPERATURE 0 #define SENSOR_FAN 1 #define SENSOR_VOLTAGE 2 #define SENSOR_GROUP_MAINBOARD 0 #define SENSOR_GROUP_DISK 1 #include struct GkrellmdConfig { gint update_HZ; gint debug_level; gint *server_fd; gint max_clients; gint server_port; gchar *server_address; gint verbose; time_t start_time; time_t time_now; gint io_timeout; gint reconnect_timeout; gint mbmon_port; gint fs_interval, nfs_interval, inet_interval; gboolean without_libsensors; gboolean use_acpi_battery; gboolean list_plugins, log_plugins; gchar *command_line_plugin; gchar *pidfile; gchar *homedir; gchar *net_timer; }; typedef struct { gchar *name, *line; } PluginConfigRec; extern struct GkrellmdConfig _GK; extern gchar *plugin_install_log; typedef void (*GkrellmdFunc)(); extern GList *gkrellmd_client_list, *gkrellmd_plugin_enable_list, *gkrellmd_plugin_config_list; void gkrellmd_client_read(gint client_fd, gint nbytes); void gkrellmd_load_monitors(void); GList *gkrellmd_plugins_load(void); gint gkrellmd_update_monitors(void); void gkrellmd_serve_setup(GkrellmdClient *client); GkrellmdMonitor *gkrellmd_init_mail_monitor(void); gint gkrellm_connect_to(gchar *, gint); gkrellm-2.3.10/server/monitor.c0000644000175000000330000014555612654235330015065 0ustar billsudo/* GKrellM | Copyright (C) 1999-2014 Bill Wilson | | Author: Bill Wilson billw@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | | GKrellM 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 3 of the License, or | (at your option) any later version. | | GKrellM 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/ | | | Additional permission under GNU GPL version 3 section 7 | | If you modify this program, or any covered work, by linking or | combining it with the OpenSSL project's OpenSSL library (or a | modified version of that library), containing parts covered by | the terms of the OpenSSL or SSLeay licenses, you are granted | additional permission to convey the resulting work. | Corresponding Source for a non-source form of such a combination | shall include the source code for the parts of OpenSSL used as well | as that of the covered work. */ #include "gkrellmd.h" #include "gkrellmd-private.h" #include GList *gkrellmd_monitor_list; static GList *serveflag_done_list; static struct tm gkrellmd_current_tm; gint gkrellm_get_timer_ticks(void) { return GK.timer_ticks; } gboolean gkrellmd_check_client_version(GkrellmdMonitor *mon, gint major, gint minor, gint rev) { GkrellmdClient *client = mon->privat->client; if ( client->major_version > major || (client->major_version == major && client->minor_version > minor) || ( client->major_version == major && client->minor_version == minor && client->rev_version >= rev ) ) return TRUE; return FALSE; } void gkrellmd_add_serveflag_done(gboolean *flag) { serveflag_done_list = g_list_append(serveflag_done_list, flag); } void gkrellmd_set_serve_name(GkrellmdMonitor *mon, const gchar *tag) { GkrellmdMonitorPrivate *mp = mon->privat; mp->serve_name = tag; mp->serve_name_sent = FALSE; } void gkrellmd_serve_data(GkrellmdMonitor *mon, gchar *line) { GkrellmdMonitorPrivate *mp = mon->privat; gchar buf[128]; if (!line || !*line) return; if (!mp->serve_name_sent) { if (mp->serve_name) { snprintf(buf, sizeof(buf), "<%s>\n", mp->serve_name); gkrellm_debug(DEBUG_SERVER, "%s", buf); mp->serve_gstring = g_string_append(mp->serve_gstring, buf); mp->serve_name_sent = TRUE; } else { g_warning("gkrellmd: %s forgot to gkrellmd_set_serve_name()\n", mon->name); return; } } gkrellm_debug(DEBUG_SERVER,"%s", line); mp->serve_gstring = g_string_append(mp->serve_gstring, line); } /* ======================================================= */ typedef struct { gint instance; gulong user, nice, sys, idle; } CpuData; static gchar *n_cpus_setup; static gboolean nice_time_unsupported; static GList *cpu_list; static GList *instance_list; void gkrellm_cpu_set_number_of_cpus(gint n) { CpuData *cpu; GList *list; gint i; n_cpus_setup = g_strdup_printf("n_cpus %d\n", n); for (i = 0; i < n; ++i) { cpu = g_new0(CpuData, 1); cpu_list = g_list_append(cpu_list, cpu); if (instance_list && (list = g_list_nth(instance_list, i)) != NULL) cpu->instance = GPOINTER_TO_INT(list->data); else cpu->instance = i; } } void gkrellm_cpu_add_instance(gint instance) { instance_list = g_list_append(instance_list, GINT_TO_POINTER(instance)); } void gkrellm_cpu_nice_time_unsupported(void) { nice_time_unsupported = TRUE; } void gkrellm_cpu_assign_composite_data(gulong user, gulong nice, gulong sys, gulong idle) { return; /* let client gkrellm compute it */ } void gkrellm_cpu_assign_data(gint n, gulong user, gulong nice, gulong sys, gulong idle) { CpuData *cpu = NULL; GList *list; for (list = cpu_list; list; list = list->next) { cpu = (CpuData *) list->data; if (cpu->instance == n) break; } if (list) { cpu->user = user; cpu->nice = nice; cpu->sys = sys; cpu->idle = idle; } } static void update_cpu(GkrellmdMonitor *mon, gboolean first_update) { gkrellm_sys_cpu_read_data(); gkrellmd_need_serve(mon); } static void serve_cpu_data(GkrellmdMonitor *mon, gboolean first_serve) { CpuData *cpu; GList *list; gchar buf[128]; gkrellmd_set_serve_name(mon, "cpu"); for (list = cpu_list; list; list = list->next) { cpu = (CpuData *) list->data; snprintf(buf, sizeof(buf), "%d %lu %lu %lu %lu\n", cpu->instance, cpu->user, cpu->nice, cpu->sys, cpu->idle); gkrellmd_serve_data(mon, buf); } } static void serve_cpu_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; GList *list; gchar buf[64]; gkrellmd_send_to_client(client, "\n"); for (list = instance_list; list; list = list->next) { snprintf(buf, sizeof(buf), "cpu_instance %d\n", GPOINTER_TO_INT(list->data)); gkrellmd_send_to_client(client, buf); } gkrellmd_send_to_client(client, n_cpus_setup); if (nice_time_unsupported) gkrellmd_send_to_client(client, "nice_time_unsupported\n"); } static GkrellmdMonitor cpu_monitor = { "cpu", update_cpu, serve_cpu_data, serve_cpu_setup }; static GkrellmdMonitor * init_cpu_monitor(void) { if (gkrellm_sys_cpu_init()) return &cpu_monitor; return NULL; } /* ======================================================= */ struct { gboolean changed; gint n_processes, n_running, n_users; gulong n_forks; gfloat fload; } proc; void gkrellm_proc_assign_data(gint n_processes, gint n_running, gulong n_forks, gfloat load) { if ( proc.n_processes != n_processes || proc.n_running != n_running || proc.n_forks != n_forks || proc.fload != load ) { proc.n_processes = n_processes; proc.n_running = n_running; proc.n_forks = n_forks; proc.fload = load; proc.changed = TRUE; } } void gkrellm_proc_assign_users(gint n_users) { if (proc.n_users != n_users) { proc.n_users = n_users; proc.changed = TRUE; } } static void update_proc(GkrellmdMonitor *mon, gboolean first_update) { proc.changed = FALSE; gkrellm_sys_proc_read_data(); if (first_update || GK.five_second_tick) gkrellm_sys_proc_read_users(); if (proc.changed) gkrellmd_need_serve(mon); } static void serve_proc_data(GkrellmdMonitor *mon, gboolean first_serve) { gchar buf[128]; gkrellmd_set_serve_name(mon, "proc"); snprintf(buf, sizeof(buf), "%d %d %lu %.2f %d\n", proc.n_processes, proc.n_running, proc.n_forks, proc.fload, proc.n_users); gkrellmd_serve_data(mon, buf); } static GkrellmdMonitor proc_monitor = { "proc", update_proc, serve_proc_data, NULL }; static GkrellmdMonitor * init_proc_monitor(void) { if (!gkrellm_sys_proc_init()) return NULL; serveflag_done_list = g_list_append(serveflag_done_list, &proc.changed); return &proc_monitor; } /* ======================================================= */ typedef struct { gchar *name; gchar *subdisk_parent; gint order, subdisk, changed; gint device_number, unit_number; gboolean virtual; guint64 rb, wb; } DiskData; static GList *disk_list; static gint n_disks; static gboolean units_are_blocks; static DiskData * add_disk(const gchar *name, gint order, gint device_number, gint unit_number) { DiskData *disk; GList *list; gint i; disk = g_new0(DiskData, 1); disk->name = g_strdup(name); disk->order = order; disk->subdisk = -1; disk->device_number = device_number; disk->unit_number = unit_number; if (order >= 0) { for (i = 0, list = disk_list; list; list = list->next, ++i) if (disk->order < ((DiskData *) list->data)->order) break; disk_list = g_list_insert(disk_list, disk, i); } else disk_list = g_list_append(disk_list, disk); ++n_disks; return disk; } static DiskData * add_subdisk(gchar *subdisk_name, gchar *disk_name, gint subdisk) { DiskData *sdisk = NULL; DiskData *disk; GList *list = NULL; for (list = disk_list; list; list = list->next) { disk = (DiskData * ) list->data; if (!strcmp(disk_name, disk->name)) break; } if (!list) return NULL; sdisk = g_new0(DiskData, 1); sdisk->name = g_strdup(subdisk_name); sdisk->subdisk_parent = g_strdup(disk_name); sdisk->order = disk->order; sdisk->subdisk = subdisk; for (list = list->next; list; list = list->next) { disk = (DiskData * ) list->data; if (disk->subdisk == -1 || disk->subdisk > subdisk) break; } disk_list = g_list_insert_before(disk_list, list, sdisk); ++n_disks; return sdisk; } static void disk_assign_data(DiskData *disk, guint64 rb, guint64 wb, gboolean virtual) { if (disk) { if (disk->rb != rb || disk->wb != wb) disk->changed = TRUE; else disk->changed = FALSE; disk->rb = rb; disk->wb = wb; disk->virtual = virtual; } } void gkrellm_disk_reset_composite(void) { /* Don't handle this. */ } void gkrellm_disk_units_are_blocks(void) { units_are_blocks = TRUE; } void gkrellm_disk_add_by_name(const gchar *name, const gchar *label) { gint order = -1; if (NULL == name) // Cannot add disk without a name return; order = gkrellm_sys_disk_order_from_name(name); /* FIXME: gkrellmd currently has no support for disk labels. Extend network-protocol and server to support disks with both name and label. */ add_disk(name, order, 0, 0); } void gkrellm_disk_assign_data_by_device(gint device_number, gint unit_number, guint64 rb, guint64 wb, gboolean virtual) { GList *list; DiskData *disk = NULL; gchar *name; gint order = -1; for (list = disk_list; list; list = list->next) { disk = (DiskData * ) list->data; if ( disk->device_number == device_number && disk->unit_number == unit_number ) break; disk = NULL; } if (!disk) { name = gkrellm_sys_disk_name_from_device(device_number, unit_number, &order); if (name) disk = add_disk(name, order, device_number, unit_number); } disk_assign_data(disk, rb, wb, virtual); } void gkrellm_disk_assign_data_nth(gint n, guint64 rb, guint64 wb, gboolean virtual) { DiskData *disk; gchar name[32]; if (n < n_disks) disk = (DiskData *) g_list_nth_data(disk_list, n); else { snprintf(name, sizeof(name), "%s%c", _("Disk"), 'A' + n); disk = add_disk(name, n, 0, 0); } disk_assign_data(disk, rb, wb, virtual); } void gkrellm_disk_assign_data_by_name(gchar *name, guint64 rb, guint64 wb, gboolean virtual) { GList *list; DiskData *disk = NULL; gint order = -1; for (list = disk_list; list; list = list->next) { disk = (DiskData * ) list->data; if (!strcmp(name, disk->name)) break; disk = NULL; } if (!disk) { order = gkrellm_sys_disk_order_from_name(name); disk = add_disk(name, order, 0, 0); } disk_assign_data(disk, rb, wb, virtual); } void gkrellm_disk_subdisk_assign_data_by_name(gchar *subdisk_name, gchar *disk_name, guint64 rb, guint64 wb) { GList *list; DiskData *disk = NULL; gchar *s, *endptr; gint subdisk; if (!subdisk_name || !disk_name) return; for (list = disk_list; list; list = list->next) { disk = (DiskData * ) list->data; if (!strcmp(subdisk_name, disk->name)) break; disk = NULL; } if (!disk) { /* A subdisk name is expected to be the disk_name with a number string | appended. Eg. "hda1" is a subdisk_name of disk_name "hda" */ s = subdisk_name + strlen(disk_name); if (*s == 'p') /* except mmcblkN SD disks have "pN" partition numbers */ ++s; subdisk = strtol(s, &endptr, 0); if (!*s || *endptr) return; disk = add_subdisk(subdisk_name, disk_name, subdisk); } disk_assign_data(disk, rb, wb, FALSE); } static void update_disk(GkrellmdMonitor *mon, gboolean first_update) { GList *list; DiskData *disk = NULL; gkrellm_sys_disk_read_data(); for (list = disk_list; list; list = list->next) { disk = (DiskData * ) list->data; if (disk->changed) { gkrellmd_need_serve(mon); break; } } } static void serve_disk_data(GkrellmdMonitor *mon, gboolean first_serve) { DiskData *disk; GList *list; gchar *buf = NULL; gkrellmd_set_serve_name(mon, "disk"); for (list = disk_list; list; list = list->next) { disk = (DiskData *) list->data; if (!disk->changed && !first_serve) continue; if (!disk->subdisk_parent) { if (gkrellmd_check_client_version(mon, 2, 2, 7) && disk->virtual) buf = g_strdup_printf("%s virtual %" PRIu64 " %" PRIu64 "\n", disk->name, disk->rb, disk->wb); else buf = g_strdup_printf("%s %" PRIu64 " %" PRIu64 "\n", disk->name, disk->rb, disk->wb); } else if (mon->privat->client->feature_subdisk) buf = g_strdup_printf("%s %s %" PRIu64 " %" PRIu64 "\n", disk->name, disk->subdisk_parent, disk->rb, disk->wb); else continue; gkrellmd_serve_data(mon, buf); g_free(buf); buf = NULL; } } static void serve_disk_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; if (units_are_blocks) gkrellmd_send_to_client(client, "\nunits_are_blocks\n"); if (gkrellmd_check_client_version(mon, 2,1,3)) client->feature_subdisk = TRUE; } static GkrellmdMonitor disk_monitor = { "disk", update_disk, serve_disk_data, serve_disk_setup }; static GkrellmdMonitor * init_disk_monitor(void) { if (gkrellm_sys_disk_init()) return &disk_monitor; return NULL; } /* ======================================================= */ #include "../src/inet.h" typedef struct { ActiveTCP tcp; gboolean alive, new_connection; } InetData; static GList *inet_list, *inet_dead_list; static gboolean inet_unsupported, inet_new; void gkrellm_inet_log_tcp_port_data(gpointer data) { GList *list; InetData *in; ActiveTCP *tcp, *active_tcp = NULL; gchar *ap, *aap; gint slen; tcp = (ActiveTCP *) data; for (list = inet_list; list; list = list->next) { in = (InetData *) list->data; active_tcp = &in->tcp; if (tcp->family == AF_INET) { ap = (char *)&tcp->remote_addr; aap = (char *)&active_tcp->remote_addr; slen = sizeof(struct in_addr); } #if defined(INET6) else if (tcp->family == AF_INET6) { ap = (char *)&tcp->remote_addr6; aap = (char *)&active_tcp->remote_addr6; slen = sizeof(struct in6_addr); } #endif else return; if ( memcmp(aap, ap, slen) == 0 && active_tcp->remote_port == tcp->remote_port && active_tcp->local_port == tcp->local_port ) { in->alive = TRUE; /* Old alive connection still alive */ return; } } inet_new = TRUE; in = g_new0(InetData, 1); in->tcp = *tcp; in->alive = TRUE; in->new_connection = TRUE; inet_list = g_list_append(inet_list, in); } static void update_inet(GkrellmdMonitor *mon, gboolean first_update) { GList *list; InetData *in; static gint check_tcp; if (!first_update && !GK.second_tick) return; if (first_update || check_tcp == 0) { gkrellm_free_glist_and_data(&inet_dead_list); inet_new = FALSE; for (list = inet_list; list; list = list->next) { in = (InetData *) list->data; in->alive = FALSE; in->new_connection = FALSE; } gkrellm_sys_inet_read_tcp_data(); for (list = inet_list; list; ) { in = (InetData *) list->data; if (!in->alive) { if (list == inet_list) inet_list = inet_list->next; list = g_list_remove(list, in); inet_dead_list = g_list_append(inet_dead_list, in); } else list = list->next; } if (inet_new || inet_dead_list) gkrellmd_need_serve(mon); } check_tcp = (check_tcp + 1) % _GK.inet_interval; } static void serve_inet_data(GkrellmdMonitor *mon, gboolean first_serve) { InetData *in; ActiveTCP *tcp; GList *list; gchar buf[128], *cp; #if defined(INET6) && defined(HAVE_GETADDRINFO) struct sockaddr_in6 sin6; char addrbuf[NI_MAXHOST]; #endif if (inet_new || first_serve) { gkrellmd_set_serve_name(mon, "inet"); for (list = inet_list; list; list = list->next) { in = (InetData *) list->data; tcp = &in->tcp; if ( tcp->family == AF_INET && (in->new_connection || first_serve) ) { cp = inet_ntoa(tcp->remote_addr); snprintf(buf, sizeof(buf), "+0 %x %s:%x\n", tcp->local_port, cp, tcp->remote_port); } #if defined(INET6) && defined(HAVE_GETADDRINFO) else if (tcp->family == AF_INET6 && (in->new_connection || first_serve)) { memset(&sin6, 0, sizeof(sin6)); memcpy(&sin6.sin6_addr, &tcp->remote_addr6, sizeof(struct in6_addr)); sin6.sin6_family = AF_INET6; #ifdef SIN6_LEN sin6.sin6_len = sizeof(struct sockaddr_in6); #endif if (getnameinfo((struct sockaddr *)&sin6, sizeof(struct sockaddr_in6), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID) != 0) continue; snprintf(buf, sizeof(buf), "+6 %x [%s]:%x\n", tcp->local_port, addrbuf, tcp->remote_port); } #endif else continue; gkrellmd_serve_data(mon, buf); } } if (!first_serve) { gkrellmd_set_serve_name(mon, "inet"); for (list = inet_dead_list; list; list = list->next) { in = (InetData *) list->data; tcp = &in->tcp; if (tcp->family == AF_INET) { cp = inet_ntoa(tcp->remote_addr); snprintf(buf, sizeof(buf), "-0 %x %s:%x\n", tcp->local_port, cp, tcp->remote_port); } #if defined(INET6) && defined(HAVE_GETADDRINFO) else if (tcp->family == AF_INET6) { memset(&sin6, 0, sizeof(sin6)); memcpy(&sin6.sin6_addr, &tcp->remote_addr6, sizeof(struct in6_addr)); sin6.sin6_family = AF_INET6; #ifdef SIN6_LEN sin6.sin6_len = sizeof(struct sockaddr_in6); #endif if (getnameinfo((struct sockaddr *)&sin6, sizeof(struct sockaddr_in6), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID) != 0) continue; snprintf(buf, sizeof(buf), "-6 %x [%s]:%x\n", tcp->local_port, addrbuf, tcp->remote_port); } #endif else continue; gkrellmd_serve_data(mon, buf); } } } static void serve_inet_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; if (inet_unsupported) gkrellmd_send_to_client(client, "\ninet_unsupported\n"); } static GkrellmdMonitor inet_monitor = { "inet", update_inet, serve_inet_data, serve_inet_setup }; static GkrellmdMonitor * init_inet_monitor(void) { if (_GK.inet_interval > 0 && gkrellm_sys_inet_init()) return &inet_monitor; inet_unsupported = TRUE; return NULL; } /* ======================================================= */ #define TIMER_TYPE_NONE 0 #define TIMER_TYPE_PPP 1 #define TIMER_TYPE_IPPP 2 typedef struct { gchar *name; gboolean changed, up, up_prev, up_event, down_event; gboolean timed_changed; time_t up_time; gulong rx, tx; } NetData; static NetData *net_timer; static GList *net_list, *net_sys_list; static time_t net_timer0; static gint net_timer_type; static gboolean net_use_routed; gchar * gkrellm_net_mon_first(void) { gchar *name = NULL; net_sys_list = net_list; if (net_sys_list) { name = ((NetData *) (net_sys_list->data))->name; net_sys_list = net_sys_list->next; } return name; } gchar * gkrellm_net_mon_next(void) { gchar *name = NULL; if (net_sys_list) { name = ((NetData *) (net_sys_list->data))->name; net_sys_list = net_sys_list->next; } return name; } void gkrellm_net_use_routed(gboolean real_routed /* not applicable in server */) { net_use_routed = TRUE; } static NetData * net_new(gchar *name) { NetData *net; net = g_new0(NetData, 1); net->name = g_strdup(name); net_list = g_list_append(net_list, net); if (net_timer_type != TIMER_TYPE_NONE && !strcmp(_GK.net_timer, net->name)) net_timer = net; return net; } void gkrellm_net_assign_data(gchar *name, gulong rx, gulong tx) { GList *list; NetData *net; for (list = net_list; list; list = list->next) { net = (NetData *) list->data; if (!strcmp(net->name, name)) { if (net->rx != rx || net->tx != tx) net->changed = TRUE; else net->changed = FALSE; break; } } if (!list) net = net_new(name); if (GK.second_tick && !net_use_routed) net->up = TRUE; net->rx = rx; net->tx = tx; } void gkrellm_net_routed_event(gchar *name, gboolean routed) { GList *list; NetData *net; for (list = net_list; list; list = list->next) { net = (NetData *) list->data; if (!strcmp(net->name, name)) break; } if (!list) net = net_new(name); if (routed) net->up_event = TRUE; else net->down_event = TRUE; net->up = routed; } void gkrellm_net_add_timer_type_ppp(gchar *name) { if (!_GK.net_timer || !name) return; if (name && !strncmp(_GK.net_timer, name, strlen(name) - 1)) net_timer_type = TIMER_TYPE_PPP; } void gkrellm_net_add_timer_type_ippp(gchar *name) { if (!_GK.net_timer || !name) return; if (name && !strncmp(_GK.net_timer, name, strlen(name) - 1)) net_timer_type = TIMER_TYPE_IPPP; } void gkrellm_net_set_lock_directory(gchar *dir) { /* Not supported remotely */ } static void update_net(GkrellmdMonitor *mon, gboolean first_update) { GList *list; NetData *net; gint up_time = 0; if (GK.second_tick) { if (!net_use_routed) { for (list = net_list; list; list = list->next) { net = (NetData *) list->data; net->up_prev = net->up; net->up = FALSE; } } else gkrellm_sys_net_check_routes(); } gkrellm_sys_net_read_data(); if (GK.second_tick && !net_use_routed) { for (list = net_list; list; list = list->next) { net = (NetData *) list->data; if (net->up && !net->up_prev) net->up_event = TRUE; else if (!net->up && net->up_prev) net->down_event = TRUE; } } if (net_timer && GK.second_tick) { if (net_timer_type == TIMER_TYPE_PPP) { struct stat st; gchar buf[256]; if (net_timer->up_event) { snprintf(buf, sizeof(buf), "/var/run/%s.pid", net_timer->name); if (g_stat(buf, &st) == 0) net_timer0 = st.st_mtime; else time(&net_timer0); } if (net_timer->up) up_time = (int) (time(0) - net_timer0); } else if (net_timer_type == TIMER_TYPE_IPPP) { /* get all isdn status from its connect state because the | net_timer->up can be UP even with isdn line not connected. | Can't get time history if gkrellmd started after connects. */ static gboolean old_connected; gboolean connected; connected = gkrellm_sys_net_isdn_online(); if (connected && !old_connected) time(&net_timer0); /* New session just started */ old_connected = connected; up_time = (int) (time(0) - net_timer0); } if (up_time != net_timer->up_time) net_timer->timed_changed = TRUE; net_timer->up_time = up_time; } gkrellmd_need_serve(mon); /* serve func checks for changed */ } static void serve_net_data(GkrellmdMonitor *mon, gboolean first_serve) { NetData *net; GList *list; gchar buf[128]; gboolean fake_up_event; gkrellmd_set_serve_name(mon, "net"); for (list = net_list; list; list = list->next) { net = (NetData *) list->data; if (net->changed || first_serve) { snprintf(buf, sizeof(buf), "%s %lu %lu\n", net->name, net->rx, net->tx); gkrellmd_serve_data(mon, buf); } } /* Since the server transmits changes only, use the routed interface | to the client regardless if the sysdep code uses routed. */ if (GK.second_tick || first_serve) { gkrellmd_set_serve_name(mon, "net_routed"); for (list = net_list; list; list = list->next) { net = (NetData *) list->data; fake_up_event = (first_serve && net->up); if (net->up_event || net->down_event || fake_up_event) { snprintf(buf, sizeof(buf), "%s %d\n", net->name, fake_up_event ? TRUE : net->up_event); gkrellmd_serve_data(mon, buf); } if (mon->privat->client->last_client) net->up_event = net->down_event = FALSE; } } if (net_timer && GK.second_tick) { if (net_timer->timed_changed || first_serve) { gkrellmd_set_serve_name(mon, "net_timer"); snprintf(buf, sizeof(buf), "%s %d\n", net_timer->name, (gint)net_timer->up_time); gkrellmd_serve_data(mon, buf); } } } static void serve_net_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; gchar buf[128]; /* The client <-> server link always uses routed mode, but the client | needs to know if server sysdep uses routed for config purposes. */ if (net_use_routed) gkrellmd_send_to_client(client, "\nnet_use_routed\n"); if (net_timer_type != TIMER_TYPE_NONE) { snprintf(buf, sizeof(buf), "\nnet_timer %s\n", _GK.net_timer); gkrellmd_send_to_client(client, buf); } } static GkrellmdMonitor net_monitor = { "net", update_net, serve_net_data, serve_net_setup }; static GkrellmdMonitor * init_net_monitor(void) { net_timer_type = TIMER_TYPE_NONE; if (gkrellm_sys_net_init()) return &net_monitor; return NULL; } /* ======================================================= */ struct { gboolean mem_changed; guint64 total, used, free, shared, buffers, cached; gboolean swap_changed; guint64 swap_total, swap_used; gulong swap_in, swap_out; } mem; void gkrellm_mem_assign_data(guint64 total, guint64 used, guint64 free, guint64 shared, guint64 buffers, guint64 cached) { if ( mem.total != total || mem.used != used || mem.free != free || mem.shared != shared || mem.buffers != buffers || mem.cached != cached ) { mem.total = total; mem.used = used; mem.free = free; mem.shared = shared; mem.buffers = buffers; mem.cached = cached; mem.mem_changed = TRUE; } } void gkrellm_swap_assign_data(guint64 total, guint64 used, gulong swap_in, gulong swap_out) { if ( mem.swap_total != total || mem.swap_used != used || mem.swap_in != swap_in || mem.swap_out != swap_out ) { mem.swap_total = total; mem.swap_used = used; mem.swap_in = swap_in; mem.swap_out = swap_out; mem.swap_changed = TRUE; } } static void update_mem(GkrellmdMonitor *mon, gboolean first_update) { mem.mem_changed = mem.swap_changed = FALSE; gkrellm_sys_swap_read_data(); if (first_update || GK.five_second_tick) gkrellm_sys_mem_read_data(); if (mem.mem_changed || mem.swap_changed) gkrellmd_need_serve(mon); } static void serve_mem_data(GkrellmdMonitor *mon, gboolean first_serve) { gchar buf[128]; if (mem.mem_changed || first_serve) { gkrellmd_set_serve_name(mon, "mem"); snprintf(buf, sizeof(buf), "%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", mem.total, mem.used, mem.free, mem.shared, mem.buffers, mem.cached); gkrellmd_serve_data(mon, buf); } if (mem.swap_changed || first_serve) { gkrellmd_set_serve_name(mon, "swap"); snprintf(buf, sizeof(buf), "%" PRIu64 " %" PRIu64 " %lu %lu\n", mem.swap_total, mem.swap_used, mem.swap_in, mem.swap_out); gkrellmd_serve_data(mon, buf); } } static GkrellmdMonitor mem_monitor = { "mem", update_mem, serve_mem_data, NULL }; static GkrellmdMonitor * init_mem_monitor(void) { if (!gkrellm_sys_mem_init()) return NULL; serveflag_done_list = g_list_append(serveflag_done_list, &mem.mem_changed); serveflag_done_list = g_list_append(serveflag_done_list,&mem.swap_changed); return &mem_monitor; } /* ======================================================= */ typedef struct { gboolean busy, deleted, is_mounted, is_nfs, changed; gchar *directory, *device, *type, *options; gint64 blocks, bavail, bfree, bsize; } Mount; static GList *mounts_list, *fstab_list; static gboolean nfs_check, fs_check, fs_need_serve, fstab_list_modified, mounts_list_modified, mounting_unsupported; static gchar *remote_fs_types[] = { "cifs", "nfs", "smbfs" }; void gkrellm_fs_setup_eject(gchar *eject_tray, gchar *close_tray, void (*eject_func)(), void (*close_func)()) { /* Not supported remotely */ } void gkrellm_fs_add_to_mounts_list(gchar *dir, gchar *dev, gchar *type) { GList *list; Mount *m; gint i; for (list = mounts_list; list; list = list->next) { m = (Mount *) list->data; if ( !strcmp(m->directory, dir) && !strcmp(m->device, dev) && !strcmp(m->type, type) ) break; } if (!list) { m = g_new0(Mount, 1); m->directory = g_strdup(dir); m->device = g_strdup(dev); m->type = g_strdup(type); mounts_list = g_list_append(mounts_list, m); mounts_list_modified = TRUE; serveflag_done_list = g_list_append(serveflag_done_list, &m->changed); for (i = 0; i < (sizeof(remote_fs_types) / sizeof(gchar *)); ++i) { if (!strcmp(m->type, remote_fs_types[i])) { m->is_nfs = TRUE; break; } } } m->is_mounted = TRUE; } void gkrellm_fs_add_to_fstab_list(gchar *dir, gchar *dev, gchar *type, gchar *opt) { Mount *m; m = g_new0(Mount, 1); m->directory = g_strdup(dir); m->device = g_strdup(dev); m->type = g_strdup(type); fstab_list = g_list_append(fstab_list, m); } void gkrellm_fs_assign_fsusage_data(gpointer pointer, gint64 blocks, gint64 bavail, gint64 bfree, gint64 bsize) { Mount *m = (Mount *) pointer; if ( m->blocks != blocks || m->bavail != bavail || m->bfree != bfree || m->bsize != bsize ) { m->blocks = blocks; m->bavail = bavail; m->bfree = bfree; m->bsize = bsize; m->changed = TRUE; } } void gkrellm_fs_mounting_unsupported(void) { mounting_unsupported = TRUE; } static void refresh_mounts_list(void) { GList *list; Mount *m; for (list = mounts_list; list; list = list->next) ((Mount *) list->data)->is_mounted = FALSE; gkrellm_sys_fs_get_mounts_list(); for (list = mounts_list; list; ) { m = (Mount *) list->data; if (!m->is_mounted) { if (list == mounts_list) mounts_list = mounts_list->next; list = g_list_remove_link(list, list); g_free(m->directory); g_free(m->device); g_free(m->type); serveflag_done_list = g_list_remove(serveflag_done_list, &m->changed); if (m->busy) m->deleted = TRUE; else g_free(m); mounts_list_modified = TRUE; } else list = list->next; } } static void refresh_fstab_list(void) { Mount *m; while (fstab_list) { m = (Mount *) fstab_list->data; g_free(m->directory); g_free(m->device); g_free(m->type); g_free(m); fstab_list = g_list_remove(fstab_list, fstab_list->data); } gkrellm_sys_fs_get_fstab_list(); fstab_list_modified = TRUE; } static gpointer get_fsusage_thread(void *data) { Mount *m = (Mount *) data; gkrellm_sys_fs_get_fsusage(m, m->directory); if (m->deleted) g_free(m); else { if (m->changed) fs_need_serve = TRUE; m->busy = FALSE; } return NULL; } static void update_fs(GkrellmdMonitor *mon, gboolean first_update) { GThread *gth; GList *list; Mount *m; static gint check_tick; if (fs_need_serve) /* Asynchronous change in fsusage thread? */ gkrellmd_need_serve(mon); fs_need_serve = FALSE; if (GK.second_tick) ++check_tick; fs_check = !(check_tick % _GK.fs_interval); if (_GK.nfs_interval > 0) nfs_check = !(check_tick % _GK.nfs_interval); else nfs_check = 0; if (!first_update && (!GK.second_tick || (!fs_check && !nfs_check))) return; refresh_mounts_list(); for (list = mounts_list; list; list = list->next) { m = (Mount *) list->data; if (fs_check && !m->is_nfs) gkrellm_sys_fs_get_fsusage(m, m->directory); else if (nfs_check && m->is_nfs && !m->busy) { m->busy = TRUE; gth = g_thread_new("get_fsusage", get_fsusage_thread, m); g_thread_unref(gth); } } if (first_update || gkrellm_sys_fs_fstab_modified()) refresh_fstab_list(); gkrellmd_need_serve(mon); } static void serve_fs_data(GkrellmdMonitor *mon, gboolean first_serve) { Mount *m; GList *list; gchar buf[128]; if (mounts_list_modified || first_serve) { gkrellmd_set_serve_name(mon, "fs_mounts"); gkrellmd_serve_data(mon, ".clear\n"); for (list = mounts_list; list; list = list->next) { m = (Mount *) list->data; snprintf(buf, sizeof(buf), "%s %s %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", m->directory, m->device, m->type, m->blocks, m->bavail, m->bfree, m->bsize); /*gkrellm_debug(DEBUG_SERVER, "Adding mount-line for %s to serve-data\n", m->directory);*/ gkrellmd_serve_data(mon, buf); } } else { gkrellmd_set_serve_name(mon, "fs"); for (list = mounts_list; list; list = list->next) { m = (Mount *) list->data; if (!m->changed) continue; snprintf(buf, sizeof(buf), "%s %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", m->directory, m->device, m->blocks, m->bavail, m->bfree, m->bsize); /*gkrellm_debug(DEBUG_SERVER, "Updating fs %s in serve-data\n", m->directory);*/ gkrellmd_serve_data(mon, buf); } } if (fstab_list_modified || first_serve) { gkrellmd_set_serve_name(mon, "fs_fstab"); gkrellmd_serve_data(mon, ".clear\n"); for (list = fstab_list; list; list = list->next) { m = (Mount *) list->data; snprintf(buf, sizeof(buf), "%s %s %s\n", m->directory, m->device, m->type); /*gkrellm_debug(DEBUG_SERVER, "Adding fstab-line for %s to serve-data\n", m->directory);*/ gkrellmd_serve_data(mon, buf); } } } static void serve_fs_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; if (mounting_unsupported) gkrellmd_send_to_client(client, "\nmounting_unsupported\n"); } static GkrellmdMonitor fs_monitor = { "fs", update_fs, serve_fs_data, serve_fs_setup }; static GkrellmdMonitor * init_fs_monitor(void) { if (!gkrellm_sys_fs_init()) return NULL; serveflag_done_list = g_list_append(serveflag_done_list, &fstab_list_modified); serveflag_done_list = g_list_append(serveflag_done_list, &mounts_list_modified); return &fs_monitor; } /* ======================================================= */ typedef struct { gboolean changed, have_data; gint id; gboolean present, on_line, charging; gint percent; gint time_left; } Battery; static GList *battery_list; static Battery *composite_battery; static Battery * battery_nth(gint n) { Battery *bat; static gint n_batteries; if (n > 10) return NULL; if (n < 0) { if (!composite_battery) { bat = g_new0(Battery, 1); battery_list = g_list_prepend(battery_list, bat); bat->id = GKRELLM_BATTERY_COMPOSITE_ID; composite_battery = bat; serveflag_done_list = g_list_append(serveflag_done_list, &composite_battery->changed); } return composite_battery; } if (composite_battery) ++n; while ((bat = (Battery *)g_list_nth_data(battery_list, n)) == NULL) { bat = g_new0(Battery, 1); battery_list = g_list_append(battery_list, bat); bat->id = n_batteries++; serveflag_done_list = g_list_append(serveflag_done_list, &bat->changed); } return bat; } void gkrellm_battery_assign_data(gint id, gboolean present, gboolean on_line, gboolean charging, gint percent, gint time_left) { Battery *bat; bat = battery_nth(id); if (!bat) return; if ( present != bat->present || on_line != bat->on_line || charging != bat->charging || percent != bat->percent || time_left != bat->time_left ) { bat->present = present; bat->on_line = on_line; bat->charging = charging; bat->percent = percent; bat->time_left = time_left; bat->changed = TRUE; } bat->have_data = TRUE; } gint gkrellm_battery_full_cap_fallback() { return 5000; /* XXX Linux ACPI bug not handled by server */ } static void update_battery(GkrellmdMonitor *mon, gboolean first_update) { GList *list; Battery *bat; if (!first_update && !GK.five_second_tick) return; for (list = battery_list; list; list = list->next) { bat = (Battery *) list->data; bat->have_data = FALSE; bat->changed = FALSE; } gkrellm_sys_battery_read_data(); for (list = battery_list; list; list = list->next) { bat = (Battery *) list->data; if (!bat->have_data && bat->present) { bat->present = FALSE; bat->changed = TRUE; } if (bat->changed) gkrellmd_need_serve(mon); } } static void serve_battery_data(GkrellmdMonitor *mon, gboolean first_serve) { Battery *bat; GList *list; gchar buf[128]; gkrellmd_set_serve_name(mon, "battery"); for (list = battery_list; list; list = list->next) { bat = (Battery *) list->data; if ( (!bat->changed && !first_serve) || ( !gkrellmd_check_client_version(mon, 2,1,9) && bat->id > 0 ) ) continue; snprintf(buf, sizeof(buf), "%d %d %d %d %d %d\n", bat->present, bat->on_line, bat->charging, bat->percent, bat->time_left, bat->id); gkrellmd_serve_data(mon, buf); } } static void serve_battery_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; gkrellm_sys_battery_read_data(); if (battery_list) gkrellmd_send_to_client(client, "\nbattery_available\n"); } static GkrellmdMonitor battery_monitor = { "battery", update_battery, serve_battery_data, serve_battery_setup }; static GkrellmdMonitor * init_battery_monitor(void) { if (!gkrellm_sys_battery_init()) return NULL; return &battery_monitor; } /* ======================================================= */ typedef struct { gboolean changed; gint type; gchar *path; /* Pathname to sensor data or device file */ gchar *id_name; /* These 4 are unique sensor identification */ gint id; /* of a particular sensor type */ gint iodev; /* One or any combination may be used. */ gint inter; gchar *vref; gchar *default_label; gint group; gfloat factor; gfloat offset; gfloat raw_value; } Sensor; static GList *sensors_list; static gboolean thread_busy, sensors_need_serve; static gpointer read_sensors(void *data) { GList *list; Sensor *sensor; gfloat tmp; gboolean need_serve = FALSE; for (list = sensors_list; list; list = list->next) { sensor = (Sensor *) list->data; tmp = sensor->raw_value; if (sensor->type == SENSOR_TEMPERATURE) gkrellm_sys_sensors_get_temperature(sensor->path, sensor->id, sensor->iodev, sensor->inter, &sensor->raw_value); else if (sensor->type == SENSOR_FAN) gkrellm_sys_sensors_get_fan(sensor->path, sensor->id, sensor->iodev, sensor->inter, &sensor->raw_value); else if (sensor->type == SENSOR_VOLTAGE) gkrellm_sys_sensors_get_voltage(sensor->path, sensor->id, sensor->iodev, sensor->inter, &sensor->raw_value); if (sensor->raw_value != tmp) { sensor->changed = TRUE; need_serve = TRUE; } else sensor->changed = FALSE; } thread_busy = FALSE; sensors_need_serve = need_serve; /* Thread, so set after data collected */ return NULL; } static void run_sensors_thread(void) { GThread *gth; if (thread_busy) return; thread_busy = TRUE; gth = g_thread_new("read_sensors", read_sensors, NULL); g_thread_unref(gth); } void gkrellm_sensors_config_migrate_connect(gboolean (*func)(), gint sysdep_version) { } void gkrellm_sensors_update_volt_order_base(void) { } void gkrellm_sensors_set_group(gpointer sr, gint group) { Sensor *sensor = (Sensor *) sr; if (sensor) sensor->group = group; } void gkrellm_sensors_sysdep_option(gchar *keyword, gchar *label, void (*func)()) { } /* A sensor within a type is uniquely identified by its id_name. | A sysdep interface may additionally use any of the triple integer | set (id, iodev, inter) for internal identification. | Monitor code here uses path to read the sensor values, but id_name is only | passed to the client since that is all that is needed for identification | (the client is no longer interfacing to sysdep code). */ gpointer gkrellm_sensors_add_sensor(gint type, gchar *sensor_path, gchar *id_name, gint id, gint iodev, gint inter, gfloat factor, gfloat offset, gchar *vref, gchar *default_label) { Sensor *sensor; if (!id_name || !*id_name || type < 0 || type > 2) return NULL; sensor = g_new0(Sensor, 1); sensor->id_name = g_strdup(id_name); if (sensor_path) sensor->path = g_strdup(sensor_path); else sensor->path = g_strdup(id_name); sensor->vref = g_strdup(vref ? vref : "NONE"); sensor->default_label = g_strdup(default_label ? default_label : "NONE"); sensor->factor = factor; sensor->offset = offset; sensor->type = type; sensor->id = id; sensor->iodev = iodev; sensor->inter = inter; sensors_list = g_list_append(sensors_list, sensor); return sensor; } static void update_sensors(GkrellmdMonitor *mon, gboolean first_update) { if (sensors_need_serve) /* Asynchronously set in thread */ gkrellmd_need_serve(mon); sensors_need_serve = FALSE; if (!GK.five_second_tick && !first_update) return; if (first_update) read_sensors(NULL); /* No thread on first read */ else run_sensors_thread(); } static void serve_sensors_data(GkrellmdMonitor *mon, gboolean first_serve) { Sensor *sr; GList *list; gchar buf[128]; gboolean sensor_disk_ok; gkrellmd_set_serve_name(mon, "sensors"); sensor_disk_ok = gkrellmd_check_client_version(mon, 2,2,0); for (list = sensors_list; list; list = list->next) { sr = (Sensor *) list->data; if (sr->group == SENSOR_GROUP_DISK && !sensor_disk_ok) continue; if (sr->changed || first_serve) { snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.2f\n", sr->type, sr->id_name, sr->id, sr->iodev, sr->inter, sr->raw_value); gkrellmd_serve_data(mon, buf); } } } static void serve_sensors_setup(GkrellmdMonitor *mon) { GkrellmdClient *client = mon->privat->client; GList *list; Sensor *s; gchar buf[256]; gboolean sensor_disk_ok; gkrellmd_send_to_client(client, "\n"); sensor_disk_ok = gkrellmd_check_client_version(mon, 2,2,0); for (list = sensors_list; list; list = list->next) { s = (Sensor *) list->data; if (s->group == SENSOR_GROUP_DISK && !sensor_disk_ok) continue; if (sensor_disk_ok) snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.4f %.4f \"%s\" \"%s\" %d\n", s->type, s->id_name, s->id, s->iodev, s->inter, s->factor, s->offset, s->vref, s->default_label, s->group); else snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.4f %.4f \"%s\" \"%s\"\n", s->type, s->id_name, s->id, s->iodev, s->inter, s->factor, s->offset, s->vref, s->default_label); gkrellmd_send_to_client(client, buf); } } static GkrellmdMonitor sensors_monitor = { "sensors", update_sensors, serve_sensors_data, serve_sensors_setup }; static GkrellmdMonitor * init_sensors_monitor(void) { if (!gkrellm_sys_sensors_init()) return NULL; return &sensors_monitor; } /* ======================================================= */ static time_t base_uptime, up_seconds; static gulong up_minutes = -1; void gkrellm_uptime_set_base_uptime(time_t base) { base_uptime = base; } static void update_uptime(GkrellmdMonitor *mon, gboolean first_update) { gint prev_up; if (GK.ten_second_tick || up_minutes < 0 || first_update) { prev_up = up_minutes; up_seconds = gkrellm_sys_uptime_read_uptime(); if (up_seconds > 0) up_minutes = (gint) (up_seconds / 60); else up_minutes = (gint)(time(0) - _GK.start_time + base_uptime) / 60; if (up_minutes != prev_up) gkrellmd_need_serve(mon); } } static void serve_uptime_data(GkrellmdMonitor *mon, gboolean first_serve) { gchar buf[128]; gkrellmd_set_serve_name(mon, "uptime"); snprintf(buf, sizeof(buf), "%lu\n", (gulong) up_minutes); gkrellmd_serve_data(mon, buf); } static GkrellmdMonitor uptime_monitor = { "uptime", update_uptime, serve_uptime_data, NULL }; static GkrellmdMonitor * init_uptime_monitor(void) { if (!gkrellm_sys_uptime_init()) return NULL; return &uptime_monitor; } /* ======================================================= */ static void send_time(GkrellmdClient *client) { struct tm *t; gchar buf[128]; t = &gkrellmd_current_tm; snprintf(buf, sizeof(buf), "