From 9be99f81a7675e574a0847780aab83c25cb0e382 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2020 22:08:29 +0200 Subject: [PATCH] homed: report a home directory as "dirty" if image file has dirty flag --- src/home/homed-home-bus.c | 1 + src/home/homed-home.c | 24 +++++++++++++++++++++++- src/home/homed-home.h | 1 + src/home/user-record-util.c | 17 ++++++++++++++++- src/home/user-record-util.h | 1 + src/shared/user-record-show.c | 2 +- 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/home/homed-home-bus.c b/src/home/homed-home-bus.c index 6be361a5aa..015eefb718 100644 --- a/src/home/homed-home-bus.c +++ b/src/home/homed-home-bus.c @@ -669,6 +669,7 @@ int bus_home_method_ref( return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name); case HOME_UNFIXATED: case HOME_INACTIVE: + case HOME_DIRTY: return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name); case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 367ac21633..6a6cde7c02 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -1134,6 +1134,7 @@ int home_fixate(Home *h, UserRecord *secret, sd_bus_error *error) { case HOME_ABSENT: return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name); case HOME_INACTIVE: + case HOME_DIRTY: case HOME_ACTIVE: case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_ALREADY_FIXATED, "Home %s is already fixated.", h->user_name); @@ -1179,6 +1180,7 @@ int home_activate(Home *h, UserRecord *secret, sd_bus_error *error) { case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); case HOME_INACTIVE: + case HOME_DIRTY: break; default: return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name); @@ -1219,6 +1221,7 @@ int home_authenticate(Home *h, UserRecord *secret, sd_bus_error *error) { return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); case HOME_UNFIXATED: case HOME_INACTIVE: + case HOME_DIRTY: case HOME_ACTIVE: break; default: @@ -1252,6 +1255,7 @@ int home_deactivate(Home *h, bool force, sd_bus_error *error) { case HOME_UNFIXATED: case HOME_ABSENT: case HOME_INACTIVE: + case HOME_DIRTY: return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name); case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); @@ -1280,6 +1284,7 @@ int home_create(Home *h, UserRecord *secret, sd_bus_error *error) { _fallthrough_; case HOME_UNFIXATED: + case HOME_DIRTY: return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Home of user %s already exists.", h->user_name); case HOME_ABSENT: break; @@ -1319,6 +1324,7 @@ int home_remove(Home *h, sd_bus_error *error) { return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); case HOME_UNFIXATED: case HOME_INACTIVE: + case HOME_DIRTY: break; case HOME_ACTIVE: default: @@ -1457,6 +1463,7 @@ int home_update(Home *h, UserRecord *hr, sd_bus_error *error) { case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); case HOME_INACTIVE: + case HOME_DIRTY: case HOME_ACTIVE: break; default: @@ -1491,6 +1498,7 @@ int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *e case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); case HOME_INACTIVE: + case HOME_DIRTY: case HOME_ACTIVE: break; default: @@ -1586,6 +1594,7 @@ int home_passwd(Home *h, case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); case HOME_INACTIVE: + case HOME_DIRTY: case HOME_ACTIVE: break; default: @@ -1668,6 +1677,7 @@ int home_unregister(Home *h, sd_bus_error *error) { return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); case HOME_ABSENT: case HOME_INACTIVE: + case HOME_DIRTY: break; case HOME_ACTIVE: default: @@ -1692,6 +1702,7 @@ int home_lock(Home *h, sd_bus_error *error) { case HOME_UNFIXATED: case HOME_ABSENT: case HOME_INACTIVE: + case HOME_DIRTY: return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s is not active.", h->user_name); case HOME_LOCKED: return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is already locked.", h->user_name); @@ -1736,6 +1747,7 @@ int home_unlock(Home *h, UserRecord *secret, sd_bus_error *error) { case HOME_ABSENT: case HOME_INACTIVE: case HOME_ACTIVE: + case HOME_DIRTY: return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_LOCKED, "Home %s is not locked.", h->user_name); case HOME_LOCKED: break; @@ -1747,6 +1759,7 @@ int home_unlock(Home *h, UserRecord *secret, sd_bus_error *error) { } HomeState home_get_state(Home *h) { + int r; assert(h); /* When the state field is initialized, it counts. */ @@ -1759,8 +1772,11 @@ HomeState home_get_state(Home *h) { return HOME_ACTIVE; /* And if we see the image being gone, we report this as absent */ - if (user_record_test_image_path(h->record) == USER_TEST_ABSENT) + r = user_record_test_image_path(h->record); + if (r == USER_TEST_ABSENT) return HOME_ABSENT; + if (r == USER_TEST_DIRTY) + return HOME_DIRTY; /* And for all other cases we return "inactive". */ return HOME_INACTIVE; @@ -2326,6 +2342,7 @@ static int home_dispatch_acquire(Home *h, Operation *o) { break; case HOME_INACTIVE: + case HOME_DIRTY: for_state = HOME_ACTIVATING_FOR_ACQUIRE; call = home_activate_internal; break; @@ -2379,6 +2396,7 @@ static int home_dispatch_release(Home *h, Operation *o) { case HOME_UNFIXATED: case HOME_ABSENT: case HOME_INACTIVE: + case HOME_DIRTY: r = 1; /* done */ break; @@ -2420,6 +2438,7 @@ static int home_dispatch_lock_all(Home *h, Operation *o) { case HOME_UNFIXATED: case HOME_ABSENT: case HOME_INACTIVE: + case HOME_DIRTY: log_info("Home %s is not active, no locking necessary.", h->user_name); r = 1; /* done */ break; @@ -2466,6 +2485,7 @@ static int home_dispatch_pipe_eof(Home *h, Operation *o) { case HOME_UNFIXATED: case HOME_ABSENT: case HOME_INACTIVE: + case HOME_DIRTY: log_info("Home %s already deactivated, no automatic deactivation needed.", h->user_name); break; @@ -2505,6 +2525,7 @@ static int home_dispatch_deactivate_force(Home *h, Operation *o) { case HOME_UNFIXATED: case HOME_ABSENT: case HOME_INACTIVE: + case HOME_DIRTY: log_debug("Home %s already deactivated, no forced deactivation due to unplug needed.", h->user_name); break; @@ -2716,6 +2737,7 @@ static const char* const home_state_table[_HOME_STATE_MAX] = { [HOME_UNFIXATED] = "unfixated", [HOME_ABSENT] = "absent", [HOME_INACTIVE] = "inactive", + [HOME_DIRTY] = "dirty", [HOME_FIXATING] = "fixating", [HOME_FIXATING_FOR_ACTIVATION] = "fixating-for-activation", [HOME_FIXATING_FOR_ACQUIRE] = "fixating-for-acquire", diff --git a/src/home/homed-home.h b/src/home/homed-home.h index ec7966fb14..b638c6cbb1 100644 --- a/src/home/homed-home.h +++ b/src/home/homed-home.h @@ -13,6 +13,7 @@ typedef enum HomeState { HOME_UNFIXATED, /* home exists, but local record does not */ HOME_ABSENT, /* local record exists, but home does not */ HOME_INACTIVE, /* record and home exist, but is not logged in */ + HOME_DIRTY, /* like HOME_INACTIVE, but the home directory wasn't cleanly deactivated */ HOME_FIXATING, /* generating local record from home */ HOME_FIXATING_FOR_ACTIVATION, /* fixating in order to activate soon */ HOME_FIXATING_FOR_ACQUIRE, /* fixating because Acquire() was called */ diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index ab79118130..0bbe44ce26 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include + #include "errno-util.h" #include "home-util.h" #include "id128-util.h" @@ -497,8 +499,21 @@ int user_record_test_image_path(UserRecord *h) { switch (user_record_storage(h)) { case USER_LUKS: - if (S_ISREG(st.st_mode)) + if (S_ISREG(st.st_mode)) { + ssize_t n; + char x[2]; + + n = getxattr(ip, "user.home-dirty", x, sizeof(x)); + if (n < 0) { + if (errno != ENODATA) + log_debug_errno(errno, "Unable to read dirty xattr off image file, ignoring: %m"); + + } else if (n == 1 && x[0] == '1') + return USER_TEST_DIRTY; + return USER_TEST_EXISTS; + } + if (S_ISBLK(st.st_mode)) { /* For block devices we can't really be sure if the device referenced actually is the * fs we look for or some other file system (think: what does /dev/sdb1 refer diff --git a/src/home/user-record-util.h b/src/home/user-record-util.h index 613c70cacb..f8bae707bc 100644 --- a/src/home/user-record-util.h +++ b/src/home/user-record-util.h @@ -31,6 +31,7 @@ enum { USER_TEST_UNDEFINED, /* Returned by user_record_test_image_path() if the storage type knows no image paths */ USER_TEST_ABSENT, USER_TEST_EXISTS, + USER_TEST_DIRTY, /* Only applies to user_record_test_image_path(), when the image exists but is marked dirty */ USER_TEST_MOUNTED, /* Only applies to user_record_test_home_directory(), when the home directory exists. */ USER_TEST_MAYBE, /* Only applies to LUKS devices: block device exists, but we don't know if it's the right one */ }; diff --git a/src/shared/user-record-show.c b/src/shared/user-record-show.c index 6aeb6bd330..551df720ba 100644 --- a/src/shared/user-record-show.c +++ b/src/shared/user-record-show.c @@ -16,7 +16,7 @@ const char *user_record_state_color(const char *state) { return ansi_grey(); else if (streq(state, "active")) return ansi_highlight_green(); - else if (streq(state, "locked")) + else if (STR_IN_SET(state, "locked", "dirty")) return ansi_highlight_yellow(); return NULL;