Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'jb49527_wait_for_activation' into 'master'
[nemo-systemsettings] Monitor session activation. Fixes JB#49527

See merge request mer-core/nemo-qml-plugin-systemsettings!141
  • Loading branch information
Tomin1 committed Apr 15, 2020
2 parents 72420a7 + 298868a commit 6a24b44
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 6 deletions.
93 changes: 87 additions & 6 deletions src/userinfo.cpp
Expand Up @@ -31,7 +31,10 @@

#include "userinfo.h"
#include "userinfo_p.h"
#include "logging_p.h"

#include <QSocketNotifier>
#include <poll.h>
#include <pwd.h>
#include <sys/types.h>
#include <systemd/sd-login.h>
Expand All @@ -40,6 +43,7 @@ namespace {

enum SpecialIds : uid_t {
DeviceOwnerId = 100000,
UnknownCurrentUserId = (uid_t)(-2),
InvalidId = (uid_t)(-1),
};

Expand Down Expand Up @@ -98,6 +102,7 @@ void UserInfoPrivate::set(struct passwd *pwd)
if (m_username != username) {
m_username = username;
emit usernameChanged();
// Username is used as displayName only if name is empty, avoid emitting changed twice
if (m_name.isEmpty() && name.isEmpty())
emit displayNameChanged();
}
Expand All @@ -113,17 +118,29 @@ void UserInfoPrivate::set(struct passwd *pwd)
* Construct UserInfo for the current user
*
* If it has been constructed before, this reuses the old data.
* If it can not determine the current user, then it constructs
* an object that doesn't point to any user until a user becomes
* active on seat0. That should happen very soon after user
* session has been started.
*/
UserInfo::UserInfo()
{
d_ptr = UserInfoPrivate::s_current.toStrongRef();
if (d_ptr.isNull()) {
uid_t uid = InvalidId;
struct passwd *pwd;
if (sd_seat_get_active("seat0", NULL, &uid) < 0 || uid == InvalidId || !(pwd = getpwuid(uid))) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
if (sd_seat_get_active("seat0", NULL, &uid) >= 0 && uid != InvalidId) {
if ((pwd = getpwuid(uid))) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
} else {
// User did not exist, should not happen
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
}
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
// User is not active yet
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
d_ptr->m_uid = UnknownCurrentUserId;
waitForActivation();
}
// pwd must not be free'd
}
Expand Down Expand Up @@ -188,12 +205,12 @@ UserInfo::~UserInfo()
}

/**
* Returns true if user exists
* Returns true if the user exists
*/
bool UserInfo::isValid() const
{
Q_D(const UserInfo);
return d->m_uid != InvalidId;
return d->m_uid != InvalidId && d->m_uid != UnknownCurrentUserId;
}

QString UserInfo::displayName() const
Expand Down Expand Up @@ -292,12 +309,36 @@ void UserInfo::reset()
updateCurrent();
}

void UserInfo::replace(QSharedPointer<UserInfoPrivate> other)
{
auto old = d_ptr;
d_ptr = other;

if (old->m_username != d_ptr->m_username) {
emit usernameChanged();
// Username is used as displayName only if name is empty, avoid emitting changed twice
if (old->m_name.isEmpty() && d_ptr->m_name.isEmpty())
emit displayNameChanged();
}

if (old->m_name != d_ptr->m_name) {
emit nameChanged();
emit displayNameChanged();
}

if (old->m_uid != d_ptr->m_uid)
emit uidChanged();

if (old->m_loggedIn != d_ptr->m_loggedIn)
emit currentChanged();
}

UserInfo &UserInfo::operator=(const UserInfo &other)
{
if (this == &other)
return *this;

d_ptr = other.d_ptr;
replace(other.d_ptr);

return *this;
}
Expand All @@ -324,3 +365,43 @@ void UserInfo::connectSignals()
connect(d_ptr.data(), &UserInfoPrivate::uidChanged, this, &UserInfo::uidChanged);
connect(d_ptr.data(), &UserInfoPrivate::currentChanged, this, &UserInfo::currentChanged);
}

void UserInfo::waitForActivation()
{
// Monitor systemd-logind for changes on seats
sd_login_monitor *monitor;
if (sd_login_monitor_new("seat", &monitor) < 0) {
qCWarning(lcUsersLog) << "Could not start monitoring seat changes";
} else {
int fd = sd_login_monitor_get_fd(monitor);
if (fd < 0) {
qCWarning(lcUsersLog) << "Could not get file descriptor, not monitoring seat changes";
sd_login_monitor_unref(monitor);
} else if (!(sd_login_monitor_get_events(monitor) & POLLIN)) {
// Should not happen
qCWarning(lcUsersLog) << "Wrong events bits, not monitoring seat changes";
sd_login_monitor_unref(monitor);
} else {
auto *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(notifier, &QSocketNotifier::activated, this, [this, notifier, monitor](int socket) {
Q_UNUSED(socket)
// Check if seat0 has got active user
uid_t uid = InvalidId;
if (sd_seat_get_active("seat0", NULL, &uid) >= 0 && uid != InvalidId) {
qCDebug(lcUsersLog) << "User activated on seat0";
replace(UserInfo().d_ptr);
notifier->deleteLater();
// Otherwise it was not the event we are waiting for, just flush
} else if (sd_login_monitor_flush(monitor) < 0) {
qCWarning(lcUsersLog) << "Monitor flush failed";
notifier->deleteLater();
}
});
connect(notifier, &QObject::destroyed, [monitor] {
qCDebug(lcUsersLog) << "Stopped monitoring seat changes";
sd_login_monitor_unref(monitor);
});
qCDebug(lcUsersLog) << "Started monitoring seat changes";
}
}
}
2 changes: 2 additions & 0 deletions src/userinfo.h
Expand Up @@ -97,8 +97,10 @@ class SYSTEMSETTINGS_EXPORT UserInfo: public QObject
void setUsername(QString username);
void setName(QString name);
bool updateCurrent();
void replace(QSharedPointer<UserInfoPrivate> other);

void connectSignals();
void waitForActivation();

QSharedPointer<UserInfoPrivate> d_ptr;
};
Expand Down

0 comments on commit 6a24b44

Please sign in to comment.