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);
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);
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:
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);
_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;
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:
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:
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:
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:
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:
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);
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;
}
HomeState home_get_state(Home *h) {
+ int r;
assert(h);
/* When the state field is initialized, it counts. */
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;
break;
case HOME_INACTIVE:
+ case HOME_DIRTY:
for_state = HOME_ACTIVATING_FOR_ACQUIRE;
call = home_activate_internal;
break;
case HOME_UNFIXATED:
case HOME_ABSENT:
case HOME_INACTIVE:
+ case HOME_DIRTY:
r = 1; /* done */
break;
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;
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;
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;
[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",
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/xattr.h>
+
#include "errno-util.h"
#include "home-util.h"
#include "id128-util.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