Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[nemo-systemsettings] Update UserInfo if user database changes. Fixes…
… JB#49699

Signed-off-by: Tomi Leppänen <tomi.leppanen@jolla.com>
  • Loading branch information
Tomin1 committed Apr 23, 2020
1 parent 6a24b44 commit 54a20b0
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 16 deletions.
82 changes: 66 additions & 16 deletions src/userinfo.cpp
Expand Up @@ -33,6 +33,8 @@
#include "userinfo_p.h"
#include "logging_p.h"

#include <QFile>
#include <QFileSystemWatcher>
#include <QSocketNotifier>
#include <poll.h>
#include <pwd.h>
Expand All @@ -41,6 +43,8 @@

namespace {

const auto UserDatabaseFile = QStringLiteral("/etc/passwd");

enum SpecialIds : uid_t {
DeviceOwnerId = 100000,
UnknownCurrentUserId = (uid_t)(-2),
Expand All @@ -65,6 +69,7 @@ QString nameFromGecos(const char *gecos)
UserInfoPrivate::UserInfoPrivate()
: m_uid(InvalidId)
, m_loggedIn(false)
, m_watcher(nullptr)
{
}

Expand All @@ -76,6 +81,7 @@ UserInfoPrivate::UserInfoPrivate(struct passwd *pwd)
// Specifying seat should make sure that remote users are not
// counted as they don't have seats.
, m_loggedIn(sd_uid_is_on_seat(m_uid, 1, "seat0") > 0)
, m_watcher(nullptr)
{
}

Expand Down Expand Up @@ -143,10 +149,11 @@ UserInfo::UserInfo()
waitForActivation();
}
// pwd must not be free'd
if (current())
UserInfoPrivate::s_current = d_ptr;
}
if (current())
UserInfoPrivate::s_current = d_ptr;
connectSignals();
watchForChanges();
}

UserInfo::UserInfo(const UserInfo &other)
Expand All @@ -161,15 +168,20 @@ UserInfo::UserInfo(const UserInfo &other)
*/
UserInfo::UserInfo(int uid)
{
struct passwd *pwd = (uid_t)uid != InvalidId ? getpwuid((uid_t)uid) : nullptr;
if (pwd) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
auto current_d = UserInfoPrivate::s_current.toStrongRef();
if (!current_d.isNull() && current_d->m_uid == (uid_t)uid) {
d_ptr = current_d;
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
struct passwd *pwd = (uid_t)uid != InvalidId ? getpwuid((uid_t)uid) : nullptr;
if (pwd) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
}
// pwd must not be free'd
if (current())
UserInfoPrivate::s_current = d_ptr;
}
// pwd must not be free'd
if (current())
UserInfoPrivate::s_current = d_ptr;
connectSignals();
}

Expand All @@ -178,15 +190,20 @@ UserInfo::UserInfo(int uid)
*/
UserInfo::UserInfo(QString username)
{
struct passwd *pwd = getpwnam(username.toUtf8().constData());
if (pwd) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
auto current_d = UserInfoPrivate::s_current.toStrongRef();
if (!current_d.isNull() && current_d->m_username == username) {
d_ptr = current_d;
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
struct passwd *pwd = getpwnam(username.toUtf8().constData());
if (pwd) {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate(pwd));
} else {
d_ptr = QSharedPointer<UserInfoPrivate>(new UserInfoPrivate);
}
// pwd must not be free'd
if (current())
UserInfoPrivate::s_current = d_ptr;
}
// pwd must not be free'd
if (current())
UserInfoPrivate::s_current = d_ptr;
connectSignals();
}

Expand Down Expand Up @@ -312,6 +329,7 @@ void UserInfo::reset()
void UserInfo::replace(QSharedPointer<UserInfoPrivate> other)
{
auto old = d_ptr;
disconnect(old.data(), 0, this, 0);
d_ptr = other;

if (old->m_username != d_ptr->m_username) {
Expand All @@ -331,6 +349,11 @@ void UserInfo::replace(QSharedPointer<UserInfoPrivate> other)

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

if (old->m_watcher)
watchForChanges();

connectSignals();
}

UserInfo &UserInfo::operator=(const UserInfo &other)
Expand Down Expand Up @@ -366,6 +389,33 @@ void UserInfo::connectSignals()
connect(d_ptr.data(), &UserInfoPrivate::currentChanged, this, &UserInfo::currentChanged);
}

void UserInfo::watchForChanges()
{
Q_D(UserInfo);
d->m_watcher = new QFileSystemWatcher(this);
if (!d->m_watcher->addPath(UserDatabaseFile)) {
qCWarning(lcUsersLog) << "Could not watch for changes in user database";
delete d->m_watcher;
d->m_watcher = nullptr;
} else {
connect(d->m_watcher, &QFileSystemWatcher::fileChanged, this, [this] {
Q_D(UserInfo);
if (QFile::exists(UserDatabaseFile)) {
// Database updated, reset
qCDebug(lcUsersLog) << "Reseting model because user database changed";
reset();
}
if (!d->m_watcher->files().contains(UserDatabaseFile)) {
if (QFile::exists(UserDatabaseFile) && d->m_watcher->addPath(UserDatabaseFile)) {
qCDebug(lcUsersLog) << "Re-watching user database for changes";
} else {
qCWarning(lcUsersLog) << "Stopped watching user database for changes";
}
}
});
}
}

void UserInfo::waitForActivation()
{
// Monitor systemd-logind for changes on seats
Expand Down
1 change: 1 addition & 0 deletions src/userinfo.h
Expand Up @@ -100,6 +100,7 @@ class SYSTEMSETTINGS_EXPORT UserInfo: public QObject
void replace(QSharedPointer<UserInfoPrivate> other);

void connectSignals();
void watchForChanges();
void waitForActivation();

QSharedPointer<UserInfoPrivate> d_ptr;
Expand Down
3 changes: 3 additions & 0 deletions src/userinfo_p.h
Expand Up @@ -38,6 +38,8 @@
#include <QString>
#include <QWeakPointer>

class QFileSystemWatcher;

class UserInfoPrivate : public QObject
{
Q_OBJECT
Expand All @@ -52,6 +54,7 @@ class UserInfoPrivate : public QObject
QString m_name;
bool m_loggedIn;
static QWeakPointer<UserInfoPrivate> s_current;
QFileSystemWatcher *m_watcher;

void set(struct passwd *pwd);

Expand Down

0 comments on commit 54a20b0

Please sign in to comment.