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