]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
tweak debug level in fd_plugin
[bacula/bacula] / bacula / src / filed / status.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2010 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  *  Bacula File Daemon Status routines
30  *
31  *    Kern Sibbald, August MMI
32  *
33  */
34
35 #include "bacula.h"
36 #include "filed.h"
37 #include "lib/status.h"
38
39 extern void *start_heap;
40
41 /* Forward referenced functions */
42 static void  list_terminated_jobs(STATUS_PKT *sp);
43 static void  list_running_jobs(STATUS_PKT *sp);
44 static void  list_status_header(STATUS_PKT *sp);
45 static void sendit(const char *msg, int len, STATUS_PKT *sp);
46 static const char *level_to_str(int level);
47
48 /* Static variables */
49 static char qstatus[] = ".status %s\n";
50
51 static char OKqstatus[]   = "2000 OK .status\n";
52 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
53
54 #if defined(HAVE_WIN32)
55 static int privs = 0;
56 #endif
57 #ifdef WIN32_VSS
58 #include "vss.h"
59 #define VSS " VSS"
60 extern VSSClient *g_pVSSClient;
61 #else
62 #define VSS ""
63 #endif
64
65 /*
66  * General status generator
67  */
68 void output_status(STATUS_PKT *sp)
69 {
70    list_status_header(sp);
71    list_running_jobs(sp);
72    list_terminated_jobs(sp);
73 }
74
75 static void  list_status_header(STATUS_PKT *sp)
76 {
77    POOL_MEM msg(PM_MESSAGE);
78    char b1[32], b2[32], b3[32], b4[32], b5[35];
79    int len;
80    char dt[MAX_TIME_LENGTH];
81
82    len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"), 
83               my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
84    sendit(msg.c_str(), len, sp);
85    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
86    len = Mmsg(msg, _("Daemon started %s. Jobs: run=%d running=%d.\n"),
87         dt, num_jobs_run, job_count());
88    sendit(msg.c_str(), len, sp);
89 #if defined(HAVE_WIN32)
90    if (debug_level > 0) {
91       if (!privs) {
92          privs = enable_backup_privileges(NULL, 1);
93       }
94       len = Mmsg(msg, "VSS %s, Priv 0x%x\n", g_pVSSClient?"enabled":"disabled", privs);
95       sendit(msg.c_str(), len, sp);
96       len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
97                  p_OpenProcessToken?"":"!",
98                  p_AdjustTokenPrivileges?"":"!",
99                  p_LookupPrivilegeValue?"":"!",
100                  p_CreateFileA?"":"!",
101                  p_CreateFileW?"":"!");
102       sendit(msg.c_str(), len, sp);
103       len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
104                  p_wunlink?"":"!",
105                  p_wmkdir?"":"!",
106                  p_GetFileAttributesA?"":"!",
107                  p_GetFileAttributesW?"":"!",
108                  p_GetFileAttributesExA?"":"!",
109                  p_GetFileAttributesExW?"":"!",
110                  p_SetFileAttributesA?"":"!",
111                  p_SetFileAttributesW?"":"!",
112                  p_BackupRead?"":"!",
113                  p_BackupWrite?"":"!",
114                  p_SetProcessShutdownParameters?"":"!");
115       sendit(msg.c_str(), len, sp);
116       len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
117                  p_WideCharToMultiByte?"":"!",
118                  p_MultiByteToWideChar?"":"!",
119                  p_FindFirstFileA?"":"!",
120                  p_FindFirstFileW?"":"!",
121                  p_FindNextFileA?"":"!",
122                  p_FindNextFileW?"":"!",
123                  p_SetCurrentDirectoryA?"":"!",
124                  p_SetCurrentDirectoryW?"":"!");
125       sendit(msg.c_str(), len, sp);
126       len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",  
127                  p_GetCurrentDirectoryA?"":"!",
128                  p_GetCurrentDirectoryW?"":"!",
129                  p_GetVolumePathNameW?"":"!",
130                  p_GetVolumeNameForVolumeMountPointW?"":"!");
131      sendit(msg.c_str(), len, sp);
132    }
133 #endif
134    len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
135          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
136          edit_uint64_with_commas(sm_bytes, b2),
137          edit_uint64_with_commas(sm_max_bytes, b3),
138          edit_uint64_with_commas(sm_buffers, b4),
139          edit_uint64_with_commas(sm_max_buffers, b5));
140    sendit(msg.c_str(), len, sp);
141    len = Mmsg(msg, _(" Sizeof: boffset_t=%d size_t=%d debug=%d trace=%d "
142                      "bwlimit=%lldkb/s\n"), sizeof(boffset_t), sizeof(size_t),
143               debug_level, get_trace(), me->max_bandwidth_per_job/1024);
144    sendit(msg.c_str(), len, sp);
145    if (debug_level > 0 && plugin_list->size() > 0) {
146       Plugin *plugin;
147       int len;
148       pm_strcpy(msg, "Plugin: ");
149       foreach_alist(plugin, plugin_list) {
150          len = pm_strcat(msg, plugin->file);
151          if (len > 80) {
152             pm_strcat(msg, "\n   ");
153          } else {
154             pm_strcat(msg, " ");
155          }
156       }
157       len = pm_strcat(msg, "\n");
158       sendit(msg.c_str(), len, sp);
159    }
160 }
161
162 static void  list_running_jobs(STATUS_PKT *sp)
163 {
164    int sec, bps;
165    POOL_MEM msg(PM_MESSAGE);
166    char b1[32], b2[32], b3[32];
167    int len;
168    bool found = false;
169    JCR *njcr;
170    char dt[MAX_TIME_LENGTH];
171    /*
172     * List running jobs
173     */
174    Dmsg0(1000, "Begin status jcr loop.\n");
175    if (!sp->api) {
176       len = Mmsg(msg, _("\nRunning Jobs:\n"));
177       sendit(msg.c_str(), len, sp);
178    }
179    const char *vss = "";
180 #ifdef WIN32_VSS
181    if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
182       vss = "VSS ";
183    }
184 #endif
185    foreach_jcr(njcr) {
186       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
187       if (njcr->JobId == 0) {
188          len = Mmsg(msg, _("Director connected at: %s\n"), dt);
189       } else {
190          len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
191                     njcr->JobId, njcr->Job);
192          sendit(msg.c_str(), len, sp);
193          len = Mmsg(msg, _("    %s%s %s Job started: %s\n"),
194                     vss, level_to_str(njcr->getJobLevel()), 
195                     job_type_to_str(njcr->getJobType()), dt);
196       }
197       sendit(msg.c_str(), len, sp);
198       if (njcr->JobId == 0) {
199          continue;
200       }
201       sec = time(NULL) - njcr->start_time;
202       if (sec <= 0) {
203          sec = 1;
204       }
205       bps = (int)(njcr->JobBytes / sec);
206       len = Mmsg(msg,  _("    Files=%s Bytes=%s Bytes/sec=%s Errors=%d\n"),
207            edit_uint64_with_commas(njcr->JobFiles, b1),
208            edit_uint64_with_commas(njcr->JobBytes, b2),
209            edit_uint64_with_commas(bps, b3),
210            njcr->JobErrors);
211       sendit(msg.c_str(), len, sp);
212       len = Mmsg(msg, _("    Files Examined=%s\n"),
213            edit_uint64_with_commas(njcr->num_files_examined, b1));
214       sendit(msg.c_str(), len, sp);
215       if (njcr->JobFiles > 0) {
216          njcr->lock();
217          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
218          njcr->unlock();
219          sendit(msg.c_str(), len, sp);
220       }
221
222       found = true;
223       if (njcr->store_bsock) {
224          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
225              njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
226          sendit(msg.c_str(), len, sp);
227       } else {
228          len = Mmsg(msg, _("    SDSocket closed.\n"));
229          sendit(msg.c_str(), len, sp);
230       }
231    }
232    endeach_jcr(njcr);
233
234    if (!sp->api) {
235       if (!found) {
236          len = Mmsg(msg, _("No Jobs running.\n"));
237          sendit(msg.c_str(), len, sp);
238       }
239       sendit(_("====\n"), 5, sp);
240    }
241 }
242   
243
244 static void list_terminated_jobs(STATUS_PKT *sp)
245 {
246    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
247    char level[10];
248    struct s_last_job *je;
249    const char *msg;
250
251    if (!sp->api) {
252       msg =  _("\nTerminated Jobs:\n");
253       sendit(msg, strlen(msg), sp);
254    }
255
256    if (last_jobs->size() == 0) {
257       if (!sp->api) sendit(_("====\n"), 5, sp);
258       return;
259    }
260    lock_last_jobs_list();
261    if (!sp->api) {
262       msg =  _(" JobId  Level    Files      Bytes   Status   Finished        Name \n");
263       sendit(msg, strlen(msg), sp);
264       msg = _("======================================================================\n");
265       sendit(msg, strlen(msg), sp);
266    }
267    foreach_dlist(je, last_jobs) {
268       char JobName[MAX_NAME_LENGTH];
269       const char *termstat;
270       char buf[1000];
271
272       bstrftime_nc(dt, sizeof(dt), je->end_time);
273       switch (je->JobType) {
274       case JT_ADMIN:
275       case JT_RESTORE:
276          bstrncpy(level, "    ", sizeof(level));
277          break;
278       default:
279          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
280          level[4] = 0;
281          break;
282       }
283       switch (je->JobStatus) {
284       case JS_Created:
285          termstat = _("Created");
286          break;
287       case JS_FatalError:
288       case JS_ErrorTerminated:
289          termstat = _("Error");
290          break;
291       case JS_Differences:
292          termstat = _("Diffs");
293          break;
294       case JS_Canceled:
295          termstat = _("Cancel");
296          break;
297       case JS_Terminated:
298          termstat = _("OK");
299          break;
300       default:
301          termstat = _("Other");
302          break;
303       }
304       bstrncpy(JobName, je->Job, sizeof(JobName));
305       /* There are three periods after the Job name */
306       char *p;
307       for (int i=0; i<3; i++) {
308          if ((p=strrchr(JobName, '.')) != NULL) {
309             *p = 0;
310          }
311       }
312       if (sp->api) {
313          bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
314             je->JobId,
315             level,
316             edit_uint64_with_commas(je->JobFiles, b1),
317             edit_uint64_with_suffix(je->JobBytes, b2),
318             termstat,
319             dt, JobName);
320       } else {
321          bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %10s  %-7s  %-8s %s\n"),
322             je->JobId,
323             level,
324             edit_uint64_with_commas(je->JobFiles, b1),
325             edit_uint64_with_suffix(je->JobBytes, b2),
326             termstat,
327             dt, JobName);
328       }
329       sendit(buf, strlen(buf), sp);
330    }
331    if (!sp->api) sendit(_("====\n"), 5, sp);
332    unlock_last_jobs_list();
333 }
334
335
336 /*
337  * Send to bsock (Director or Console)
338  */
339 static void sendit(const char *msg, int len, STATUS_PKT *sp)          
340 {
341    if (sp->bs) {
342       BSOCK *user = sp->bs;
343       user->msg = check_pool_memory_size(user->msg, len+1);
344       memcpy(user->msg, msg, len+1);
345       user->msglen = len+1;
346       user->send();
347    } else {
348       sp->callback(msg, len, sp->context);
349    }
350 }
351
352 /*
353  * Status command from Director
354  */
355 int status_cmd(JCR *jcr)
356 {
357    BSOCK *user = jcr->dir_bsock;
358    STATUS_PKT sp;
359
360    user->fsend("\n");
361    sp.bs = user;
362    sp.api = false;                         /* no API output */
363    output_status(&sp);
364
365    user->signal(BNET_EOD);
366    return 1;
367 }
368
369 /*
370  * .status command from Director
371  */
372 int qstatus_cmd(JCR *jcr)
373 {
374    BSOCK *dir = jcr->dir_bsock;
375    POOLMEM *cmd;
376    JCR *njcr;
377    s_last_job* job;
378    STATUS_PKT sp;
379
380    sp.bs = dir;
381    cmd = get_memory(dir->msglen+1);
382
383    if (sscanf(dir->msg, qstatus, cmd) != 1) {
384       pm_strcpy(&jcr->errmsg, dir->msg);
385       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
386       dir->fsend(_("2900 Bad .status command, missing argument.\n"));
387       dir->signal(BNET_EOD);
388       free_memory(cmd);
389       return 0;
390    }
391    unbash_spaces(cmd);
392
393    if (strcmp(cmd, "current") == 0) {
394       dir->fsend(OKqstatus, cmd);
395       foreach_jcr(njcr) {
396          if (njcr->JobId != 0) {
397             dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
398          }
399       }
400       endeach_jcr(njcr);
401    } else if (strcmp(cmd, "last") == 0) {
402       dir->fsend(OKqstatus, cmd);
403       if ((last_jobs) && (last_jobs->size() > 0)) {
404          job = (s_last_job*)last_jobs->last();
405          dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
406       }
407    } else if (strcasecmp(cmd, "header") == 0) {
408        sp.api = true;
409        list_status_header(&sp);
410    } else if (strcasecmp(cmd, "running") == 0) {
411        sp.api = true;
412        list_running_jobs(&sp);
413    } else if (strcasecmp(cmd, "terminated") == 0) {
414        sp.api = true;
415        list_terminated_jobs(&sp);
416    } else {
417       pm_strcpy(&jcr->errmsg, dir->msg);
418       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
419       dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
420       dir->signal(BNET_EOD);
421       free_memory(cmd);
422       return 0;
423    }
424
425    dir->signal(BNET_EOD);
426    free_memory(cmd);
427    return 1;
428 }
429
430 /*
431  * Convert Job Level into a string
432  */
433 static const char *level_to_str(int level)
434 {
435    const char *str;
436
437    switch (level) {
438    case L_BASE:
439       str = _("Base");
440    case L_FULL:
441       str = _("Full");
442       break;
443    case L_INCREMENTAL:
444       str = _("Incremental");
445       break;
446    case L_DIFFERENTIAL:
447       str = _("Differential");
448       break;
449    case L_SINCE:
450       str = _("Since");
451       break;
452    case L_VERIFY_CATALOG:
453       str = _("Verify Catalog");
454       break;
455    case L_VERIFY_INIT:
456       str = _("Init Catalog");
457       break;
458    case L_VERIFY_VOLUME_TO_CATALOG:
459       str = _("Volume to Catalog");
460       break;
461    case L_VERIFY_DISK_TO_CATALOG:
462       str = _("Disk to Catalog");
463       break;
464    case L_VERIFY_DATA:
465       str = _("Data");
466       break;
467    case L_NONE:
468       str = " ";
469       break;
470    default:
471       str = _("Unknown Job Level");
472       break;
473    }
474    return str;
475 }
476
477
478 #if defined(HAVE_WIN32)
479 int bacstat = 0;
480
481 /*
482  * Put message in Window List Box
483  */
484 char *bac_status(char *buf, int buf_len)
485 {
486    JCR *njcr;
487    const char *termstat = _("Bacula Client: Idle");
488    struct s_last_job *job;
489    int stat = 0;                      /* Idle */
490
491    if (!last_jobs) {
492       goto done;
493    }
494    Dmsg0(1000, "Begin bac_status jcr loop.\n");
495    foreach_jcr(njcr) {
496       if (njcr->JobId != 0) {
497          stat = JS_Running;
498          termstat = _("Bacula Client: Running");
499          break;
500       }
501    }
502    endeach_jcr(njcr);
503
504    if (stat != 0) {
505       goto done;
506    }
507    if (last_jobs->size() > 0) {
508       job = (struct s_last_job *)last_jobs->last();
509       stat = job->JobStatus;
510       switch (job->JobStatus) {
511       case JS_Canceled:
512          termstat = _("Bacula Client: Last Job Canceled");
513          break;
514       case JS_ErrorTerminated:
515       case JS_FatalError:
516          termstat = _("Bacula Client: Last Job Failed");
517          break;
518       default:
519          if (job->Errors) {
520             termstat = _("Bacula Client: Last Job had Warnings");
521          }
522          break;
523       }
524    }
525    Dmsg0(1000, "End bac_status jcr loop.\n");
526 done:
527    bacstat = stat;
528    if (buf) {
529       bstrncpy(buf, termstat, buf_len);
530    }
531    return buf;
532 }
533
534 #endif /* HAVE_WIN32 */