]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/pythonlib.c
commit changes
[bacula/bacula] / bacula / src / lib / pythonlib.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    Copyright (C) 2004-2005 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    version 2 as amended with additional clauses defined in the
16    file LICENSE in the main source directory.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
21    the file LICENSE for additional details.
22
23  */
24
25 #include "bacula.h"
26 #include "jcr.h"
27
28 #ifdef HAVE_PYTHON
29
30 #undef _POSIX_C_SOURCE
31 #include <Python.h>
32
33 extern char *configfile;
34
35 /* Imported subroutines */
36 //extern PyMethodDef JobMethods[];
37 extern PyObject *job_getattr(PyObject *self, char *attrname);
38 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
39
40 static PyObject *bacula_module = NULL;    /* We create this */
41 static PyObject *StartUp_module = NULL;   /* We import this */
42
43 /* These are the daemon events or methods that are defined */
44 static PyObject *JobStart_method = NULL;
45 static PyObject *JobEnd_method = NULL;
46 static PyObject *Exit_method = NULL;
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, const 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 static char my_version[] = VERSION " " BDATE;
61
62 /*
63  * This is a Bacula Job type as defined in Python. We store a pointer
64  *   to the jcr. That is all we need, but the user's script may keep
65  *   local data attached to this. 
66  */
67 typedef struct s_JobObject {
68     PyObject_HEAD
69     JCR *jcr;
70 } JobObject;
71
72 static PyTypeObject JobType = {
73     PyObject_HEAD_INIT(NULL)
74     /* Other items filled in in code below */
75 };
76
77 /* Return the JCR pointer from the JobObject */
78 JCR *get_jcr_from_PyObject(PyObject *self)
79 {
80    if (!self) {
81       return NULL;
82    }
83    return ((JobObject *)self)->jcr;
84 }
85
86
87 /* Start the interpreter */
88 void init_python_interpreter(const char *progname, const char *scripts,
89     const char *module)
90 {
91    char buf[MAXSTRING];
92
93    if (!scripts || scripts[0] == 0) {
94       Dmsg1(100, "No script dir. prog=%s\n", module);
95       return;
96    }
97    Dmsg2(100, "Script dir=%s prog=%s\n", scripts, module);
98
99    Py_SetProgramName((char *)progname);
100    Py_Initialize();
101    PyEval_InitThreads();
102    bacula_module = Py_InitModule("bacula", BaculaMethods);
103    PyModule_AddStringConstant(bacula_module, "Name", my_name);
104    PyModule_AddStringConstant(bacula_module, "Version", my_version);
105    PyModule_AddStringConstant(bacula_module, "ConfigFile", configfile);
106    PyModule_AddStringConstant(bacula_module, "WorkingDir", (char *)working_directory);
107    if (!bacula_module) {
108       Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python\n"));
109    }
110    bsnprintf(buf, sizeof(buf), "import sys\n"
111             "sys.path.append('%s')\n", scripts);
112    if (PyRun_SimpleString(buf) != 0) {
113       Jmsg1(NULL, M_ERROR_TERM, 0, _("Could not Run Python string %s\n"), buf);
114    }   
115
116    /* Explicitly set values we want */
117    JobType.tp_name = "Bacula.Job";
118    JobType.tp_basicsize = sizeof(JobObject);
119    JobType.tp_flags = Py_TPFLAGS_DEFAULT;
120    JobType.tp_doc = "Bacula Job object";
121    JobType.tp_getattr = job_getattr;
122    JobType.tp_setattr = job_setattr;
123
124    if (PyType_Ready(&JobType) != 0) {
125       Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python Job type.\n"));
126       PyErr_Print();
127    }   
128    StartUp_module = PyImport_ImportModule((char *)module);
129    if (!StartUp_module) {
130       Emsg2(M_ERROR, 0, _("Could not import Python script %s/%s. Python disabled.\n"),
131            scripts, module);
132       if (PyErr_Occurred()) {
133          PyErr_Print();
134          Dmsg0(000, "Python Import error.\n");
135       }
136    }
137    PyEval_ReleaseLock();
138 }
139
140
141 void term_python_interpreter()
142 {
143    if (StartUp_module) {
144       Py_XDECREF(StartUp_module);
145       Py_Finalize();
146    }
147 }
148
149 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
150 {
151    PyObject *eObject;
152
153    Dmsg0(100, "In set_bacula_events.\n");
154    if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
155       return NULL;
156    }
157    JobStart_method = find_method(eObject, JobStart_method, "JobStart");
158    JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
159    Exit_method = find_method(eObject, Exit_method, "Exit");
160
161    Py_XINCREF(eObject);
162    Py_INCREF(Py_None);
163    return Py_None;
164 }
165
166 /* Write text to daemon output */
167 static PyObject *bacula_write(PyObject *self, PyObject *args)
168 {
169    char *text;
170    if (!PyArg_ParseTuple(args, "s:write", &text)) {
171       return NULL;
172    }
173    if (text) {
174       Jmsg(NULL, M_INFO, 0, "%s", text);
175    }
176    Py_INCREF(Py_None);
177    return Py_None;
178 }
179
180
181 /*
182  * Check that a method exists and is callable.
183  */
184 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
185 {
186    Py_XDECREF(method);             /* release old method if any */
187    method = PyObject_GetAttrString(eventsObject, (char *)name);
188    if (method == NULL) {
189        Dmsg1(000, "Python method %s not found\n", name);
190    } else if (PyCallable_Check(method) == 0) {
191        Dmsg1(000, "Python object %s found but not a method.\n", name);
192        Py_XDECREF(method);
193        method = NULL;
194    } else {
195        Dmsg1(100, "Got method %s\n", name);
196    }
197    return method; 
198 }
199
200
201 /*
202  * Generate and process a Bacula event by importing a Python
203  *  module and running it.
204  *
205  *  Returns: 0 if Python not configured or module not found
206  *          -1 on Python error
207  *           1 OK
208  */
209 int generate_daemon_event(JCR *jcr, const char *event)
210 {
211    PyObject *pJob;
212    int stat = -1;
213    PyObject *result = NULL;
214
215    if (!StartUp_module) {
216       Dmsg0(100, "No startup module.\n");
217       return 0;
218    }
219
220    Dmsg1(100, "event=%s\n", event);
221    PyEval_AcquireLock();
222    if (strcmp(event, "JobStart") == 0) {
223       if (!JobStart_method) {
224          stat = 0;
225          goto bail_out;
226       }
227       /* Create JCR argument to send to function */
228       pJob = (PyObject *)PyObject_New(JobObject, &JobType);
229       if (!pJob) {
230          Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n"));
231          goto bail_out;
232       }
233       ((JobObject *)pJob)->jcr = jcr;
234       bstrncpy(jcr->event, event, sizeof(jcr->event));
235       result = PyObject_CallFunction(JobStart_method, "O", pJob);
236       jcr->event[0] = 0;             /* no event in progress */
237       if (result == NULL) {
238          JobStart_method = NULL;
239          if (PyErr_Occurred()) {
240             PyErr_Print();
241             Dmsg0(000, "Python JobStart error.\n");
242          }
243          Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
244          Py_XDECREF(pJob);
245          goto bail_out;
246       }
247       jcr->Python_job = (void *)pJob;
248       stat = 1;                       /* OK */
249       goto jobstart_ok;
250
251    } else if (strcmp(event, "JobEnd") == 0) {
252       if (!JobEnd_method || !jcr->Python_job) {
253          stat = 0;                    /* probably already here */
254          goto bail_out;
255       }
256       bstrncpy(jcr->event, event, sizeof(jcr->event));
257       Dmsg1(100, "Call daemon event=%s\n", event);
258       result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_job);
259       jcr->event[0] = 0;             /* no event in progress */
260       if (result == NULL) {
261          if (PyErr_Occurred()) {
262             PyErr_Print();
263             Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
264                jcr->JobId);
265             JobEnd_method = NULL;
266          }
267          Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
268          goto bail_out;
269       }
270       stat = 1;                    /* OK */
271    } else if (strcmp(event, "Exit") == 0) {
272       if (!Exit_method) {
273          stat = 0;
274          goto bail_out;
275       }
276       result = PyObject_CallFunction(Exit_method, NULL);
277       if (result == NULL) {
278          goto bail_out;
279       }
280       stat = 1;                    /* OK */
281    } else {
282       Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event);
283    }
284
285 bail_out:
286    if (jcr) {
287       Py_XDECREF((PyObject *)jcr->Python_job);
288       jcr->Python_job = NULL;
289       Py_XDECREF((PyObject *)jcr->Python_events);
290       jcr->Python_events = NULL;
291    }
292    /* Fall through */
293 jobstart_ok:
294    Py_XDECREF(result);
295    PyEval_ReleaseLock();
296    return stat; 
297 }
298
299 #else
300
301 /*
302  *  No Python configured -- create external entry points and
303  *    dummy routines so that library code can call this without
304  *    problems even if it is not configured.
305  */
306 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
307 void init_python_interpreter(const char *progname, const char *scripts,
308          const char *module) { }
309 void term_python_interpreter() { }
310
311 #endif /* HAVE_PYTHON */