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