diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-12-00-12-28.bpo-40950.tzMy7m.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-12-00-12-28.bpo-40950.tzMy7m.rst new file mode 100644 index 00000000000..925b5790f73 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-06-12-00-12-28.bpo-40950.tzMy7m.rst @@ -0,0 +1,2 @@ +Add a state to the :mod:`nis` module (:pep:`3121`) and apply +the multiphase initialization. Patch by Dong-hee Na. diff --git a/Modules/nismodule.c b/Modules/nismodule.c index a24978e0686..6655451ebd2 100644 --- a/Modules/nismodule.c +++ b/Modules/nismodule.c @@ -44,12 +44,42 @@ PyDoc_STRVAR(maps__doc__, Returns an array of all available NIS maps within a domain. If domain\n\ is not specified it defaults to the system default domain.\n"); -static PyObject *NisError; +typedef struct { + PyObject *nis_error; +} nis_state; + +static inline nis_state* +get_nis_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (nis_state *)state; +} + +static int +nis_clear(PyObject *m) +{ + Py_CLEAR(get_nis_state(m)->nis_error); + return 0; +} + +static int +nis_traverse(PyObject *m, visitproc visit, void *arg) +{ + Py_VISIT(get_nis_state(m)->nis_error); + return 0; +} + +static void +nis_free(void *m) +{ + nis_clear((PyObject *) m); +} static PyObject * -nis_error (int err) +nis_error(nis_state *state, int err) { - PyErr_SetString(NisError, yperr_string(err)); + PyErr_SetString(state->nis_error, yperr_string(err)); return NULL; } @@ -70,7 +100,7 @@ static struct nis_map { }; static char * -nis_mapname (char *map, int *pfix) +nis_mapname(char *map, int *pfix) { int i; @@ -98,7 +128,7 @@ struct ypcallback_data { }; static int -nis_foreach (int instatus, char *inkey, int inkeylen, char *inval, +nis_foreach(int instatus, char *inkey, int inkeylen, char *inval, int invallen, struct ypcallback_data *indata) { if (instatus == YP_TRUE) { @@ -137,21 +167,22 @@ nis_foreach (int instatus, char *inkey, int inkeylen, char *inval, } static PyObject * -nis_get_default_domain (PyObject *self, PyObject *Py_UNUSED(ignored)) +nis_get_default_domain(PyObject *module, PyObject *Py_UNUSED(ignored)) { char *domain; int err; PyObject *res; - - if ((err = yp_get_default_domain(&domain)) != 0) - return nis_error(err); + nis_state *state = get_nis_state(module); + if ((err = yp_get_default_domain(&domain)) != 0) { + return nis_error(state, err); + } res = PyUnicode_FromStringAndSize (domain, strlen(domain)); return res; } static PyObject * -nis_match (PyObject *self, PyObject *args, PyObject *kwdict) +nis_match(PyObject *module, PyObject *args, PyObject *kwdict) { char *match; char *domain = NULL; @@ -165,18 +196,22 @@ nis_match (PyObject *self, PyObject *args, PyObject *kwdict) if (!PyArg_ParseTupleAndKeywords(args, kwdict, "Us|s:match", kwlist, - &ukey, &map, &domain)) + &ukey, &map, &domain)) { return NULL; - if ((bkey = PyUnicode_EncodeFSDefault(ukey)) == NULL) + } + if ((bkey = PyUnicode_EncodeFSDefault(ukey)) == NULL) { return NULL; + } /* check for embedded null bytes */ if (PyBytes_AsStringAndSize(bkey, &key, &keylen) == -1) { Py_DECREF(bkey); return NULL; } + + nis_state *state = get_nis_state(module); if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) { Py_DECREF(bkey); - return nis_error(err); + return nis_error(state, err); } map = nis_mapname (map, &fix); if (fix) @@ -187,15 +222,16 @@ nis_match (PyObject *self, PyObject *args, PyObject *kwdict) Py_DECREF(bkey); if (fix) len--; - if (err != 0) - return nis_error(err); + if (err != 0) { + return nis_error(state, err); + } res = PyUnicode_DecodeFSDefaultAndSize(match, len); free (match); return res; } static PyObject * -nis_cat (PyObject *self, PyObject *args, PyObject *kwdict) +nis_cat(PyObject *module, PyObject *args, PyObject *kwdict) { char *domain = NULL; char *map; @@ -206,10 +242,13 @@ nis_cat (PyObject *self, PyObject *args, PyObject *kwdict) static char *kwlist[] = {"map", "domain", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat", - kwlist, &map, &domain)) + kwlist, &map, &domain)) { return NULL; - if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) - return nis_error(err); + } + nis_state *state = get_nis_state(module); + if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) { + return nis_error(state, err); + } dict = PyDict_New (); if (dict == NULL) return NULL; @@ -222,7 +261,7 @@ nis_cat (PyObject *self, PyObject *args, PyObject *kwdict) PyEval_RestoreThread(data.state); if (err != 0) { Py_DECREF(dict); - return nis_error(err); + return nis_error(state, err); } return dict; } @@ -352,7 +391,7 @@ nisproc_maplist_2(domainname *argp, CLIENT *clnt) static nismaplist * -nis_maplist (char *dom) +nis_maplist(nis_state *state, char *dom) { nisresp_maplist *list; CLIENT *cl; @@ -364,12 +403,12 @@ nis_maplist (char *dom) mapi++; } if (!server) { - PyErr_SetString(NisError, "No NIS master found for any map"); + PyErr_SetString(state->nis_error, "No NIS master found for any map"); return NULL; } cl = clnt_create(server, YPPROG, YPVERS, "tcp"); if (cl == NULL) { - PyErr_SetString(NisError, clnt_spcreateerror(server)); + PyErr_SetString(state->nis_error, clnt_spcreateerror(server)); goto finally; } list = nisproc_maplist_2 (&dom, cl); @@ -388,7 +427,7 @@ nis_maplist (char *dom) } static PyObject * -nis_maps (PyObject *self, PyObject *args, PyObject *kwdict) +nis_maps (PyObject *module, PyObject *args, PyObject *kwdict) { char *domain = NULL; nismaplist *maps; @@ -397,17 +436,22 @@ nis_maps (PyObject *self, PyObject *args, PyObject *kwdict) static char *kwlist[] = {"domain", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, - "|s:maps", kwlist, &domain)) - return NULL; - if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) { - nis_error(err); + "|s:maps", kwlist, &domain)) { return NULL; } - if ((maps = nis_maplist (domain)) == NULL) + nis_state *state = get_nis_state(module); + if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) { + nis_error(state, err); return NULL; - if ((list = PyList_New(0)) == NULL) + } + + if ((maps = nis_maplist(state, domain)) == NULL) { return NULL; + } + if ((list = PyList_New(0)) == NULL) { + return NULL; + } for (; maps; maps = maps->next) { PyObject *str = PyUnicode_FromString(maps->map); if (!str || PyList_Append(list, str) < 0) @@ -439,31 +483,45 @@ static PyMethodDef nis_methods[] = { {NULL, NULL} /* Sentinel */ }; +static int +nis_exec(PyObject *module) +{ + nis_state* state = get_nis_state(module); + state->nis_error = PyErr_NewException("nis.error", NULL, NULL); + if (state->nis_error == NULL) { + return -1; + } + + Py_INCREF(state->nis_error); + if (PyModule_AddObject(module, "error", state->nis_error) < 0) { + Py_DECREF(state->nis_error); + return -1; + } + return 0; +} + +static PyModuleDef_Slot nis_slots[] = { + {Py_mod_exec, nis_exec}, + {0, NULL} +}; + PyDoc_STRVAR(nis__doc__, "This module contains functions for accessing NIS maps.\n"); static struct PyModuleDef nismodule = { PyModuleDef_HEAD_INIT, - "nis", - nis__doc__, - -1, - nis_methods, - NULL, - NULL, - NULL, - NULL + .m_name = "nis", + .m_doc = nis__doc__, + .m_size = sizeof(nis_state), + .m_methods = nis_methods, + .m_traverse = nis_traverse, + .m_clear = nis_clear, + .m_free = nis_free, + .m_slots = nis_slots, }; PyMODINIT_FUNC PyInit_nis(void) { - PyObject *m, *d; - m = PyModule_Create(&nismodule); - if (m == NULL) - return NULL; - d = PyModule_GetDict(m); - NisError = PyErr_NewException("nis.error", NULL, NULL); - if (NisError != NULL) - PyDict_SetItemString(d, "error", NisError); - return m; + return PyModuleDef_Init(&nismodule); }