예제 #1
0
int virSystemdCanHybridSleep(bool *result)
{
    return virSystemdPMSupportTarget("CanHybridSleep", result);
}
예제 #2
0
int virSystemdCanSuspend(bool *result)
{
    return virSystemdPMSupportTarget("CanSuspend", result);
}
예제 #3
0
int virSystemdCanHibernate(bool *result)
{
    return virSystemdPMSupportTarget("CanHibernate", result);
}
예제 #4
0
void
virSystemdNotifyStartup(void)
{
#ifdef HAVE_SYS_UN_H
    const char *path;
    const char *msg = "READY=1";
    int fd;
    struct sockaddr_un un = {
        .sun_family = AF_UNIX,
    };
    struct iovec iov = {
        .iov_base = (char *)msg,
        .iov_len = strlen(msg),
    };
    struct msghdr mh = {
        .msg_name = &un,
        .msg_iov = &iov,
        .msg_iovlen = 1,
    };

    if (!(path = virGetEnvBlockSUID("NOTIFY_SOCKET"))) {
        VIR_DEBUG("Skipping systemd notify, not requested");
        return;
    }

    /* NB sun_path field is *not* NUL-terminated, hence >, not >= */
    if (strlen(path) > sizeof(un.sun_path)) {
        VIR_WARN("Systemd notify socket path '%s' too long", path);
        return;
    }

    memcpy(un.sun_path, path, strlen(path));
    if (un.sun_path[0] == '@')
        un.sun_path[0] = '\0';

    mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(path);

    fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (fd < 0) {
        VIR_WARN("Unable to create socket FD");
        return;
    }

    if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0)
        VIR_WARN("Failed to notify systemd");

    VIR_FORCE_CLOSE(fd);
#endif /* HAVE_SYS_UN_H */
}

static int
virSystemdPMSupportTarget(const char *methodName, bool *result)
{
    int ret;
    DBusConnection *conn;
    DBusMessage *message = NULL;
    char *response;

    ret = virDBusIsServiceEnabled("org.freedesktop.login1");
    if (ret < 0)
        return ret;

    if ((ret = virDBusIsServiceRegistered("org.freedesktop.login1")) < 0)
        return ret;

    if (!(conn = virDBusGetSystemBus()))
        return -1;

    ret = -1;

    if (virDBusCallMethod(conn,
                          &message,
                          NULL,
                          "org.freedesktop.login1",
                          "/org/freedesktop/login1",
                          "org.freedesktop.login1.Manager",
                          methodName,
                          NULL) < 0)
        return ret;

    if ((ret = virDBusMessageDecode(message, "s", &response)) < 0)
        goto cleanup;

    *result = STREQ("yes", response) || STREQ("challenge", response);

    ret = 0;

 cleanup:
    virDBusMessageUnref(message);
    VIR_FREE(response);

    return ret;
}

int virSystemdCanSuspend(bool *result)
{
    return virSystemdPMSupportTarget("CanSuspend", result);
}

int virSystemdCanHibernate(bool *result)
{
    return virSystemdPMSupportTarget("CanHibernate", result);
}

int virSystemdCanHybridSleep(bool *result)
{
    return virSystemdPMSupportTarget("CanHybridSleep", result);
}