]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/pythondir.c
Fix python module compilation
[bacula/bacula] / bacula / src / dird / pythondir.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2012 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *
30  * Bacula interface to Python for the Director
31  *
32  * Kern Sibbald, November MMIV
33  *
34  *
35  */
36
37 #include "bacula.h"
38 #include "dird.h"
39
40 #ifdef HAVE_PYTHON
41 #undef _POSIX_C_SOURCE
42 #include <Python.h>
43
44 #include <lib/pythonlib.h>
45
46 extern struct s_jl joblevels[];
47
48 static PyObject *set_job_events(PyObject *self, PyObject *arg);
49 static PyObject *job_run(PyObject *self, PyObject *arg);
50 static PyObject *job_write(PyObject *self, PyObject *arg);
51 static PyObject *job_cancel(PyObject *self, PyObject *arg);
52 static PyObject *job_does_vol_exist(PyObject *self, PyObject *arg);
53
54 PyMethodDef JobMethods[] = {
55     {"set_events", set_job_events, METH_VARARGS, "Set Job events"},
56     {"run", job_run, METH_VARARGS, "Run a Job"},
57     {"write", job_write, METH_VARARGS, "Write to output"},
58     {"cancel", job_cancel, METH_VARARGS, "Cancel a Job"},
59     {"DoesVolumeExist", job_does_vol_exist, METH_VARARGS, "Does Volume Exist"},
60     {NULL, NULL, 0, NULL}             /* last item */
61 };
62  
63 struct s_vars {
64    const char *name;
65    const char *fmt;
66 };
67
68 /* Read-only variables */
69 static struct s_vars getvars[] = {
70    { "Job",        "s"},
71    { "Level",      "s"},
72    { "Type",       "s"},
73    { "JobId",      "i"},
74    { "Client",     "s"},
75    { "NumVols",    "i"},
76    { "Pool",       "s"},
77    { "Storage",    "s"},
78    { "Catalog",    "s"},
79    { "MediaType",  "s"},
80    { "JobName",    "s"},
81    { "JobStatus",  "s"},
82    { "Priority",   "i"},
83    { "VolumeName", "s"},
84    { "CatalogRes", "(sssssis)"},
85    { "JobErrors",  "i"},
86    { "JobFiles",   "i"},
87    { "SDJobFiles", "i"},
88    { "SDErrors",   "i"},
89    { "FDJobStatus","s"},
90    { "SDJobStatus","s"},
91
92    { NULL,             NULL}
93 };
94
95 /* Writable variables */
96 static struct s_vars setvars[] = {
97    { "JobReport",   "s"},
98    { "VolumeName",  "s"},
99    { "Priority",    "i"},
100    { "JobLevel",    "s"},
101
102    { NULL,             NULL}
103 };
104
105
106 /* Return Job variables */
107 /* Returns:  NULL if error
108  *           PyObject * return value if OK
109  */
110 PyObject *job_getattr(PyObject *self, char *attrname)
111 {
112    JCR *jcr;
113    bool found = false;
114    int i;
115    char buf[10];
116    char errmsg[200];
117
118    Dmsg0(100, "In job_getattr.\n");
119    jcr = get_jcr_from_PyObject(self);
120    if (!jcr) {
121       bstrncpy(errmsg, _("Job pointer not found."), sizeof(errmsg));
122       goto bail_out;
123    }
124    for (i=0; getvars[i].name; i++) {
125       if (strcmp(getvars[i].name, attrname) == 0) {
126          found = true;
127          break;
128       }
129    }
130    if (!found) {
131       /* Try our methods */
132       return Py_FindMethod(JobMethods, self, attrname);
133    }
134    switch (i) {
135    case 0:                            /* Job */
136       return Py_BuildValue((char *)getvars[i].fmt, jcr->job->hdr.name);
137    case 1:                            /* level */
138       return Py_BuildValue((char *)getvars[i].fmt, job_level_to_str(jcr->getJobLevel()));
139    case 2:                            /* type */
140       return Py_BuildValue((char *)getvars[i].fmt, job_type_to_str(jcr->getJobType()));
141    case 3:                            /* JobId */
142       return Py_BuildValue((char *)getvars[i].fmt, jcr->JobId);
143    case 4:                            /* Client */
144       return Py_BuildValue((char *)getvars[i].fmt, jcr->client->hdr.name);
145    case 5:                            /* NumVols */
146       POOL_DBR pr;
147       memset(&pr, 0, sizeof(pr));
148       bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
149       if (db_get_pool_record(jcr, jcr->db, &pr)) {
150          jcr->NumVols = pr.NumVols;
151          return Py_BuildValue((char *)getvars[i].fmt, jcr->NumVols);
152       } else {
153          bsnprintf(errmsg, sizeof(errmsg), _("Pool record not found."));
154          goto bail_out;
155       }
156    case 6:                            /* Pool */
157       return Py_BuildValue((char *)getvars[i].fmt, jcr->pool->name());
158    case 7:                            /* Storage */
159       if (jcr->wstore) {
160          return Py_BuildValue((char *)getvars[i].fmt, jcr->wstore->name());
161       } else if (jcr->rstore) {
162          return Py_BuildValue((char *)getvars[i].fmt, jcr->rstore->name());
163       } else {
164          goto bail_out;
165       }
166    case 8:
167       return Py_BuildValue((char *)getvars[i].fmt, jcr->catalog->name());
168    case  9:                           /* MediaType */
169       if (jcr->wstore) {
170          return Py_BuildValue((char *)getvars[i].fmt, jcr->wstore->media_type);
171       } else if (jcr->rstore) {
172          return Py_BuildValue((char *)getvars[i].fmt, jcr->rstore->media_type);
173       } else {
174          goto bail_out;
175       }
176    case 10:                           /* JobName */
177       return Py_BuildValue((char *)getvars[i].fmt, jcr->Job);
178    case 11:                           /* JobStatus */
179       buf[1] = 0;
180       buf[0] = jcr->JobStatus;
181       return Py_BuildValue((char *)getvars[i].fmt, buf);
182    case 12:                           /* Priority */
183       return Py_BuildValue((char *)getvars[i].fmt, jcr->JobPriority);
184    case 13:
185       return Py_BuildValue((char *)getvars[i].fmt, jcr->VolumeName);
186    case 14:                           /* CatalogRes */
187       return Py_BuildValue((char *)getvars[i].fmt,
188          jcr->catalog->db_name, jcr->catalog->db_address, 
189          jcr->catalog->db_user, jcr->catalog->db_password,
190          jcr->catalog->db_socket, jcr->catalog->db_port,
191          db_get_type(jcr->db));
192    case 15:                           /* JobErrors */
193       return Py_BuildValue((char *)getvars[i].fmt, jcr->JobErrors);
194    case 16:                           /* JobFiles */
195       return Py_BuildValue((char *)getvars[i].fmt, jcr->JobFiles);
196    case 17:                           /* SDJobFiles */
197       return Py_BuildValue((char *)getvars[i].fmt, jcr->SDJobFiles);
198    case 18:                           /* SDErrors */
199       return Py_BuildValue((char *)getvars[i].fmt, jcr->SDErrors);
200    case 19:                           /* FDJobStatus */
201       buf[1] = 0;
202       buf[0] = jcr->FDJobStatus;
203       return Py_BuildValue((char *)getvars[i].fmt, buf);
204    case 20:                           /* SDJobStatus */
205       buf[1] = 0;
206       buf[0] = jcr->SDJobStatus;
207       return Py_BuildValue((char *)getvars[i].fmt, buf);
208    }
209    bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
210 bail_out:
211    PyErr_SetString(PyExc_AttributeError, errmsg);
212    return NULL;
213 }
214
215
216 /* Set Job variables */
217 /*  Returns:   0 for OK
218  *            -1 for error
219  */
220 int job_setattr(PyObject *self, char *attrname, PyObject *value)
221 {
222    JCR *jcr;
223    bool found = false;
224    char *strval = NULL;
225    int intval = 0;
226    int i;
227
228    Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
229    if (value == NULL) {                /* Cannot delete variables */
230        goto bail_out;
231    }
232    jcr = get_jcr_from_PyObject(self);
233    if (!jcr) {
234       goto bail_out;
235    }
236
237    /* Find attribute name in list */
238    for (i=0; setvars[i].name; i++) {
239       if (strcmp(setvars[i].name, attrname) == 0) {
240          found = true;
241          break;
242       }
243    }
244    if (!found) {
245       goto bail_out;
246    }
247    /* Get argument value */
248    if (setvars[i].fmt != NULL) {
249       switch (setvars[i].fmt[0]) {
250       case 's':
251          if (!PyArg_Parse(value, (char *)setvars[i].fmt, &strval)) {
252             PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
253             return -1;
254          }
255          break;
256       case 'i':
257          if (!PyArg_Parse(value, (char *)setvars[i].fmt, &intval)) {
258             PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
259             return -1;
260          }
261          break;
262       }
263    }   
264    switch (i) {
265    case 0:                            /* JobReport */
266       Jmsg(jcr, M_INFO, 0, "%s", strval);
267       return 0;
268    case 1:                            /* VolumeName */
269       /* Make sure VolumeName is valid and we are in VolumeName event */
270       if (strcmp("NewVolume", jcr->event) == 0 &&
271           is_volume_name_legal(NULL, strval)) {
272          pm_strcpy(jcr->VolumeName, strval);
273          Dmsg1(100, "Set Vol=%s\n", strval);
274          return 0;
275       } else {
276          jcr->VolumeName[0] = 0;
277       }
278       break;
279    case 2:                            /* Priority */
280       Dmsg1(000, "Set priority=%d\n", intval);
281       if (intval >= 1 && intval <= 100) {
282          jcr->JobPriority = intval;
283       } else {
284          PyErr_SetString(PyExc_ValueError, _("Priority must be 1-100"));
285          return -1;
286       }
287    case 3:                            /* Job Level */
288       if (strcmp("JobInit", jcr->event) != 0) {
289          PyErr_SetString(PyExc_RuntimeError, _("Job Level can be set only during JobInit"));
290          return -1;
291       }
292       if (strval != NULL) {
293          for (i=0; joblevels[i].level_name; i++) {
294             if (strcmp(strval, joblevels[i].level_name) == 0) {
295                if (joblevels[i].job_type == jcr->getJobType()) {
296                   jcr->setJobLevel(joblevels[i].level);
297                   jcr->jr.JobLevel = jcr->getJobLevel();
298                   return 0;
299                }
300             }
301          }
302       }
303       PyErr_SetString(PyExc_ValueError, _("Bad JobLevel string"));
304       return -1;
305    }
306 bail_out:
307    PyErr_SetString(PyExc_AttributeError, attrname);
308    return -1;
309 }
310
311 /*
312  * Set pointer to instantiated events class
313  */
314 static PyObject *set_job_events(PyObject *self, PyObject *arg)
315 {
316    PyObject *eObject;
317    JCR *jcr;
318
319    Dmsg0(100, "In set_job_events.\n");
320    if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
321       Dmsg0(000, "Error in ParseTuple\n");
322       return NULL;
323    }
324    jcr = get_jcr_from_PyObject(self);
325    Py_XDECREF((PyObject *)jcr->Python_events);
326    Py_INCREF(eObject);
327    jcr->Python_events = (void *)eObject;
328    Py_INCREF(Py_None);
329    return Py_None;
330 }
331
332 /* Run a Bacula job */
333 static PyObject *job_run(PyObject *self, PyObject *arg)
334 {
335    JCR *jcr;
336    char *item;
337    int stat;
338
339    if (!PyArg_ParseTuple(arg, "s:run", &item)) {
340       Dmsg0(000, "Error in ParseTuple\n");
341       return NULL;
342    }
343    /* Release lock due to recursion */
344 // PyEval_ReleaseLock();
345    jcr = get_jcr_from_PyObject(self);
346    UAContext *ua = new_ua_context(jcr);
347    ua->batch = true;
348    pm_strcpy(ua->cmd, item);          /* copy command */
349    parse_ua_args(ua);                 /* parse command */
350    stat = run_cmd(ua, ua->cmd);
351    free_ua_context(ua);
352 // PyEval_AcquireLock();
353    return PyInt_FromLong((long)stat);
354 }
355
356 static PyObject *job_write(PyObject *self, PyObject *args)
357 {
358    char *text = NULL;
359
360    if (!PyArg_ParseTuple(args, "s:write", &text)) {
361       Dmsg0(000, "Parse tuple error in job_write\n");
362       return NULL;
363    }
364    if (text) {
365       JCR *jcr = get_jcr_from_PyObject(self);
366       Jmsg(jcr, M_INFO, 0, "%s", text);
367    }
368    Py_INCREF(Py_None);
369    return Py_None;
370 }
371
372 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
373 {
374    char *VolName = NULL;
375
376    if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
377       Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
378       return NULL;
379    }
380    if (VolName) {
381       MEDIA_DBR mr;
382       int ok;
383       JCR *jcr = get_jcr_from_PyObject(self);
384       memset(&mr, 0, sizeof(mr));
385       bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
386       ok = db_get_media_record(jcr, jcr->db, &mr);
387       return Py_BuildValue("i", ok);
388    }
389    Py_INCREF(Py_None);
390    return Py_None;
391 }
392
393
394 static PyObject *job_cancel(PyObject *self, PyObject *args)
395 {
396    JobId_t JobId = 0;
397    JCR *jcr;
398    bool found = false;
399
400    if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
401       Dmsg0(000, "Parse tuple error in job_write\n");
402       return NULL;
403    }
404    foreach_jcr(jcr) {
405       if (jcr->JobId == 0) {
406          continue;
407       }
408       if (jcr->JobId == JobId) {
409          found = true;
410          break;
411       }
412    }
413    /* endeach_jcr(jcr) not needed because freed below */
414
415    if (!found) {
416       /* ***FIXME*** raise exception */
417       return NULL;
418    }
419 // PyEval_ReleaseLock();
420    UAContext *ua = new_ua_context(jcr);
421    ua->batch = true;
422    if (!cancel_job(ua, jcr, true)) {
423       /* ***FIXME*** raise exception */
424       return NULL;
425    }
426    free_ua_context(ua);
427    free_jcr(jcr);
428 // PyEval_AcquireLock();   
429    Py_INCREF(Py_None);
430    return Py_None;
431 }
432
433 /*
434  * Generate a Job event, which means look up the event
435  *  method defined by the user, and if it exists, 
436  *  call it.
437  */
438 int generate_job_event(JCR *jcr, const char *event)
439 {
440    PyObject *method = NULL;
441    PyObject *Job = (PyObject *)jcr->Python_job;
442    PyObject *events = (PyObject *)jcr->Python_events;
443    PyObject *result = NULL;
444    int stat = 0;
445
446    if (!Job || !events) {
447       return 0;
448    }
449
450    lock_python();
451 // PyEval_AcquireLock();
452
453    method = find_method(events, method, event);
454    if (!method) {
455       goto bail_out;
456    }
457
458    bstrncpy(jcr->event, event, sizeof(jcr->event));
459    result = PyObject_CallFunction(method, (char *)"O", Job);
460    jcr->event[0] = 0;             /* no event in progress */
461    if (result == NULL) {
462       if (PyErr_Occurred()) {
463          PyErr_Print();
464          Dmsg1(000, "Error in Python method %s\n", event);
465       }
466    } else {
467       stat = 1;
468    }
469    Py_XDECREF(result);
470
471 bail_out:
472    unlock_python();
473 // PyEval_ReleaseLock();
474    return stat;
475 }
476
477 bool python_set_prog(JCR*, char const*) { return false; }
478
479 #else
480
481 /* Dummy if Python not configured */
482 int generate_job_event(JCR *jcr, const char *event) { return 1; }
483    
484
485 #endif /* HAVE_PYTHON */