(root)/
Python-3.12.0/
Modules/
syslogmodule.c
       1  /***********************************************************
       2  Copyright 1994 by Lance Ellinghouse,
       3  Cathedral City, California Republic, United States of America.
       4  
       5                          All Rights Reserved
       6  
       7  Permission to use, copy, modify, and distribute this software and its
       8  documentation for any purpose and without fee is hereby granted,
       9  provided that the above copyright notice appear in all copies and that
      10  both that copyright notice and this permission notice appear in
      11  supporting documentation, and that the name of Lance Ellinghouse
      12  not be used in advertising or publicity pertaining to distribution
      13  of the software without specific, written prior permission.
      14  
      15  LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
      16  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
      17  FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL,
      18  INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
      19  FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
      20  NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
      21  WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      22  
      23  ******************************************************************/
      24  
      25  /******************************************************************
      26  
      27  Revision history:
      28  
      29  2010/04/20 (Sean Reifschneider)
      30    - Use basename(sys.argv[0]) for the default "ident".
      31    - Arguments to openlog() are now keyword args and are all optional.
      32    - syslog() calls openlog() if it hasn't already been called.
      33  
      34  1998/04/28 (Sean Reifschneider)
      35    - When facility not specified to syslog() method, use default from openlog()
      36      (This is how it was claimed to work in the documentation)
      37    - Potential resource leak of o_ident, now cleaned up in closelog()
      38    - Minor comment accuracy fix.
      39  
      40  95/06/29 (Steve Clift)
      41    - Changed arg parsing to use PyArg_ParseTuple.
      42    - Added PyErr_Clear() call(s) where needed.
      43    - Fix core dumps if user message contains format specifiers.
      44    - Change openlog arg defaults to match normal syslog behavior.
      45    - Plug memory leak in openlog().
      46    - Fix setlogmask() to return previous mask value.
      47  
      48  ******************************************************************/
      49  
      50  /* syslog module */
      51  
      52  #include "Python.h"
      53  #include "osdefs.h"               // SEP
      54  
      55  #include <syslog.h>
      56  
      57  /*[clinic input]
      58  module syslog
      59  [clinic start generated code]*/
      60  /*[clinic end generated code: output=da39a3ee5e6b4b0d input=478f4ac94a1d4cae]*/
      61  
      62  #include "clinic/syslogmodule.c.h"
      63  
      64  /*  only one instance, only one syslog, so globals should be ok,
      65   *  these fields are writable from the main interpreter only. */
      66  static PyObject *S_ident_o = NULL;  // identifier, held by openlog()
      67  static char S_log_open = 0;
      68  
      69  static inline int
      70  is_main_interpreter(void)
      71  {
      72      return (PyInterpreterState_Get() == PyInterpreterState_Main());
      73  }
      74  
      75  static PyObject *
      76  syslog_get_argv(void)
      77  {
      78      /* Figure out what to use for as the program "ident" for openlog().
      79       * This swallows exceptions and continues rather than failing out,
      80       * because the syslog module can still be used because openlog(3)
      81       * is optional.
      82       */
      83  
      84      Py_ssize_t argv_len, scriptlen;
      85      PyObject *scriptobj;
      86      Py_ssize_t slash;
      87      PyObject *argv = PySys_GetObject("argv");
      88  
      89      if (argv == NULL) {
      90          return(NULL);
      91      }
      92  
      93      argv_len = PyList_Size(argv);
      94      if (argv_len == -1) {
      95          PyErr_Clear();
      96          return(NULL);
      97      }
      98      if (argv_len == 0) {
      99          return(NULL);
     100      }
     101  
     102      scriptobj = PyList_GetItem(argv, 0);
     103      if (scriptobj == NULL) {
     104          PyErr_Clear();
     105          return NULL;
     106      }
     107      if (!PyUnicode_Check(scriptobj)) {
     108          return(NULL);
     109      }
     110      scriptlen = PyUnicode_GET_LENGTH(scriptobj);
     111      if (scriptlen == 0) {
     112          return(NULL);
     113      }
     114  
     115      slash = PyUnicode_FindChar(scriptobj, SEP, 0, scriptlen, -1);
     116      if (slash == -2) {
     117          PyErr_Clear();
     118          return NULL;
     119      }
     120      if (slash != -1) {
     121          return PyUnicode_Substring(scriptobj, slash + 1, scriptlen);
     122      } else {
     123          Py_INCREF(scriptobj);
     124          return(scriptobj);
     125      }
     126  }
     127  
     128  
     129  /*[clinic input]
     130  syslog.openlog
     131  
     132      ident: unicode = NULL
     133      logoption as logopt: long = 0
     134      facility: long(c_default="LOG_USER") = LOG_USER
     135  
     136  Set logging options of subsequent syslog() calls.
     137  [clinic start generated code]*/
     138  
     139  static PyObject *
     140  syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt,
     141                      long facility)
     142  /*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/
     143  {
     144      // Since the sys.openlog changes the process level state of syslog library,
     145      // this operation is only allowed for the main interpreter.
     146      if (!is_main_interpreter()) {
     147          PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.openlog()");
     148          return NULL;
     149      }
     150  
     151      const char *ident_str = NULL;
     152  
     153      if (ident) {
     154          Py_INCREF(ident);
     155      }
     156      else {
     157          /* get sys.argv[0] or NULL if we can't for some reason  */
     158          ident = syslog_get_argv();
     159      }
     160  
     161      /* At this point, ident should be INCREF()ed.  openlog(3) does not
     162       * make a copy, and syslog(3) later uses it.  We can't garbagecollect it.
     163       * If NULL, just let openlog figure it out (probably using C argv[0]).
     164       */
     165      if (ident) {
     166          ident_str = PyUnicode_AsUTF8(ident);
     167          if (ident_str == NULL) {
     168              Py_DECREF(ident);
     169              return NULL;
     170          }
     171      }
     172      if (PySys_Audit("syslog.openlog", "Oll", ident ? ident : Py_None, logopt, facility) < 0) {
     173          Py_DECREF(ident);
     174          return NULL;
     175      }
     176  
     177      openlog(ident_str, logopt, facility);
     178      S_log_open = 1;
     179      Py_XSETREF(S_ident_o, ident);
     180  
     181      Py_RETURN_NONE;
     182  }
     183  
     184  
     185  
     186  /*[clinic input]
     187  syslog.syslog
     188  
     189      [
     190      priority: int(c_default="LOG_INFO") = LOG_INFO
     191      ]
     192  
     193      message: str
     194  
     195      /
     196  
     197  Send the string message to the system logger.
     198  [clinic start generated code]*/
     199  
     200  static PyObject *
     201  syslog_syslog_impl(PyObject *module, int group_left_1, int priority,
     202                     const char *message)
     203  /*[clinic end generated code: output=c3dbc73445a0e078 input=ac83d92b12ea3d4e]*/
     204  {
     205      if (PySys_Audit("syslog.syslog", "is", priority, message) < 0) {
     206          return NULL;
     207      }
     208  
     209      /*  if log is not opened, open it now  */
     210      if (!S_log_open) {
     211          if (!is_main_interpreter()) {
     212              PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog() "
     213                                                  "until the syslog is opened by the main interpreter");
     214              return NULL;
     215          }
     216          PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER);
     217          if (openlog_ret == NULL) {
     218              return NULL;
     219          }
     220          Py_DECREF(openlog_ret);
     221      }
     222  
     223      /* Incref ident, because it can be decrefed if syslog.openlog() is
     224       * called when the GIL is released.
     225       */
     226      PyObject *ident = Py_XNewRef(S_ident_o);
     227  #ifdef __APPLE__
     228      // gh-98178: On macOS, libc syslog() is not thread-safe
     229      syslog(priority, "%s", message);
     230  #else
     231      Py_BEGIN_ALLOW_THREADS;
     232      syslog(priority, "%s", message);
     233      Py_END_ALLOW_THREADS;
     234  #endif
     235      Py_XDECREF(ident);
     236      Py_RETURN_NONE;
     237  }
     238  
     239  
     240  /*[clinic input]
     241  syslog.closelog
     242  
     243  Reset the syslog module values and call the system library closelog().
     244  [clinic start generated code]*/
     245  
     246  static PyObject *
     247  syslog_closelog_impl(PyObject *module)
     248  /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/
     249  {
     250      // Since the sys.closelog changes the process level state of syslog library,
     251      // this operation is only allowed for the main interpreter.
     252      if (!is_main_interpreter()) {
     253          PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can't use syslog.closelog()");
     254          return NULL;
     255      }
     256  
     257      if (PySys_Audit("syslog.closelog", NULL) < 0) {
     258          return NULL;
     259      }
     260      if (S_log_open) {
     261          closelog();
     262          Py_CLEAR(S_ident_o);
     263          S_log_open = 0;
     264      }
     265      Py_RETURN_NONE;
     266  }
     267  
     268  /*[clinic input]
     269  syslog.setlogmask -> long
     270  
     271      maskpri: long
     272      /
     273  
     274  Set the priority mask to maskpri and return the previous mask value.
     275  [clinic start generated code]*/
     276  
     277  static long
     278  syslog_setlogmask_impl(PyObject *module, long maskpri)
     279  /*[clinic end generated code: output=d6ed163917b434bf input=adff2c2b76c7629c]*/
     280  {
     281      if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) {
     282          return -1;
     283      }
     284  
     285      return setlogmask(maskpri);
     286  }
     287  
     288  /*[clinic input]
     289  syslog.LOG_MASK -> long
     290  
     291      pri: long
     292      /
     293  
     294  Calculates the mask for the individual priority pri.
     295  [clinic start generated code]*/
     296  
     297  static long
     298  syslog_LOG_MASK_impl(PyObject *module, long pri)
     299  /*[clinic end generated code: output=c4a5bbfcc74c7c94 input=534829cb7fb5f7d2]*/
     300  {
     301      return LOG_MASK(pri);
     302  }
     303  
     304  /*[clinic input]
     305  syslog.LOG_UPTO -> long
     306  
     307      pri: long
     308      /
     309  
     310  Calculates the mask for all priorities up to and including pri.
     311  [clinic start generated code]*/
     312  
     313  static long
     314  syslog_LOG_UPTO_impl(PyObject *module, long pri)
     315  /*[clinic end generated code: output=9eab083c90601d7e input=5e906d6c406b7458]*/
     316  {
     317      return LOG_UPTO(pri);
     318  }
     319  
     320  /* List of functions defined in the module */
     321  
     322  static PyMethodDef syslog_methods[] = {
     323      SYSLOG_OPENLOG_METHODDEF
     324      SYSLOG_CLOSELOG_METHODDEF
     325      SYSLOG_SYSLOG_METHODDEF
     326      SYSLOG_SETLOGMASK_METHODDEF
     327      SYSLOG_LOG_MASK_METHODDEF
     328      SYSLOG_LOG_UPTO_METHODDEF
     329      {NULL,              NULL,                   0}
     330  };
     331  
     332  
     333  static int
     334  syslog_exec(PyObject *module)
     335  {
     336  #define ADD_INT_MACRO(module, macro)                                  \
     337      do {                                                              \
     338          if (PyModule_AddIntConstant(module, #macro, macro) < 0) {     \
     339              return -1;                                                \
     340          }                                                             \
     341      } while (0)
     342      /* Priorities */
     343      ADD_INT_MACRO(module, LOG_EMERG);
     344      ADD_INT_MACRO(module, LOG_ALERT);
     345      ADD_INT_MACRO(module, LOG_CRIT);
     346      ADD_INT_MACRO(module, LOG_ERR);
     347      ADD_INT_MACRO(module, LOG_WARNING);
     348      ADD_INT_MACRO(module, LOG_NOTICE);
     349      ADD_INT_MACRO(module, LOG_INFO);
     350      ADD_INT_MACRO(module, LOG_DEBUG);
     351  
     352      /* openlog() option flags */
     353      ADD_INT_MACRO(module, LOG_PID);
     354      ADD_INT_MACRO(module, LOG_CONS);
     355      ADD_INT_MACRO(module, LOG_NDELAY);
     356  #ifdef LOG_ODELAY
     357      ADD_INT_MACRO(module, LOG_ODELAY);
     358  #endif
     359  #ifdef LOG_NOWAIT
     360      ADD_INT_MACRO(module, LOG_NOWAIT);
     361  #endif
     362  #ifdef LOG_PERROR
     363      ADD_INT_MACRO(module, LOG_PERROR);
     364  #endif
     365  
     366      /* Facilities */
     367      ADD_INT_MACRO(module, LOG_KERN);
     368      ADD_INT_MACRO(module, LOG_USER);
     369      ADD_INT_MACRO(module, LOG_MAIL);
     370      ADD_INT_MACRO(module, LOG_DAEMON);
     371      ADD_INT_MACRO(module, LOG_AUTH);
     372      ADD_INT_MACRO(module, LOG_LPR);
     373      ADD_INT_MACRO(module, LOG_LOCAL0);
     374      ADD_INT_MACRO(module, LOG_LOCAL1);
     375      ADD_INT_MACRO(module, LOG_LOCAL2);
     376      ADD_INT_MACRO(module, LOG_LOCAL3);
     377      ADD_INT_MACRO(module, LOG_LOCAL4);
     378      ADD_INT_MACRO(module, LOG_LOCAL5);
     379      ADD_INT_MACRO(module, LOG_LOCAL6);
     380      ADD_INT_MACRO(module, LOG_LOCAL7);
     381  
     382  #ifndef LOG_SYSLOG
     383  #define LOG_SYSLOG              LOG_DAEMON
     384  #endif
     385  #ifndef LOG_NEWS
     386  #define LOG_NEWS                LOG_MAIL
     387  #endif
     388  #ifndef LOG_UUCP
     389  #define LOG_UUCP                LOG_MAIL
     390  #endif
     391  #ifndef LOG_CRON
     392  #define LOG_CRON                LOG_DAEMON
     393  #endif
     394  
     395      ADD_INT_MACRO(module, LOG_SYSLOG);
     396      ADD_INT_MACRO(module, LOG_CRON);
     397      ADD_INT_MACRO(module, LOG_UUCP);
     398      ADD_INT_MACRO(module, LOG_NEWS);
     399  
     400  #ifdef LOG_AUTHPRIV
     401      ADD_INT_MACRO(module, LOG_AUTHPRIV);
     402  #endif
     403  
     404      return 0;
     405  }
     406  
     407  static PyModuleDef_Slot syslog_slots[] = {
     408      {Py_mod_exec, syslog_exec},
     409      {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
     410      {0, NULL}
     411  };
     412  
     413  /* Initialization function for the module */
     414  
     415  static struct PyModuleDef syslogmodule = {
     416      PyModuleDef_HEAD_INIT,
     417      .m_name = "syslog",
     418      .m_size = 0,
     419      .m_methods = syslog_methods,
     420      .m_slots = syslog_slots,
     421  };
     422  
     423  PyMODINIT_FUNC
     424  PyInit_syslog(void)
     425  {
     426      return PyModuleDef_Init(&syslogmodule);
     427  }