blob: 634b5cf35b606aee52bd79ecbf4342f0f11fcf87 [file]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "error.h"
#include <structmember.h> // PyMemberDef.
#include <sstream>
namespace error {
// TODO(https://fxbug.dev/127163): This has been copied from zircon code, as vdso doesn't build this for
// host.
const char *zx_status_get_string(zx_status_t status) {
switch (status) {
case ZX_OK:
return "ZX_OK";
case ZX_ERR_INTERNAL:
return "ZX_ERR_INTERNAL";
case ZX_ERR_NOT_SUPPORTED:
return "ZX_ERR_NOT_SUPPORTED";
case ZX_ERR_NO_RESOURCES:
return "ZX_ERR_NO_RESOURCES";
case ZX_ERR_NO_MEMORY:
return "ZX_ERR_NO_MEMORY";
case ZX_ERR_INTERNAL_INTR_RETRY:
return "ZX_ERR_INTERNAL_INTR_RETRY";
case ZX_ERR_INVALID_ARGS:
return "ZX_ERR_INVALID_ARGS";
case ZX_ERR_BAD_HANDLE:
return "ZX_ERR_BAD_HANDLE";
case ZX_ERR_WRONG_TYPE:
return "ZX_ERR_WRONG_TYPE";
case ZX_ERR_BAD_SYSCALL:
return "ZX_ERR_BAD_SYSCALL";
case ZX_ERR_OUT_OF_RANGE:
return "ZX_ERR_OUT_OF_RANGE";
case ZX_ERR_BUFFER_TOO_SMALL:
return "ZX_ERR_BUFFER_TOO_SMALL";
case ZX_ERR_BAD_STATE:
return "ZX_ERR_BAD_STATE";
case ZX_ERR_TIMED_OUT:
return "ZX_ERR_TIMED_OUT";
case ZX_ERR_SHOULD_WAIT:
return "ZX_ERR_SHOULD_WAIT";
case ZX_ERR_CANCELED:
return "ZX_ERR_CANCELED";
case ZX_ERR_PEER_CLOSED:
return "ZX_ERR_PEER_CLOSED";
case ZX_ERR_NOT_FOUND:
return "ZX_ERR_NOT_FOUND";
case ZX_ERR_ALREADY_EXISTS:
return "ZX_ERR_ALREADY_EXISTS";
case ZX_ERR_ALREADY_BOUND:
return "ZX_ERR_ALREADY_BOUND";
case ZX_ERR_UNAVAILABLE:
return "ZX_ERR_UNAVAILABLE";
case ZX_ERR_ACCESS_DENIED:
return "ZX_ERR_ACCESS_DENIED";
case ZX_ERR_IO:
return "ZX_ERR_IO";
case ZX_ERR_IO_REFUSED:
return "ZX_ERR_IO_REFUSED";
case ZX_ERR_IO_DATA_INTEGRITY:
return "ZX_ERR_IO_DATA_INTEGRITY";
case ZX_ERR_IO_DATA_LOSS:
return "ZX_ERR_IO_DATA_LOSS";
case ZX_ERR_IO_NOT_PRESENT:
return "ZX_ERR_IO_NOT_PRESENT";
case ZX_ERR_IO_OVERRUN:
return "ZX_ERR_IO_OVERRUN";
case ZX_ERR_IO_MISSED_DEADLINE:
return "ZX_ERR_IO_MISSED_DEADLINE";
case ZX_ERR_IO_INVALID:
return "ZX_ERR_IO_INVALID";
case ZX_ERR_BAD_PATH:
return "ZX_ERR_BAD_PATH";
case ZX_ERR_NOT_DIR:
return "ZX_ERR_NOT_DIR";
case ZX_ERR_NOT_FILE:
return "ZX_ERR_NOT_FILE";
case ZX_ERR_FILE_BIG:
return "ZX_ERR_FILE_BIG";
case ZX_ERR_NO_SPACE:
return "ZX_ERR_NO_SPACE";
case ZX_ERR_NOT_EMPTY:
return "ZX_ERR_NOT_EMPTY";
case ZX_ERR_STOP:
return "ZX_ERR_STOP";
case ZX_ERR_NEXT:
return "ZX_ERR_NEXT";
case ZX_ERR_ASYNC:
return "ZX_ERR_ASYNC";
case ZX_ERR_PROTOCOL_NOT_SUPPORTED:
return "ZX_ERR_PROTOCOL_NOT_SUPPORTED";
case ZX_ERR_ADDRESS_UNREACHABLE:
return "ZX_ERR_ADDRESS_UNREACHABLE";
case ZX_ERR_ADDRESS_IN_USE:
return "ZX_ERR_ADDRESS_IN_USE";
case ZX_ERR_NOT_CONNECTED:
return "ZX_ERR_NOT_CONNECTED";
case ZX_ERR_CONNECTION_REFUSED:
return "ZX_ERR_CONNECTION_REFUSED";
case ZX_ERR_CONNECTION_RESET:
return "ZX_ERR_CONNECTION_RESET";
case ZX_ERR_CONNECTION_ABORTED:
return "ZX_ERR_CONNECTION_ABORTED";
default:
return "(UNKNOWN)";
}
}
std::string ZxStatus_reprstr_helper(PyObject *self) {
if (!PyObject_HasAttrString(self, "args")) {
return "";
}
auto args = PyObject_GetAttrString(self, "args");
if (PyTuple_Size(args) < 1) {
Py_DECREF(args);
return "unknown";
}
Py_DECREF(args);
std::stringstream ss;
PyObject *i = PyTuple_GetItem(args, 0);
if (!PyLong_Check(i)) {
return "unknown";
}
ss << zx_status_get_string(static_cast<zx_status_t>(PyLong_AsLong(i)));
return ss.str();
}
PyObject *ZxStatus_repr(PyObject *self, PyTypeObject *defining_class, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames) {
return PyUnicode_FromString(ZxStatus_reprstr_helper(self).c_str());
}
PyObject *ZxStatus_str(PyObject *self) {
std::stringstream ss;
ss << "FIDL status: " << ZxStatus_reprstr_helper(self);
return PyUnicode_FromString(ss.str().c_str());
}
PyMethodDef ZxStatus_repr_def = {
"__repr__",
reinterpret_cast<PyCFunction>(ZxStatus_repr),
METH_METHOD | METH_FASTCALL | METH_KEYWORDS,
nullptr,
};
PyMethodDef ZxStatus_str_def = {
"__str__",
reinterpret_cast<PyCFunction>(ZxStatus_str),
METH_METHOD | METH_FASTCALL | METH_KEYWORDS,
nullptr,
};
// This was copied and macro'd from the rust fuchsia_zircon_status files.
PyObject *ZxStatus_make_constants() {
PyObject *dict = PyDict_New();
if (dict == nullptr) {
return nullptr;
}
if (PyDict_SetItemString(dict, "ZX_OK", PyLong_FromLong(ZX_OK)) < 0) {
return nullptr;
}
PyDict_SetItemString(dict, "ZX_ERR_INTERNAL", PyLong_FromLong(ZX_ERR_INTERNAL));
PyDict_SetItemString(dict, "ZX_ERR_NOT_SUPPORTED", PyLong_FromLong(ZX_ERR_NOT_SUPPORTED));
PyDict_SetItemString(dict, "ZX_ERR_NO_RESOURCES", PyLong_FromLong(ZX_ERR_NO_RESOURCES));
PyDict_SetItemString(dict, "ZX_ERR_NO_MEMORY", PyLong_FromLong(ZX_ERR_NO_MEMORY));
PyDict_SetItemString(dict, "ZX_ERR_INVALID_ARGS", PyLong_FromLong(ZX_ERR_INVALID_ARGS));
PyDict_SetItemString(dict, "ZX_ERR_BAD_HANDLE", PyLong_FromLong(ZX_ERR_BAD_HANDLE));
PyDict_SetItemString(dict, "ZX_ERR_WRONG_TYPE", PyLong_FromLong(ZX_ERR_WRONG_TYPE));
PyDict_SetItemString(dict, "ZX_ERR_BAD_SYSCALL", PyLong_FromLong(ZX_ERR_BAD_SYSCALL));
PyDict_SetItemString(dict, "ZX_ERR_OUT_OF_RANGE", PyLong_FromLong(ZX_ERR_OUT_OF_RANGE));
PyDict_SetItemString(dict, "ZX_ERR_BUFFER_TOO_SMALL", PyLong_FromLong(ZX_ERR_BUFFER_TOO_SMALL));
PyDict_SetItemString(dict, "ZX_ERR_BAD_STATE", PyLong_FromLong(ZX_ERR_BAD_STATE));
PyDict_SetItemString(dict, "ZX_ERR_TIMED_OUT", PyLong_FromLong(ZX_ERR_TIMED_OUT));
PyDict_SetItemString(dict, "ZX_ERR_SHOULD_WAIT", PyLong_FromLong(ZX_ERR_SHOULD_WAIT));
PyDict_SetItemString(dict, "ZX_ERR_CANCELED", PyLong_FromLong(ZX_ERR_CANCELED));
PyDict_SetItemString(dict, "ZX_ERR_PEER_CLOSED", PyLong_FromLong(ZX_ERR_PEER_CLOSED));
PyDict_SetItemString(dict, "ZX_ERR_NOT_FOUND", PyLong_FromLong(ZX_ERR_NOT_FOUND));
PyDict_SetItemString(dict, "ZX_ERR_ALREADY_EXISTS", PyLong_FromLong(ZX_ERR_ALREADY_EXISTS));
PyDict_SetItemString(dict, "ZX_ERR_ALREADY_BOUND", PyLong_FromLong(ZX_ERR_ALREADY_BOUND));
PyDict_SetItemString(dict, "ZX_ERR_UNAVAILABLE", PyLong_FromLong(ZX_ERR_UNAVAILABLE));
PyDict_SetItemString(dict, "ZX_ERR_ACCESS_DENIED", PyLong_FromLong(ZX_ERR_ACCESS_DENIED));
PyDict_SetItemString(dict, "ZX_ERR_IO", PyLong_FromLong(ZX_ERR_IO));
PyDict_SetItemString(dict, "ZX_ERR_IO_REFUSED", PyLong_FromLong(ZX_ERR_IO_REFUSED));
PyDict_SetItemString(dict, "ZX_ERR_IO_DATA_INTEGRITY", PyLong_FromLong(ZX_ERR_IO_DATA_INTEGRITY));
PyDict_SetItemString(dict, "ZX_ERR_IO_DATA_LOSS", PyLong_FromLong(ZX_ERR_IO_DATA_LOSS));
PyDict_SetItemString(dict, "ZX_ERR_IO_NOT_PRESENT", PyLong_FromLong(ZX_ERR_IO_NOT_PRESENT));
PyDict_SetItemString(dict, "ZX_ERR_IO_OVERRUN", PyLong_FromLong(ZX_ERR_IO_OVERRUN));
PyDict_SetItemString(dict, "ZX_ERR_IO_MISSED_DEADLINE",
PyLong_FromLong(ZX_ERR_IO_MISSED_DEADLINE));
PyDict_SetItemString(dict, "ZX_ERR_IO_INVALID", PyLong_FromLong(ZX_ERR_IO_INVALID));
PyDict_SetItemString(dict, "ZX_ERR_BAD_PATH", PyLong_FromLong(ZX_ERR_BAD_PATH));
PyDict_SetItemString(dict, "ZX_ERR_NOT_DIR", PyLong_FromLong(ZX_ERR_NOT_DIR));
PyDict_SetItemString(dict, "ZX_ERR_NOT_FILE", PyLong_FromLong(ZX_ERR_NOT_FILE));
PyDict_SetItemString(dict, "ZX_ERR_FILE_BIG", PyLong_FromLong(ZX_ERR_FILE_BIG));
PyDict_SetItemString(dict, "ZX_ERR_NO_SPACE", PyLong_FromLong(ZX_ERR_NO_SPACE));
PyDict_SetItemString(dict, "ZX_ERR_NOT_EMPTY", PyLong_FromLong(ZX_ERR_NOT_EMPTY));
PyDict_SetItemString(dict, "ZX_ERR_STOP", PyLong_FromLong(ZX_ERR_STOP));
PyDict_SetItemString(dict, "ZX_ERR_NEXT", PyLong_FromLong(ZX_ERR_NEXT));
PyDict_SetItemString(dict, "ZX_ERR_ASYNC", PyLong_FromLong(ZX_ERR_ASYNC));
PyDict_SetItemString(dict, "ZX_ERR_PROTOCOL_NOT_SUPPORTED",
PyLong_FromLong(ZX_ERR_PROTOCOL_NOT_SUPPORTED));
PyDict_SetItemString(dict, "ZX_ERR_ADDRESS_UNREACHABLE",
PyLong_FromLong(ZX_ERR_ADDRESS_UNREACHABLE));
PyDict_SetItemString(dict, "ZX_ERR_ADDRESS_IN_USE", PyLong_FromLong(ZX_ERR_ADDRESS_IN_USE));
PyDict_SetItemString(dict, "ZX_ERR_NOT_CONNECTED", PyLong_FromLong(ZX_ERR_NOT_CONNECTED));
PyDict_SetItemString(dict, "ZX_ERR_CONNECTION_REFUSED",
PyLong_FromLong(ZX_ERR_CONNECTION_REFUSED));
PyDict_SetItemString(dict, "ZX_ERR_CONNECTION_RESET", PyLong_FromLong(ZX_ERR_CONNECTION_RESET));
PyDict_SetItemString(dict, "ZX_ERR_CONNECTION_ABORTED",
PyLong_FromLong(ZX_ERR_CONNECTION_ABORTED));
return dict;
}
PyTypeObject *ZxStatusType = nullptr;
// This is necessary as Python exception extensions in C are weird. Python exceptions can't be
// wholesale subclassed from the base exception class, as they are expected to have an args
// attribute from which they are constructed. Attempting to make any sort of non-trivial subclassing
// of the Python error subclass will result in segfaulting.
PyTypeObject *ZxStatusType_Create() {
assert(ZxStatusType == nullptr);
auto constants = ZxStatus_make_constants();
if (constants == nullptr) {
return nullptr;
}
auto res =
PyTypeCast(PyErr_NewException("fuchsia_controller_py.ZxStatus", PyExc_Exception, constants));
if (res == nullptr) {
return nullptr;
}
auto repr = PyDescr_NewMethod(res, &ZxStatus_repr_def);
if (repr == nullptr) {
return nullptr;
}
if (PyObject_SetAttrString(PyObjCast(res), "__repr__", repr) < 0) {
return nullptr;
}
auto str = PyDescr_NewMethod(res, &ZxStatus_str_def);
if (str == nullptr) {
return nullptr;
}
if (PyObject_SetAttrString(PyObjCast(res), "__str__", str) < 0) {
return nullptr;
}
Py_IncRef(PyObjCast(res));
ZxStatusType = res;
return res;
}
} // namespace error