2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2008 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 two of the GNU 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 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 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.
29 * Bacula File Daemon Status routines
31 * Kern Sibbald, August MMI
39 #include "lib/status.h"
41 extern void *start_heap;
43 /* Forward referenced functions */
44 static void list_terminated_jobs(STATUS_PKT *sp, bool api);
45 static void list_running_jobs(STATUS_PKT *sp, bool api);
46 static void list_status_header(STATUS_PKT *sp, bool api);
47 static void sendit(const char *msg, int len, STATUS_PKT *sp);
48 static const char *level_to_str(int level);
50 /* Static variables */
51 static char qstatus[] = ".status %s\n";
53 static char OKqstatus[] = "2000 OK .status\n";
54 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
56 #if defined(HAVE_WIN32)
62 extern VSSClient *g_pVSSClient;
68 * General status generator
70 void output_status(STATUS_PKT *sp)
72 list_status_header(sp, false /*no api*/);
73 list_running_jobs(sp, false /*no api*/);
74 list_terminated_jobs(sp, false /*no api*/);
77 static void list_status_header(STATUS_PKT *sp, bool api)
79 POOL_MEM msg(PM_MESSAGE);
80 char b1[32], b2[32], b3[32], b4[32], b5[35];
82 char dt[MAX_TIME_LENGTH];
84 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
85 my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
86 sendit(msg.c_str(), len, sp);
87 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
88 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
89 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
90 sendit(msg.c_str(), len, sp);
91 #if defined(HAVE_WIN32)
92 if (debug_level > 0) {
94 privs = enable_backup_privileges(NULL, 1);
96 len = Mmsg(msg, "VSS %s, Priv 0x%x\n", g_pVSSClient?"enabled":"disabled", privs);
97 sendit(msg.c_str(), len, sp);
98 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
99 p_OpenProcessToken?"":"!",
100 p_AdjustTokenPrivileges?"":"!",
101 p_LookupPrivilegeValue?"":"!",
102 p_CreateFileA?"":"!",
103 p_CreateFileW?"":"!");
104 sendit(msg.c_str(), len, sp);
105 len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
108 p_GetFileAttributesA?"":"!",
109 p_GetFileAttributesW?"":"!",
110 p_GetFileAttributesExA?"":"!",
111 p_GetFileAttributesExW?"":"!",
112 p_SetFileAttributesA?"":"!",
113 p_SetFileAttributesW?"":"!",
115 p_BackupWrite?"":"!",
116 p_SetProcessShutdownParameters?"":"!");
117 sendit(msg.c_str(), len, sp);
118 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
119 p_WideCharToMultiByte?"":"!",
120 p_MultiByteToWideChar?"":"!",
121 p_FindFirstFileA?"":"!",
122 p_FindFirstFileW?"":"!",
123 p_FindNextFileA?"":"!",
124 p_FindNextFileW?"":"!",
125 p_SetCurrentDirectoryA?"":"!",
126 p_SetCurrentDirectoryW?"":"!");
127 sendit(msg.c_str(), len, sp);
128 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",
129 p_GetCurrentDirectoryA?"":"!",
130 p_GetCurrentDirectoryW?"":"!",
131 p_GetVolumePathNameW?"":"!",
132 p_GetVolumeNameForVolumeMountPointW?"":"!");
133 sendit(msg.c_str(), len, sp);
136 len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
137 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
138 edit_uint64_with_commas(sm_bytes, b2),
139 edit_uint64_with_commas(sm_max_bytes, b3),
140 edit_uint64_with_commas(sm_buffers, b4),
141 edit_uint64_with_commas(sm_max_buffers, b5));
142 sendit(msg.c_str(), len, sp);
143 len = Mmsg(msg, _(" Sizeof: boffset_t=%d size_t=%d debug=%d trace=%d\n"),
144 sizeof(boffset_t), sizeof(size_t), debug_level, get_trace());
145 sendit(msg.c_str(), len, sp);
148 static void list_running_jobs(STATUS_PKT *sp, bool api)
151 POOL_MEM msg(PM_MESSAGE);
152 char b1[32], b2[32], b3[32];
156 char dt[MAX_TIME_LENGTH];
160 Dmsg0(1000, "Begin status jcr loop.\n");
162 len = Mmsg(msg, _("\nRunning Jobs:\n"));
163 sendit(msg.c_str(), len, sp);
165 const char *vss = "";
167 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
172 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
173 if (njcr->JobId == 0) {
174 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
176 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
177 njcr->JobId, njcr->Job);
178 sendit(msg.c_str(), len, sp);
179 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
180 vss, job_type_to_str(njcr->JobType), dt);
182 sendit(msg.c_str(), len, sp);
183 if (njcr->JobId == 0) {
186 sec = time(NULL) - njcr->start_time;
190 bps = (int)(njcr->JobBytes / sec);
191 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s Errors=%d\n"),
192 edit_uint64_with_commas(njcr->JobFiles, b1),
193 edit_uint64_with_commas(njcr->JobBytes, b2),
194 edit_uint64_with_commas(bps, b3),
196 sendit(msg.c_str(), len, sp);
197 len = Mmsg(msg, _(" Files Examined=%s\n"),
198 edit_uint64_with_commas(njcr->num_files_examined, b1));
199 sendit(msg.c_str(), len, sp);
200 if (njcr->JobFiles > 0) {
202 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
204 sendit(msg.c_str(), len, sp);
208 if (njcr->store_bsock) {
209 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
210 njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
211 sendit(msg.c_str(), len, sp);
213 len = Mmsg(msg, _(" SDSocket closed.\n"));
214 sendit(msg.c_str(), len, sp);
221 len = Mmsg(msg, _("No Jobs running.\n"));
222 sendit(msg.c_str(), len, sp);
224 sendit(_("====\n"), 5, sp);
229 static void list_terminated_jobs(STATUS_PKT *sp, bool api)
231 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
233 struct s_last_job *je;
237 msg = _("\nTerminated Jobs:\n");
238 sendit(msg, strlen(msg), sp);
241 if (last_jobs->size() == 0) {
242 if (!api) sendit(_("====\n"), 5, sp);
245 lock_last_jobs_list();
247 msg = _(" JobId Level Files Bytes Status Finished Name \n");
248 sendit(msg, strlen(msg), sp);
249 msg = _("======================================================================\n");
250 sendit(msg, strlen(msg), sp);
252 foreach_dlist(je, last_jobs) {
253 char JobName[MAX_NAME_LENGTH];
254 const char *termstat;
257 bstrftime_nc(dt, sizeof(dt), je->end_time);
258 switch (je->JobType) {
261 bstrncpy(level, " ", sizeof(level));
264 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
268 switch (je->JobStatus) {
270 termstat = _("Created");
273 case JS_ErrorTerminated:
274 termstat = _("Error");
277 termstat = _("Diffs");
280 termstat = _("Cancel");
286 termstat = _("Other");
289 bstrncpy(JobName, je->Job, sizeof(JobName));
290 /* There are three periods after the Job name */
292 for (int i=0; i<3; i++) {
293 if ((p=strrchr(JobName, '.')) != NULL) {
298 bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
301 edit_uint64_with_commas(je->JobFiles, b1),
302 edit_uint64_with_suffix(je->JobBytes, b2),
306 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
309 edit_uint64_with_commas(je->JobFiles, b1),
310 edit_uint64_with_suffix(je->JobBytes, b2),
314 sendit(buf, strlen(buf), sp);
316 if (!api) sendit(_("====\n"), 5, sp);
317 unlock_last_jobs_list();
322 * Send to bsock (Director or Console)
324 static void sendit(const char *msg, int len, STATUS_PKT *sp)
327 BSOCK *user = sp->bs;
328 user->msg = check_pool_memory_size(user->msg, len+1);
329 memcpy(user->msg, msg, len+1);
330 user->msglen = len+1;
333 sp->callback(msg, len, sp->context);
338 * Status command from Director
340 int status_cmd(JCR *jcr)
342 BSOCK *user = jcr->dir_bsock;
349 user->signal(BNET_EOD);
354 * .status command from Director
356 int qstatus_cmd(JCR *jcr)
358 BSOCK *dir = jcr->dir_bsock;
365 cmd = get_memory(dir->msglen+1);
367 if (sscanf(dir->msg, qstatus, cmd) != 1) {
368 pm_strcpy(&jcr->errmsg, dir->msg);
369 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
370 dir->fsend(_("2900 Bad .status command, missing argument.\n"));
371 dir->signal(BNET_EOD);
377 if (strcmp(cmd, "current") == 0) {
378 dir->fsend(OKqstatus, cmd);
380 if (njcr->JobId != 0) {
381 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
385 } else if (strcmp(cmd, "last") == 0) {
386 dir->fsend(OKqstatus, cmd);
387 if ((last_jobs) && (last_jobs->size() > 0)) {
388 job = (s_last_job*)last_jobs->last();
389 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
391 } else if (strcasecmp(cmd, "header") == 0) {
392 list_status_header(&sp, true/*api*/);
393 } else if (strcasecmp(cmd, "running") == 0) {
394 list_running_jobs(&sp, true/*api*/);
395 } else if (strcasecmp(cmd, "terminated") == 0) {
396 list_terminated_jobs(&sp, true/*api*/);
398 pm_strcpy(&jcr->errmsg, dir->msg);
399 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
400 dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
401 dir->signal(BNET_EOD);
406 dir->signal(BNET_EOD);
412 * Convert Job Level into a string
414 static const char *level_to_str(int level)
425 str = _("Incremental");
428 str = _("Differential");
433 case L_VERIFY_CATALOG:
434 str = _("Verify Catalog");
437 str = _("Init Catalog");
439 case L_VERIFY_VOLUME_TO_CATALOG:
440 str = _("Volume to Catalog");
442 case L_VERIFY_DISK_TO_CATALOG:
443 str = _("Disk to Catalog");
452 str = _("Unknown Job Level");
459 #if defined(HAVE_WIN32)
463 * Put message in Window List Box
465 char *bac_status(char *buf, int buf_len)
468 const char *termstat = _("Bacula Client: Idle");
469 struct s_last_job *job;
470 int stat = 0; /* Idle */
475 Dmsg0(1000, "Begin bac_status jcr loop.\n");
477 if (njcr->JobId != 0) {
479 termstat = _("Bacula Client: Running");
488 if (last_jobs->size() > 0) {
489 job = (struct s_last_job *)last_jobs->last();
490 stat = job->JobStatus;
491 switch (job->JobStatus) {
493 termstat = _("Bacula Client: Last Job Canceled");
495 case JS_ErrorTerminated:
497 termstat = _("Bacula Client: Last Job Failed");
501 termstat = _("Bacula Client: Last Job had Warnings");
506 Dmsg0(1000, "End bac_status jcr loop.\n");
510 bstrncpy(buf, termstat, buf_len);
515 #endif /* HAVE_WIN32 */