2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
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
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.
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
23 Bacula® is a registered trademark of John Walker.
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.
30 * Bacula common code library interface to Python
32 * Kern Sibbald, November MMIV
43 #undef _POSIX_C_SOURCE
46 /* Forward referenced subroutines */
47 static void init_python_lock();
48 static void term_python_lock();
52 extern char *configfile;
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);
59 static PyObject *bacula_module = NULL; /* We create this */
60 static PyObject *StartUp_module = NULL; /* We import this */
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;
67 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
68 static PyObject *bacula_write(PyObject *self, PyObject *args);
70 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name);
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 */
79 static char my_version[] = VERSION " " BDATE;
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.
86 typedef struct s_JobObject {
91 static PyTypeObject JobType = {
92 PyObject_HEAD_INIT(NULL)
93 /* Other items filled in in code below */
96 /* Return the JCR pointer from the JobObject */
97 JCR *get_jcr_from_PyObject(PyObject *self)
102 return ((JobObject *)self)->jcr;
106 /* Start the interpreter */
107 void init_python_interpreter(const char *progname, const char *scripts,
112 if (!scripts || scripts[0] == 0) {
113 Dmsg1(100, "No script dir. prog=%s\n", module);
116 Dmsg2(100, "Script dir=%s prog=%s\n", scripts, module);
118 Py_SetProgramName((char *)progname);
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"));
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);
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;
143 if (PyType_Ready(&JobType) != 0) {
144 Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python Job type.\n"));
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"),
151 if (PyErr_Occurred()) {
153 Dmsg0(000, "Python Import error.\n");
156 PyEval_ReleaseLock();
161 void term_python_interpreter()
163 if (StartUp_module) {
164 Py_XDECREF(StartUp_module);
170 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
174 Dmsg0(100, "In set_bacula_events.\n");
175 if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
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");
187 /* Write text to daemon output */
188 static PyObject *bacula_write(PyObject *self, PyObject *args)
191 if (!PyArg_ParseTuple(args, "s:write", &text)) {
195 Jmsg(NULL, M_INFO, 0, "%s", text);
203 * Check that a method exists and is callable.
205 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
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);
216 Dmsg1(100, "Got method %s\n", name);
223 * Generate and process a Bacula event by importing a Python
224 * module and running it.
226 * Returns: 0 if Python not configured or module not found
230 int generate_daemon_event(JCR *jcr, const char *event)
234 PyObject *result = NULL;
235 char *obj_fmt = (char *)"O";
237 if (!StartUp_module) {
238 Dmsg0(100, "No startup module.\n");
242 Dmsg1(100, "event=%s\n", event);
244 // PyEval_AcquireLock();
245 if (strcmp(event, "JobStart") == 0) {
246 if (!JobStart_method) {
250 /* Create JCR argument to send to function */
251 pJob = (PyObject *)PyObject_New(JobObject, &JobType);
253 Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n"));
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()) {
264 Dmsg0(000, "Python JobStart error.\n");
266 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
270 jcr->Python_job = (void *)pJob;
274 } else if (strcmp(event, "JobEnd") == 0) {
275 if (!JobEnd_method || !jcr->Python_job) {
276 stat = 0; /* probably already here */
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()) {
286 Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
288 JobEnd_method = NULL;
290 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
294 } else if (strcmp(event, "Exit") == 0) {
299 result = PyObject_CallFunction(Exit_method, NULL);
300 if (result == NULL) {
305 Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event);
310 Py_XDECREF((PyObject *)jcr->Python_job);
311 jcr->Python_job = NULL;
312 Py_XDECREF((PyObject *)jcr->Python_events);
313 jcr->Python_events = NULL;
319 // PyEval_ReleaseLock();
323 static brwlock_t python_rwlock;
325 static void init_python_lock()
328 if ((errstat=rwl_init(&python_rwlock)) != 0) {
330 Emsg1(M_ABORT, 0, _("Unable to initialize the Python lock. ERR=%s\n"),
331 be.bstrerror(errstat));
336 static void term_python_lock()
338 rwl_destroy(&python_rwlock);
341 /* This applies to a drive and to Volumes */
345 if ((errstat=rwl_writelock(&python_rwlock)) != 0) {
347 Emsg2(M_ABORT, 0, "Python rwl_writelock failure. stat=%d: ERR=%s\n",
348 errstat, be.bstrerror(errstat));
355 if ((errstat=rwl_writeunlock(&python_rwlock)) != 0) {
357 Emsg2(M_ABORT, 0, "Python rwl_writeunlock failure. stat=%d: ERR=%s\n",
358 errstat, be.bstrerror(errstat));
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.
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() { }
375 #endif /* HAVE_PYTHON */