328 lines
8.8 KiB
C
328 lines
8.8 KiB
C
/*
|
|
* (C) 2022 Soleta Consulting S.L. <info@soleta.eu>
|
|
*
|
|
* 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.
|
|
*
|
|
* Author: Jose M. Guisado <jguisado@soleta.eu>
|
|
*/
|
|
|
|
|
|
#include "fdisk.h"
|
|
|
|
static PyMemberDef Context_members[] = {
|
|
{ NULL }
|
|
};
|
|
|
|
static void Context_dealloc(ContextObject *self)
|
|
{
|
|
if (!self->cxt) /* if init fails */
|
|
return;
|
|
|
|
fdisk_unref_context(self->cxt);
|
|
Py_TYPE(self)->tp_free((PyObject *) self);
|
|
}
|
|
|
|
static PyObject *Context_new(PyTypeObject *type,
|
|
PyObject *args __attribute__((unused)),
|
|
PyObject *kwds __attribute__((unused)))
|
|
{
|
|
ContextObject *self = (ContextObject*) type->tp_alloc(type, 0);
|
|
|
|
if (self) {
|
|
self->cxt = NULL;
|
|
self->tb = NULL;
|
|
}
|
|
|
|
return (PyObject *)self;
|
|
}
|
|
|
|
#define Context_HELP "Context(device=None, details=True, readonly=False)"
|
|
static int Context_init(ContextObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
static char *kwlist[] = {
|
|
"device", "details", "readonly",
|
|
NULL
|
|
};
|
|
int details = 1, readonly = 0, rc = 0;
|
|
char *device = NULL;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args,
|
|
kwds, "|spp", kwlist,
|
|
&device, &details, &readonly)) {
|
|
PyErr_SetString(PyExc_TypeError, ARG_ERR);
|
|
return -1;
|
|
}
|
|
|
|
if (self->cxt)
|
|
fdisk_unref_context(self->cxt);
|
|
|
|
self->cxt = fdisk_new_context();
|
|
if (!self->cxt) {
|
|
PyErr_SetString(PyExc_MemoryError, "Couldn't allocate context");
|
|
return -1;
|
|
}
|
|
|
|
if (device && (rc = fdisk_assign_device(self->cxt, device, readonly))) {
|
|
set_PyErr_from_rc(-rc);
|
|
return -1;
|
|
}
|
|
if (details && (rc = fdisk_enable_details(self->cxt, details))) {
|
|
set_PyErr_from_rc(-rc);
|
|
return -1;
|
|
}
|
|
fdisk_get_partitions(self->cxt, &self->tb);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define Context_assign_device_HELP "assign_device(device)\n\n" \
|
|
"Open the device, discovery topology, geometry, detect disklabel " \
|
|
"and switch the current label driver to reflect the probing result. "
|
|
static PyObject *Context_assign_device(ContextObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
char *fname;
|
|
|
|
if (!PyArg_ParseTuple(args, "s", &fname)) {
|
|
PyErr_SetString(PyExc_TypeError, ARG_ERR);
|
|
return NULL;
|
|
}
|
|
|
|
/* Assert self->cxt */
|
|
|
|
/* XXX: readonly */
|
|
fdisk_assign_device(self->cxt, fname, 1);
|
|
|
|
fdisk_get_partitions(self->cxt, &self->tb);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
#define Context_partition_to_string_HELP "partition_to_string(pa, field)\n\n" \
|
|
"Retrieve partition field using fdisk_partition_to_string." \
|
|
"Field constants are available as FDISK_LABEL_*"
|
|
static PyObject *Context_partition_to_string(ContextObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
struct fdisk_partition *pa;
|
|
enum fdisk_fieldtype field;
|
|
PartitionObject *part;
|
|
PyObject *ret;
|
|
char *data;
|
|
|
|
if (!PyArg_ParseTuple(args, "O!i", &PartitionType, &part, &field)) {
|
|
PyErr_SetString(PyExc_TypeError, ARG_ERR);
|
|
return NULL;
|
|
}
|
|
|
|
pa = part->pa;
|
|
|
|
fdisk_partition_to_string(pa, self->cxt, field, &data);
|
|
ret = Py_BuildValue("s", data);
|
|
free(data);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#define Context_create_disklabel_HELP "create_disklabel(label)\n\n" \
|
|
"Creates a new disk label of type name . If name is NULL, " \
|
|
"then it will create a default system label type, either SUN or DOS."
|
|
static PyObject *Context_create_disklabel(ContextObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
char *label_name = NULL;
|
|
|
|
if (!PyArg_ParseTuple(args, "|s", &label_name)) {
|
|
PyErr_SetString(PyExc_TypeError, ARG_ERR);
|
|
return NULL;
|
|
}
|
|
|
|
if (fdisk_create_disklabel(self->cxt, label_name)) {
|
|
PyErr_Format(PyExc_RuntimeError, "Error creating label %s", label_name);
|
|
return NULL;
|
|
}
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
#define Context_write_disklabel_HELP "write_disklabel()\n\n" \
|
|
"This function wipes the device (if enabled by fdisk_enable_wipe()) " \
|
|
"and then it writes in-memory changes to disk. Be careful!"
|
|
static PyObject *Context_write_disklabel(ContextObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
int ret;
|
|
|
|
ret = fdisk_write_disklabel(self->cxt);
|
|
if (ret < 0) {
|
|
PyErr_Format(PyExc_RuntimeError, "Error writing label to disk: %s", strerror(-ret));
|
|
return NULL;
|
|
}
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
#define Context_add_partition_HELP "add_partition(fdisk.Partition)\n\n" \
|
|
"Adds partition to context. Returns partno of the new partition."
|
|
static PyObject *Context_add_partition(ContextObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
PartitionObject *partobj;
|
|
size_t partno;
|
|
int rc;
|
|
|
|
if (!PyArg_ParseTuple(args, "O!", &PartitionType, &partobj)) {
|
|
PyErr_SetString(PyExc_TypeError, ARG_ERR);
|
|
return NULL;
|
|
}
|
|
|
|
if (!partobj->pa) {
|
|
PyErr_SetString(PyExc_TypeError, ARG_ERR);
|
|
return NULL;
|
|
}
|
|
|
|
rc = fdisk_add_partition(self->cxt, partobj->pa, &partno);
|
|
if (rc < 0) {
|
|
PyErr_Format(PyExc_RuntimeError, "Error adding partition to context: %s", strerror(-rc));
|
|
return NULL;
|
|
}
|
|
|
|
return Py_BuildValue("n", partno);
|
|
}
|
|
|
|
static PyMethodDef Context_methods[] = {
|
|
{"assign_device", (PyCFunction)Context_assign_device, METH_VARARGS, Context_assign_device_HELP},
|
|
{"partition_to_string", (PyCFunction)Context_partition_to_string, METH_VARARGS, Context_partition_to_string_HELP},
|
|
{"create_disklabel", (PyCFunction)Context_create_disklabel, METH_VARARGS, Context_create_disklabel_HELP},
|
|
{"write_disklabel", (PyCFunction)Context_write_disklabel, METH_NOARGS, Context_write_disklabel_HELP},
|
|
{"add_partition", (PyCFunction)Context_add_partition, METH_VARARGS, Context_add_partition_HELP},
|
|
{NULL}
|
|
};
|
|
|
|
static PyObject *Context_get_nsectors(ContextObject *self)
|
|
{
|
|
return PyLong_FromUnsignedLong(fdisk_get_nsectors(self->cxt));
|
|
}
|
|
|
|
static PyObject *Context_get_sector_size(ContextObject *self)
|
|
{
|
|
return PyLong_FromUnsignedLong(fdisk_get_sector_size(self->cxt));
|
|
}
|
|
|
|
static PyObject *Context_get_devname(ContextObject *self)
|
|
{
|
|
return PyObjectResultStr(fdisk_get_devname(self->cxt));
|
|
}
|
|
|
|
static PyObject *Context_get_label(ContextObject *self)
|
|
{
|
|
struct fdisk_context *cxt = self->cxt;
|
|
|
|
if (fdisk_has_label(cxt)) {
|
|
return PyObjectResultLabel(fdisk_get_label(cxt, NULL));
|
|
} else {
|
|
Py_RETURN_NONE;
|
|
}
|
|
}
|
|
|
|
static PyObject *Context_get_nparts(ContextObject *self)
|
|
{
|
|
return PyLong_FromLong(fdisk_table_get_nents(self->tb));
|
|
}
|
|
|
|
static PyObject *Context_get_partitions(ContextObject *self)
|
|
{
|
|
PyObject *p, *list = PyList_New(0); /* XXX: null if failed*/
|
|
struct fdisk_partition *pa;
|
|
struct fdisk_iter *itr;
|
|
struct fdisk_table *tb;
|
|
/* char *data; */
|
|
|
|
tb = self->tb;
|
|
itr = fdisk_new_iter(FDISK_ITER_FORWARD);
|
|
|
|
while(fdisk_table_next_partition(tb, itr, &pa) == 0) {
|
|
/* const char *name = fdisk_partition_get_name(pa);*/
|
|
p = PyObjectResultPartition(pa);
|
|
PyList_Append(list, p);
|
|
/*free(data);*/
|
|
}
|
|
|
|
fdisk_free_iter(itr);
|
|
|
|
return list;
|
|
}
|
|
|
|
static PyObject *Context_get_size_unit(ContextObject *self)
|
|
{
|
|
return PyLong_FromLong(fdisk_get_size_unit(self->cxt));
|
|
}
|
|
|
|
static int Context_set_size_unit(ContextObject *self, PyObject *value, void *closure)
|
|
{
|
|
int szunit;
|
|
|
|
if (value == NULL) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Cannot set unit size: null size type");
|
|
return -1;
|
|
}
|
|
|
|
if (!PyLong_Check(value)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Cannot set unit size: invalid size type");
|
|
return -1;
|
|
}
|
|
|
|
szunit = (int) PyLong_AsLong(value);
|
|
if (fdisk_set_size_unit(self->cxt, szunit) < 0) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Cannot set unit size: invalid size type value");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PyGetSetDef Context_getseters[] = {
|
|
{"nsectors", (getter)Context_get_nsectors, NULL, "context number of sectors", NULL},
|
|
{"sector_size", (getter)Context_get_sector_size, NULL, "context sector size", NULL},
|
|
{"devname", (getter)Context_get_devname, NULL, "context devname", NULL},
|
|
{"label", (getter)Context_get_label, NULL, "context label type", NULL},
|
|
{"nparts", (getter)Context_get_nparts, NULL, "context label number of existing partitions", NULL},
|
|
{"partitions", (getter)Context_get_partitions, NULL, "context partitions", NULL},
|
|
{"size_unit", (getter)Context_get_size_unit, (setter)Context_set_size_unit, "context unit size", NULL},
|
|
{NULL}
|
|
};
|
|
|
|
static PyObject *Context_repr(ContextObject *self)
|
|
{
|
|
return PyUnicode_FromFormat("<libfdisk.Context object at %p, details=%s, readonly=%s>",
|
|
self,
|
|
fdisk_is_details(self->cxt) ? "True" : "False",
|
|
fdisk_is_readonly(self->cxt) ? "True" : "False");
|
|
}
|
|
|
|
PyTypeObject ContextType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
.tp_name = "libfdisk.Context",
|
|
.tp_basicsize = sizeof(ContextObject),
|
|
.tp_dealloc = (destructor)Context_dealloc,
|
|
.tp_repr = (reprfunc) Context_repr,
|
|
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
.tp_doc = Context_HELP,
|
|
.tp_methods = Context_methods,
|
|
.tp_members = Context_members,
|
|
.tp_getset = Context_getseters,
|
|
.tp_init = (initproc)Context_init,
|
|
.tp_new = Context_new,
|
|
};
|
|
|
|
void Context_AddModuleObject(PyObject *mod)
|
|
{
|
|
if (PyType_Ready(&ContextType) < 0)
|
|
return;
|
|
|
|
Py_INCREF(&ContextType);
|
|
PyModule_AddObject(mod, "Context", (PyObject *)&ContextType);
|
|
}
|