X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fpythonlib.c;h=3c6f6723104bccb00e23898bcb8ddfd710abfa7e;hb=5450f5e38d6dd94600c7c35fedf7f9ccea3e7adb;hp=378c85036af27fc42c323f93d0d5fdf9c1704e56;hpb=0c5d8b51885dac300f98665302313e889bdb5503;p=bacula%2Fbacula diff --git a/bacula/src/lib/pythonlib.c b/bacula/src/lib/pythonlib.c index 378c85036a..3c6f672310 100644 --- a/bacula/src/lib/pythonlib.c +++ b/bacula/src/lib/pythonlib.c @@ -1,31 +1,38 @@ /* - * - * Bacula common code library interface to Python - * - * Kern Sibbald, November MMIV - * - * Version $Id$ - * - */ + Bacula® - The Network Backup Solution -/* - Copyright (C) 2004-2005 Kern Sibbald + Copyright (C) 2004-2008 Free Software Foundation Europe e.V. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * + * Bacula common code library interface to Python + * + * Kern Sibbald, November MMIV + * + * Version $Id$ + * */ #include "bacula.h" @@ -36,10 +43,11 @@ #undef _POSIX_C_SOURCE #include -/* Imported subroutines */ -//extern PyMethodDef JobMethods[]; -extern PyObject *job_getattr(PyObject *self, char *attrname); -extern int job_setattr(PyObject *self, char *attrname, PyObject *value); +#include "pythonlib.h" + +/* Forward referenced subroutines */ +static void init_python_lock(); +static void term_python_lock(); static PyObject *bacula_module = NULL; /* We create this */ static PyObject *StartUp_module = NULL; /* We import this */ @@ -61,11 +69,12 @@ static PyMethodDef BaculaMethods[] = { {NULL, NULL, 0, NULL} /* last item */ }; +static char my_version[] = VERSION " " BDATE; /* * This is a Bacula Job type as defined in Python. We store a pointer - * to the jcr. That is all we need, but the user's script may keep - * local data attached to this. + * to the jcr. That is all we need, but the user's script may keep + * local data attached to this. */ typedef struct s_JobObject { PyObject_HEAD @@ -86,31 +95,32 @@ JCR *get_jcr_from_PyObject(PyObject *self) return ((JobObject *)self)->jcr; } - /* Start the interpreter */ -void init_python_interpreter(const char *progname, const char *scripts, - const char *module) +void init_python_interpreter(init_python_interpreter_args *args) { char buf[MAXSTRING]; - if (!scripts || scripts[0] == 0) { - Dmsg1(100, "No script dir. prog=%s\n", module); + if (!args->scriptdir || args->scriptdir[0] == 0) { + Dmsg1(100, "No script dir. prog=%s\n", args->modulename); return; } - Dmsg2(100, "Script dir=%s prog=%s\n", scripts, module); + Dmsg2(100, "Script dir=%s prog=%s\n", args->scriptdir, args->modulename); - Py_SetProgramName((char *)progname); + Py_SetProgramName((char *)args->progname); Py_Initialize(); PyEval_InitThreads(); bacula_module = Py_InitModule("bacula", BaculaMethods); - PyModule_AddStringConstant(bacula_module, "name", my_name); + PyModule_AddStringConstant(bacula_module, "Name", my_name); + PyModule_AddStringConstant(bacula_module, "Version", my_version); + PyModule_AddStringConstant(bacula_module, "ConfigFile", (char *)args->configfile); + PyModule_AddStringConstant(bacula_module, "WorkingDir", (char *)args->workingdir); if (!bacula_module) { - Jmsg0(NULL, M_ERROR_TERM, 0, "Could not initialize Python\n"); + Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python\n")); } bsnprintf(buf, sizeof(buf), "import sys\n" - "sys.path.append('%s')\n", scripts); + "sys.path.append('%s')\n", args->scriptdir); if (PyRun_SimpleString(buf) != 0) { - Jmsg1(NULL, M_ERROR_TERM, 0, "Could not Run Python string %s\n", buf); + Jmsg1(NULL, M_ERROR_TERM, 0, _("Could not Run Python string %s\n"), buf); } /* Explicitly set values we want */ @@ -118,32 +128,33 @@ void init_python_interpreter(const char *progname, const char *scripts, JobType.tp_basicsize = sizeof(JobObject); JobType.tp_flags = Py_TPFLAGS_DEFAULT; JobType.tp_doc = "Bacula Job object"; - JobType.tp_getattr = job_getattr; - JobType.tp_setattr = job_setattr; - + JobType.tp_getattr = args->job_getattr; + JobType.tp_setattr = args->job_setattr; + if (PyType_Ready(&JobType) != 0) { - Jmsg0(NULL, M_ERROR_TERM, 0, "Could not initialize Python Job type.\n"); + Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python Job type.\n")); PyErr_Print(); } - StartUp_module = PyImport_ImportModule((char *)module); + StartUp_module = PyImport_ImportModule((char *)args->modulename); if (!StartUp_module) { - Emsg2(M_ERROR, 0, "Could not import Python script %s/%s. Python disabled.\n", - scripts, module); + Emsg2(M_ERROR, 0, _("Could not import Python script %s/%s. Python disabled.\n"), + args->scriptdir, args->modulename); if (PyErr_Occurred()) { PyErr_Print(); Dmsg0(000, "Python Import error.\n"); } } PyEval_ReleaseLock(); + init_python_lock(); } - void term_python_interpreter() { if (StartUp_module) { Py_XDECREF(StartUp_module); Py_Finalize(); } + term_python_lock(); } static PyObject *set_bacula_events(PyObject *self, PyObject *args) @@ -177,7 +188,6 @@ static PyObject *bacula_write(PyObject *self, PyObject *args) return Py_None; } - /* * Check that a method exists and is callable. */ @@ -211,6 +221,7 @@ int generate_daemon_event(JCR *jcr, const char *event) PyObject *pJob; int stat = -1; PyObject *result = NULL; + char *obj_fmt = (char *)"O"; if (!StartUp_module) { Dmsg0(100, "No startup module.\n"); @@ -218,7 +229,8 @@ int generate_daemon_event(JCR *jcr, const char *event) } Dmsg1(100, "event=%s\n", event); - PyEval_AcquireLock(); + lock_python(); +// PyEval_AcquireLock(); if (strcmp(event, "JobStart") == 0) { if (!JobStart_method) { stat = 0; @@ -227,12 +239,12 @@ int generate_daemon_event(JCR *jcr, const char *event) /* Create JCR argument to send to function */ pJob = (PyObject *)PyObject_New(JobObject, &JobType); if (!pJob) { - Jmsg(jcr, M_ERROR, 0, "Could not create Python Job Object.\n"); + Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n")); goto bail_out; } ((JobObject *)pJob)->jcr = jcr; bstrncpy(jcr->event, event, sizeof(jcr->event)); - result = PyObject_CallFunction(JobStart_method, "O", pJob); + result = PyObject_CallFunction(JobStart_method, obj_fmt, pJob); jcr->event[0] = 0; /* no event in progress */ if (result == NULL) { JobStart_method = NULL; @@ -240,7 +252,7 @@ int generate_daemon_event(JCR *jcr, const char *event) PyErr_Print(); Dmsg0(000, "Python JobStart error.\n"); } - Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event); + Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event); Py_XDECREF(pJob); goto bail_out; } @@ -250,22 +262,21 @@ int generate_daemon_event(JCR *jcr, const char *event) } else if (strcmp(event, "JobEnd") == 0) { if (!JobEnd_method || !jcr->Python_job) { - Dmsg2(000, "No JobEnd method=%p Job=%p\n", JobEnd_method, jcr->Python_job); - stat = 0; + stat = 0; /* probably already here */ goto bail_out; } bstrncpy(jcr->event, event, sizeof(jcr->event)); Dmsg1(100, "Call daemon event=%s\n", event); - result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_job); + result = PyObject_CallFunction(JobEnd_method, obj_fmt, jcr->Python_job); jcr->event[0] = 0; /* no event in progress */ if (result == NULL) { if (PyErr_Occurred()) { PyErr_Print(); Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job, - jcr->JobId); - JobEnd_method = NULL; + jcr->JobId); + JobEnd_method = NULL; } - Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event); + Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event); goto bail_out; } stat = 1; /* OK */ @@ -280,21 +291,63 @@ int generate_daemon_event(JCR *jcr, const char *event) } stat = 1; /* OK */ } else { - Jmsg1(jcr, M_ABORT, 0, "Unknown Python daemon event %s\n", event); + Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event); } bail_out: - Py_XDECREF((PyObject *)jcr->Python_job); - jcr->Python_job = NULL; - Py_XDECREF((PyObject *)jcr->Python_events); - jcr->Python_events = NULL; + if (jcr) { + Py_XDECREF((PyObject *)jcr->Python_job); + jcr->Python_job = NULL; + Py_XDECREF((PyObject *)jcr->Python_events); + jcr->Python_events = NULL; + } /* Fall through */ jobstart_ok: Py_XDECREF(result); - PyEval_ReleaseLock(); + unlock_python(); +// PyEval_ReleaseLock(); return stat; } +static brwlock_t python_rwlock; + +static void init_python_lock() +{ + int errstat; + if ((errstat=rwl_init(&python_rwlock)) != 0) { + berrno be; + Emsg1(M_ABORT, 0, _("Unable to initialize the Python lock. ERR=%s\n"), + be.bstrerror(errstat)); + } + +} + +static void term_python_lock() +{ + rwl_destroy(&python_rwlock); +} + +/* This applies to a drive and to Volumes */ +void lock_python() +{ + int errstat; + if ((errstat=rwl_writelock(&python_rwlock)) != 0) { + berrno be; + Emsg2(M_ABORT, 0, "Python rwl_writelock failure. stat=%d: ERR=%s\n", + errstat, be.bstrerror(errstat)); + } +} + +void unlock_python() +{ + int errstat; + if ((errstat=rwl_writeunlock(&python_rwlock)) != 0) { + berrno be; + Emsg2(M_ABORT, 0, "Python rwl_writeunlock failure. stat=%d: ERR=%s\n", + errstat, be.bstrerror(errstat)); + } +} + #else /* @@ -303,8 +356,5 @@ jobstart_ok: * problems even if it is not configured. */ int generate_daemon_event(JCR *jcr, const char *event) { return 0; } -void init_python_interpreter(const char *progname, const char *scripts, - const char *module) { } -void term_python_interpreter() { } #endif /* HAVE_PYTHON */