]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/python.c
Cleanup Python build so that Python is not dragged
[bacula/bacula] / bacula / src / lib / python.c
1 /*
2  *
3  * Bacula common code library interface to Python
4  *
5  * Kern Sibbald, November MMIV
6  *
7  *   Version $Id$
8  *
9  */
10
11 /*
12    Copyright (C) 2004-2005 Kern Sibbald
13
14    This program is free software; you can redistribute it and/or
15    modify it under the terms of the GNU General Public License as
16    published by the Free Software Foundation; either version 2 of
17    the License, or (at your option) any later version.
18
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22    General Public License for more details.
23
24    You should have received a copy of the GNU General Public
25    License along with this program; if not, write to the Free
26    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27    MA 02111-1307, USA.
28
29  */
30
31 #include "bacula.h"
32 #include "jcr.h"
33
34 #ifdef HAVE_PYTHON
35
36 #undef _POSIX_C_SOURCE
37 #include <Python.h>
38
39 static PyObject *bacula_module = NULL;    /* We create this */
40 static PyObject *StartUp_module = NULL;   /* We import this */
41
42 /* These are the daemon events or methods that are defined */
43 static PyObject *JobStart_method = NULL;
44 static PyObject *JobEnd_method = NULL;
45 static PyObject *Exit_method = NULL;
46
47
48 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
49 static PyObject *bacula_write(PyObject *self, PyObject *args);
50
51 PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name);
52
53 /* Define Bacula daemon method entry points */
54 static PyMethodDef BaculaMethods[] = {
55     {"set_events", set_bacula_events, METH_VARARGS, "Define Bacula events."},
56     {"write", bacula_write, METH_VARARGS, "Write output."},
57     {NULL, NULL, 0, NULL}             /* last item */
58 };
59
60
61 /*
62  * This is a Bacula Job type as defined in Python. We store a pointer
63  *   to the jcr. That is all we need, but the user's script may keep
64  *   local data attached to this. 
65  */
66 typedef struct JCRObject {
67     PyObject_HEAD
68     JCR *jcr;
69 } JCRObject;
70
71 static PyTypeObject JCRType = {
72     PyObject_HEAD_INIT(NULL)
73     0,                         /*ob_size*/
74     "bacula.jcr",              /*tp_name*/
75     sizeof(JCRObject),         /*tp_basicsize*/
76     0,                         /*tp_itemsize*/
77     0,                         /*tp_dealloc*/
78     0,                         /*tp_print*/
79     0,                         /*tp_getattr*/
80     0,                         /*tp_setattr*/
81     0,                         /*tp_compare*/
82     0,                         /*tp_repr*/
83     0,                         /*tp_as_number*/
84     0,                         /*tp_as_sequence*/
85     0,                         /*tp_as_mapping*/
86     0,                         /*tp_hash */
87     0,                         /*tp_call*/
88     0,                         /*tp_str*/
89     0,                         /*tp_getattro*/
90     0,                         /*tp_setattro*/
91     0,                         /*tp_as_buffer*/
92     Py_TPFLAGS_DEFAULT, /*tp_flags*/
93     "JCR objects",             /* tp_doc */
94     0,                         /* tp_traverse */
95     0,                         /* tp_clear */
96     0,                         /* tp_richcompare */
97     0,                         /* tp_weaklistoffset */
98     0,                         /* tp_iter */
99     0,                         /* tp_iternext */
100     0,                         /* tp_methods */
101     0,                         /* tp_members */
102     0,                         /* tp_getset */
103     0,                         /* tp_base */
104     0,                         /* tp_dict */
105     0,                         /* tp_descr_get */
106     0,                         /* tp_descr_set */
107     0,                         /* tp_dictoffset */
108     0,                         /* tp_init */
109     0,                         /* tp_alloc */
110     0,                         /* tp_new */
111 };
112
113 /* Return the JCR pointer from the JCRObject */
114 JCR *get_jcr_from_PyObject(PyObject *self)
115 {
116    return ((JCRObject *)self)->jcr;
117 }
118
119
120 /* Start the interpreter */
121 void init_python_interpreter(const char *progname, const char *scripts,
122     const char *module)
123 {
124    char buf[MAXSTRING];
125    Py_SetProgramName((char *)progname);
126    Py_Initialize();
127    PyEval_InitThreads();
128    bacula_module = Py_InitModule("bacula", BaculaMethods);
129    if (!bacula_module) {
130       Jmsg(NULL, M_ERROR_TERM, 0, "Could not initialize Python\n");
131    }
132    bsnprintf(buf, sizeof(buf), "import sys\n"
133             "sys.path.append('%s')\n", scripts);
134    if (PyRun_SimpleString(buf) != 0) {
135       Jmsg(NULL, M_ERROR_TERM, 0, "Could not Run Python string %s\n", buf);
136    }   
137    JCRType.tp_methods = BaculaMethods;
138    if(PyType_Ready(&JCRType) != 0) {
139       Jmsg(NULL, M_ERROR_TERM, 0, "Could not initialize Python Job type.\n");
140       PyErr_Print();
141    }   
142    StartUp_module = PyImport_ImportModule((char *)module);
143    if (!StartUp_module) {
144       Jmsg(NULL, M_ERROR_TERM, 0, "Could not import script %s/%s.\n",
145            scripts, module);
146       PyErr_Clear();
147    }
148    PyEval_ReleaseLock();
149 }
150
151
152 void term_python_interpreter()
153 {
154    Py_XDECREF(StartUp_module);
155    Py_Finalize();
156 }
157
158 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
159 {
160    PyObject *eObject;
161    if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
162       return NULL;
163    }
164    JobStart_method = find_method(eObject, JobStart_method, "JobStart");
165    JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
166    Exit_method = find_method(eObject, Exit_method, "Exit");
167
168    Py_XINCREF(eObject);
169    Py_INCREF(Py_None);
170    return Py_None;
171 }
172
173 /* Write text to daemon output */
174 static PyObject *bacula_write(PyObject *self, PyObject *args)
175 {
176    char *text;
177    if (!PyArg_ParseTuple(args, "s:write", &text)) {
178       return NULL;
179    }
180    if (text) {
181       Jmsg(NULL, M_INFO, 0, "%s", text);
182    }
183    Py_INCREF(Py_None);
184    return Py_None;
185 }
186
187
188 /*
189  * Check that a method exists and is callable.
190  */
191 PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name)
192 {
193    Py_XDECREF(method);             /* release old method if any */
194    method = PyObject_GetAttrString(eventsObject, name);
195    if (method == NULL) {
196        Dmsg1(000, "Python method %s not found\n", name);
197    } else if (PyCallable_Check(method) == 0) {
198        Dmsg1(000, "Python object %s found but not a method.\n", name);
199        Py_XDECREF(method);
200        method = NULL;
201    } else {
202        Dmsg1(000, "Got method %s\n", name);
203    }
204    return method; 
205 }
206
207
208 /*
209  * Generate and process a Bacula event by importing a Python
210  *  module and running it.
211  *
212  *  Returns: 0 if Python not configured or module not found
213  *          -1 on Python error
214  *           1 OK
215  */
216 int generate_daemon_event(JCR *jcr, const char *event)
217 {
218    PyObject *pJCR;
219    int stat = -1;
220    PyObject *result = NULL;
221
222    PyEval_AcquireLock();
223    if (strcmp(event, "JobStart") == 0) {
224       if (!JobStart_method) {
225          stat = 0;
226          goto bail_out;
227       }
228       /* Create JCR argument to send to function */
229       pJCR = (PyObject *)PyObject_New(JCRObject, &JCRType);
230       if (!pJCR) {
231          Jmsg(jcr, M_ERROR, 0, "Could not create JCR Python Object.\n");
232          goto bail_out;
233       }
234       ((JCRObject *)pJCR)->jcr = jcr;
235       bstrncpy(jcr->event, event, sizeof(jcr->event));
236       result = PyObject_CallFunction(JobStart_method, "O", pJCR);
237       jcr->event[0] = 0;             /* no event in progress */
238       if (result == NULL) {
239          JobStart_method = NULL;
240          if (PyErr_Occurred()) {
241             PyErr_Print();
242          }
243          Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
244          Py_XDECREF(pJCR);
245          goto bail_out;
246       }
247       jcr->Python_jcr = (void *)pJCR;
248       stat = 1;                       /* OK */
249
250    } else if (strcmp(event, "JobEnd") == 0) {
251       if (!JobEnd_method) {
252          Py_XDECREF((PyObject *)jcr->Python_jcr);
253          stat = 0;
254          goto bail_out;
255       }
256       bstrncpy(jcr->event, event, sizeof(jcr->event));
257       result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_jcr);
258       jcr->event[0] = 0;             /* no event in progress */
259       if (result == NULL) {
260          JobEnd_method = NULL;
261          if (PyErr_Occurred()) {
262             PyErr_Print();
263          }
264          Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
265          Py_XDECREF((PyObject *)jcr->Python_jcr);
266          goto bail_out;
267       }
268       Py_XDECREF((PyObject *)jcr->Python_jcr);
269       stat = 1;                    /* OK */
270    }
271
272 bail_out:
273    Py_XDECREF(result);
274    PyEval_ReleaseLock();
275    return stat; 
276 }
277
278 #ifdef xxx
279    PyObject *pName, *pModule, *pDict, *pFunc;
280    PyObject *pArgs, *pJCR, *pCall;
281    
282    Dmsg1(100, "Generate event %s\n", event);
283    pName = PyString_FromString(event);
284    if (!pName) {
285       Jmsg(jcr, M_ERROR, 0, "Could not convert \"%s\" to Python string.\n", event);
286       return -1;                      /* Could not convert string */
287    }
288
289    pModule = PyImport_Import(pName);
290    Py_DECREF(pName);                  /* release pName */
291
292    if (pModule != NULL) {
293       pDict = PyModule_GetDict(pModule);
294       /* pDict is a borrowed reference */
295
296       pFunc = PyDict_GetItemString(pDict, (char *)event);
297       /* pFun: Borrowed reference */
298
299       if (pFunc && PyCallable_Check(pFunc)) {
300           /* Create JCR argument to send to function */
301           pArgs = PyTuple_New(1);
302           pJCR = (PyObject *)PyObject_New(JCRObject, &JCRType);
303           ((JCRObject *)pJCR)->jcr = jcr;
304           if (!pJCR) {
305              Py_DECREF(pArgs);
306              Py_DECREF(pModule);
307              Jmsg(jcr, M_ERROR, 0, "Could not create JCR Python Object.\n");
308              return -1;
309           }
310           Py_INCREF(pJCR);
311           /* pJCR reference stolen here: */
312           PyTuple_SetItem(pArgs, 0, pJCR);
313
314           /* Finally, we call the module here */
315           bstrncpy(jcr->event, event, sizeof(jcr->event));
316           pCall = PyObject_CallObject(pFunc, pArgs);
317           jcr->event[0] = 0;             /* no event in progress */
318           Py_DECREF(pArgs);
319           Py_DECREF(pJCR);
320           if (pCall != NULL) {
321              Py_DECREF(pCall);
322           } else {
323              Py_DECREF(pModule);
324              PyErr_Print();
325              Jmsg(jcr, M_ERROR, 0, "Error running Python module: %s\n", event);
326              return 0;                /* error running function */
327           }
328           /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */
329       } else {
330          if (PyErr_Occurred()) {
331             PyErr_Print();
332          }
333          Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found in module.\n", event);
334          return -1;                   /* function not found */
335       }
336       Py_DECREF(pModule);
337    } else {
338       return 0;                       /* Module not present */
339    }
340    Dmsg0(100, "Generate event OK\n");
341    return 1;
342 }
343 #endif
344
345 #else
346
347 /*
348  *  No Python configured -- create external entry points and
349  *    dummy routines so that library code can call this without
350  *    problems even if it is not configured.
351  */
352 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
353 void init_python_interpreter(const char *progname, const char *scripts,
354          const char *module) { }
355 void term_python_interpreter() { }
356
357 #endif /* HAVE_PYTHON */