]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/pythonlib.c
ebl decrease the debug ouput
[bacula/bacula] / bacula / src / lib / pythonlib.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  * Bacula common code library interface to Python
31  *
32  * Kern Sibbald, November MMIV
33  *
34  *   Version $Id$
35  *
36  */
37
38 #include "bacula.h"
39 #include "jcr.h"
40
41 #ifdef HAVE_PYTHON
42
43 #undef _POSIX_C_SOURCE
44 #include <Python.h>
45
46 /* Forward referenced subroutines */
47 static void init_python_lock();
48 static void term_python_lock();
49 void lock_python();
50 void unlock_python();
51
52 extern char *configfile;
53
54 /* Imported subroutines */
55 //extern PyMethodDef JobMethods[];
56 extern PyObject *job_getattr(PyObject *self, char *attrname);
57 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
58
59 static PyObject *bacula_module = NULL;    /* We create this */
60 static PyObject *StartUp_module = NULL;   /* We import this */
61
62 /* These are the daemon events or methods that are defined */
63 static PyObject *JobStart_method = NULL;
64 static PyObject *JobEnd_method = NULL;
65 static PyObject *Exit_method = NULL;
66
67 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
68 static PyObject *bacula_write(PyObject *self, PyObject *args);
69
70 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name);
71
72 /* Define Bacula daemon method entry points */
73 static PyMethodDef BaculaMethods[] = {
74     {"set_events", set_bacula_events, METH_VARARGS, "Define Bacula events."},
75     {"write", bacula_write, METH_VARARGS, "Write output."},
76     {NULL, NULL, 0, NULL}             /* last item */
77 };
78
79 static char my_version[] = VERSION " " BDATE;
80
81 /*
82  * This is a Bacula Job type as defined in Python. We store a pointer
83  *   to the jcr. That is all we need, but the user's script may keep
84  *   local data attached to this. 
85  */
86 typedef struct s_JobObject {
87     PyObject_HEAD
88     JCR *jcr;
89 } JobObject;
90
91 static PyTypeObject JobType = {
92     PyObject_HEAD_INIT(NULL)
93     /* Other items filled in in code below */
94 };
95
96 /* Return the JCR pointer from the JobObject */
97 JCR *get_jcr_from_PyObject(PyObject *self)
98 {
99    if (!self) {
100       return NULL;
101    }
102    return ((JobObject *)self)->jcr;
103 }
104
105
106 /* Start the interpreter */
107 void init_python_interpreter(const char *progname, const char *scripts,
108     const char *module)
109 {
110    char buf[MAXSTRING];
111
112    if (!scripts || scripts[0] == 0) {
113       Dmsg1(100, "No script dir. prog=%s\n", module);
114       return;
115    }
116    Dmsg2(100, "Script dir=%s prog=%s\n", scripts, module);
117
118    Py_SetProgramName((char *)progname);
119    Py_Initialize();
120    PyEval_InitThreads();
121    bacula_module = Py_InitModule("bacula", BaculaMethods);
122    PyModule_AddStringConstant(bacula_module, "Name", my_name);
123    PyModule_AddStringConstant(bacula_module, "Version", my_version);
124    PyModule_AddStringConstant(bacula_module, "ConfigFile", configfile);
125    PyModule_AddStringConstant(bacula_module, "WorkingDir", (char *)working_directory);
126    if (!bacula_module) {
127       Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python\n"));
128    }
129    bsnprintf(buf, sizeof(buf), "import sys\n"
130             "sys.path.append('%s')\n", scripts);
131    if (PyRun_SimpleString(buf) != 0) {
132       Jmsg1(NULL, M_ERROR_TERM, 0, _("Could not Run Python string %s\n"), buf);
133    }   
134
135    /* Explicitly set values we want */
136    JobType.tp_name = "Bacula.Job";
137    JobType.tp_basicsize = sizeof(JobObject);
138    JobType.tp_flags = Py_TPFLAGS_DEFAULT;
139    JobType.tp_doc = "Bacula Job object";
140    JobType.tp_getattr = job_getattr;
141    JobType.tp_setattr = job_setattr;
142
143    if (PyType_Ready(&JobType) != 0) {
144       Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python Job type.\n"));
145       PyErr_Print();
146    }   
147    StartUp_module = PyImport_ImportModule((char *)module);
148    if (!StartUp_module) {
149       Emsg2(M_ERROR, 0, _("Could not import Python script %s/%s. Python disabled.\n"),
150            scripts, module);
151       if (PyErr_Occurred()) {
152          PyErr_Print();
153          Dmsg0(000, "Python Import error.\n");
154       }
155    }
156    PyEval_ReleaseLock();
157    init_python_lock();
158 }
159
160
161 void term_python_interpreter()
162 {
163    if (StartUp_module) {
164       Py_XDECREF(StartUp_module);
165       Py_Finalize();
166    }
167    term_python_lock();
168 }
169
170 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
171 {
172    PyObject *eObject;
173
174    Dmsg0(100, "In set_bacula_events.\n");
175    if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
176       return NULL;
177    }
178    JobStart_method = find_method(eObject, JobStart_method, "JobStart");
179    JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
180    Exit_method = find_method(eObject, Exit_method, "Exit");
181
182    Py_XINCREF(eObject);
183    Py_INCREF(Py_None);
184    return Py_None;
185 }
186
187 /* Write text to daemon output */
188 static PyObject *bacula_write(PyObject *self, PyObject *args)
189 {
190    char *text;
191    if (!PyArg_ParseTuple(args, "s:write", &text)) {
192       return NULL;
193    }
194    if (text) {
195       Jmsg(NULL, M_INFO, 0, "%s", text);
196    }
197    Py_INCREF(Py_None);
198    return Py_None;
199 }
200
201
202 /*
203  * Check that a method exists and is callable.
204  */
205 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
206 {
207    Py_XDECREF(method);             /* release old method if any */
208    method = PyObject_GetAttrString(eventsObject, (char *)name);
209    if (method == NULL) {
210        Dmsg1(000, "Python method %s not found\n", name);
211    } else if (PyCallable_Check(method) == 0) {
212        Dmsg1(000, "Python object %s found but not a method.\n", name);
213        Py_XDECREF(method);
214        method = NULL;
215    } else {
216        Dmsg1(100, "Got method %s\n", name);
217    }
218    return method; 
219 }
220
221
222 /*
223  * Generate and process a Bacula event by importing a Python
224  *  module and running it.
225  *
226  *  Returns: 0 if Python not configured or module not found
227  *          -1 on Python error
228  *           1 OK
229  */
230 int generate_daemon_event(JCR *jcr, const char *event)
231 {
232    PyObject *pJob;
233    int stat = -1;
234    PyObject *result = NULL;
235    char *obj_fmt = (char *)"O";
236
237    if (!StartUp_module) {
238       Dmsg0(100, "No startup module.\n");
239       return 0;
240    }
241
242    Dmsg1(100, "event=%s\n", event);
243    lock_python();
244 // PyEval_AcquireLock();
245    if (strcmp(event, "JobStart") == 0) {
246       if (!JobStart_method) {
247          stat = 0;
248          goto bail_out;
249       }
250       /* Create JCR argument to send to function */
251       pJob = (PyObject *)PyObject_New(JobObject, &JobType);
252       if (!pJob) {
253          Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n"));
254          goto bail_out;
255       }
256       ((JobObject *)pJob)->jcr = jcr;
257       bstrncpy(jcr->event, event, sizeof(jcr->event));
258       result = PyObject_CallFunction(JobStart_method, obj_fmt, pJob);
259       jcr->event[0] = 0;             /* no event in progress */
260       if (result == NULL) {
261          JobStart_method = NULL;
262          if (PyErr_Occurred()) {
263             PyErr_Print();
264             Dmsg0(000, "Python JobStart error.\n");
265          }
266          Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
267          Py_XDECREF(pJob);
268          goto bail_out;
269       }
270       jcr->Python_job = (void *)pJob;
271       stat = 1;                       /* OK */
272       goto jobstart_ok;
273
274    } else if (strcmp(event, "JobEnd") == 0) {
275       if (!JobEnd_method || !jcr->Python_job) {
276          stat = 0;                    /* probably already here */
277          goto bail_out;
278       }
279       bstrncpy(jcr->event, event, sizeof(jcr->event));
280       Dmsg1(100, "Call daemon event=%s\n", event);
281       result = PyObject_CallFunction(JobEnd_method, obj_fmt, jcr->Python_job);
282       jcr->event[0] = 0;             /* no event in progress */
283       if (result == NULL) {
284          if (PyErr_Occurred()) {
285             PyErr_Print();
286             Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
287                jcr->JobId);
288             JobEnd_method = NULL;
289          }
290          Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
291          goto bail_out;
292       }
293       stat = 1;                    /* OK */
294    } else if (strcmp(event, "Exit") == 0) {
295       if (!Exit_method) {
296          stat = 0;
297          goto bail_out;
298       }
299       result = PyObject_CallFunction(Exit_method, NULL);
300       if (result == NULL) {
301          goto bail_out;
302       }
303       stat = 1;                    /* OK */
304    } else {
305       Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event);
306    }
307
308 bail_out:
309    if (jcr) {
310       Py_XDECREF((PyObject *)jcr->Python_job);
311       jcr->Python_job = NULL;
312       Py_XDECREF((PyObject *)jcr->Python_events);
313       jcr->Python_events = NULL;
314    }
315    /* Fall through */
316 jobstart_ok:
317    Py_XDECREF(result);
318    unlock_python();
319 // PyEval_ReleaseLock();
320    return stat; 
321 }
322
323 static brwlock_t python_rwlock;
324
325 static void init_python_lock()
326 {
327    int errstat;
328    if ((errstat=rwl_init(&python_rwlock)) != 0) {
329       berrno be;
330       Emsg1(M_ABORT, 0, _("Unable to initialize the Python lock. ERR=%s\n"),
331             be.bstrerror(errstat));
332    }
333
334 }
335
336 static void term_python_lock()
337 {
338    rwl_destroy(&python_rwlock);
339 }
340
341 /* This applies to a drive and to Volumes */
342 void lock_python()
343 {
344    int errstat;
345    if ((errstat=rwl_writelock(&python_rwlock)) != 0) {
346       berrno be;
347       Emsg2(M_ABORT, 0, "Python rwl_writelock failure. stat=%d: ERR=%s\n",
348            errstat, be.bstrerror(errstat));
349    }
350 }
351
352 void unlock_python()
353 {
354    int errstat;
355    if ((errstat=rwl_writeunlock(&python_rwlock)) != 0) {
356       berrno be;
357       Emsg2(M_ABORT, 0, "Python rwl_writeunlock failure. stat=%d: ERR=%s\n",
358            errstat, be.bstrerror(errstat));
359    }
360 }
361
362
363 #else
364
365 /*
366  *  No Python configured -- create external entry points and
367  *    dummy routines so that library code can call this without
368  *    problems even if it is not configured.
369  */
370 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
371 void init_python_interpreter(const char *progname, const char *scripts,
372          const char *module) { }
373 void term_python_interpreter() { }
374
375 #endif /* HAVE_PYTHON */