2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2010 Free Software Foundation Europe e.V.
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
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.
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
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.
29 * Bacula File Daemon Status routines
31 * Kern Sibbald, August MMI
37 #include "lib/status.h"
39 extern void *start_heap;
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);
48 /* Static variables */
49 static char qstatus[] = ".status %s\n";
51 static char OKqstatus[] = "2000 OK .status\n";
52 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
54 #if defined(HAVE_WIN32)
60 extern VSSClient *g_pVSSClient;
66 * General status generator
68 void output_status(STATUS_PKT *sp)
70 list_status_header(sp);
71 list_running_jobs(sp);
72 list_terminated_jobs(sp);
75 static void list_status_header(STATUS_PKT *sp)
77 POOL_MEM msg(PM_MESSAGE);
78 char b1[32], b2[32], b3[32], b4[32], b5[35];
80 char dt[MAX_TIME_LENGTH];
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) {
92 privs = enable_backup_privileges(NULL, 1);
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",
106 p_GetFileAttributesA?"":"!",
107 p_GetFileAttributesW?"":"!",
108 p_GetFileAttributesExA?"":"!",
109 p_GetFileAttributesExW?"":"!",
110 p_SetFileAttributesA?"":"!",
111 p_SetFileAttributesW?"":"!",
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);
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/1024);
144 sendit(msg.c_str(), len, sp);
145 if (debug_level > 0 && plugin_list->size() > 0) {
148 pm_strcpy(msg, "Plugin: ");
149 foreach_alist(plugin, plugin_list) {
150 len = pm_strcat(msg, plugin->file);
152 pm_strcat(msg, "\n ");
157 len = pm_strcat(msg, "\n");
158 sendit(msg.c_str(), len, sp);
162 static void list_running_jobs(STATUS_PKT *sp)
165 POOL_MEM msg(PM_MESSAGE);
166 char b1[32], b2[32], b3[32];
170 char dt[MAX_TIME_LENGTH];
174 Dmsg0(1000, "Begin status jcr loop.\n");
176 len = Mmsg(msg, _("\nRunning Jobs:\n"));
177 sendit(msg.c_str(), len, sp);
179 const char *vss = "";
181 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
186 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
187 if (njcr->JobId == 0) {
188 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
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);
197 sendit(msg.c_str(), len, sp);
198 if (njcr->JobId == 0) {
201 sec = time(NULL) - njcr->start_time;
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),
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) {
217 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
219 sendit(msg.c_str(), len, sp);
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);
228 len = Mmsg(msg, _(" SDSocket closed.\n"));
229 sendit(msg.c_str(), len, sp);
236 len = Mmsg(msg, _("No Jobs running.\n"));
237 sendit(msg.c_str(), len, sp);
239 sendit(_("====\n"), 5, sp);
244 static void list_terminated_jobs(STATUS_PKT *sp)
246 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
248 struct s_last_job *je;
252 msg = _("\nTerminated Jobs:\n");
253 sendit(msg, strlen(msg), sp);
256 if (last_jobs->size() == 0) {
257 if (!sp->api) sendit(_("====\n"), 5, sp);
260 lock_last_jobs_list();
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);
267 foreach_dlist(je, last_jobs) {
268 char JobName[MAX_NAME_LENGTH];
269 const char *termstat;
272 bstrftime_nc(dt, sizeof(dt), je->end_time);
273 switch (je->JobType) {
276 bstrncpy(level, " ", sizeof(level));
279 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
283 switch (je->JobStatus) {
285 termstat = _("Created");
288 case JS_ErrorTerminated:
289 termstat = _("Error");
292 termstat = _("Diffs");
295 termstat = _("Cancel");
301 termstat = _("Other");
304 bstrncpy(JobName, je->Job, sizeof(JobName));
305 /* There are three periods after the Job name */
307 for (int i=0; i<3; i++) {
308 if ((p=strrchr(JobName, '.')) != NULL) {
313 bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
316 edit_uint64_with_commas(je->JobFiles, b1),
317 edit_uint64_with_suffix(je->JobBytes, b2),
321 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
324 edit_uint64_with_commas(je->JobFiles, b1),
325 edit_uint64_with_suffix(je->JobBytes, b2),
329 sendit(buf, strlen(buf), sp);
331 if (!sp->api) sendit(_("====\n"), 5, sp);
332 unlock_last_jobs_list();
337 * Send to bsock (Director or Console)
339 static void sendit(const char *msg, int len, STATUS_PKT *sp)
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;
348 sp->callback(msg, len, sp->context);
353 * Status command from Director
355 int status_cmd(JCR *jcr)
357 BSOCK *user = jcr->dir_bsock;
362 sp.api = false; /* no API output */
365 user->signal(BNET_EOD);
370 * .status command from Director
372 int qstatus_cmd(JCR *jcr)
374 BSOCK *dir = jcr->dir_bsock;
381 cmd = get_memory(dir->msglen+1);
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);
393 if (strcmp(cmd, "current") == 0) {
394 dir->fsend(OKqstatus, cmd);
396 if (njcr->JobId != 0) {
397 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
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);
407 } else if (strcasecmp(cmd, "header") == 0) {
409 list_status_header(&sp);
410 } else if (strcasecmp(cmd, "running") == 0) {
412 list_running_jobs(&sp);
413 } else if (strcasecmp(cmd, "terminated") == 0) {
415 list_terminated_jobs(&sp);
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);
425 dir->signal(BNET_EOD);
431 * Convert Job Level into a string
433 static const char *level_to_str(int level)
444 str = _("Incremental");
447 str = _("Differential");
452 case L_VERIFY_CATALOG:
453 str = _("Verify Catalog");
456 str = _("Init Catalog");
458 case L_VERIFY_VOLUME_TO_CATALOG:
459 str = _("Volume to Catalog");
461 case L_VERIFY_DISK_TO_CATALOG:
462 str = _("Disk to Catalog");
471 str = _("Unknown Job Level");
478 #if defined(HAVE_WIN32)
482 * Put message in Window List Box
484 char *bac_status(char *buf, int buf_len)
487 const char *termstat = _("Bacula Client: Idle");
488 struct s_last_job *job;
489 int stat = 0; /* Idle */
494 Dmsg0(1000, "Begin bac_status jcr loop.\n");
496 if (njcr->JobId != 0) {
498 termstat = _("Bacula Client: Running");
507 if (last_jobs->size() > 0) {
508 job = (struct s_last_job *)last_jobs->last();
509 stat = job->JobStatus;
510 switch (job->JobStatus) {
512 termstat = _("Bacula Client: Last Job Canceled");
514 case JS_ErrorTerminated:
516 termstat = _("Bacula Client: Last Job Failed");
520 termstat = _("Bacula Client: Last Job had Warnings");
525 Dmsg0(1000, "End bac_status jcr loop.\n");
529 bstrncpy(buf, termstat, buf_len);
534 #endif /* HAVE_WIN32 */