1/***********************************************************
2Copyright 1994 by Lance Ellinghouse,
3Cathedral City, California Republic, United States of America.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the name of Lance Ellinghouse
12not be used in advertising or publicity pertaining to distribution
13of the software without specific, written prior permission.
14
15LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL,
18INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
19FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/******************************************************************
26
27Revision history:
28
292010/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
341998/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
4095/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"
54
55#include <syslog.h>
56
57/*  only one instance, only one syslog, so globals should be ok  */
58static PyObject *S_ident_o = NULL;                      /*  identifier, held by openlog()  */
59static char S_log_open = 0;
60
61
62static PyObject *
63syslog_get_argv(void)
64{
65    /* Figure out what to use for as the program "ident" for openlog().
66     * This swallows exceptions and continues rather than failing out,
67     * because the syslog module can still be used because openlog(3)
68     * is optional.
69     */
70
71    Py_ssize_t argv_len;
72    PyObject *scriptobj;
73    char *atslash;
74    PyObject *argv = PySys_GetObject("argv");
75
76    if (argv == NULL) {
77        return(NULL);
78    }
79
80    argv_len = PyList_Size(argv);
81    if (argv_len == -1) {
82        PyErr_Clear();
83        return(NULL);
84    }
85    if (argv_len == 0) {
86        return(NULL);
87    }
88
89    scriptobj = PyList_GetItem(argv, 0);
90    if (!PyString_Check(scriptobj)) {
91        return(NULL);
92    }
93    if (PyString_GET_SIZE(scriptobj) == 0) {
94        return(NULL);
95    }
96
97    atslash = strrchr(PyString_AsString(scriptobj), SEP);
98    if (atslash) {
99        return(PyString_FromString(atslash + 1));
100    } else {
101        Py_INCREF(scriptobj);
102        return(scriptobj);
103    }
104
105    return(NULL);
106}
107
108
109static PyObject *
110syslog_openlog(PyObject * self, PyObject * args, PyObject *kwds)
111{
112    long logopt = 0;
113    long facility = LOG_USER;
114    PyObject *new_S_ident_o = NULL;
115    static char *keywords[] = {"ident", "logoption", "facility", 0};
116
117    if (!PyArg_ParseTupleAndKeywords(args, kwds,
118                          "|Sll:openlog", keywords, &new_S_ident_o, &logopt, &facility))
119        return NULL;
120
121    if (new_S_ident_o) { Py_INCREF(new_S_ident_o); }
122
123    /*  get sys.argv[0] or NULL if we can't for some reason  */
124    if (!new_S_ident_o) {
125        new_S_ident_o = syslog_get_argv();
126        }
127
128    Py_XDECREF(S_ident_o);
129    S_ident_o = new_S_ident_o;
130
131    /* At this point, S_ident_o should be INCREF()ed.  openlog(3) does not
132     * make a copy, and syslog(3) later uses it.  We can't garbagecollect it
133     * If NULL, just let openlog figure it out (probably using C argv[0]).
134     */
135
136    openlog(S_ident_o ? PyString_AsString(S_ident_o) : NULL, logopt, facility);
137    S_log_open = 1;
138
139    Py_INCREF(Py_None);
140    return Py_None;
141}
142
143
144static PyObject *
145syslog_syslog(PyObject * self, PyObject * args)
146{
147    char *message;
148    int   priority = LOG_INFO;
149
150    if (!PyArg_ParseTuple(args, "is;[priority,] message string",
151                          &priority, &message)) {
152        PyErr_Clear();
153        if (!PyArg_ParseTuple(args, "s;[priority,] message string",
154                              &message))
155            return NULL;
156    }
157
158    /*  if log is not opened, open it now  */
159    if (!S_log_open) {
160        PyObject *openargs;
161
162        /* Continue even if PyTuple_New fails, because openlog(3) is optional.
163         * So, we can still do loggin in the unlikely event things are so hosed
164         * that we can't do this tuple.
165         */
166        if ((openargs = PyTuple_New(0))) {
167            PyObject *openlog_ret = syslog_openlog(self, openargs, NULL);
168            Py_XDECREF(openlog_ret);
169            Py_DECREF(openargs);
170        }
171    }
172
173    Py_BEGIN_ALLOW_THREADS;
174    syslog(priority, "%s", message);
175    Py_END_ALLOW_THREADS;
176    Py_INCREF(Py_None);
177    return Py_None;
178}
179
180static PyObject *
181syslog_closelog(PyObject *self, PyObject *unused)
182{
183    if (S_log_open) {
184        closelog();
185        Py_XDECREF(S_ident_o);
186        S_ident_o = NULL;
187        S_log_open = 0;
188    }
189    Py_INCREF(Py_None);
190    return Py_None;
191}
192
193static PyObject *
194syslog_setlogmask(PyObject *self, PyObject *args)
195{
196    long maskpri, omaskpri;
197
198    if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri))
199        return NULL;
200    omaskpri = setlogmask(maskpri);
201    return PyInt_FromLong(omaskpri);
202}
203
204static PyObject *
205syslog_log_mask(PyObject *self, PyObject *args)
206{
207    long mask;
208    long pri;
209    if (!PyArg_ParseTuple(args, "l:LOG_MASK", &pri))
210        return NULL;
211    mask = LOG_MASK(pri);
212    return PyInt_FromLong(mask);
213}
214
215static PyObject *
216syslog_log_upto(PyObject *self, PyObject *args)
217{
218    long mask;
219    long pri;
220    if (!PyArg_ParseTuple(args, "l:LOG_UPTO", &pri))
221        return NULL;
222    mask = LOG_UPTO(pri);
223    return PyInt_FromLong(mask);
224}
225
226/* List of functions defined in the module */
227
228static PyMethodDef syslog_methods[] = {
229    {"openlog",         (PyCFunction) syslog_openlog,           METH_VARARGS | METH_KEYWORDS},
230    {"closelog",        syslog_closelog,        METH_NOARGS},
231    {"syslog",          syslog_syslog,          METH_VARARGS},
232    {"setlogmask",      syslog_setlogmask,      METH_VARARGS},
233    {"LOG_MASK",        syslog_log_mask,        METH_VARARGS},
234    {"LOG_UPTO",        syslog_log_upto,        METH_VARARGS},
235    {NULL,              NULL,                   0}
236};
237
238/* Initialization function for the module */
239
240PyMODINIT_FUNC
241initsyslog(void)
242{
243    PyObject *m;
244
245    /* Create the module and add the functions */
246    m = Py_InitModule("syslog", syslog_methods);
247    if (m == NULL)
248        return;
249
250    /* Add some symbolic constants to the module */
251
252    /* Priorities */
253    PyModule_AddIntConstant(m, "LOG_EMERG",       LOG_EMERG);
254    PyModule_AddIntConstant(m, "LOG_ALERT",       LOG_ALERT);
255    PyModule_AddIntConstant(m, "LOG_CRIT",        LOG_CRIT);
256    PyModule_AddIntConstant(m, "LOG_ERR",         LOG_ERR);
257    PyModule_AddIntConstant(m, "LOG_WARNING", LOG_WARNING);
258    PyModule_AddIntConstant(m, "LOG_NOTICE",  LOG_NOTICE);
259    PyModule_AddIntConstant(m, "LOG_INFO",        LOG_INFO);
260    PyModule_AddIntConstant(m, "LOG_DEBUG",       LOG_DEBUG);
261
262    /* openlog() option flags */
263    PyModule_AddIntConstant(m, "LOG_PID",         LOG_PID);
264    PyModule_AddIntConstant(m, "LOG_CONS",        LOG_CONS);
265    PyModule_AddIntConstant(m, "LOG_NDELAY",  LOG_NDELAY);
266#ifdef LOG_NOWAIT
267    PyModule_AddIntConstant(m, "LOG_NOWAIT",  LOG_NOWAIT);
268#endif
269#ifdef LOG_PERROR
270    PyModule_AddIntConstant(m, "LOG_PERROR",  LOG_PERROR);
271#endif
272
273    /* Facilities */
274    PyModule_AddIntConstant(m, "LOG_KERN",        LOG_KERN);
275    PyModule_AddIntConstant(m, "LOG_USER",        LOG_USER);
276    PyModule_AddIntConstant(m, "LOG_MAIL",        LOG_MAIL);
277    PyModule_AddIntConstant(m, "LOG_DAEMON",  LOG_DAEMON);
278    PyModule_AddIntConstant(m, "LOG_AUTH",        LOG_AUTH);
279    PyModule_AddIntConstant(m, "LOG_LPR",         LOG_LPR);
280    PyModule_AddIntConstant(m, "LOG_LOCAL0",  LOG_LOCAL0);
281    PyModule_AddIntConstant(m, "LOG_LOCAL1",  LOG_LOCAL1);
282    PyModule_AddIntConstant(m, "LOG_LOCAL2",  LOG_LOCAL2);
283    PyModule_AddIntConstant(m, "LOG_LOCAL3",  LOG_LOCAL3);
284    PyModule_AddIntConstant(m, "LOG_LOCAL4",  LOG_LOCAL4);
285    PyModule_AddIntConstant(m, "LOG_LOCAL5",  LOG_LOCAL5);
286    PyModule_AddIntConstant(m, "LOG_LOCAL6",  LOG_LOCAL6);
287    PyModule_AddIntConstant(m, "LOG_LOCAL7",  LOG_LOCAL7);
288
289#ifndef LOG_SYSLOG
290#define LOG_SYSLOG              LOG_DAEMON
291#endif
292#ifndef LOG_NEWS
293#define LOG_NEWS                LOG_MAIL
294#endif
295#ifndef LOG_UUCP
296#define LOG_UUCP                LOG_MAIL
297#endif
298#ifndef LOG_CRON
299#define LOG_CRON                LOG_DAEMON
300#endif
301
302    PyModule_AddIntConstant(m, "LOG_SYSLOG",  LOG_SYSLOG);
303    PyModule_AddIntConstant(m, "LOG_CRON",        LOG_CRON);
304    PyModule_AddIntConstant(m, "LOG_UUCP",        LOG_UUCP);
305    PyModule_AddIntConstant(m, "LOG_NEWS",        LOG_NEWS);
306}
307