2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2011 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 three of the GNU Affero 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 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
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.
30 * Bacula common code library interface to Python
32 * Kern Sibbald, November MMIV
41 #undef _POSIX_C_SOURCE
44 #include "pythonlib.h"
46 /* Forward referenced subroutines */
47 static void init_python_lock();
48 static void term_python_lock();
50 static PyObject *bacula_module = NULL; /* We create this */
51 static PyObject *StartUp_module = NULL; /* We import this */
53 /* These are the daemon events or methods that are defined */
54 static PyObject *JobStart_method = NULL;
55 static PyObject *JobEnd_method = NULL;
56 static PyObject *Exit_method = NULL;
58 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
59 static PyObject *bacula_write(PyObject *self, PyObject *args);
61 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name);
63 /* Define Bacula daemon method entry points */
64 static PyMethodDef BaculaMethods[] = {
65 {"set_events", set_bacula_events, METH_VARARGS, "Define Bacula events."},
66 {"write", bacula_write, METH_VARARGS, "Write output."},
67 {NULL, NULL, 0, NULL} /* last item */
70 static char my_version[] = VERSION " " BDATE;
73 * This is a Bacula Job type as defined in Python. We store a pointer
74 * to the jcr. That is all we need, but the user's script may keep
75 * local data attached to this.
77 typedef struct s_JobObject {
82 static PyTypeObject JobType = {
83 PyObject_HEAD_INIT(NULL)
84 /* Other items filled in in code below */
87 /* Return the JCR pointer from the JobObject */
88 JCR *get_jcr_from_PyObject(PyObject *self)
93 return ((JobObject *)self)->jcr;
96 /* Start the interpreter */
97 void init_python_interpreter(init_python_interpreter_args *args)
101 if (!args->scriptdir || args->scriptdir[0] == 0) {
102 Dmsg1(100, "No script dir. prog=%s\n", args->modulename);
105 Dmsg2(100, "Script dir=%s prog=%s\n", args->scriptdir, args->modulename);
107 Py_SetProgramName((char *)args->progname);
109 PyEval_InitThreads();
110 bacula_module = Py_InitModule("bacula", BaculaMethods);
111 PyModule_AddStringConstant(bacula_module, "Name", my_name);
112 PyModule_AddStringConstant(bacula_module, "Version", my_version);
113 PyModule_AddStringConstant(bacula_module, "ConfigFile", (char *)args->configfile);
114 PyModule_AddStringConstant(bacula_module, "WorkingDir", (char *)args->workingdir);
115 if (!bacula_module) {
116 Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python\n"));
118 bsnprintf(buf, sizeof(buf), "import sys\n"
119 "sys.path.append('%s')\n", args->scriptdir);
120 if (PyRun_SimpleString(buf) != 0) {
121 Jmsg1(NULL, M_ERROR_TERM, 0, _("Could not Run Python string %s\n"), buf);
124 /* Explicitly set values we want */
125 JobType.tp_name = "Bacula.Job";
126 JobType.tp_basicsize = sizeof(JobObject);
127 JobType.tp_flags = Py_TPFLAGS_DEFAULT;
128 JobType.tp_doc = "Bacula Job object";
129 JobType.tp_getattr = args->job_getattr;
130 JobType.tp_setattr = args->job_setattr;
132 if (PyType_Ready(&JobType) != 0) {
133 Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python Job type.\n"));
136 StartUp_module = PyImport_ImportModule((char *)args->modulename);
137 if (!StartUp_module) {
138 Emsg2(M_ERROR, 0, _("Could not import Python script %s/%s. Python disabled.\n"),
139 args->scriptdir, args->modulename);
140 if (PyErr_Occurred()) {
142 Dmsg0(000, "Python Import error.\n");
145 PyEval_ReleaseLock();
149 void term_python_interpreter()
151 if (StartUp_module) {
152 Py_XDECREF(StartUp_module);
158 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
162 Dmsg0(100, "In set_bacula_events.\n");
163 if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
166 JobStart_method = find_method(eObject, JobStart_method, "JobStart");
167 JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
168 Exit_method = find_method(eObject, Exit_method, "Exit");
175 /* Write text to daemon output */
176 static PyObject *bacula_write(PyObject *self, PyObject *args)
179 if (!PyArg_ParseTuple(args, "s:write", &text)) {
183 Jmsg(NULL, M_INFO, 0, "%s", text);
190 * Check that a method exists and is callable.
192 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
194 Py_XDECREF(method); /* release old method if any */
195 method = PyObject_GetAttrString(eventsObject, (char *)name);
196 if (method == NULL) {
197 Dmsg1(000, "Python method %s not found\n", name);
198 } else if (PyCallable_Check(method) == 0) {
199 Dmsg1(000, "Python object %s found but not a method.\n", name);
203 Dmsg1(100, "Got method %s\n", name);
210 * Generate and process a Bacula event by importing a Python
211 * module and running it.
213 * Returns: 0 if Python not configured or module not found
217 int generate_daemon_event(JCR *jcr, const char *event)
221 PyObject *result = NULL;
222 char *obj_fmt = (char *)"O";
224 if (!StartUp_module) {
225 Dmsg0(100, "No startup module.\n");
229 Dmsg1(100, "event=%s\n", event);
231 // PyEval_AcquireLock();
232 if (strcmp(event, "JobStart") == 0) {
233 if (!JobStart_method) {
237 /* Create JCR argument to send to function */
238 pJob = (PyObject *)PyObject_New(JobObject, &JobType);
240 Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n"));
243 ((JobObject *)pJob)->jcr = jcr;
244 bstrncpy(jcr->event, event, sizeof(jcr->event));
245 result = PyObject_CallFunction(JobStart_method, obj_fmt, pJob);
246 jcr->event[0] = 0; /* no event in progress */
247 if (result == NULL) {
248 JobStart_method = NULL;
249 if (PyErr_Occurred()) {
251 Dmsg0(000, "Python JobStart error.\n");
253 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
257 jcr->Python_job = (void *)pJob;
261 } else if (strcmp(event, "JobEnd") == 0) {
262 if (!JobEnd_method || !jcr->Python_job) {
263 stat = 0; /* probably already here */
266 bstrncpy(jcr->event, event, sizeof(jcr->event));
267 Dmsg1(100, "Call daemon event=%s\n", event);
268 result = PyObject_CallFunction(JobEnd_method, obj_fmt, jcr->Python_job);
269 jcr->event[0] = 0; /* no event in progress */
270 if (result == NULL) {
271 if (PyErr_Occurred()) {
273 Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
275 JobEnd_method = NULL;
277 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
281 } else if (strcmp(event, "Exit") == 0) {
286 result = PyObject_CallFunction(Exit_method, NULL);
287 if (result == NULL) {
292 Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event);
297 Py_XDECREF((PyObject *)jcr->Python_job);
298 jcr->Python_job = NULL;
299 Py_XDECREF((PyObject *)jcr->Python_events);
300 jcr->Python_events = NULL;
306 // PyEval_ReleaseLock();
310 static brwlock_t python_rwlock;
312 static void init_python_lock()
315 if ((errstat=rwl_init(&python_rwlock)) != 0) {
317 Emsg1(M_ABORT, 0, _("Unable to initialize the Python lock. ERR=%s\n"),
318 be.bstrerror(errstat));
323 static void term_python_lock()
325 rwl_destroy(&python_rwlock);
328 /* This applies to a drive and to Volumes */
332 if ((errstat=rwl_writelock(&python_rwlock)) != 0) {
334 Emsg2(M_ABORT, 0, "Python rwl_writelock failure. stat=%d: ERR=%s\n",
335 errstat, be.bstrerror(errstat));
342 if ((errstat=rwl_writeunlock(&python_rwlock)) != 0) {
344 Emsg2(M_ABORT, 0, "Python rwl_writeunlock failure. stat=%d: ERR=%s\n",
345 errstat, be.bstrerror(errstat));
352 * No Python configured -- create external entry points and
353 * dummy routines so that library code can call this without
354 * problems even if it is not configured.
356 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
358 #endif /* HAVE_PYTHON */