/* * Copyright (C) 2020 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . * */ #include "pyblkid.h" #include "probe.h" #include "topology.h" #include "partitions.h" #include "cache.h" #include #include #include #define UNUSED __attribute__((unused)) PyDoc_STRVAR(Blkid_init_debug__doc__, "init_debug (mask)\n\n" "If the mask is not specified then this function reads LIBBLKID_DEBUG environment variable to get the mask.\n" "Already initialized debugging stuff cannot be changed. It does not have effect to call this function twice.\n\n" "Use '0xffff' to enable full debugging.\n"); static PyObject *Blkid_init_debug (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { int mask = 0; char *kwlist[] = { "mask", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|i", kwlist, &mask)) return NULL; blkid_init_debug (mask); Py_RETURN_NONE; } PyDoc_STRVAR(Blkid_known_fstype__doc__, "known_fstype (fstype)\n\n" "Returns whether fstype is a known filesystem type or not.\n"); static PyObject *Blkid_known_fstype (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { const char *fstype = NULL; char *kwlist[] = { "fstype", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &fstype)) return NULL; return PyBool_FromLong (blkid_known_fstype (fstype)); } PyDoc_STRVAR(Blkid_send_uevent__doc__, "send_uevent (devname, action)\n\n"); static PyObject *Blkid_send_uevent (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { const char *devname = NULL; const char *action = NULL; char *kwlist[] = { "devname", "action", NULL }; int ret = 0; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "ss", kwlist, &devname, &action)) return NULL; ret = blkid_send_uevent (devname, action); if (ret < 0) { PyErr_Format (PyExc_RuntimeError, "Failed to send %s uevent do device '%s'", action, devname); return NULL; } Py_RETURN_NONE; } PyDoc_STRVAR(Blkid_known_pttype__doc__, "known_pttype (pttype)\n\n" "Returns whether pttype is a known partition type or not.\n"); static PyObject *Blkid_known_pttype (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { const char *pttype = NULL; char *kwlist[] = { "pttype", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &pttype)) return NULL; return PyBool_FromLong (blkid_known_pttype (pttype)); } static int _Py_Dev_Converter (PyObject *obj, void *p) { #ifdef HAVE_LONG_LONG *((dev_t *)p) = PyLong_AsUnsignedLongLong (obj); #else *((dev_t *)p) = PyLong_AsUnsignedLong (obj); #endif if (PyErr_Occurred ()) return 0; return 1; } #ifdef HAVE_LONG_LONG #define _PyLong_FromDev PyLong_FromLongLong #else #define _PyLong_FromDev PyLong_FromLong #endif PyDoc_STRVAR(Blkid_devno_to_devname__doc__, "devno_to_devname (devno)\n\n" "This function finds the pathname to a block device with a given device number.\n"); static PyObject *Blkid_devno_to_devname (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { dev_t devno = 0; char *kwlist[] = { "devno", NULL }; char *devname = NULL; PyObject *ret = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O&:devno_to_devname", kwlist, _Py_Dev_Converter, &devno)) return NULL; devname = blkid_devno_to_devname (devno); if (!devname) { PyErr_SetString (PyExc_RuntimeError, "Failed to get devname"); return NULL; } ret = PyUnicode_FromString (devname); free (devname); return ret; } PyDoc_STRVAR(Blkid_devno_to_wholedisk__doc__, "devno_to_wholedisk (devno)\n\n" "This function uses sysfs to convert the devno device number to the name and devno of the whole disk."); static PyObject *Blkid_devno_to_wholedisk (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { dev_t devno = 0; dev_t diskdevno = 0; char *kwlist[] = { "devno", NULL }; #ifdef HAVE_BLKID_2_28 char diskname[32]; #else char diskname[PATH_MAX]; #endif int ret = 0; PyObject *tuple = NULL; PyObject *py_name = NULL; PyObject *py_devno = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O&:devno_to_wholedisk", kwlist, _Py_Dev_Converter, &devno)) return NULL; #ifdef HAVE_BLKID_2_28 ret = blkid_devno_to_wholedisk (devno, diskname, 32, &diskdevno); #else ret = blkid_devno_to_wholedisk (devno, diskname, PATH_MAX, &diskdevno); #endif if (ret != 0) { PyErr_SetString (PyExc_RuntimeError, "Failed to get whole disk name"); return NULL; } tuple = PyTuple_New (2); py_name = PyUnicode_FromString (diskname); if (py_name == NULL) { Py_INCREF (Py_None); py_name = Py_None; } PyTuple_SetItem (tuple, 0, py_name); py_devno = _PyLong_FromDev (diskdevno); if (py_devno == NULL) { Py_INCREF (Py_None); py_devno = Py_None; } PyTuple_SetItem (tuple, 1, py_devno); return tuple; } PyDoc_STRVAR(Blkid_parse_version_string__doc__, "parse_version_string (version)\n\n" "Convert version string (e.g. '2.16.0') to release version code (e.g. '2160').\n"); static PyObject *Blkid_parse_version_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { char *ver_str = NULL; char *kwlist[] = { "version", NULL }; int ret = 0; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &ver_str)) return NULL; ret = blkid_parse_version_string (ver_str); return PyLong_FromLong (ret); } PyDoc_STRVAR(Blkid_get_library_version__doc__, "get_library_version ()\n\n" "Returns tuple of release version code (int), version string and date.\n"); static PyObject *Blkid_get_library_version (ProbeObject *self UNUSED, PyObject *Py_UNUSED (ignored)) { const char *ver_str = NULL; const char *date = NULL; int ver_code = 0; PyObject *ret = NULL; PyObject *py_code = NULL; PyObject *py_ver = NULL; PyObject *py_date = NULL; ver_code = blkid_get_library_version (&ver_str, &date); ret = PyTuple_New (3); py_code = PyLong_FromLong (ver_code); PyTuple_SetItem (ret, 0, py_code); py_ver = PyUnicode_FromString (ver_str); if (py_ver == NULL) { Py_INCREF (Py_None); py_ver = Py_None; } PyTuple_SetItem (ret, 1, py_ver); py_date = PyUnicode_FromString (date); if (py_date == NULL) { Py_INCREF (Py_None); py_date = Py_None; } PyTuple_SetItem (ret, 2, py_date); return ret; } PyDoc_STRVAR(Blkid_parse_tag_string__doc__, "parse_tag_string (tag)\n\n" "Parse a 'NAME=value' string, returns tuple of type and value.\n"); static PyObject *Blkid_parse_tag_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { char *tag_str = NULL; char *kwlist[] = { "tag", NULL }; int ret = 0; char *type = NULL; char *value = NULL; PyObject *py_type = NULL; PyObject *py_value = NULL; PyObject *tuple = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &tag_str)) return NULL; ret = blkid_parse_tag_string (tag_str, &type, &value); if (ret < 0) { PyErr_Format (PyExc_RuntimeError, "Failed to parse tag '%s'", tag_str); return NULL; } tuple = PyTuple_New (2); py_type = PyUnicode_FromString (type); if (py_type == NULL) { Py_INCREF (Py_None); py_type = Py_None; } PyTuple_SetItem (tuple, 0, py_type); free (type); py_value = PyUnicode_FromString (value); if (py_value == NULL) { Py_INCREF (Py_None); py_value = Py_None; } PyTuple_SetItem (tuple, 1, py_value); free (value); return tuple; } PyDoc_STRVAR(Blkid_get_dev_size__doc__, "get_dev_size (device)\n\n" "Returns size (in bytes) of the block device or size of the regular file.\n"); static PyObject *Blkid_get_dev_size (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { char *device = NULL; char *kwlist[] = { "device", NULL }; blkid_loff_t ret = 0; int fd = 0; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &device)) return NULL; fd = open (device, O_RDONLY|O_CLOEXEC); if (fd == -1) { PyErr_Format (PyExc_OSError, "Failed to open device '%s': %s", device, strerror (errno)); return NULL; } ret = blkid_get_dev_size (fd); if (ret == 0) { PyErr_Format (PyExc_RuntimeError, "Failed to get size of device '%s'", device); close (fd); return NULL; } close (fd); return PyLong_FromLongLong (ret); } PyDoc_STRVAR(Blkid_encode_string__doc__, "encode_string (string)\n\n" "Encode all potentially unsafe characters of a string to the corresponding hex value prefixed by '\\x'.\n"); static PyObject *Blkid_encode_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { char *string = NULL; char *kwlist[] = { "string", NULL }; char *encoded_string = NULL; int ret = 0; size_t inlen = 0; size_t outlen = 0; PyObject *py_ret = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &string)) return NULL; inlen = strlen (string); outlen = inlen * 4; encoded_string = malloc (sizeof (char) * (outlen + 1 )); ret = blkid_encode_string (string, encoded_string, outlen); if (ret != 0) { PyErr_Format (PyExc_RuntimeError, "Failed to encode string"); free (encoded_string); return NULL; } py_ret = PyUnicode_FromString (encoded_string); free (encoded_string); return py_ret; } PyDoc_STRVAR(Blkid_safe_string__doc__, "safe_string (string)\n\n" "Allows plain ascii, hex-escaping and valid utf8. Replaces all whitespaces with '_'.\n"); static PyObject *Blkid_safe_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { char *string = NULL; char *kwlist[] = { "string", NULL }; char *safe_string = NULL; int ret = 0; size_t inlen = 0; size_t outlen = 0; PyObject *py_ret = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &string)) return NULL; inlen = strlen (string); outlen = inlen * 4; safe_string = malloc (sizeof (char) * (outlen + 1 )); ret = blkid_safe_string (string, safe_string, outlen); if (ret != 0) { PyErr_Format (PyExc_RuntimeError, "Failed to make safe string"); free (safe_string); return NULL; } py_ret = PyUnicode_FromString (safe_string); free (safe_string); return py_ret; } #ifdef HAVE_BLKID_2_30 PyDoc_STRVAR(Blkid_partition_types__doc__, "partition_types ()\n\n" "List of supported partition types.\n"); static PyObject *Blkid_partition_types (ProbeObject *self UNUSED, PyObject *Py_UNUSED (ignored)) { PyObject *ret = NULL; PyObject *py_name = NULL; size_t idx = 0; const char *name = NULL; ret = PyList_New (0); while (blkid_partitions_get_name (idx++, &name) == 0) { py_name = PyUnicode_FromString (name); if (py_name != NULL) PyList_Append (ret, py_name); } return ret; } #endif PyDoc_STRVAR(Blkid_superblocks__doc__, "superblocks ()\n\n" "List of supported superblocks.\n"); static PyObject *Blkid_superblocks (ProbeObject *self UNUSED, PyObject *Py_UNUSED (ignored)) { PyObject *ret = NULL; PyObject *py_name = NULL; size_t idx = 0; const char *name = NULL; ret = PyList_New (0); while (blkid_superblocks_get_name (idx++, &name, NULL) == 0) { py_name = PyUnicode_FromString (name); if (py_name != NULL) PyList_Append (ret, py_name); } return ret; } PyDoc_STRVAR(Blkid_evaluate_tag__doc__, "evaluate_tag (token, value)\n\n" "Get device name that match the specified token (e.g \"LABEL\" or \"UUID\") and token value.\n" "The evaluation could be controlled by the /etc/blkid.conf config file. The default is to try \"udev\" and then \"scan\" method.\n"); static PyObject *Blkid_evaluate_tag (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { char *token = NULL; char *value = NULL; char *kwlist[] = { "token", "value", NULL }; PyObject *py_ret = NULL; char *ret = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "ss", kwlist, &token, &value)) return NULL; ret = blkid_evaluate_tag (token, value, NULL); if (ret == NULL) { Py_INCREF (Py_None); py_ret = Py_None; } else { py_ret = PyUnicode_FromString (ret); free (ret); } return py_ret; } PyDoc_STRVAR(Blkid_evaluate_spec__doc__, "evaluate_spec (spec)\n\n" "Get device name that match the unparsed tag (e.g. \"LABEL=foo\") or path (e.g. /dev/dm-0)\n" "The evaluation could be controlled by the /etc/blkid.conf config file. The default is to try \"udev\" and then \"scan\" method.\n"); static PyObject *Blkid_evaluate_spec (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { char *spec = NULL; char *kwlist[] = { "spec", NULL }; PyObject *py_ret = NULL; char *ret = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &spec)) return NULL; ret = blkid_evaluate_spec (spec, NULL); if (ret == NULL) { Py_INCREF (Py_None); py_ret = Py_None; } else { py_ret = PyUnicode_FromString (ret); free (ret); } return py_ret; } static PyMethodDef BlkidMethods[] = { {"init_debug", (PyCFunction)(void(*)(void)) Blkid_init_debug, METH_VARARGS|METH_KEYWORDS, Blkid_init_debug__doc__}, {"known_fstype", (PyCFunction)(void(*)(void)) Blkid_known_fstype, METH_VARARGS|METH_KEYWORDS, Blkid_known_fstype__doc__}, {"send_uevent", (PyCFunction)(void(*)(void)) Blkid_send_uevent, METH_VARARGS|METH_KEYWORDS, Blkid_send_uevent__doc__}, {"devno_to_devname", (PyCFunction)(void(*)(void)) Blkid_devno_to_devname, METH_VARARGS|METH_KEYWORDS, Blkid_devno_to_devname__doc__}, {"devno_to_wholedisk", (PyCFunction)(void(*)(void)) Blkid_devno_to_wholedisk, METH_VARARGS|METH_KEYWORDS, Blkid_devno_to_wholedisk__doc__}, {"known_pttype", (PyCFunction)(void(*)(void)) Blkid_known_pttype, METH_VARARGS|METH_KEYWORDS, Blkid_known_pttype__doc__}, {"parse_version_string", (PyCFunction)(void(*)(void)) Blkid_parse_version_string, METH_VARARGS|METH_KEYWORDS, Blkid_parse_version_string__doc__}, {"get_library_version", (PyCFunction) Blkid_get_library_version, METH_NOARGS, Blkid_get_library_version__doc__}, {"parse_tag_string", (PyCFunction)(void(*)(void)) Blkid_parse_tag_string, METH_VARARGS|METH_KEYWORDS, Blkid_parse_tag_string__doc__}, {"get_dev_size", (PyCFunction)(void(*)(void)) Blkid_get_dev_size, METH_VARARGS|METH_KEYWORDS, Blkid_get_dev_size__doc__}, {"encode_string", (PyCFunction)(void(*)(void)) Blkid_encode_string, METH_VARARGS|METH_KEYWORDS, Blkid_encode_string__doc__}, {"safe_string", (PyCFunction)(void(*)(void)) Blkid_safe_string, METH_VARARGS|METH_KEYWORDS, Blkid_safe_string__doc__}, #ifdef HAVE_BLKID_2_30 {"partition_types", (PyCFunction) Blkid_partition_types, METH_NOARGS, Blkid_partition_types__doc__}, #endif {"superblocks", (PyCFunction) Blkid_superblocks, METH_NOARGS, Blkid_superblocks__doc__}, {"evaluate_tag", (PyCFunction)(void(*)(void)) Blkid_evaluate_tag, METH_VARARGS|METH_KEYWORDS, Blkid_evaluate_tag__doc__}, {"evaluate_spec", (PyCFunction)(void(*)(void)) Blkid_evaluate_spec, METH_VARARGS|METH_KEYWORDS, Blkid_evaluate_spec__doc__}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef blkidmodule = { PyModuleDef_HEAD_INIT, .m_name = "blkid", .m_doc = "Python interface for the libblkid C library", .m_size = -1, .m_methods = BlkidMethods, }; PyMODINIT_FUNC PyInit_blkid (void) { PyObject *module = NULL; if (PyType_Ready (&ProbeType) < 0) return NULL; if (PyType_Ready (&TopologyType) < 0) return NULL; if (PyType_Ready (&PartlistType) < 0) return NULL; if (PyType_Ready (&ParttableType) < 0) return NULL; if (PyType_Ready (&PartitionType) < 0) return NULL; if (PyType_Ready (&CacheType) < 0) return NULL; if (PyType_Ready (&DeviceType) < 0) return NULL; module = PyModule_Create (&blkidmodule); if (!module) return NULL; PyModule_AddIntConstant (module, "FLTR_NOTIN", BLKID_FLTR_NOTIN); PyModule_AddIntConstant (module, "FLTR_ONLYIN", BLKID_FLTR_ONLYIN); PyModule_AddIntConstant (module, "DEV_CREATE", BLKID_DEV_CREATE); PyModule_AddIntConstant (module, "DEV_FIND", BLKID_DEV_FIND); PyModule_AddIntConstant (module, "DEV_NORMAL", BLKID_DEV_NORMAL); PyModule_AddIntConstant (module, "DEV_VERIFY", BLKID_DEV_VERIFY); PyModule_AddIntConstant (module, "PARTS_ENTRY_DETAILS", BLKID_PARTS_ENTRY_DETAILS); PyModule_AddIntConstant (module, "PARTS_FORCE_GPT", BLKID_PARTS_FORCE_GPT); PyModule_AddIntConstant (module, "PARTS_MAGIC", BLKID_PARTS_MAGIC); #ifdef HAVE_BLKID_2_24 PyModule_AddIntConstant (module, "SUBLKS_BADCSUM", BLKID_SUBLKS_BADCSUM); #endif PyModule_AddIntConstant (module, "SUBLKS_DEFAULT", BLKID_SUBLKS_DEFAULT); #ifdef HAVE_BLKID_2_39 PyModule_AddIntConstant (module, "SUBLKS_FSINFO", BLKID_SUBLKS_FSINFO); #endif PyModule_AddIntConstant (module, "SUBLKS_LABEL", BLKID_SUBLKS_LABEL); PyModule_AddIntConstant (module, "SUBLKS_LABELRAW", BLKID_SUBLKS_LABELRAW); PyModule_AddIntConstant (module, "SUBLKS_MAGIC", BLKID_SUBLKS_MAGIC); PyModule_AddIntConstant (module, "SUBLKS_SECTYPE", BLKID_SUBLKS_SECTYPE); PyModule_AddIntConstant (module, "SUBLKS_TYPE", BLKID_SUBLKS_TYPE); PyModule_AddIntConstant (module, "SUBLKS_USAGE", BLKID_SUBLKS_USAGE); PyModule_AddIntConstant (module, "SUBLKS_UUID", BLKID_SUBLKS_UUID); PyModule_AddIntConstant (module, "SUBLKS_UUIDRAW", BLKID_SUBLKS_UUIDRAW); PyModule_AddIntConstant (module, "SUBLKS_VERSION", BLKID_SUBLKS_VERSION); PyModule_AddIntConstant (module, "USAGE_CRYPTO", BLKID_USAGE_CRYPTO); PyModule_AddIntConstant (module, "USAGE_FILESYSTEM", BLKID_USAGE_FILESYSTEM); PyModule_AddIntConstant (module, "USAGE_OTHER", BLKID_USAGE_OTHER); PyModule_AddIntConstant (module, "USAGE_RAID", BLKID_USAGE_RAID); Py_INCREF (&ProbeType); if (PyModule_AddObject (module, "Probe", (PyObject *) &ProbeType) < 0) { Py_DECREF (&ProbeType); Py_DECREF (module); return NULL; } Py_INCREF (&TopologyType); if (PyModule_AddObject (module, "Topology", (PyObject *) &TopologyType) < 0) { Py_DECREF (&ProbeType); Py_DECREF (&TopologyType); Py_DECREF (module); return NULL; } Py_INCREF (&PartlistType); if (PyModule_AddObject (module, "Partlist", (PyObject *) &PartlistType) < 0) { Py_DECREF (&ProbeType); Py_DECREF (&TopologyType); Py_DECREF (&PartlistType); Py_DECREF (module); return NULL; } Py_INCREF (&ParttableType); if (PyModule_AddObject (module, "Parttable", (PyObject *) &ParttableType) < 0) { Py_DECREF (&ProbeType); Py_DECREF (&TopologyType); Py_DECREF (&PartlistType); Py_DECREF (&ParttableType); Py_DECREF (module); return NULL; } Py_INCREF (&PartitionType); if (PyModule_AddObject (module, "Partition", (PyObject *) &PartitionType) < 0) { Py_DECREF (&ProbeType); Py_DECREF (&TopologyType); Py_DECREF (&PartlistType); Py_DECREF (&ParttableType); Py_DECREF (&PartitionType); Py_DECREF (module); return NULL; } Py_INCREF (&CacheType); if (PyModule_AddObject (module, "Cache", (PyObject *) &CacheType) < 0) { Py_DECREF (&ProbeType); Py_DECREF (&TopologyType); Py_DECREF (&PartlistType); Py_DECREF (&ParttableType); Py_DECREF (&PartitionType); Py_DECREF (&CacheType); Py_DECREF (module); return NULL; } Py_INCREF (&DeviceType); if (PyModule_AddObject (module, "Device", (PyObject *) &DeviceType) < 0) { Py_DECREF (&ProbeType); Py_DECREF (&TopologyType); Py_DECREF (&PartlistType); Py_DECREF (&ParttableType); Py_DECREF (&PartitionType); Py_DECREF (&CacheType); Py_DECREF (&DeviceType); Py_DECREF (module); return NULL; } return module; }