[PATCH 0/2] qemu_tpm: Try harder to create emulator state

*** BLURB HERE *** Michal Prívozník (2): virfile: Introduce virDirIsEmpty() qemu_tpm: Try harder to create emulator state src/libvirt_private.syms | 1 + src/qemu/qemu_tpm.c | 3 ++- src/util/virfile.c | 39 +++++++++++++++++++++++++++++++++++++++ src/util/virfile.h | 3 +++ 4 files changed, 45 insertions(+), 1 deletion(-) -- 2.41.0

There might be cases where we want to know whether given directory is empty or not. Introduce a helper for that: virDirIsEmpty(). Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virfile.c | 39 +++++++++++++++++++++++++++++++++++++++ src/util/virfile.h | 3 +++ 3 files changed, 43 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3071dec13a..da60c965dd 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2271,6 +2271,7 @@ safezero; virBuildPathInternal; virDirClose; virDirCreate; +virDirIsEmpty; virDirOpen; virDirOpenIfExists; virDirOpenQuiet; diff --git a/src/util/virfile.c b/src/util/virfile.c index 6b4d4c3522..7c44a2a963 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -3036,6 +3036,45 @@ void virDirClose(DIR *dirp) closedir(dirp); /* exempt from syntax-check */ } +/** + * virDirIsEmpty: + * @path: path to the directory + * @hidden: whether hidden files matter + * + * Check whether given directory (@path) is empty, i.e. it + * contains just the usual entries '.' and '..'. Hidden files are + * ignored unless @hidden is true. IOW, a directory containing + * nothing but hidden files is considered empty if @hidden is + * false and not empty if @hidden is true. + * + * Returns: 1 if the directory is empty, + * 0 if the directory is not empty, + * -1 otherwise (no error reported). + */ +int virDirIsEmpty(const char *path, + bool hidden) +{ + g_autoptr(DIR) dir = NULL; + struct dirent *ent; + int direrr; + + if (virDirOpenQuiet(&dir, path) < 0) + return -1; + + while ((direrr = virDirRead(dir, &ent, NULL)) > 0) { + /* virDirRead() skips over '.' and '..' so here we have + * actual directory entry. */ + if (!hidden || + (hidden && ent->d_name[0] != '.')) + return 0; + } + + if (direrr < 0) + return -1; + + return 1; +} + /* * virFileChownFiles: diff --git a/src/util/virfile.h b/src/util/virfile.h index 6a14173625..b75a7cc53b 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -283,6 +283,9 @@ int virDirRead(DIR *dirp, struct dirent **ent, const char *dirname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; void virDirClose(DIR *dirp); G_DEFINE_AUTOPTR_CLEANUP_FUNC(DIR, virDirClose); +int virDirIsEmpty(const char *path, + bool hidden) + ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT; int virFileMakeParentPath(const char *path) G_GNUC_WARN_UNUSED_RESULT; -- 2.41.0

On a Friday in 2023, Michal Privoznik wrote:
There might be cases where we want to know whether given directory is empty or not. Introduce a helper for that: virDirIsEmpty().
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virfile.c | 39 +++++++++++++++++++++++++++++++++++++++ src/util/virfile.h | 3 +++ 3 files changed, 43 insertions(+)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

If a per-domain SWTPM state directory exists but is empty our code still considers it a valid state and skips running 'swtpm_setup' (handled in qemuTPMEmulatorRunSetup()). While we should not try to inspect individual files created by swtpm, we can still consider empty folder as non-existent state. Resolves: https://gitlab.com/libvirt/libvirt/-/issues/320 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_tpm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index 0b77ce2bc7..121f98174c 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -186,7 +186,8 @@ qemuTPMEmulatorCreateStorage(virDomainTPMDef *tpm, *created = false; - if (!virFileExists(storagepath)) + if (!virFileExists(storagepath) || + virDirIsEmpty(storagepath, false) > 0) *created = true; if (virDirCreate(storagepath, 0700, swtpm_user, swtpm_group, -- 2.41.0

On a Friday in 2023, Michal Privoznik wrote:
If a per-domain SWTPM state directory exists but is empty our code still considers it a valid state and skips running 'swtpm_setup' (handled in qemuTPMEmulatorRunSetup()). While we should not try to inspect individual files created by swtpm, we can still consider empty folder as non-existent state.
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/320 Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_tpm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index 0b77ce2bc7..121f98174c 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -186,7 +186,8 @@ qemuTPMEmulatorCreateStorage(virDomainTPMDef *tpm,
*created = false;
- if (!virFileExists(storagepath)) + if (!virFileExists(storagepath) || + virDirIsEmpty(storagepath, false) > 0) *created = true;
This means we will possibly delete a directory we did not create on error in qemuTPMEmulatorBuildCommand. That is possibly harmless, but I would call virDirIsEmpty with hidden=true, to make sure we don't delete a non-empty directory. Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
if (virDirCreate(storagepath, 0700, swtpm_user, swtpm_group, -- 2.41.0
participants (2)
-
Ján Tomko
-
Michal Privoznik