Updated patch according to comments from thread:
http://fedorahosted.org/pipermail/matahari/2011-June/001124.html
thanks & regards
Jaroslav
---
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 | 144 ++++++++++++++
src/pm/pm-qmf.cpp | 112 +++++++++++
src/pm/schema.xml | 21 ++
src/schema.xml | 18 ++
src/windows/install.bat | 2 +-
18 files changed, 1250 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 5dda02d..7013e1e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -132,6 +132,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 ab21bba..7c9fc14 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..bfc1c99
--- /dev/null
+++ b/src/pm/pm-dbus.c
@@ -0,0 +1,144 @@
+/*
+ * 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)
+{
+ switch (property_id) {
+ case PROP_UUID:
+ g_value_set_string(value, mh_uuid());
+ break;
+ case PROP_HOSTNAME:
+ g_value_set_string(value, mh_hostname());
+ 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..9577d93
--- /dev/null
+++ b/src/pm/pm-qmf.cpp
@@ -0,0 +1,112 @@
+/* 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)
+{
+ _package.configure(session);
+ _instance = qmf::Data(_package.data_PM);
+
+ _instance.setProperty("hostname", mh_hostname());
+ _instance.setProperty("uuid", mh_uuid());
+
+ 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.4.4