]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homed: report a home directory as "dirty" if image file has dirty flag
authorLennart Poettering <lennart@poettering.net>
Mon, 17 Aug 2020 20:08:29 +0000 (22:08 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 25 Aug 2020 16:18:56 +0000 (18:18 +0200)
src/home/homed-home-bus.c
src/home/homed-home.c
src/home/homed-home.h
src/home/user-record-util.c
src/home/user-record-util.h
src/shared/user-record-show.c

index 6be361a5aace96b4847e288c4b78a78b428e7ae2..015eefb718a02c08df57355dfb0e495578a27636 100644 (file)
@@ -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);
index 367ac21633e3b211a790e66d8228aaab61749e73..6a6cde7c02d3082734dae4e405fca18ab21df410 100644 (file)
@@ -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",
index ec7966fb14bd49b9c5301e7f6f0e0c003c46e447..b638c6cbb1be7d276190940cbf5220b3df6c6162 100644 (file)
@@ -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 */
index ab79118130e45d0a1e7dcf326b254bc8053ed7ee..0bbe44ce264826b18bea1946da7b3634a7809849 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/xattr.h>
+
 #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
index 613c70cacb642877522f359c65a7ab5bca82a3ac..f8bae707bcf36fb28b3a70ccbae3f03ba44f5b99 100644 (file)
@@ -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 */
 };
index 6aeb6bd33008d98f8a4a58d2e6018a9fe5f49be9..551df720ba840e794d8ec9214f84f92b1a9c80ac 100644 (file)
@@ -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;