Add Power Management (PM) agent - this RFE was received from users.
It provides pm_set_profile, pm_get_profile, and pm_list_profiles
methods for setting, getting, and listing all available PM profiles.
For PM profiles handling it uses "tuned" on Linux and "powercfg" on
Windows. Functionality was tested on F15 and Windows Server 2008 R2.
In the future we could extend it to support power capping and
power consumption sensors reading (on supported HW platforms)
thanks & regards
Jaroslav Škarvada
SIGs/PowerManagement
---
CMakeLists.txt | 3 +
matahari.spec | 45 +++++
src/CMakeLists.txt | 1 +
src/include/matahari/pm.h | 70 +++++++
src/lib/CMakeLists.txt | 6 +-
src/lib/pm.c | 45 +++++
src/lib/pm_linux.c | 335 +++++++++++++++++++++++++++++++++
src/lib/pm_private.h | 39 ++++
src/lib/pm_windows.c | 301 +++++++++++++++++++++++++++++
src/pm/CMakeLists.txt | 61 ++++++
src/pm/org.matahariproject.PM.conf | 18 ++
src/pm/org.matahariproject.PM.policy | 27 +++
src/pm/org.matahariproject.PM.service | 4 +
src/pm/pm-dbus.c | 148 +++++++++++++++
src/pm/pm-qmf.cpp | 116 ++++++++++++
src/pm/schema.xml | 21 ++
src/schema.xml | 18 ++
src/windows/install.bat | 2 +-
18 files changed, 1258 insertions(+), 2 deletions(-)
create mode 100644 src/include/matahari/pm.h
create mode 100644 src/lib/pm.c
create mode 100644 src/lib/pm_linux.c
create mode 100644 src/lib/pm_private.h
create mode 100644 src/lib/pm_windows.c
create mode 100644 src/pm/CMakeLists.txt
create mode 100644 src/pm/org.matahariproject.PM.conf
create mode 100644 src/pm/org.matahariproject.PM.policy
create mode 100644 src/pm/org.matahariproject.PM.service
create mode 100644 src/pm/pm-dbus.c
create mode 100644 src/pm/pm-qmf.cpp
create mode 100644 src/pm/schema.xml
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e4daf05..a656085 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -79,15 +79,18 @@ if(WIN32)
set( CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS ${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}
" Some comment\\n DetailPrint \\\"Stopping Matahari
services\\\"\\n"
" Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe stop
mh_hostd\\\"'\\n"
+ " Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe stop
mh_pmd\\\"'\\n"
" Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe stop
mh_netd\\\"'\\n"
" Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe stop
mh_serviced\\\"'\\n"
" Give them time to stop\\n Sleep 10000\\n"
" Some comment\\n DetailPrint \\\"Removing Matahari
services\\\"\\n"
" Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe delete
mh_hostd\\\"'\\n"
+ " Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe delete
mh_pmd\\\"'\\n"
" Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe delete
mh_netd\\\"'\\n"
" Some comment\\n ExecWait '\\\"$SYSDIR\\\\sc.exe delete
mh_serviced\\\"'\\n"
" Some comment\\n DetailPrint \\\"Removing Matahari service
binaries\\\"\\n"
" Some comment\\n ExecWait 'del
\\\"$INSTDIR\\\\mh_hostd.exe\\\"'\\n"
+ " Some comment\\n ExecWait 'del
\\\"$INSTDIR\\\\mh_pmd.exe\\\"'\\n"
" Some comment\\n ExecWait 'del
\\\"$INSTDIR\\\\mh_netd.exe\\\"'\\n"
" Some comment\\n ExecWait 'del
\\\"$INSTDIR\\\\mh_serviced.exe\\\"'\\n"
)
diff --git a/matahari.spec b/matahari.spec
index a52b1d7..f0e8ffa 100644
--- a/matahari.spec
+++ b/matahari.spec
@@ -107,6 +107,17 @@ Requires: %{name}-agent-lib = %{version}-%{release}
%description host
QMF agent for viewing and controlling remote hosts
+%package pm
+License: GPLv2+
+Summary: QMF agent for PM
+Group: Applications/System
+Requires: %{name}-lib = %{version}-%{release}
+Requires: %{name}-agent-lib = %{version}-%{release}
+Requires: tuned
+
+%description pm
+QMF agent for viewing and controlling power management settings
+
%package network
License: GPLv2+
Summary: QMF agent for network devices
@@ -202,6 +213,22 @@ if [ "$1" -ge "1" ]; then
/sbin/service matahari-host condrestart >/dev/null 2>&1 || :
fi
+#== PM
+
+%post pm
+/sbin/service matahari-pm condrestart
+
+%preun pm
+if [ $1 = 0 ]; then
+ /sbin/service matahari-pm stop >/dev/null 2>&1 || :
+ chkconfig --del matahari-pm
+fi
+
+%postun pm
+if [ "$1" -ge "1" ]; then
+ /sbin/service matahari-pm condrestart >/dev/null 2>&1 || :
+fi
+
#== Network
%post network
@@ -297,6 +324,7 @@ test "x%{buildroot}" != "x" && rm -rf
%{buildroot}
%defattr(644, root, root, 755)
%{_libdir}/libmcommon.so.*
%{_libdir}/libmhost.so.*
+%{_libdir}/libmpm.so.*
%{_libdir}/libmnetwork.so.*
%{_libdir}/libmservice.so.*
%{_libdir}/libmconfig.so.*
@@ -328,6 +356,19 @@ test "x%{buildroot}" != "x" && rm -rf
%{buildroot}
%attr(755, root, root) %{_sbindir}/matahari-dbus-hostd
%endif
+%files pm
+%defattr(644, root, root, 755)
+%doc AUTHORS COPYING
+
+%if %{with qmf}
+%attr(755, root, root) %{_initddir}/matahari-pm
+%attr(755, root, root) %{_sbindir}/matahari-qmf-pmd
+%endif
+
+%if %{with dbus}
+%attr(755, root, root) %{_sbindir}/matahari-dbus-pmd
+%endif
+
%files service
%defattr(644, root, root, 755)
%doc AUTHORS COPYING
@@ -372,15 +413,19 @@ test "x%{buildroot}" != "x" && rm -rf
%{buildroot}
%if %{with dbus}
%files dbus
%{_sysconfdir}/dbus-1/system.d/org.matahariproject.Host.conf
+%{_sysconfdir}/dbus-1/system.d/org.matahariproject.PM.conf
%{_sysconfdir}/dbus-1/system.d/org.matahariproject.Network.conf
%{_sysconfdir}/dbus-1/system.d/org.matahariproject.Services.conf
%{_datadir}/dbus-1/interfaces/org.matahariproject.Host.xml
+%{_datadir}/dbus-1/interfaces/org.matahariproject.PM.xml
%{_datadir}/dbus-1/interfaces/org.matahariproject.Network.xml
%{_datadir}/dbus-1/interfaces/org.matahariproject.Services.xml
%{_datadir}/dbus-1/system-services/org.matahariproject.Host.service
+%{_datadir}/dbus-1/system-services/org.matahariproject.PM.service
%{_datadir}/dbus-1/system-services/org.matahariproject.Network.service
%{_datadir}/dbus-1/system-services/org.matahariproject.Services.service
%{_datadir}/polkit-1/actions/org.matahariproject.Host.policy
+%{_datadir}/polkit-1/actions/org.matahariproject.PM.policy
%{_datadir}/polkit-1/actions/org.matahariproject.Network.policy
%{_datadir}/polkit-1/actions/org.matahariproject.Services.policy
%endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d3fd72f..e238ed1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -131,6 +131,7 @@ endif(WITH-QMF)
### Subdirectories
add_subdirectory(lib)
add_subdirectory(host)
+add_subdirectory(pm)
add_subdirectory(network)
add_subdirectory(service)
add_subdirectory(config)
diff --git a/src/include/matahari/pm.h b/src/include/matahari/pm.h
new file mode 100644
index 0000000..4857a47
--- /dev/null
+++ b/src/include/matahari/pm.h
@@ -0,0 +1,70 @@
+/* ph.h - Copyright (C) 2011 Red Hat, Inc.
+ * Written by Jaroslav Škarvada <jskarvad(a)redhat.com>
+ * Based on code from Arjun Roy <arroy(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This software 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * \file
+ * \brief PM API
+ * \ingroup coreapi
+ */
+
+#ifndef __MH_PM_H__
+#define __MH_PM_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#define TIMEOUT 10
+#define TA_PATH "/usr/bin/"
+#define TA_SETPROFILE "profile"
+#define TA_GETPROFILE "active"
+#define TA_LISTPROFILES "list"
+#define TA_OFF "off"
+#define TUNEDADM TA_PATH "tuned-adm"
+
+#define SYSTEM32 "system32"
+#define POWERCFG "powercfg"
+#define PC_SETPROFILE "-SETACTIVE"
+#define PC_GETPROFILE "-GETACTIVESCHEME"
+#define PC_LISTPROFILES "-LIST"
+
+#define STR_UNK "UNKNOWN"
+#define STR_ERR "ERROR"
+
+enum exec_exitcode {
+ EC_OK = 0,
+ EC_UNKNOWN_ERROR = 1,
+ EC_INVALID_PARAM = 2,
+ EC_UNIMPLEMENT_FEATURE = 3,
+ EC_INSUFFICIENT_PRIV = 4,
+ EC_NOT_INSTALLED = 5,
+
+ /* 150-199<>reserved for application use */
+ EC_SIGNAL = 194,
+ EC_NOT_SUPPORTED = 195,
+ EC_PENDING = 196,
+ EC_CANCELLED = 197,
+ EC_TIMEOUT = 198,
+ EC_OTHER_ERROR = 199, /* Keep the same codes as LSB */
+};
+
+extern gboolean mh_pm_set_profile(const char *profile);
+extern const char *mh_pm_get_profile(void);
+extern GList *mh_pm_list_profiles(void);
+
+#endif // __MH_PM_H__
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index d33057b..fc48c74 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -1,6 +1,6 @@
# Library
-set(LIBS mcommon mhost mnetwork mservice mconfig)
+set(LIBS mcommon mhost mnetwork mpm mservice mconfig)
include_directories(${pcre_INCLUDE_DIRS})
# See
http://sourceware.org/autobook/autobook/autobook_91.html for
@@ -18,6 +18,10 @@ add_library (mnetwork SHARED network.c network_${VARIANT}.c)
set_target_properties(mnetwork PROPERTIES SOVERSION 1.0.0)
target_link_libraries(mnetwork ${pcre_LIBRARIES} mcommon ${SIGAR} ${glib_LIBRARIES})
+add_library (mpm SHARED pm.c pm_${VARIANT}.c)
+set_target_properties(mpm PROPERTIES SOVERSION 1.0.0)
+target_link_libraries(mpm ${pcre_LIBRARIES} mcommon ${SIGAR} ${glib_LIBRARIES})
+
add_library (mservice SHARED services.c services_${VARIANT}.c)
set_target_properties(mservice PROPERTIES SOVERSION 1.0.0)
target_link_libraries(mservice ${pcre_LIBRARIES} mcommon ${SIGAR} ${glib_LIBRARIES})
diff --git a/src/lib/pm.c b/src/lib/pm.c
new file mode 100644
index 0000000..a413c94
--- /dev/null
+++ b/src/lib/pm.c
@@ -0,0 +1,45 @@
+/* pm.c - Copyright (C) 2011 Red Hat, Inc.
+ * Written by Jaroslav Škarvada <andrew(a)beekhof.net>
+ * Based on code from Andrew Beekhof <andrew(a)beekhof.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This software 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef WIN32
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <glib.h>
+#include "matahari/pm.h"
+#include "matahari/logging.h"
+#include "pm_private.h"
+
+MH_TRACE_INIT_DATA(mh_pm);
+
+gboolean mh_pm_set_profile(const char* profile)
+{
+ return pm_set_profile(profile);
+}
+
+const char *mh_pm_get_profile(void)
+{
+ return pm_get_profile();
+}
+
+GList *mh_pm_list_profiles(void)
+{
+ return pm_list_profiles();
+}
diff --git a/src/lib/pm_linux.c b/src/lib/pm_linux.c
new file mode 100644
index 0000000..db8821e
--- /dev/null
+++ b/src/lib/pm_linux.c
@@ -0,0 +1,335 @@
+/* pm_linux.c - Copyright (C) 2011 Red Hat, Inc.
+ * Written by Jaroslav Škarvada <jskarvad(a)redhat.com>
+ * Based on code from Andrew Beekhof <andrew(a)beekhof.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This software 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#include "matahari/logging.h"
+#include "matahari/pm.h"
+#include "host_private.h"
+#include "sigar.h"
+
+static gboolean read_output(int fd, char **data)
+{
+ int rc = 0, len = 0;
+ char buf[500];
+ static const size_t bufsize = sizeof(buf);
+
+ if (*data)
+ len = strlen(*data);
+
+ do {
+ rc = read(fd, buf, bufsize - 1);
+ if (rc > 0) {
+ buf[rc] = 0;
+ *data = realloc(*data, len + rc + 1);
+ snprintf(*data + len, bufsize, "%s", buf);
+ len += rc;
+
+ } else if (errno != EINTR)
+ return FALSE;
+ } while (rc == bufsize - 1 || rc < 0);
+
+ return TRUE;
+}
+
+static int exec_command(const char *command, int atimeout, char **stdoutbuf,
+ char **stderrbuf, char *const argv[])
+{
+ pid_t pid;
+ int fd, rc = 0;
+ int stdout_fd[2];
+ int stderr_fd[2];
+
+ if (! command)
+ return EC_OTHER_ERROR;
+
+ if (pipe(stdout_fd) < 0) {
+ mh_perror(LOG_ERR, "pipe() failed");
+ }
+ if (pipe(stderr_fd) < 0) {
+ mh_perror(LOG_ERR, "pipe() failed");
+ }
+ pid = fork();
+
+ switch (pid) {
+ case -1:
+ mh_perror(LOG_ERR, "fork() failed");
+ close(stdout_fd[0]);
+ close(stdout_fd[1]);
+ close(stderr_fd[0]);
+ close(stderr_fd[1]);
+ return EC_OTHER_ERROR;
+ /* Child. */
+ case 0:
+ setpgid(0, 0);
+ close(stdout_fd[0]);
+ close(stderr_fd[0]);
+ if (STDOUT_FILENO != stdout_fd[1]) {
+ if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ mh_perror(LOG_ERR, "dup2() failed (stdout)");
+ }
+ close(stdout_fd[1]);
+ }
+ if (STDERR_FILENO != stderr_fd[1]) {
+ if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
+ mh_perror(LOG_ERR, "dup2() failed (stderr)");
+ }
+ close(stderr_fd[1]);
+ }
+
+ /* close all descriptors except stdin/out/err and channels to logd */
+ for (fd = getdtablesize() - 1; fd > STDERR_FILENO; fd--)
+ close(fd);
+
+ /* execute the command */
+ execvp(command, argv);
+
+ switch (errno) { /* see execvp */
+ case ENOENT: /* No such file or directory */
+ case EISDIR: /* Is a directory */
+ rc = EC_NOT_INSTALLED;
+ break;
+ case EACCES: /* permission denied (various errors) */
+ rc = EC_INSUFFICIENT_PRIV;
+ break;
+ default:
+ rc = EC_UNKNOWN_ERROR;
+ break;
+ }
+ exit(rc);
+ }
+ /* Only the parent reaches here */
+ close(stdout_fd[1]);
+ close(stderr_fd[1]);
+
+ int status = 0;
+ int timeout = atimeout;
+ mh_trace("Waiting for %d", pid);
+ while (timeout > 0 && waitpid(pid, &status, WNOHANG) <= 0) {
+ sleep(1);
+ timeout--;
+ }
+
+ if (timeout == 0) {
+ int killrc = sigar_proc_kill(pid, SIGKILL);
+
+ rc = EC_TIMEOUT;
+ mh_warn("%d - timed out after %dms", pid, atimeout);
+
+ if (killrc != SIGAR_OK && killrc != ESRCH) {
+ mh_err("kill(%d, KILL) failed: %d", pid, killrc);
+ }
+
+ } else if (WIFEXITED(status)) {
+ rc = WEXITSTATUS(status);
+ mh_err("Managed process %d exited with rc=%d", pid, rc);
+
+ } else if (WIFSIGNALED(status)) {
+ int signo = WTERMSIG(status);
+ rc = EC_SIGNAL;
+ mh_err("Managed process %d exited with signal=%d", pid, signo);
+ }
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status)) {
+ rc = EC_OTHER_ERROR;
+ mh_err("Managed process %d dumped core", pid);
+ }
+#endif
+ mh_trace("Child done: %d", pid);
+
+ read_output(stdout_fd[0], stdoutbuf);
+ read_output(stderr_fd[0], stderrbuf);
+
+ close(stdout_fd[0]);
+ close(stdout_fd[0]);
+ return rc;
+}
+
+
+GList *pm_list_profiles(void)
+{
+ char *stdoutbuf = NULL;
+ char *stderrbuf = NULL;
+ char *c1, *c2;
+ char *args[3] = {0};
+ int cnt = 0;
+ GList *list = NULL;
+ gboolean rc;
+
+ args[0] = TUNEDADM;
+ args[1] = TA_LISTPROFILES;
+ args[2] = NULL;
+
+ rc = exec_command(args[0], TIMEOUT, &stdoutbuf, &stderrbuf, args) == EC_OK;
+
+ if (stdoutbuf) {
+ mh_trace(" > stdout: %s", stdoutbuf);
+ }
+ if (stderrbuf) {
+ mh_trace(" > stderr: %s", stderrbuf);
+ free(stderrbuf);
+ }
+
+ if (rc && stdoutbuf)
+ {
+ c1 = stdoutbuf;
+ do
+ {
+ if (*c1 == '-')
+ {
+ c2 = strchr(c1++, '\n');
+ if (c2 > c1)
+ {
+ *c2 = 0;
+ list = g_list_append(list, strdup(++c1));
+ *c2 = '\n';
+ cnt++;
+ }
+ }
+ c2 = strchr(c1, '\n');
+ if (c2)
+ c1 = ++c2;
+ }
+ while (c2 && c1 - stdoutbuf < strlen(stdoutbuf));
+
+ if (cnt)
+ list = g_list_append(list, strdup(TA_OFF));
+ }
+
+ free(stdoutbuf);
+
+ return list;
+}
+
+static gboolean check_profile(const char *profile)
+{
+ GList *list = NULL;
+ GList *llist;
+ gboolean rc = FALSE;
+
+ if (!(list = pm_list_profiles()))
+ return FALSE;
+
+ if (! g_list_length(list))
+ return FALSE;
+
+ for (llist = g_list_first(list); llist && !rc; llist = g_list_next(llist))
+ {
+ mh_trace("comparing '%s' with '%s'", (char
*)llist->data, profile);
+ if (! strcmp(profile, (char *)llist->data))
+ rc = TRUE;
+ free(llist->data);
+ }
+ g_list_free(list);
+
+ return rc;
+}
+
+gboolean pm_set_profile(const char *profile)
+{
+ char *stdoutbuf = NULL;
+ char *stderrbuf = NULL;
+ char *args[4] = {0};
+ gboolean rc;
+
+ args[0] = TUNEDADM;
+ if (! profile)
+ return FALSE;
+
+ if (! strcmp(profile, TA_OFF)) {
+ args[1] = TA_OFF;
+ mh_trace("switching tuning off");
+ }
+ else
+ {
+ if (! check_profile(profile)) {
+ mh_err("invalid profile: %s", profile);
+ return FALSE;
+ }
+ args[1] = TA_SETPROFILE;
+ mh_trace("setting profile: %s", profile);
+ }
+
+ args[2] = strdup(profile);
+ args[3] = NULL;
+
+ rc = exec_command(args[0], TIMEOUT, &stdoutbuf, &stderrbuf, args) == EC_OK;
+ free(args[2]);
+
+ if (stdoutbuf) {
+ mh_trace(" > stdout: %s", stdoutbuf);
+ free(stdoutbuf);
+ }
+ if (stderrbuf) {
+ mh_trace(" > stderr: %s", stderrbuf);
+ free(stderrbuf);
+ }
+
+ return rc;
+}
+
+const char *pm_get_profile(void)
+{
+ char *stdoutbuf = NULL;
+ char *stderrbuf = NULL;
+ char *rbuf = NULL;
+ char *c1, *c2;
+ char *args[3] = {0};
+ gboolean rc;
+
+ args[0] = TUNEDADM;
+ args[1] = TA_GETPROFILE;
+ args[2] = NULL;
+
+ rc = exec_command(args[0], TIMEOUT, &stdoutbuf, &stderrbuf, args) == EC_OK;
+
+ if (stdoutbuf) {
+ mh_trace(" > stdout: %s", stdoutbuf);
+ }
+ if (stderrbuf) {
+ mh_trace(" > stderr: %s", stderrbuf);
+ free(stderrbuf);
+ }
+
+ if (rc)
+ {
+ if (stdoutbuf && strlen(stdoutbuf) && (c1 = strchr(stdoutbuf,
':')) &&
+ (++c1 - stdoutbuf < strlen(stdoutbuf)))
+ {
+ if ((c2 = strchr(stdoutbuf, '\n')))
+ *c2 = 0;
+ rbuf = strdup(c1);
+ }
+ else
+ rbuf = strdup(STR_UNK);
+ }
+ else
+ rbuf = strdup(STR_ERR);
+
+ free(stdoutbuf);
+
+ return rbuf;
+}
diff --git a/src/lib/pm_private.h b/src/lib/pm_private.h
new file mode 100644
index 0000000..019f605
--- /dev/null
+++ b/src/lib/pm_private.h
@@ -0,0 +1,39 @@
+/* pm_private.h - Copyright (C) 2011 Red Hat, Inc.
+ * Written by Jaroslav Škarvada <jskarvad(a)redhat.com>
+ * Based on code from Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This software 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * \file
+ * \brief Platform specific function prototypes.
+ *
+ * The functions in this header must be implemented by the platform
+ * specific pm data code.
+ * - pm_linux.c
+ * - pm_windows.c
+ */
+
+#ifndef __MH_PM_PRIVATE_H__
+#define __MH_PM_PRIVATE_H__
+
+#include <glib.h>
+
+extern gboolean pm_set_profile(const char *profile);
+extern const char *pm_get_profile(void);
+extern GList *pm_list_profiles(void);
+
+#endif /* __MH_PM_PRIVATE_H__ */
diff --git a/src/lib/pm_windows.c b/src/lib/pm_windows.c
new file mode 100644
index 0000000..7725f4c
--- /dev/null
+++ b/src/lib/pm_windows.c
@@ -0,0 +1,301 @@
+/* pm_windows.c - Copyright (C) 2011 Red Hat, Inc.
+ * Written by Jaroslav Škarvada <jskarvad(a)redhat.com>
+ * Based on code from Andrew Beekhof <andrew(a)beekhof.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This software 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Some code adapted from
http://msdn.microsoft.com/en-us/library/ms682499(v=vs.85).aspx
*/
+
+#include <winsock.h>
+#include <windows.h>
+#include <winbase.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "matahari/logging.h"
+#include "matahari/pm.h"
+#include "host_private.h"
+
+#define BUFSIZE 4096
+
+#define malloc_usable_size(size) _msize(size)
+
+static void
+read_output(HANDLE h, char **output, int *len)
+{
+ /* Read output from the child process's pipe for STDOUT
+ * Stop when there is no more data.
+ */
+ DWORD bytes = 0;
+ char buf[BUFSIZE];
+
+ *len = 0;
+ while (ReadFile(h, buf, BUFSIZE - 1, &bytes, NULL) && bytes > 0
&&
+ (*output = realloc(*output, *len + (int) bytes + 1)))
+ {
+ buf[bytes] = 0;
+ mh_info("Read %d: %.*s", *len, (int) bytes, buf);
+ sprintf(*output + *len, "%s", buf);
+ *len += (int)bytes;
+ }
+
+ mh_info("Read %d bytes", len);
+}
+
+static
+int exec_command(char *apath, char *acommand, int atimeout,
+ char **stdoutbuf)
+{
+ DWORD status = 0;
+ int max = 0;
+ int len;
+ char *bcommand;
+ LPWSTR command;
+ STARTUPINFO siStartInfo;
+ SECURITY_ATTRIBUTES saAttr;
+ PROCESS_INFORMATION piProcInfo;
+ HANDLE child_pipe_rd = NULL;
+ HANDLE child_pipe_wr = NULL;
+
+ if (! acommand)
+ return EC_OTHER_ERROR;
+
+ /* Initialize all structures */
+ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
+ ZeroMemory(&saAttr, sizeof(SECURITY_ATTRIBUTES));
+ ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
+
+ /* Set the bInheritHandle flag so pipe handles are inherited. */
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+
+ /* Copyrightreate a pipe for the child process's stdout */
+ if (!CreatePipe(&child_pipe_rd, &child_pipe_wr, &saAttr, 0)) {
+ mh_err("Couldn't create child pipe");
+ return FALSE;
+ }
+
+ /* Ensure the read handle to the pipe for STDOUT is not inherited. */
+ if (!SetHandleInformation(child_pipe_rd, HANDLE_FLAG_INHERIT, 0)) {
+ mh_err("Couldn't set pipe handle information");
+ CloseHandle(child_pipe_rd);
+ CloseHandle(child_pipe_wr);
+ return FALSE;
+ }
+
+ if (apath)
+ {
+ bcommand = malloc((len = strlen(apath) + strlen(acommand) + 2));
+ len--;
+ if (! bcommand)
+ {
+ CloseHandle(child_pipe_rd);
+ CloseHandle(child_pipe_wr);
+ return EC_OTHER_ERROR;
+ }
+ bcommand[len] = 0;
+ strcpy(bcommand, apath);
+ strcat(bcommand, "\\");
+ strcat(bcommand, acommand);
+ }
+ else bcommand = strdup(acommand);
+
+ command = char2wide(bcommand);
+ free(bcommand);
+
+ siStartInfo.cb = sizeof(STARTUPINFO);
+ siStartInfo.hStdError = child_pipe_wr;
+ siStartInfo.hStdOutput = child_pipe_wr;
+ siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ if (!CreateProcess(NULL,
+ command, // command line
+ NULL, // process security attributes
+ NULL, // primary thread security attributes
+ TRUE, // handles are inherited
+ 0, // creation flags
+ NULL, // use parent's environment
+ NULL, // use parent's current directory
+ &siStartInfo, // STARTUPINFO pointer
+ &piProcInfo)) { // receives PROCESS_INFORMATION
+ mh_err("Could not create child process");
+ CloseHandle(child_pipe_rd);
+ CloseHandle(child_pipe_wr);
+ free(command);
+ return EC_OTHER_ERROR;
+ }
+
+ WaitForSingleObject(piProcInfo.hProcess, atimeout);
+
+ if (GetExitCodeProcess(piProcInfo.hProcess, &status) == 0) {
+ mh_err("Could not get exit code: %lu", GetLastError());
+ status = EC_PENDING;
+ }
+
+ if (status == EC_PENDING) {
+ status = EC_TIMEOUT;
+ TerminateProcess(piProcInfo.hProcess, 1);
+ mh_err("Operation timeout out after %dms", atimeout);
+
+ }
+ /* Nice to log it somewhere */
+ mh_debug("Result of '%ls' was %d", command, (int)status);
+
+ /* Close the write end of the pipe before reading from the
+ * read end of the pipe, to control child process execution.
+ * The pipe is assumed to have enough buffer space to hold the
+ * data the child process has already written to it.
+ */
+
+ if (!CloseHandle(child_pipe_wr))
+ mh_err("Couldn't close write end of child pipe");
+
+ read_output(child_pipe_rd, stdoutbuf, &max);
+
+ if (*stdoutbuf)
+ mh_debug("RAW: %s", *stdoutbuf);
+
+ CloseHandle(piProcInfo.hProcess);
+ CloseHandle(piProcInfo.hThread);
+ CloseHandle(child_pipe_rd);
+
+ free(command);
+
+ return (int) status;
+}
+
+static
+gboolean get_profiles(GList **names, GList **guids)
+{
+ gboolean rc = FALSE;
+ int len;
+ char *stdoutbuf = NULL;
+ char *c1, *c2;
+
+ if (exec_command(getenv("WINDIR"),
+ SYSTEM32 "\\" POWERCFG " " PC_LISTPROFILES, TIMEOUT * 1000,
+ &stdoutbuf) == EC_OK && stdoutbuf)
+ {
+ rc = TRUE;
+ len = strlen(stdoutbuf);
+ c1 = stdoutbuf;
+
+ while ((c1 = strstr(c1, "GUID: ")))
+ {
+ c1 += 6;
+ if (c1 - stdoutbuf < len && (c2 = strchr(c1, ' ')))
+ {
+ *c2++ = 0;
+ *guids = g_list_append(*guids, strdup(c1));
+ if ((c1 = strchr(c2, '(')) && ++c1 - stdoutbuf < len
&&
+ (c2 = strchr(c1, ')')))
+ {
+ *c2 = 0;
+ *names = g_list_append(*names, strdup(c1));
+ *c2 = ')';
+ }
+ }
+ }
+ }
+
+ if (!*names || !*guids || g_list_length(*names) != g_list_length(*guids))
+ rc = FALSE;
+
+ free(stdoutbuf);
+
+ return rc;
+}
+
+#define PMSP_COMMAND SYSTEM32 "\\" POWERCFG " " PC_SETPROFILE "
"
+gboolean pm_set_profile(const char *profile)
+{
+ gboolean rc = FALSE;
+ char *guid = NULL;
+ char *stdoutbuf = NULL;
+ char *cmd = NULL;
+ GList *names = NULL;
+ GList *guids = NULL;
+ GList *pnames, *pguids;
+
+ if (! get_profiles(&names, &guids))
+ return FALSE;
+
+ for (pnames = g_list_first(names), pguids = g_list_first(guids);
+ pnames && pguids;
+ pnames = g_list_next(pnames), pguids = g_list_next(pguids))
+ {
+ if (!strcmp((char *)pnames->data, profile))
+ guid = strdup((char *)pguids->data);
+ free(pnames->data);
+ free(pguids->data);
+ }
+ g_list_free(names);
+ g_list_free(guids);
+
+ if (guid && (cmd = malloc(strlen(PMSP_COMMAND) + strlen(guid) + 1)))
+ {
+ strcpy(cmd, PMSP_COMMAND);
+ strcat(cmd, guid);
+ rc = exec_command(getenv("WINDIR"), cmd, TIMEOUT * 1000,
+ &stdoutbuf) == EC_OK;
+ free(cmd);
+ free(stdoutbuf);
+ }
+
+ return rc;
+}
+#undef PMSP_COMMAND
+
+const char *pm_get_profile(void)
+{
+ char *rbuf = NULL;
+ char *stdoutbuf = NULL;
+ char *c1, *c2;
+
+ if (exec_command(getenv("WINDIR"), SYSTEM32 "\\" POWERCFG "
" PC_GETPROFILE,
+ TIMEOUT * 1000, &stdoutbuf) == EC_OK && stdoutbuf &&
+ (c1 = strchr(stdoutbuf, '(')) && ++c1 - stdoutbuf <
strlen(stdoutbuf) &&
+ (c2 = strchr(c1, ')')))
+ {
+ *c2 = 0;
+ rbuf = strdup(c1);
+ }
+ else rbuf = strdup(STR_ERR);
+
+ free(stdoutbuf);
+
+ return rbuf;
+}
+
+GList *pm_list_profiles(void)
+{
+ GList *list;
+ GList *names = NULL;
+ GList *guids = NULL;
+
+ get_profiles(&names, &guids);
+
+ for (list = g_list_first(guids); list; list = g_list_next(list))
+ free((char *)list->data);
+
+ g_list_free(guids);
+
+ return names;
+}
diff --git a/src/pm/CMakeLists.txt b/src/pm/CMakeLists.txt
new file mode 100644
index 0000000..512f3f4
--- /dev/null
+++ b/src/pm/CMakeLists.txt
@@ -0,0 +1,61 @@
+set(BASE "pm")
+set(BASE_LIB "m${BASE}")
+set(QMF_AGENT "matahari-qmf-${BASE}d")
+set(DBUS_AGENT "matahari-dbus-${BASE}d")
+
+# QMF daemon
+if(WITH-QMF)
+ set(SCHEMA_SOURCES
${CMAKE_CURRENT_BINARY_DIR}/qmf/org/matahariproject/QmfPackage.cpp)
+ generate_qmf_schemas(${CMAKE_CURRENT_SOURCE_DIR}/schema.xml ${SCHEMA_SOURCES})
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ add_executable(${QMF_AGENT} ${BASE}-qmf.cpp ${SCHEMA_SOURCES})
+ target_link_libraries(${QMF_AGENT} ${BASE_LIB} mcommon mcommon_qmf)
+
+ target_link_libraries(${QMF_AGENT} ${QPIDCOMMON_LIBRARY} ${QPIDCLIENT_LIBRARY}
${QPIDMESSAGING_LIBRARY} ${QMF2_LIBRARY})
+ if(QPIDTYPES_LIBRARY)
+ target_link_libraries(${QMF_AGENT} ${QPIDTYPES_LIBRARY})
+ endif(QPIDTYPES_LIBRARY)
+
+ if(WIN32)
+ target_link_libraries(${QMF_AGENT} wsock32)
+ endif(WIN32)
+
+ if(NOT WIN32)
+ configure_file(${CMAKE_SOURCE_DIR}/matahari.init.in
${CMAKE_CURRENT_BINARY_DIR}/matahari-${BASE})
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/matahari-${BASE} DESTINATION
${initdir})
+ endif(NOT WIN32)
+
+ install(TARGETS ${QMF_AGENT} DESTINATION sbin)
+endif(WITH-QMF)
+
+
+# DBus daemon
+if(WITH-DBUS)
+ # Auto-generated stuff
+ generate_dbus_headers(${BASE}
${CMAKE_CURRENT_BINARY_DIR}/org.matahariproject.PM.xml)
+ # Create src/dbus directory and generate DBus XML definition files into it
+ generate_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/schema.xml)
+
+ # Must be included to find matahari-API-dbus-properties.h
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+ set(DBUS_AGENT_SOURCE
+ ${BASE}-dbus.c
+ ${BASE}-dbus-glue.h
+ ${BASE}-dbus-properties.h
+ )
+
+ add_executable(${DBUS_AGENT} ${DBUS_AGENT_SOURCE})
+
+ target_link_libraries(${DBUS_AGENT} ${BASE_LIB} mcommon_dbus ${dbus-glib_LIBRARIES})
+ include_directories(${dbus-glib_INCLUDE_DIRS})
+
+ # Install targets
+ # TODO: fix hardcoded paths, should go to libexec
+ install(TARGETS ${DBUS_AGENT} DESTINATION sbin)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.matahariproject.PM.xml DESTINATION
share/dbus-1/interfaces)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.matahariproject.PM.service DESTINATION
share/dbus-1/system-services)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.matahariproject.PM.conf DESTINATION
/etc/dbus-1/system.d)
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.matahariproject.PM.policy DESTINATION
share/polkit-1/actions)
+endif(WITH-DBUS)
diff --git a/src/pm/org.matahariproject.PM.conf b/src/pm/org.matahariproject.PM.conf
new file mode 100644
index 0000000..1afe8a8
--- /dev/null
+++ b/src/pm/org.matahariproject.PM.conf
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- Only root can own the service -->
+ <policy user="root">
+ <allow own="org.matahariproject.PM"/>
+ </policy>
+
+ <!-- Allow anyone to invoke methods on the interfaces -->
+ <policy context="default">
+ <allow send_destination="org.matahariproject.PM"/>
+ </policy>
+
+</busconfig>
diff --git a/src/pm/org.matahariproject.PM.policy b/src/pm/org.matahariproject.PM.policy
new file mode 100644
index 0000000..eb2c617
--- /dev/null
+++ b/src/pm/org.matahariproject.PM.policy
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration
1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+<policyconfig>
+ <vendor>Matahari</vendor>
+ <
vendor_url>https://fedorahosted.org/matahari/</vendor_url>
+ <action id="org.matahariproject.PM.set_profile">
+ <defaults>
+ <allow_any>no</allow_any>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin</allow_active>
+ </defaults>
+ </action>
+ <action id="org.matahariproject.PM.get_profile">
+ <defaults>
+ <allow_any>no</allow_any>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin</allow_active>
+ </defaults>
+ </action>
+ <action id="org.matahariproject.PM.list_profiles">
+ <defaults>
+ <allow_any>no</allow_any>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin</allow_active>
+ </defaults>
+ </action>
+</policyconfig>
diff --git a/src/pm/org.matahariproject.PM.service
b/src/pm/org.matahariproject.PM.service
new file mode 100644
index 0000000..f293a71
--- /dev/null
+++ b/src/pm/org.matahariproject.PM.service
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.matahariproject.PM
+Exec=/usr/sbin/matahari-dbus-pmd
+User=root
diff --git a/src/pm/pm-dbus.c b/src/pm/pm-dbus.c
new file mode 100644
index 0000000..e7fbf10
--- /dev/null
+++ b/src/pm/pm-dbus.c
@@ -0,0 +1,148 @@
+/*
+ * matahari-pm-dbus.c
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Written by Jaroslav Škarvada <jskarvad(a)redhat.com>
+ * Based on code from Roman Rakus <rrakus(a)redhat.com>,
+ * Radek Novacek <rnovacek(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <string.h>
+
+#include "matahari/mh_dbus_common.h"
+#include "matahari/utilities.h"
+
+/* PM methods */
+#include "matahari/pm.h"
+
+/* Generated properties list */
+#include "pm-dbus-properties.h"
+
+/* DBus names */
+#define PM_BUS_NAME "org.matahariproject.PM"
+#define PM_OBJECT_PATH "/org/matahariproject/PM"
+#define PM_INTERFACE_NAME "org.matahariproject.PM"
+#define DBUS_PROPERTY_INTERAFACE_NAME "org.freedesktop.DBus.Properties"
+
+/* Dbus methods */
+gboolean
+PM_set_profile(Matahari* matahari, const char *profile, DBusGMethodInvocation *context)
+{
+ GError* error = NULL;
+ if (!check_authorization(PM_BUS_NAME ".set_profile", &error, context))
{
+ dbus_g_method_return_error(context, error);
+ return FALSE;
+ }
+ dbus_g_method_return(context, mh_pm_set_profile(profile));
+ return TRUE;
+}
+
+gboolean
+PM_get_profile(Matahari* matahari, DBusGMethodInvocation *context)
+{
+ char *profile;
+ GError* error = NULL;
+ if (!check_authorization(PM_BUS_NAME ".get_profile", &error, context))
{
+ dbus_g_method_return_error(context, error);
+ return FALSE;
+ }
+ profile = (char *)mh_pm_get_profile();
+ dbus_g_method_return(context, g_strdup(profile));
+ free(profile);
+ return TRUE;
+}
+
+gboolean
+PM_list_profiles(Matahari* matahari, DBusGMethodInvocation *context)
+{
+ GError* error = NULL;
+ GList *list;
+ GList *plist;
+ char **profiles;
+ int i = 0;
+
+ if (!check_authorization(PM_BUS_NAME ".list_profiles", &error,
context)) {
+ dbus_g_method_return_error(context, error);
+ return FALSE;
+ }
+ list = mh_pm_list_profiles();
+ profiles = g_new(char *, g_list_length(list) + 1);
+ for (plist = g_list_first(list); plist; plist = g_list_next(plist)) {
+ profiles[i++] = g_strdup((char *)plist->data);
+ free(plist->data);
+ }
+ profiles[i] = NULL;
+ dbus_g_method_return(context, profiles);
+ g_strfreev(profiles);
+ g_list_free(list);
+ return TRUE;
+}
+
+/* Generated dbus stuff for pm
+ * MUST be after declaration of user defined functions.
+ */
+#include "pm-dbus-glue.h"
+
+void
+matahari_set_property(GObject *object, guint property_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+void
+matahari_get_property(GObject *object, guint property_id, GValue *value,
+ GParamSpec *pspec)
+{
+ char *str;
+
+ switch (property_id) {
+ case PROP_UUID:
+ g_value_set_string(value, str = (char *)mh_uuid());
+ free(str);
+ break;
+ case PROP_HOSTNAME:
+ g_value_set_string(value, str = (char *)mh_hostname());
+ free(str);
+ break;
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+GType
+matahari_dict_type(int prop)
+{
+ g_printerr("Type of property %s is map of unknown types\n",
+ properties[prop].name);
+ return G_TYPE_VALUE;
+}
+
+int
+main(int argc, char** argv)
+{
+ g_type_init();
+ return run_dbus_server(PM_BUS_NAME, PM_OBJECT_PATH);
+}
diff --git a/src/pm/pm-qmf.cpp b/src/pm/pm-qmf.cpp
new file mode 100644
index 0000000..e070d41
--- /dev/null
+++ b/src/pm/pm-qmf.cpp
@@ -0,0 +1,116 @@
+/* matahari-pm.cpp - Copyright (C) 2011 Red Hat, Inc.
+ * Written by Jaroslav Škarvada <jskarvad(a)redhat.com>
+ * Based on code from Roman Rakus <rrakus(a)redhat.com>,
+ * Radek Novacek <rnovacek(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This software 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef WIN32
+#include "config.h"
+#endif
+
+#include "matahari/mh_agent.h"
+#include <qmf/Data.h>
+#include "qmf/org/matahariproject/QmfPackage.h"
+
+extern "C" {
+#include <string.h>
+#include "matahari/pm.h"
+#include "matahari/logging.h"
+#include "matahari/utilities.h"
+}
+
+class PMAgent : public MatahariAgent
+{
+private:
+ qmf::org::matahariproject::PackageDefinition _package;
+public:
+ virtual int setup(qmf::AgentSession session);
+ virtual gboolean invoke(qmf::AgentSession session, qmf::AgentEvent event,
+ gpointer user_data);
+};
+
+int
+main(int argc, char **argv)
+{
+ PMAgent *agent = new PMAgent();
+ int rc = agent->init(argc, argv, "pm");
+ if (rc == 0) {
+ agent->run();
+ }
+
+ return rc;
+}
+
+gboolean
+PMAgent::invoke(qmf::AgentSession session, qmf::AgentEvent event,
+ gpointer user_data)
+{
+ if (event.getType() != qmf::AGENT_METHOD) {
+ session.methodSuccess(event);
+ return TRUE;
+ }
+
+ const std::string& methodName(event.getMethodName());
+
+ if (methodName == "set_profile") {
+ event.addReturnArgument("status",
+
mh_pm_set_profile(event.getArguments()["profile"].asString().c_str()));
+ } else if (methodName == "get_profile") {
+ _qtype::Variant profile;
+ char *pprofile = (char *)mh_pm_get_profile();
+ profile = pprofile;
+ free(pprofile);
+ event.addReturnArgument("profile", profile);
+ } else if (methodName == "list_profiles") {
+ GList *plist = NULL;
+ GList *profiles = mh_pm_list_profiles();
+ _qtype::Variant::List s_list;
+ for (plist = g_list_first(profiles); plist;
+ plist = g_list_next(plist))
+ {
+ s_list.push_back((char *)plist->data);
+ free(plist->data);
+ }
+ g_list_free(profiles);
+ event.addReturnArgument("profiles", s_list);
+ } else {
+ session.raiseException(event, MH_NOT_IMPLEMENTED);
+ goto bail;
+ }
+
+ session.methodSuccess(event);
+
+bail:
+ return TRUE;
+}
+
+int
+PMAgent::setup(qmf::AgentSession session)
+{
+ char *str;
+
+ _package.configure(session);
+ _instance = qmf::Data(_package.data_PM);
+
+ _instance.setProperty("hostname", str = (char *)mh_hostname());
+ free(str);
+ _instance.setProperty("uuid", str = (char *)mh_uuid());
+ free(str);
+
+ session.addData(_instance);
+ return 0;
+}
diff --git a/src/pm/schema.xml b/src/pm/schema.xml
new file mode 100644
index 0000000..c2e580b
--- /dev/null
+++ b/src/pm/schema.xml
@@ -0,0 +1,21 @@
+<schema package="org.matahariproject">
+
+<!-- PM API -->
+ <class name="PM">
+ <property name="uuid" type="sstr"
access="RO" desc="Host UUID" />
+ <property name="hostname" type="sstr"
access="RO" desc="Hostname" index="y" />
+
+ <!-- APIs -->
+ <method name="set_profile" desc="Set PM profile">
+ <arg name="profile" dir="I" type="sstr" />
+ <arg name="status" dir="O" type="uint32" />
+ </method>
+ <method name="get_profile" desc="Get current PM
profile">
+ <arg name="profile" dir="O" type="sstr" />
+ </method>
+ <method name="list_profiles" desc="List available PM
profiles">
+ <arg name="profiles" dir="O" type="list" />
+ </method>
+ </class>
+
+</schema>
diff --git a/src/schema.xml b/src/schema.xml
index d39c82d..1645bf4 100644
--- a/src/schema.xml
+++ b/src/schema.xml
@@ -58,6 +58,24 @@
<event name="heartbeat" args="timestamp,sequence" />
+<!-- PM API -->
+ <class name="PM">
+ <property name="uuid" type="sstr"
access="RO" desc="Host UUID" />
+ <property name="hostname" type="sstr"
access="RO" desc="Hostname" index="y" />
+
+ <!-- APIs -->
+ <method name="set_profile" desc="Set PM profile">
+ <arg name="profile" dir="I" type="sstr" />
+ <arg name="status" dir="O" type="uint32" />
+ </method>
+ <method name="get_profile" desc="Get current PM
profile">
+ <arg name="profile" dir="O" type="sstr" />
+ </method>
+ <method name="list_profiles" desc="List available PM
profiles">
+ <arg name="profiles" dir="O" type="list" />
+ </method>
+ </class>
+
<!-- Network API -->
<class name="Network">
<property name="uuid" type="sstr"
access="RO" desc="Host UUID" />
diff --git a/src/windows/install.bat b/src/windows/install.bat
index 5e6307e..5a47775 100644
--- a/src/windows/install.bat
+++ b/src/windows/install.bat
@@ -12,7 +12,7 @@ cd "%target%"
rem Now install the agents as services and start them
-set agents=hostd networkd serviced
+set agents=hostd pmd networkd serviced
for %%A in (%agents%) do sc delete mh_%%A
for %%A in (%agents%) do del mh_%%A.exe
for %%A in (%agents%) do copy srvany.exe mh_%%A.exe
--
1.7.5.2