diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/home/homed-home.c | 211 | ||||
-rw-r--r-- | src/home/homed-home.h | 3 | ||||
-rw-r--r-- | src/shared/user-record.c | 32 |
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 }, {}, }; |