summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/home/homed-home.c211
-rw-r--r--src/home/homed-home.h3
-rw-r--r--src/shared/user-record.c32
3 files changed, 183 insertions, 63 deletions
diff --git a/src/home/homed-home.c b/src/home/homed-home.c
index 10bb96a797..2b4e5dde8f 100644
--- a/src/home/homed-home.c
+++ b/src/home/homed-home.c
@@ -17,9 +17,11 @@
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "home-util.h"
#include "homed-home-bus.h"
#include "homed-home.h"
+#include "missing_magic.h"
#include "missing_syscall.h"
#include "mkdir.h"
#include "path-util.h"
@@ -32,9 +34,9 @@
#include "stat-util.h"
#include "string-table.h"
#include "strv.h"
+#include "user-record-pwquality.h"
#include "user-record-sign.h"
#include "user-record-util.h"
-#include "user-record-pwquality.h"
#include "user-record.h"
#include "user-util.h"
@@ -2105,29 +2107,27 @@ static int home_get_disk_status_luks(
uint64_t *ret_disk_usage,
uint64_t *ret_disk_free,
uint64_t *ret_disk_ceiling,
- uint64_t *ret_disk_floor) {
+ uint64_t *ret_disk_floor,
+ statfs_f_type_t *ret_fstype,
+ mode_t *ret_access_mode) {
uint64_t disk_size = UINT64_MAX, disk_usage = UINT64_MAX, disk_free = UINT64_MAX,
disk_ceiling = UINT64_MAX, disk_floor = UINT64_MAX,
stat_used = UINT64_MAX, fs_size = UINT64_MAX, header_size = 0;
-
+ mode_t access_mode = MODE_INVALID;
+ statfs_f_type_t fstype = 0;
struct statfs sfs;
+ struct stat st;
const char *hd;
int r;
assert(h);
- assert(ret_disk_size);
- assert(ret_disk_usage);
- assert(ret_disk_free);
- assert(ret_disk_ceiling);
if (state != HOME_ABSENT) {
const char *ip;
ip = user_record_image_path(h->record);
if (ip) {
- struct stat st;
-
if (stat(ip, &st) < 0)
log_debug_errno(errno, "Failed to stat() %s, ignoring: %m", ip);
else if (S_ISREG(st.st_mode)) {
@@ -2175,11 +2175,26 @@ static int home_get_disk_status_luks(
if (!hd)
goto finish;
+ if (stat(hd, &st) < 0) {
+ log_debug_errno(errno, "Failed to stat() %s, ignoring: %m", hd);
+ goto finish;
+ }
+
+ r = stat_verify_directory(&st);
+ if (r < 0) {
+ log_debug_errno(r, "Home directory %s is not a directory, ignoring: %m", hd);
+ goto finish;
+ }
+
+ access_mode = st.st_mode & 07777;
+
if (statfs(hd, &sfs) < 0) {
log_debug_errno(errno, "Failed to statfs() %s, ignoring: %m", hd);
goto finish;
}
+ fstype = sfs.f_type;
+
disk_free = sfs.f_bsize * sfs.f_bavail;
fs_size = sfs.f_bsize * sfs.f_blocks;
if (disk_size != UINT64_MAX && disk_size > fs_size)
@@ -2209,11 +2224,20 @@ finish:
if (disk_floor == UINT64_MAX)
disk_floor = minimal_size_by_fs_name(user_record_file_system_type(h->record));
- *ret_disk_size = disk_size;
- *ret_disk_usage = disk_usage;
- *ret_disk_free = disk_free;
- *ret_disk_ceiling = disk_ceiling;
- *ret_disk_floor = disk_floor;
+ if (ret_disk_size)
+ *ret_disk_size = disk_size;
+ if (ret_disk_usage)
+ *ret_disk_usage = disk_usage;
+ if (ret_disk_free)
+ *ret_disk_free = disk_free;
+ if (ret_disk_ceiling)
+ *ret_disk_ceiling = disk_ceiling;
+ if (ret_disk_floor)
+ *ret_disk_floor = disk_floor;
+ if (ret_fstype)
+ *ret_fstype = fstype;
+ if (ret_access_mode)
+ *ret_access_mode = access_mode;
return 0;
}
@@ -2225,20 +2249,20 @@ static int home_get_disk_status_directory(
uint64_t *ret_disk_usage,
uint64_t *ret_disk_free,
uint64_t *ret_disk_ceiling,
- uint64_t *ret_disk_floor) {
+ uint64_t *ret_disk_floor,
+ statfs_f_type_t *ret_fstype,
+ mode_t *ret_access_mode) {
uint64_t disk_size = UINT64_MAX, disk_usage = UINT64_MAX, disk_free = UINT64_MAX,
disk_ceiling = UINT64_MAX, disk_floor = UINT64_MAX;
+ mode_t access_mode = MODE_INVALID;
+ statfs_f_type_t fstype = 0;
struct statfs sfs;
struct dqblk req;
const char *path = NULL;
int r;
- assert(ret_disk_size);
- assert(ret_disk_usage);
- assert(ret_disk_free);
- assert(ret_disk_ceiling);
- assert(ret_disk_floor);
+ assert(h);
if (HOME_STATE_IS_ACTIVE(state))
path = user_record_home_directory(h->record);
@@ -2261,6 +2285,8 @@ static int home_get_disk_status_directory(
/* We don't initialize disk_usage from statfs() data here, since the device is likely not used
* by us alone, and disk_usage should only reflect our own use. */
+
+ fstype = sfs.f_type;
}
if (IN_SET(h->record->storage, USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME)) {
@@ -2349,15 +2375,109 @@ static int home_get_disk_status_directory(
}
finish:
- *ret_disk_size = disk_size;
- *ret_disk_usage = disk_usage;
- *ret_disk_free = disk_free;
- *ret_disk_ceiling = disk_ceiling;
- *ret_disk_floor = disk_floor;
+ if (ret_disk_size)
+ *ret_disk_size = disk_size;
+ if (ret_disk_usage)
+ *ret_disk_usage = disk_usage;
+ if (ret_disk_free)
+ *ret_disk_free = disk_free;
+ if (ret_disk_ceiling)
+ *ret_disk_ceiling = disk_ceiling;
+ if (ret_disk_floor)
+ *ret_disk_floor = disk_floor;
+ if (ret_fstype)
+ *ret_fstype = fstype;
+ if (ret_access_mode)
+ *ret_access_mode = access_mode;
return 0;
}
+static int home_get_disk_status_internal(
+ Home *h,
+ HomeState state,
+ uint64_t *ret_disk_size,
+ uint64_t *ret_disk_usage,
+ uint64_t *ret_disk_free,
+ uint64_t *ret_disk_ceiling,
+ uint64_t *ret_disk_floor,
+ statfs_f_type_t *ret_fstype,
+ mode_t *ret_access_mode) {
+
+ assert(h);
+ assert(h->record);
+
+ switch (h->record->storage) {
+
+ case USER_LUKS:
+ return home_get_disk_status_luks(h, state, ret_disk_size, ret_disk_usage, ret_disk_free, ret_disk_ceiling, ret_disk_floor, ret_fstype, ret_access_mode);
+
+ case USER_CLASSIC:
+ case USER_DIRECTORY:
+ case USER_SUBVOLUME:
+ case USER_FSCRYPT:
+ case USER_CIFS:
+ return home_get_disk_status_directory(h, state, ret_disk_size, ret_disk_usage, ret_disk_free, ret_disk_ceiling, ret_disk_floor, ret_fstype, ret_access_mode);
+
+ default:
+ /* don't know */
+
+ if (ret_disk_size)
+ *ret_disk_size = UINT64_MAX;
+ if (ret_disk_usage)
+ *ret_disk_usage = UINT64_MAX;
+ if (ret_disk_free)
+ *ret_disk_free = UINT64_MAX;
+ if (ret_disk_ceiling)
+ *ret_disk_ceiling = UINT64_MAX;
+ if (ret_disk_floor)
+ *ret_disk_floor = UINT64_MAX;
+ if (ret_fstype)
+ *ret_fstype = 0;
+ if (ret_access_mode)
+ *ret_access_mode = MODE_INVALID;
+
+ return 0;
+ }
+}
+
+int home_get_disk_status(
+ Home *h,
+ uint64_t *ret_disk_size,
+ uint64_t *ret_disk_usage,
+ uint64_t *ret_disk_free,
+ uint64_t *ret_disk_ceiling,
+ uint64_t *ret_disk_floor,
+ statfs_f_type_t *ret_fstype,
+ mode_t *ret_access_mode) {
+
+ assert(h);
+
+ return home_get_disk_status_internal(
+ h,
+ home_get_state(h),
+ ret_disk_size,
+ ret_disk_usage,
+ ret_disk_free,
+ ret_disk_ceiling,
+ ret_disk_floor,
+ ret_fstype,
+ ret_access_mode);
+}
+
+static const char *fstype_magic_to_name(statfs_f_type_t magic) {
+ /* For now, let's only translate the magic values of the file systems we actually are able to manage */
+
+ if (F_TYPE_EQUAL(magic, EXT4_SUPER_MAGIC))
+ return "ext4";
+ if (F_TYPE_EQUAL(magic, XFS_SUPER_MAGIC))
+ return "xfs";
+ if (F_TYPE_EQUAL(magic, BTRFS_SUPER_MAGIC))
+ return "btrfs";
+
+ return NULL;
+}
+
int home_augment_status(
Home *h,
UserRecordLoadFlags flags,
@@ -2366,6 +2486,9 @@ int home_augment_status(
uint64_t disk_size = UINT64_MAX, disk_usage = UINT64_MAX, disk_free = UINT64_MAX, disk_ceiling = UINT64_MAX, disk_floor = UINT64_MAX;
_cleanup_(json_variant_unrefp) JsonVariant *j = NULL, *v = NULL, *m = NULL, *status = NULL;
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
+ statfs_f_type_t magic;
+ const char *fstype;
+ mode_t access_mode;
HomeState state;
sd_id128_t id;
int r;
@@ -2382,29 +2505,19 @@ int home_augment_status(
state = home_get_state(h);
- switch (h->record->storage) {
-
- case USER_LUKS:
- r = home_get_disk_status_luks(h, state, &disk_size, &disk_usage, &disk_free, &disk_ceiling, &disk_floor);
- if (r < 0)
- return r;
-
- break;
-
- case USER_CLASSIC:
- case USER_DIRECTORY:
- case USER_SUBVOLUME:
- case USER_FSCRYPT:
- case USER_CIFS:
- r = home_get_disk_status_directory(h, state, &disk_size, &disk_usage, &disk_free, &disk_ceiling, &disk_floor);
- if (r < 0)
- return r;
-
- break;
+ r = home_get_disk_status_internal(
+ h, state,
+ &disk_size,
+ &disk_usage,
+ &disk_free,
+ &disk_ceiling,
+ &disk_floor,
+ &magic,
+ &access_mode);
+ if (r < 0)
+ return r;
- default:
- ; /* unset */
- }
+ fstype = fstype_magic_to_name(magic);
if (disk_floor == UINT64_MAX || (disk_usage != UINT64_MAX && disk_floor < disk_usage))
disk_floor = disk_usage;
@@ -2422,7 +2535,9 @@ int home_augment_status(
JSON_BUILD_PAIR_CONDITION(disk_free != UINT64_MAX, "diskFree", JSON_BUILD_UNSIGNED(disk_free)),
JSON_BUILD_PAIR_CONDITION(disk_ceiling != UINT64_MAX, "diskCeiling", JSON_BUILD_UNSIGNED(disk_ceiling)),
JSON_BUILD_PAIR_CONDITION(disk_floor != UINT64_MAX, "diskFloor", JSON_BUILD_UNSIGNED(disk_floor)),
- JSON_BUILD_PAIR_CONDITION(h->signed_locally >= 0, "signedLocally", JSON_BUILD_BOOLEAN(h->signed_locally))
+ JSON_BUILD_PAIR_CONDITION(h->signed_locally >= 0, "signedLocally", JSON_BUILD_BOOLEAN(h->signed_locally)),
+ JSON_BUILD_PAIR_CONDITION(fstype, "fileSystemType", JSON_BUILD_STRING(fstype)),
+ JSON_BUILD_PAIR_CONDITION(access_mode != MODE_INVALID, "accessMode", JSON_BUILD_UNSIGNED(access_mode))
));
if (r < 0)
return r;
diff --git a/src/home/homed-home.h b/src/home/homed-home.h
index 7cd8a9edb4..37c54b0557 100644
--- a/src/home/homed-home.h
+++ b/src/home/homed-home.h
@@ -7,6 +7,7 @@ typedef struct Home Home;
#include "homed-operation.h"
#include "list.h"
#include "ordered-set.h"
+#include "stat-util.h"
#include "user-record.h"
typedef enum HomeState {
@@ -190,6 +191,8 @@ int home_unlock(Home *h, UserRecord *secret, sd_bus_error *error);
HomeState home_get_state(Home *h);
+int home_get_disk_status(Home *h, uint64_t *ret_disk_size,uint64_t *ret_disk_usage, uint64_t *ret_disk_free, uint64_t *ret_disk_ceiling, uint64_t *ret_disk_floor, statfs_f_type_t *ret_fstype, mode_t *ret_access_mode);
+
void home_process_notify(Home *h, char **l, int fd);
int home_killall(Home *h);
diff --git a/src/shared/user-record.c b/src/shared/user-record.c
index 6413fc904d..2fbe6ad5bd 100644
--- a/src/shared/user-record.c
+++ b/src/shared/user-record.c
@@ -1356,21 +1356,23 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
static const JsonDispatch status_dispatch_table[] = {
- { "diskUsage", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_usage), 0 },
- { "diskFree", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_free), 0 },
- { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
- { "diskCeiling", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_ceiling), 0 },
- { "diskFloor", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_floor), 0 },
- { "state", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, state), JSON_SAFE },
- { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
- { "signedLocally", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, signed_locally), 0 },
- { "goodAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, good_authentication_counter), 0 },
- { "badAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, bad_authentication_counter), 0 },
- { "lastGoodAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_good_authentication_usec), 0 },
- { "lastBadAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_bad_authentication_usec), 0 },
- { "rateLimitBeginUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_begin_usec), 0 },
- { "rateLimitCount", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_count), 0 },
- { "removable", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, removable), 0 },
+ { "diskUsage", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_usage), 0 },
+ { "diskFree", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_free), 0 },
+ { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
+ { "diskCeiling", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_ceiling), 0 },
+ { "diskFloor", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_floor), 0 },
+ { "state", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, state), JSON_SAFE },
+ { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
+ { "signedLocally", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, signed_locally), 0 },
+ { "goodAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, good_authentication_counter), 0 },
+ { "badAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, bad_authentication_counter), 0 },
+ { "lastGoodAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_good_authentication_usec), 0 },
+ { "lastBadAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_bad_authentication_usec), 0 },
+ { "rateLimitBeginUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_begin_usec), 0 },
+ { "rateLimitCount", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_count), 0 },
+ { "removable", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, removable), 0 },
+ { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
+ { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
{},
};