| /*********************************************************** | |
| Copyright 1994 by Lance Ellinghouse, | |
| Cathedral City, California Republic, United States of America. | |
| All Rights Reserved | |
| Permission to use, copy, modify, and distribute this software and its | |
| documentation for any purpose and without fee is hereby granted, | |
| provided that the above copyright notice appear in all copies and that | |
| both that copyright notice and this permission notice appear in | |
| supporting documentation, and that the name of Lance Ellinghouse | |
| not be used in advertising or publicity pertaining to distribution | |
| of the software without specific, written prior permission. | |
| LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO | |
| THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL, | |
| INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING | |
| FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | |
| NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION | |
| WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| ******************************************************************/ | |
| /****************************************************************** | |
| Revision history: | |
| 2010/04/20 (Sean Reifschneider) | |
| - Use basename(sys.argv[0]) for the default "ident". | |
| - Arguments to openlog() are now keyword args and are all optional. | |
| - syslog() calls openlog() if it hasn't already been called. | |
| 1998/04/28 (Sean Reifschneider) | |
| - When facility not specified to syslog() method, use default from openlog() | |
| (This is how it was claimed to work in the documentation) | |
| - Potential resource leak of o_ident, now cleaned up in closelog() | |
| - Minor comment accuracy fix. | |
| 95/06/29 (Steve Clift) | |
| - Changed arg parsing to use PyArg_ParseTuple. | |
| - Added PyErr_Clear() call(s) where needed. | |
| - Fix core dumps if user message contains format specifiers. | |
| - Change openlog arg defaults to match normal syslog behavior. | |
| - Plug memory leak in openlog(). | |
| - Fix setlogmask() to return previous mask value. | |
| ******************************************************************/ | |
| /* syslog module */ | |
| // clinic/syslogmodule.c.h uses internal pycore_modsupport.h API | |
| #ifndef Py_BUILD_CORE_BUILTIN | |
| # define Py_BUILD_CORE_MODULE 1 | |
| #endif | |
| #include "Python.h" | |
| #include "osdefs.h" // SEP | |
| #include <syslog.h> | |
| /*[clinic input] | |
| module syslog | |
| [clinic start generated code]*/ | |
| /*[clinic end generated code: output=da39a3ee5e6b4b0d input=478f4ac94a1d4cae]*/ | |
| #include "clinic/syslogmodule.c.h" | |
| /* only one instance, only one syslog, so globals should be ok, | |
| * these fields are writable from the main interpreter only. */ | |
| static PyObject *S_ident_o = NULL; // identifier, held by openlog() | |
| static int S_log_open = 0; | |
| static inline int | |
| is_main_interpreter(void) | |
| { | |
| return (PyInterpreterState_Get() == PyInterpreterState_Main()); | |
| } | |
| static PyObject * | |
| syslog_get_argv(void) | |
| { | |
| /* Figure out what to use for as the program "ident" for openlog(). | |
| * This swallows exceptions and continues rather than failing out, | |
| * because the syslog module can still be used because openlog(3) | |
| * is optional. | |
| */ | |
| Py_ssize_t argv_len, scriptlen; | |
| PyObject *scriptobj; | |
| Py_ssize_t slash; | |
| PyObject *argv; | |
| if (PySys_GetOptionalAttrString("argv", &argv) <= 0) { | |
| return NULL; | |
| } | |
| argv_len = PyList_Size(argv); | |
| if (argv_len == -1) { | |
| PyErr_Clear(); | |
| Py_DECREF(argv); | |
| return NULL; | |
| } | |
| if (argv_len == 0) { | |
| Py_DECREF(argv); | |
| return NULL; | |
| } | |
| scriptobj = PyList_GetItem(argv, 0); | |
| Py_XINCREF(scriptobj); | |
| Py_DECREF(argv); | |
| if (scriptobj == NULL) { | |
| PyErr_Clear(); | |
| return NULL; | |
| } | |
| if (!PyUnicode_Check(scriptobj)) { | |
| Py_DECREF(scriptobj); | |
| return NULL; | |
| } | |
| scriptlen = PyUnicode_GET_LENGTH(scriptobj); | |
| if (scriptlen == 0) { | |
| Py_DECREF(scriptobj); | |
| return NULL; | |
| } | |
| slash = PyUnicode_FindChar(scriptobj, SEP, 0, scriptlen, -1); | |
| if (slash == -2) { | |
| PyErr_Clear(); | |
| Py_DECREF(scriptobj); | |
| return NULL; | |
| } | |
| if (slash != -1) { | |
| Py_SETREF(scriptobj, PyUnicode_Substring(scriptobj, slash + 1, scriptlen)); | |
| } | |
| return scriptobj; | |
| } | |
| /*[clinic input] | |
| @critical_section | |
| syslog.openlog | |
| ident: unicode = NULL | |
| logoption as logopt: long = 0 | |
| facility: long(c_default="LOG_USER") = LOG_USER | |
| Set logging options of subsequent syslog() calls. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, | |
| long facility) | |
| /*[clinic end generated code: output=5476c12829b6eb75 input=ee700b8786f81c23]*/ | |
| { | |
| // Since the sys.openlog changes the process level state of syslog library, | |
| // this operation is only allowed for the main interpreter. | |
| if (!is_main_interpreter()) { | |
| PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.openlog()"); | |
| return NULL; | |
| } | |
| const char *ident_str = NULL; | |
| if (ident) { | |
| Py_INCREF(ident); | |
| } | |
| else { | |
| /* get sys.argv[0] or NULL if we can't for some reason */ | |
| ident = syslog_get_argv(); | |
| if (ident == NULL && PyErr_Occurred()) { | |
| return NULL; | |
| } | |
| } | |
| /* At this point, ident should be INCREF()ed. openlog(3) does not | |
| * make a copy, and syslog(3) later uses it. We can't garbagecollect it. | |
| * If NULL, just let openlog figure it out (probably using C argv[0]). | |
| */ | |
| if (ident) { | |
| ident_str = PyUnicode_AsUTF8(ident); | |
| if (ident_str == NULL) { | |
| Py_DECREF(ident); | |
| return NULL; | |
| } | |
| } | |
| if (PySys_Audit("syslog.openlog", "Oll", ident ? ident : Py_None, logopt, facility) < 0) { | |
| Py_XDECREF(ident); | |
| return NULL; | |
| } | |
| openlog(ident_str, logopt, facility); | |
| _Py_atomic_store_int(&S_log_open, 1); | |
| Py_XSETREF(S_ident_o, ident); | |
| Py_RETURN_NONE; | |
| } | |
| /*[clinic input] | |
| @critical_section | |
| syslog.syslog | |
| [ | |
| priority: int(c_default="LOG_INFO") = LOG_INFO | |
| ] | |
| message: str | |
| / | |
| Send the string message to the system logger. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| syslog_syslog_impl(PyObject *module, int group_left_1, int priority, | |
| const char *message) | |
| /*[clinic end generated code: output=c3dbc73445a0e078 input=6588ddb0b113af8e]*/ | |
| { | |
| if (PySys_Audit("syslog.syslog", "is", priority, message) < 0) { | |
| return NULL; | |
| } | |
| /* if log is not opened, open it now */ | |
| if (!_Py_atomic_load_int(&S_log_open)) { | |
| if (!is_main_interpreter()) { | |
| PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog() " | |
| "until the syslog is opened by the main interpreter"); | |
| return NULL; | |
| } | |
| PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); | |
| if (openlog_ret == NULL) { | |
| return NULL; | |
| } | |
| Py_DECREF(openlog_ret); | |
| } | |
| #ifdef __APPLE__ | |
| // gh-98178: On macOS, libc syslog() is not thread-safe | |
| syslog(priority, "%s", message); | |
| #else | |
| Py_BEGIN_ALLOW_THREADS; | |
| syslog(priority, "%s", message); | |
| Py_END_ALLOW_THREADS; | |
| #endif | |
| Py_RETURN_NONE; | |
| } | |
| /*[clinic input] | |
| @critical_section | |
| syslog.closelog | |
| Reset the syslog module values and call the system library closelog(). | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| syslog_closelog_impl(PyObject *module) | |
| /*[clinic end generated code: output=97890a80a24b1b84 input=167f489868bd5a72]*/ | |
| { | |
| // Since the sys.closelog changes the process level state of syslog library, | |
| // this operation is only allowed for the main interpreter. | |
| if (!is_main_interpreter()) { | |
| PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.closelog()"); | |
| return NULL; | |
| } | |
| if (PySys_Audit("syslog.closelog", NULL) < 0) { | |
| return NULL; | |
| } | |
| int was_open = _Py_atomic_exchange_int(&S_log_open, 0); | |
| if (was_open) { | |
| closelog(); | |
| Py_CLEAR(S_ident_o); | |
| } | |
| Py_RETURN_NONE; | |
| } | |
| /*[clinic input] | |
| syslog.setlogmask -> long | |
| maskpri: long | |
| / | |
| Set the priority mask to maskpri and return the previous mask value. | |
| [clinic start generated code]*/ | |
| static long | |
| syslog_setlogmask_impl(PyObject *module, long maskpri) | |
| /*[clinic end generated code: output=d6ed163917b434bf input=adff2c2b76c7629c]*/ | |
| { | |
| if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) { | |
| return -1; | |
| } | |
| static PyMutex setlogmask_mutex = {0}; | |
| PyMutex_Lock(&setlogmask_mutex); | |
| // Linux man page (3): setlogmask() is MT-Unsafe race:LogMask. | |
| long previous_mask = setlogmask(maskpri); | |
| PyMutex_Unlock(&setlogmask_mutex); | |
| return previous_mask; | |
| } | |
| /*[clinic input] | |
| syslog.LOG_MASK -> long | |
| pri: long | |
| / | |
| Calculates the mask for the individual priority pri. | |
| [clinic start generated code]*/ | |
| static long | |
| syslog_LOG_MASK_impl(PyObject *module, long pri) | |
| /*[clinic end generated code: output=c4a5bbfcc74c7c94 input=534829cb7fb5f7d2]*/ | |
| { | |
| return LOG_MASK(pri); | |
| } | |
| /*[clinic input] | |
| syslog.LOG_UPTO -> long | |
| pri: long | |
| / | |
| Calculates the mask for all priorities up to and including pri. | |
| [clinic start generated code]*/ | |
| static long | |
| syslog_LOG_UPTO_impl(PyObject *module, long pri) | |
| /*[clinic end generated code: output=9eab083c90601d7e input=5e906d6c406b7458]*/ | |
| { | |
| return LOG_UPTO(pri); | |
| } | |
| /* List of functions defined in the module */ | |
| static PyMethodDef syslog_methods[] = { | |
| SYSLOG_OPENLOG_METHODDEF | |
| SYSLOG_CLOSELOG_METHODDEF | |
| SYSLOG_SYSLOG_METHODDEF | |
| SYSLOG_SETLOGMASK_METHODDEF | |
| SYSLOG_LOG_MASK_METHODDEF | |
| SYSLOG_LOG_UPTO_METHODDEF | |
| {NULL, NULL, 0} | |
| }; | |
| static int | |
| syslog_exec(PyObject *module) | |
| { | |
| #define ADD_INT_MACRO(module, macro) \ | |
| do { \ | |
| if (PyModule_AddIntConstant(module, #macro, macro) < 0) { \ | |
| return -1; \ | |
| } \ | |
| } while (0) | |
| /* Priorities */ | |
| ADD_INT_MACRO(module, LOG_EMERG); | |
| ADD_INT_MACRO(module, LOG_ALERT); | |
| ADD_INT_MACRO(module, LOG_CRIT); | |
| ADD_INT_MACRO(module, LOG_ERR); | |
| ADD_INT_MACRO(module, LOG_WARNING); | |
| ADD_INT_MACRO(module, LOG_NOTICE); | |
| ADD_INT_MACRO(module, LOG_INFO); | |
| ADD_INT_MACRO(module, LOG_DEBUG); | |
| /* openlog() option flags */ | |
| ADD_INT_MACRO(module, LOG_PID); | |
| ADD_INT_MACRO(module, LOG_CONS); | |
| ADD_INT_MACRO(module, LOG_NDELAY); | |
| #ifdef LOG_ODELAY | |
| ADD_INT_MACRO(module, LOG_ODELAY); | |
| #endif | |
| #ifdef LOG_NOWAIT | |
| ADD_INT_MACRO(module, LOG_NOWAIT); | |
| #endif | |
| #ifdef LOG_PERROR | |
| ADD_INT_MACRO(module, LOG_PERROR); | |
| #endif | |
| /* Facilities */ | |
| ADD_INT_MACRO(module, LOG_KERN); | |
| ADD_INT_MACRO(module, LOG_USER); | |
| ADD_INT_MACRO(module, LOG_MAIL); | |
| ADD_INT_MACRO(module, LOG_DAEMON); | |
| ADD_INT_MACRO(module, LOG_AUTH); | |
| ADD_INT_MACRO(module, LOG_LPR); | |
| ADD_INT_MACRO(module, LOG_LOCAL0); | |
| ADD_INT_MACRO(module, LOG_LOCAL1); | |
| ADD_INT_MACRO(module, LOG_LOCAL2); | |
| ADD_INT_MACRO(module, LOG_LOCAL3); | |
| ADD_INT_MACRO(module, LOG_LOCAL4); | |
| ADD_INT_MACRO(module, LOG_LOCAL5); | |
| ADD_INT_MACRO(module, LOG_LOCAL6); | |
| ADD_INT_MACRO(module, LOG_LOCAL7); | |
| #ifndef LOG_SYSLOG | |
| #define LOG_SYSLOG LOG_DAEMON | |
| #endif | |
| #ifndef LOG_NEWS | |
| #define LOG_NEWS LOG_MAIL | |
| #endif | |
| #ifndef LOG_UUCP | |
| #define LOG_UUCP LOG_MAIL | |
| #endif | |
| #ifndef LOG_CRON | |
| #define LOG_CRON LOG_DAEMON | |
| #endif | |
| ADD_INT_MACRO(module, LOG_SYSLOG); | |
| ADD_INT_MACRO(module, LOG_CRON); | |
| ADD_INT_MACRO(module, LOG_UUCP); | |
| ADD_INT_MACRO(module, LOG_NEWS); | |
| #ifdef LOG_AUTHPRIV | |
| ADD_INT_MACRO(module, LOG_AUTHPRIV); | |
| #endif | |
| #ifdef LOG_FTP | |
| ADD_INT_MACRO(module, LOG_FTP); | |
| #endif | |
| #ifdef LOG_NETINFO | |
| ADD_INT_MACRO(module, LOG_NETINFO); | |
| #endif | |
| #ifdef LOG_REMOTEAUTH | |
| ADD_INT_MACRO(module, LOG_REMOTEAUTH); | |
| #endif | |
| #ifdef LOG_INSTALL | |
| ADD_INT_MACRO(module, LOG_INSTALL); | |
| #endif | |
| #ifdef LOG_RAS | |
| ADD_INT_MACRO(module, LOG_RAS); | |
| #endif | |
| #ifdef LOG_LAUNCHD | |
| ADD_INT_MACRO(module, LOG_LAUNCHD); | |
| #endif | |
| return 0; | |
| } | |
| static PyModuleDef_Slot syslog_slots[] = { | |
| _Py_ABI_SLOT, | |
| {Py_mod_exec, syslog_exec}, | |
| {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, | |
| {Py_mod_gil, Py_MOD_GIL_NOT_USED}, | |
| {0, NULL} | |
| }; | |
| /* Initialization function for the module */ | |
| static struct PyModuleDef syslogmodule = { | |
| PyModuleDef_HEAD_INIT, | |
| .m_name = "syslog", | |
| .m_size = 0, | |
| .m_methods = syslog_methods, | |
| .m_slots = syslog_slots, | |
| }; | |
| PyMODINIT_FUNC | |
| PyInit_syslog(void) | |
| { | |
| return PyModuleDef_Init(&syslogmodule); | |
| } |