]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/pythonlib.c
bat: Add pattern filter and make restore to start from brestore
[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 three of the GNU Affero 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 Affero 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 #include "pythonlib.h"
47
48 /* Forward referenced subroutines */
49 static void init_python_lock();
50 static void term_python_lock();
51
52 static PyObject *bacula_module = NULL;    /* We create this */
53 static PyObject *StartUp_module = NULL;   /* We import this */
54
55 /* These are the daemon events or methods that are defined */
56 static PyObject *JobStart_method = NULL;
57 static PyObject *JobEnd_method = NULL;
58 static PyObject *Exit_method = NULL;
59
60 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
61 static PyObject *bacula_write(PyObject *self, PyObject *args);
62
63 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name);
64
65 /* Define Bacula daemon method entry points */
66 static PyMethodDef BaculaMethods[] = {
67     {"set_events", set_bacula_events, METH_VARARGS, "Define Bacula events."},
68     {"write", bacula_write, METH_VARARGS, "Write output."},
69     {NULL, NULL, 0, NULL}             /* last item */
70 };
71
72 static char my_version[] = VERSION " " BDATE;
73
74 /*
75  * This is a Bacula Job type as defined in Python. We store a pointer
76  * to the jcr. That is all we need, but the user's script may keep
77  * local data attached to this.
78  */
79 typedef struct s_JobObject {
80     PyObject_HEAD
81     JCR *jcr;
82 } JobObject;
83
84 static PyTypeObject JobType = {
85     PyObject_HEAD_INIT(NULL)
86     /* Other items filled in in code below */
87 };
88
89 /* Return the JCR pointer from the JobObject */
90 JCR *get_jcr_from_PyObject(PyObject *self)
91 {
92    if (!self) {
93       return NULL;
94    }
95    return ((JobObject *)self)->jcr;
96 }
97
98 /* Start the interpreter */
99 void init_python_interpreter(init_python_interpreter_args *args)
100 {
101    char buf[MAXSTRING];
102
103    if (!args->scriptdir || args->scriptdir[0] == 0) {
104       Dmsg1(100, "No script dir. prog=%s\n", args->modulename);
105       return;
106    }
107    Dmsg2(100, "Script dir=%s prog=%s\n", args->scriptdir, args->modulename);
108
109    Py_SetProgramName((char *)args->progname);
110    Py_Initialize();
111    PyEval_InitThreads();
112    bacula_module = Py_InitModule("bacula", BaculaMethods);
113    PyModule_AddStringConstant(bacula_module, "Name", my_name);
114    PyModule_AddStringConstant(bacula_module, "Version", my_version);
115    PyModule_AddStringConstant(bacula_module, "ConfigFile", (char *)args->configfile);
116    PyModule_AddStringConstant(bacula_module, "WorkingDir", (char *)args->workingdir);
117    if (!bacula_module) {
118       Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python\n"));
119    }
120    bsnprintf(buf, sizeof(buf), "import sys\n"
121             "sys.path.append('%s')\n", args->scriptdir);
122    if (PyRun_SimpleString(buf) != 0) {
123       Jmsg1(NULL, M_ERROR_TERM, 0, _("Could not Run Python string %s\n"), buf);
124    }   
125
126    /* Explicitly set values we want */
127    JobType.tp_name = "Bacula.Job";
128    JobType.tp_basicsize = sizeof(JobObject);
129    JobType.tp_flags = Py_TPFLAGS_DEFAULT;
130    JobType.tp_doc = "Bacula Job object";
131    JobType.tp_getattr = args->job_getattr;
132    JobType.tp_setattr = args->job_setattr;
133
134    if (PyType_Ready(&JobType) != 0) {
135       Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python Job type.\n"));
136       PyErr_Print();
137    }   
138    StartUp_module = PyImport_ImportModule((char *)args->modulename);
139    if (!StartUp_module) {
140       Emsg2(M_ERROR, 0, _("Could not import Python script %s/%s. Python disabled.\n"),
141            args->scriptdir, args->modulename);
142       if (PyErr_Occurred()) {
143          PyErr_Print();
144          Dmsg0(000, "Python Import error.\n");
145       }
146    }
147    PyEval_ReleaseLock();
148    init_python_lock();
149 }
150
151 void term_python_interpreter()
152 {
153    if (StartUp_module) {
154       Py_XDECREF(StartUp_module);
155       Py_Finalize();
156    }
157    term_python_lock();
158 }
159
160 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
161 {
162    PyObject *eObject;
163
164    Dmsg0(100, "In set_bacula_events.\n");
165    if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
166       return NULL;
167    }
168    JobStart_method = find_method(eObject, JobStart_method, "JobStart");
169    JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
170    Exit_method = find_method(eObject, Exit_method, "Exit");
171
172    Py_XINCREF(eObject);
173    Py_INCREF(Py_None);
174    return Py_None;
175 }
176
177 /* Write text to daemon output */
178 static PyObject *bacula_write(PyObject *self, PyObject *args)
179 {
180    char *text;
181    if (!PyArg_ParseTuple(args, "s:write", &text)) {
182       return NULL;
183    }
184    if (text) {
185       Jmsg(NULL, M_INFO, 0, "%s", text);
186    }
187    Py_INCREF(Py_None);
188    return Py_None;
189 }
190
191 /*
192  * Check that a method exists and is callable.
193  */
194 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
195 {
196    Py_XDECREF(method);             /* release old method if any */
197    method = PyObject_GetAttrString(eventsObject, (char *)name);
198    if (method == NULL) {
199        Dmsg1(000, "Python method %s not found\n", name);
200    } else if (PyCallable_Check(method) == 0) {
201        Dmsg1(000, "Python object %s found but not a method.\n", name);
202        Py_XDECREF(method);
203        method = NULL;
204    } else {
205        Dmsg1(100, "Got method %s\n", name);
206    }
207    return method; 
208 }
209
210
211 /*
212  * Generate and process a Bacula event by importing a Python
213  *  module and running it.
214  *
215  *  Returns: 0 if Python not configured or module not found
216  *          -1 on Python error
217  *           1 OK
218  */
219 int generate_daemon_event(JCR *jcr, const char *event)
220 {
221    PyObject *pJob;
222    int stat = -1;
223    PyObject *result = NULL;
224    char *obj_fmt = (char *)"O";
225
226    if (!StartUp_module) {
227       Dmsg0(100, "No startup module.\n");
228       return 0;
229    }
230
231    Dmsg1(100, "event=%s\n", event);
232    lock_python();
233 // PyEval_AcquireLock();
234    if (strcmp(event, "JobStart") == 0) {
235       if (!JobStart_method) {
236          stat = 0;
237          goto bail_out;
238       }
239       /* Create JCR argument to send to function */
240       pJob = (PyObject *)PyObject_New(JobObject, &JobType);
241       if (!pJob) {
242          Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n"));
243          goto bail_out;
244       }
245       ((JobObject *)pJob)->jcr = jcr;
246       bstrncpy(jcr->event, event, sizeof(jcr->event));
247       result = PyObject_CallFunction(JobStart_method, obj_fmt, pJob);
248       jcr->event[0] = 0;             /* no event in progress */
249       if (result == NULL) {
250          JobStart_method = NULL;
251          if (PyErr_Occurred()) {
252             PyErr_Print();
253             Dmsg0(000, "Python JobStart error.\n");
254          }
255          Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
256          Py_XDECREF(pJob);
257          goto bail_out;
258       }
259       jcr->Python_job = (void *)pJob;
260       stat = 1;                       /* OK */
261       goto jobstart_ok;
262
263    } else if (strcmp(event, "JobEnd") == 0) {
264       if (!JobEnd_method || !jcr->Python_job) {
265          stat = 0;                    /* probably already here */
266          goto bail_out;
267       }
268       bstrncpy(jcr->event, event, sizeof(jcr->event));
269       Dmsg1(100, "Call daemon event=%s\n", event);
270       result = PyObject_CallFunction(JobEnd_method, obj_fmt, jcr->Python_job);
271       jcr->event[0] = 0;             /* no event in progress */
272       if (result == NULL) {
273          if (PyErr_Occurred()) {
274             PyErr_Print();
275             Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
276                jcr->JobId);
277             JobEnd_method = NULL;
278          }
279          Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
280          goto bail_out;
281       }
282       stat = 1;                    /* OK */
283    } else if (strcmp(event, "Exit") == 0) {
284       if (!Exit_method) {
285          stat = 0;
286          goto bail_out;
287       }
288       result = PyObject_CallFunction(Exit_method, NULL);
289       if (result == NULL) {
290          goto bail_out;
291       }
292       stat = 1;                    /* OK */
293    } else {
294       Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event);
295    }
296
297 bail_out:
298    if (jcr) {
299       Py_XDECREF((PyObject *)jcr->Python_job);
300       jcr->Python_job = NULL;
301       Py_XDECREF((PyObject *)jcr->Python_events);
302       jcr->Python_events = NULL;
303    }
304    /* Fall through */
305 jobstart_ok:
306    Py_XDECREF(result);
307    unlock_python();
308 // PyEval_ReleaseLock();
309    return stat; 
310 }
311
312 static brwlock_t python_rwlock;
313
314 static void init_python_lock()
315 {
316    int errstat;
317    if ((errstat=rwl_init(&python_rwlock)) != 0) {
318       berrno be;
319       Emsg1(M_ABORT, 0, _("Unable to initialize the Python lock. ERR=%s\n"),
320             be.bstrerror(errstat));
321    }
322
323 }
324
325 static void term_python_lock()
326 {
327    rwl_destroy(&python_rwlock);
328 }
329
330 /* This applies to a drive and to Volumes */
331 void lock_python()
332 {
333    int errstat;
334    if ((errstat=rwl_writelock(&python_rwlock)) != 0) {
335       berrno be;
336       Emsg2(M_ABORT, 0, "Python rwl_writelock failure. stat=%d: ERR=%s\n",
337            errstat, be.bstrerror(errstat));
338    }
339 }
340
341 void unlock_python()
342 {
343    int errstat;
344    if ((errstat=rwl_writeunlock(&python_rwlock)) != 0) {
345       berrno be;
346       Emsg2(M_ABORT, 0, "Python rwl_writeunlock failure. stat=%d: ERR=%s\n",
347            errstat, be.bstrerror(errstat));
348    }
349 }
350
351 #else
352
353 /*
354  *  No Python configured -- create external entry points and
355  *    dummy routines so that library code can call this without
356  *    problems even if it is not configured.
357  */
358 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
359
360 #endif /* HAVE_PYTHON */