From b1f4b393f1456c2de46c283618bbd8d6da770f7d Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Fri, 26 Jan 2024 19:01:23 +0100 Subject: [PATCH] libbtrfsutil: add btrfs_util_get_label Extend libbtrfs with a method to obtain to btrfs filesystem label. Signed-off-by: Jelle van der Waa --- libbtrfsutil/README.md | 1 + libbtrfsutil/btrfsutil.h | 19 +++++++++ libbtrfsutil/errors.c | 2 + libbtrfsutil/filesystem.c | 41 ++++++++++++++++++++ libbtrfsutil/libbtrfsutil.sym | 2 + libbtrfsutil/python/btrfsutilpy.h | 1 + libbtrfsutil/python/filesystem.c | 25 ++++++++++++ libbtrfsutil/python/module.c | 6 +++ libbtrfsutil/python/tests/test_filesystem.py | 4 ++ 9 files changed, 101 insertions(+) diff --git a/libbtrfsutil/README.md b/libbtrfsutil/README.md index d20f339805..d0e7884f5a 100644 --- a/libbtrfsutil/README.md +++ b/libbtrfsutil/README.md @@ -479,6 +479,7 @@ everywhere. The following checklist should help to make sure nothing is missing: ### API summary * filesystem + * get_label * sync * wait for sync * subvolume diff --git a/libbtrfsutil/btrfsutil.h b/libbtrfsutil/btrfsutil.h index e55502f193..2094d261d2 100644 --- a/libbtrfsutil/btrfsutil.h +++ b/libbtrfsutil/btrfsutil.h @@ -67,6 +67,7 @@ enum btrfs_util_error { BTRFS_UTIL_ERROR_GET_SUBVOL_ROOTREF_FAILED, BTRFS_UTIL_ERROR_INO_LOOKUP_USER_FAILED, BTRFS_UTIL_ERROR_FS_INFO_FAILED, + BTRFS_UTIL_ERROR_FS_GET_LABEL_FAILED, }; /** @@ -78,6 +79,24 @@ enum btrfs_util_error { */ const char *btrfs_util_strerror(enum btrfs_util_error err); +/** + * btrfs_util_get_label() - Get the filesystem label for a + * filesystem. + * @path: Path on a Btrfs filesystem. + * @label: Returned filesytem label. + * + * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. + */ +enum btrfs_util_error btrfs_util_get_label(const char *path, + char **label); + +/** + * btrfs_util_get_label_fd() - See + * btrfs_util_get_label(). + */ +enum btrfs_util_error btrfs_util_get_label_fd(int fd, + char **label); + /** * btrfs_util_sync() - Force a sync on a specific Btrfs filesystem. * @path: Path on a Btrfs filesystem. diff --git a/libbtrfsutil/errors.c b/libbtrfsutil/errors.c index 989096e2b6..9d4896be6d 100644 --- a/libbtrfsutil/errors.c +++ b/libbtrfsutil/errors.c @@ -53,6 +53,8 @@ static const char * const error_messages[] = { "Could not resolve subvolume path with BTRFS_IOC_INO_LOOKUP_USER", [BTRFS_UTIL_ERROR_FS_INFO_FAILED] = "Could not get filesystem information", + [BTRFS_UTIL_ERROR_FS_GET_LABEL_FAILED] = + "Could not get filesystem label", }; PUBLIC const char *btrfs_util_strerror(enum btrfs_util_error err) diff --git a/libbtrfsutil/filesystem.c b/libbtrfsutil/filesystem.c index e4c65e24ff..7d7c7c4150 100644 --- a/libbtrfsutil/filesystem.c +++ b/libbtrfsutil/filesystem.c @@ -19,11 +19,52 @@ #include #include +#include #include #include #include "btrfsutil_internal.h" + +PUBLIC enum btrfs_util_error btrfs_util_get_label(const char *path, + char **label_ret) +{ + enum btrfs_util_error err; + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) + return BTRFS_UTIL_ERROR_OPEN_FAILED; + + err = btrfs_util_get_label_fd(fd, label_ret); + if (err) + return err; + + return BTRFS_UTIL_OK; +} + +PUBLIC enum btrfs_util_error btrfs_util_get_label_fd(int fd, + char **label_ret) +{ + int ret; + size_t len; + + char label[BTRFS_PATH_NAME_MAX]; + ret = ioctl(fd, BTRFS_IOC_GET_FSLABEL, label); + if (ret == -1) + return BTRFS_UTIL_ERROR_SUBVOL_SETFLAGS_FAILED; + + len = strlen(label); + *label_ret = malloc(len + 1); + if (!*label_ret) + return BTRFS_UTIL_ERROR_NO_MEMORY; + + memcpy(*label_ret, label, len); + label_ret[len] = '\0'; + + return BTRFS_UTIL_OK; +} + PUBLIC enum btrfs_util_error btrfs_util_sync(const char *path) { enum btrfs_util_error err; diff --git a/libbtrfsutil/libbtrfsutil.sym b/libbtrfsutil/libbtrfsutil.sym index e1ab715248..0059ea430c 100644 --- a/libbtrfsutil/libbtrfsutil.sym +++ b/libbtrfsutil/libbtrfsutil.sym @@ -16,6 +16,8 @@ global: btrfs_util_destroy_subvolume_iterator; btrfs_util_get_default_subvolume; btrfs_util_get_default_subvolume_fd; + btrfs_util_get_label; + btrfs_util_get_label_fd; btrfs_util_get_subvolume_read_only; btrfs_util_get_subvolume_read_only_fd; btrfs_util_is_subvolume; diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h index ee70c23ac2..9a11f1ac5b 100644 --- a/libbtrfsutil/python/btrfsutilpy.h +++ b/libbtrfsutil/python/btrfsutilpy.h @@ -63,6 +63,7 @@ void SetFromBtrfsUtilErrorWithPaths(enum btrfs_util_error err, struct path_arg *path1, struct path_arg *path2); +PyObject *filesystem_get_label(PyObject *self, PyObject *args, PyObject *kwds); PyObject *filesystem_sync(PyObject *self, PyObject *args, PyObject *kwds); PyObject *start_sync(PyObject *self, PyObject *args, PyObject *kwds); PyObject *wait_sync(PyObject *self, PyObject *args, PyObject *kwds); diff --git a/libbtrfsutil/python/filesystem.c b/libbtrfsutil/python/filesystem.c index 5177c75d6a..5765ce5a17 100644 --- a/libbtrfsutil/python/filesystem.c +++ b/libbtrfsutil/python/filesystem.c @@ -19,6 +19,31 @@ #include "btrfsutilpy.h" +PyObject *filesystem_get_label(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *keywords[] = {"path", NULL}; + struct path_arg path = {.allow_fd = true}; + enum btrfs_util_error err; + char *label; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:get_label", keywords, + &path_converter, &path)) + return NULL; + + if (path.path) + err = btrfs_util_get_label(path.path, &label); + else + err = btrfs_util_get_label_fd(path.fd, &label); + if (err) { + SetFromBtrfsUtilErrorWithPath(err, &path); + path_cleanup(&path); + return NULL; + } + + path_cleanup(&path); + return PyUnicode_FromString(label); +} + PyObject *filesystem_sync(PyObject *self, PyObject *args, PyObject *kwds) { static char *keywords[] = {"path", NULL}; diff --git a/libbtrfsutil/python/module.c b/libbtrfsutil/python/module.c index 2657ee289f..1c24c3d4ee 100644 --- a/libbtrfsutil/python/module.c +++ b/libbtrfsutil/python/module.c @@ -155,6 +155,12 @@ void path_cleanup(struct path_arg *path) } static PyMethodDef btrfsutil_methods[] = { + {"get_label", (PyCFunction)filesystem_get_label, + METH_VARARGS | METH_KEYWORDS, + "get_label(path)\n\n" + "Get the filesystem label.\n\n" + "Arguments:\n" + "path -- string, bytes, path-like object, or open file descriptor"}, {"sync", (PyCFunction)filesystem_sync, METH_VARARGS | METH_KEYWORDS, "sync(path)\n\n" diff --git a/libbtrfsutil/python/tests/test_filesystem.py b/libbtrfsutil/python/tests/test_filesystem.py index f084261ab7..637725d475 100644 --- a/libbtrfsutil/python/tests/test_filesystem.py +++ b/libbtrfsutil/python/tests/test_filesystem.py @@ -71,3 +71,7 @@ def test_wait_sync(self): new_generation = self.super_generation() self.assertGreater(new_generation, old_generation) old_generation = new_generation + + def test_get_label(self): + label = btrfsutil.get_label(self.mountpoint) + self.assertIsNotNone(label)