Skip to content

Commit

Permalink
homework: support creating a home for a specified partition
Browse files Browse the repository at this point in the history
This commit enable homework-luks to create a user home partition on an
existing partition. This allows us to have multiple user home partitions
on a single disk, or share user home partitions with the system
partitions.

This commit address systemd#15273 for "vanilla" partitions
Partitions on LVM have not been tested.

This works by getting the parent block device of the selected partition,
and if it has a GPT partition table, edit the partition table entry and
format the partition as a per-user home partition.

Testing:

```
$ sudo mkosi --force build
[...]
$ truncate -s 16G ./mkosi.output/arch~rolling/image.raw && sfdisk -a ./mkosi.output/arch~rolling/image.raw <<EOF
label: gpt
device: /dev/sda
unit: sectors
sector-size: 512

/dev/sda3 : size=8G, uuid=$(systemd-id128 new -u), name=test
EOF
$ sudo mkosi qemu
[...]
[root@archlinux ~]# NEWPASSWORD=APassword111 homectl create user1 --storage=luks --image-path=/dev/sda3 --fs-type=ext4 # Testing with ext4 because of systemd#22255
[root@archlinux ~]# homectl activate user1
[root@archlinux ~]# su user1
[user1@archlinux root]$ cd
[user1@archlinux ~]$ lsblk
NAME           MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
sda              8:0    0   16G  0 disk
├─sda1           8:1    0  256M  0 part
├─sda2           8:2    0    3G  0 part  /
└─sda3           8:3    0    8G  0 part
  └─home-user1 254:0    0    8G  0 crypt /home/user1
```
  • Loading branch information
pimzero committed Nov 25, 2022
1 parent 90ed880 commit 18e7266
Showing 1 changed file with 101 additions and 12 deletions.
113 changes: 101 additions & 12 deletions src/home/homework-luks.c
Expand Up @@ -1974,6 +1974,56 @@ static int make_partition_table(
return 0;
}

static int update_partition_table(
int fd,
const char *label,
uint64_t partno,
sd_id128_t partition_uuid,
uint64_t *ret_offset,
uint64_t *ret_size,
sd_id128_t *ret_disk_uuid) {
uint64_t partition_offset = 0, partition_size = 0;
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
_cleanup_(fdisk_unref_partitionp) struct fdisk_partition *p = NULL;
int r;

r = fdisk_new_context_fd(fd, /* read_only= */ false, &c);
if (r < 0)
return log_error_errno(r, "Failed to open device: %m");

if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
return log_error_errno(SYNTHETIC_ERRNO(ENOMEDIUM), "Disk has no GPT partition table.");

r = fdisk_get_partition(c, partno, &p);
if (r < 0)
return log_error_errno(r, "Failed to get partition %" PRIu64 ": %m", partno);

r = make_partition(p, label, partition_uuid);
if (r < 0)
return r;

r = fdisk_set_partition(c, partno, p);
if (r < 0)
return log_error_errno(r, "Failed to set partition %" PRIu64 ": %m", partno);

r = fdisk_write_disklabel(c);
if (r < 0)
return log_error_errno(r, "Failed to write disk label: %m");

r = query_partition_offset_and_size(c, partno, &partition_offset, &partition_size);
if (r < 0)
return r;

r = sd_id128_from_string(ASSERT_PTR(fdisk_partition_get_uuid(p)), ret_disk_uuid);
if (r < 0)
return log_error_errno(r, "Failed to parse disk label UUID: %m");

*ret_offset = partition_offset;
*ret_size = partition_size;

return 0;
}

static bool supported_fs_size(const char *fstype, uint64_t host_size) {
uint64_t m;

Expand Down Expand Up @@ -2140,15 +2190,17 @@ int home_create_luks(
char **effective_passwords,
UserRecord **ret_home) {

_cleanup_free_ char *subdir = NULL, *disk_uuid_path = NULL;
uint64_t encrypted_size,
_cleanup_free_ char *subdir = NULL, *disk_uuid_path = NULL, *partno_buf = NULL;
uint64_t encrypted_size, partno,
host_size = 0, partition_offset = 0, partition_size = 0; /* Unnecessary initialization to appease gcc */
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid;
_cleanup_close_ int mount_fd = -1;
const char *fstype, *ip;
struct statfs sfs;
int r;
bool is_partition = false;
dev_t dev_parent;

assert(h);
assert(h->storage < 0 || h->storage == USER_LUKS);
Expand Down Expand Up @@ -2232,11 +2284,37 @@ int home_create_luks(

if (asprintf(&sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/partition", DEVNUM_FORMAT_VAL(st.st_rdev)) < 0)
return log_oom();
if (access(sysfs, F_OK) < 0) {

r = read_virtual_file(sysfs, /* TODO */ 64, &partno_buf, NULL);
if (r < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to check whether %s exists: %m", sysfs);
} else
return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Operating on partitions is currently not supported, sorry. Please specify a top-level block device.");
/* TODO should we comment why we don't do anything here ? - given this is not
* necessarly explicit */
} else {
_cleanup_free_ char *parent_path = NULL;

is_partition = true;
r = block_get_whole_disk(st.st_rdev, &dev_parent);
if (r < 0)
return r;

r = safe_atou64(partno_buf, &partno);
if (r < 0)
return log_error_errno(r, "Failed to parse partition number: %m");

if (partno <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid partition number");
partno--;

r = device_path_make_canonical(S_IFBLK, dev_parent, &parent_path);
if (r < 0)
return log_error_errno(r, "Failed to build partition parent path: %m");

setup->image_fd = open_image_file(h, parent_path, &st);
if (setup->image_fd < 0)
return setup->image_fd;
}

if (flock(setup->image_fd, LOCK_EX) < 0) /* make sure udev doesn't read from it while we operate on the device */
return log_error_errno(errno, "Failed to lock block device %s: %m", ip);
Expand Down Expand Up @@ -2310,13 +2388,24 @@ int home_create_luks(
log_info("Allocating image file completed.");
}

r = make_partition_table(
setup->image_fd,
user_record_user_name_and_realm(h),
partition_uuid,
&partition_offset,
&partition_size,
&disk_uuid);
if (!is_partition) {
r = make_partition_table(
setup->image_fd,
user_record_user_name_and_realm(h),
partition_uuid,
&partition_offset,
&partition_size,
&disk_uuid);
} else {
r = update_partition_table(
setup->image_fd,
user_record_user_name_and_realm(h),
partno,
partition_uuid,
&partition_offset,
&partition_size,
&disk_uuid);
}
if (r < 0)
return r;

Expand Down

0 comments on commit 18e7266

Please sign in to comment.