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;
236 if (!StartUp_module) {
237 Dmsg0(100, "No startup module.\n");
241 Dmsg1(100, "event=%s\n", event);
243 // PyEval_AcquireLock();
244 if (strcmp(event, "JobStart") == 0) {
245 if (!JobStart_method) {
249 /* Create JCR argument to send to function */
250 pJob = (PyObject *)PyObject_New(JobObject, &JobType);
252 Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n"));
255 ((JobObject *)pJob)->jcr = jcr;
256 bstrncpy(jcr->event, event, sizeof(jcr->event));
257 result = PyObject_CallFunction(JobStart_method, "O", pJob);
258 jcr->event[0] = 0; /* no event in progress */
259 if (result == NULL) {
260 JobStart_method = NULL;
261 if (PyErr_Occurred()) {
263 Dmsg0(000, "Python JobStart error.\n");
265 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
269 jcr->Python_job = (void *)pJob;
273 } else if (strcmp(event, "JobEnd") == 0) {
274 if (!JobEnd_method || !jcr->Python_job) {
275 stat = 0; /* probably already here */
278 bstrncpy(jcr->event, event, sizeof(jcr->event));
279 Dmsg1(100, "Call daemon event=%s\n", event);
280 result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_job);
281 jcr->event[0] = 0; /* no event in progress */
282 if (result == NULL) {
283 if (PyErr_Occurred()) {
285 Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
287 JobEnd_method = NULL;
289 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
293 } else if (strcmp(event, "Exit") == 0) {
298 result = PyObject_CallFunction(Exit_method, NULL);
299 if (result == NULL) {
304 Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event);
309 Py_XDECREF((PyObject *)jcr->Python_job);
310 jcr->Python_job = NULL;
311 Py_XDECREF((PyObject *)jcr->Python_events);
312 jcr->Python_events = NULL;
318 // PyEval_ReleaseLock();
322 static brwlock_t python_rwlock;
324 static void init_python_lock()
327 if ((errstat=rwl_init(&python_rwlock)) != 0) {
329 Emsg1(M_ABORT, 0, _("Unable to initialize the Python lock. ERR=%s\n"),
330 be.bstrerror(errstat));
335 static void term_python_lock()
337 rwl_destroy(&python_rwlock);
340 /* This applies to a drive and to Volumes */
344 if ((errstat=rwl_writelock(&python_rwlock)) != 0) {
346 Emsg2(M_ABORT, 0, "Python rwl_writelock failure. stat=%d: ERR=%s\n",
347 errstat, be.bstrerror(errstat));
354 if ((errstat=rwl_writeunlock(&python_rwlock)) != 0) {
356 Emsg2(M_ABORT, 0, "Python rwl_writeunlock failure. stat=%d: ERR=%s\n",
357 errstat, be.bstrerror(errstat));
365 * No Python configured -- create external entry points and
366 * dummy routines so that library code can call this without
367 * problems even if it is not configured.
369 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
370 void init_python_interpreter(const char *progname, const char *scripts,
371 const char *module) { }
372 void term_python_interpreter() { }
374 #endif /* HAVE_PYTHON */