return ret;
}
+int d_bus_call_method_sync_gvariant_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ GVariant *gv, GVariant **out_reply)
+{
+ GVariant *reply = NULL;
+ GError *err = NULL;
+
+ reply = g_dbus_connection_call_sync(d_bus_get_connection(), dest, path,
+ interface, method, gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ if (err || !reply) {
+ /* The case where !err && !reply (i.e. reply type mismatch) can't currently happen
+ * because we don't specify the desired reply type, but it's good to be future-proof */
+ _E("Failed to call D-Bus name %s, objpath %s, iface %s, method %s: %s",
+ dest, path, interface, method, err ? err->message : "reply signature mismatch");
+ if (err)
+ g_error_free(err);
+ return -ECOMM;
+ }
+
+ *out_reply = reply;
+
+ return 0;
+}
+
int d_bus_call_method_async(const char *dest, const char *path,
const char *interface, const char *method,
const char *sig, char *param[])
#include "module.h"
#include "module-data.h"
#include "vip-process.h"
+#include "dbus-handler.h"
-#define VIP_CONF_FILE RD_CONFIG_FILE(vip-process)
+#define VIP_CONF_FILE RD_CONFIG_FILE(vip-process)
+
+#define SYSTEMD_DBUS_DEST "org.freedesktop.systemd1"
+#define SYSTEMD_DBUS_UNIT_PATH "/org/freedesktop/systemd1/unit/"
+#define SYSTEMD_DBUS_SERVICE_IFACE SYSTEMD_DBUS_DEST".Service"
+#define DBUS_IFACE_DBUS_PROPERTIES "org.freedesktop.DBus.Properties"
+
+#define SYSTEMD_UNIT_ESCAPE_CHAR ".-"
static char **arg_vip_proc_names = NULL;
static char **arg_vip_systemd_services = NULL;
+/* copy of libsyscommon/libsystemd.c: systemd_get_unit_dbus_path() */
+static int vip_get_escaped_name(const char *unit, char **escaped)
+{
+ char *path = NULL;
+ int i;
+ size_t p, k, prefix_len, unit_len;
+ size_t path_len, len, escape;
+
+ if (!unit) {
+ _E("Invalid parameter.");
+ return -EINVAL;
+ }
+ unit_len = strlen(unit);
+
+ for (escape = 0, p = 0; p < unit_len; escape++) {
+ k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
+ if (p + k >= unit_len)
+ break;
+ p += k+1;
+ }
+
+ prefix_len = strlen(SYSTEMD_DBUS_UNIT_PATH);
+ /* assume we try to get object path of foo-bar.service then
+ * the object path will be
+ * "/org/freedesktop/systemd1/unit/foo_2dbar_2eservice\n". In
+ * this case we can find two escape characters, one of escape
+ * char('-') is changed to three of char("_2d"). So the total
+ * length will be: */
+ /* (PREFIX) + (unit - escape + 3*escape) + NULL */
+ path_len = prefix_len + (unit_len - escape)
+ + (escape * 3 * sizeof(char)) + 1;
+ path = (char *)calloc(path_len, sizeof(char));
+ if (!path) {
+ _E("Not enough memory.");
+ return -ENOMEM;
+ }
+
+ *escaped = path;
+
+ strncpy(path, SYSTEMD_DBUS_UNIT_PATH, prefix_len + 1);
+ for (i = 0, p = 0; i <= escape; i++) {
+ k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
+ strncpy(path + prefix_len, unit + p, k);
+ if (k < strlen(unit + p)) {
+ len = path_len - (prefix_len + k);
+ snprintf(path + prefix_len + k, len,
+ "_%x", *(unit + p + k) & 0xff);
+ prefix_len += k + 3;
+ p += k+1;
+ }
+ }
+
+ return 0;
+}
+
+/* get MainPID of a service. */
+static int vip_get_service_mainpid(const char *service, int *pid)
+{
+ char *escaped;
+ int ret = 0;
+ GVariant *reply = NULL;
+ GVariant *inner_reply = NULL;
+
+ if (!service)
+ return -EINVAL;
+
+ ret = vip_get_escaped_name(service, &escaped);
+ if (ret < 0) {
+ _E("Failed to makeup escaped service name.");
+ return ret;
+ }
+
+ ret = d_bus_call_method_sync_gvariant_with_reply(SYSTEMD_DBUS_DEST,
+ escaped,
+ DBUS_IFACE_DBUS_PROPERTIES,
+ "Get",
+ g_variant_new("(ss)", SYSTEMD_DBUS_SERVICE_IFACE, "ExecMainPID"),
+ &reply);
+
+ free(escaped);
+
+ if (!reply || ret < 0) {
+ _E("Failed to get pid of service=%s", service);
+ if (reply)
+ g_variant_unref(reply);
+ return -ECOMM;
+ }
+
+ do_expr_unless_g_variant_consume_typechecked(return -EINVAL, reply, "(v)", &inner_reply);
+ do_expr_unless_g_variant_consume_typechecked(return -EINVAL, inner_reply, "u", pid);
+
+ return 0;
+}
+
+static bool vip_check_all(void)
+{
+ int pid;
+ int ret_val;
+ bool ret = true;
+ char **pname = NULL;
+
+ FOREACH_STRV(pname, arg_vip_proc_names) {
+ pid = find_pid_from_cmdline(*pname);
+ if (pid < 0) {
+ _E("VIP %s not found", *pname);
+ ret = false;
+ }
+ }
+
+ FOREACH_STRV(pname, arg_vip_systemd_services) {
+ ret_val = vip_get_service_mainpid(*pname, &pid);
+ if (ret_val < 0) {
+ _E("Failed to get MainPID of service=%s", *pname);
+ continue;
+ }
+
+ /* The property MainPID can return a positive MainPID
+ * as a pid of inactive(dead) service if the service had once
+ * been active before. Therefore, it is necessary to check
+ * whether it is still alive. */
+ if (pid == 0 || kill(pid, 0) != 0) {
+ _E("VIP %s not found", *pname);
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static void vip_force_reboot(void)
+{
+ _E("VIP force reboot.");
+ execl("/usr/bin/vip-release-agent", "/usr/bin/vip-release-agent", NULL);
+
+ _E("Failed to execute vip-release-agent");
+}
+
static int vip_load_config(struct parse_result *result, void *user_data)
{
char ***strv;
return;
FOREACH_STRV(pname, arg_vip_systemd_services) {
- _cleanup_free_ char *err_msg = NULL;
- int r;
- char path[128];
- FILE *fp;
+ int ret_val;
pid_t pid;
- if (snprintf(path, sizeof(path), "%s/systemd/system.slice/%s/tasks",
- DEFAULT_CGROUP, *pname) < 0) {
- _E("Fail to make task path");
- continue;
- }
-
- fp = fopen(path, "r");
- if (!fp) {
- _E("%s is user level service or not running", *pname);
+ ret_val = vip_get_service_mainpid(*pname, &pid);
+ if (ret_val == -ECOMM)
continue;
- }
- if (fscanf(fp, "%d", &pid) < 0) {
- _E("Fail to get pid of %s", *pname);
- fclose(fp);
- continue;
- }
if (pid > 0) {
- r = vip_create_sub_cgroup(*pname, pid);
- if (r < 0)
+ ret_val = vip_create_sub_cgroup(*pname, pid);
+ if (ret_val < 0)
_E("failed to create "
"sub cgroup of '%s', ignoring", *pname);
}
-
- fclose(fp);
}
}
vip_create_proc_name_groups();
vip_create_systemd_service_groups();
+ if (vip_check_all() == false)
+ vip_force_reboot();
+
return 0;
}