2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2009 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 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
39 #include "lib/status.h"
41 extern void *start_heap;
43 /* Forward referenced functions */
44 static void list_terminated_jobs(STATUS_PKT *sp);
45 static void list_running_jobs(STATUS_PKT *sp);
46 static void list_status_header(STATUS_PKT *sp);
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);
73 list_running_jobs(sp);
74 list_terminated_jobs(sp);
77 static void list_status_header(STATUS_PKT *sp)
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);
146 if (debug_level > 0 && plugin_list->size() > 0) {
149 pm_strcpy(msg, "Plugin: ");
150 foreach_alist(plugin, plugin_list) {
151 len = pm_strcat(msg, plugin->file);
153 pm_strcat(msg, "\n ");
158 len = pm_strcat(msg, "\n");
159 sendit(msg.c_str(), len, sp);
163 static void list_running_jobs(STATUS_PKT *sp)
166 POOL_MEM msg(PM_MESSAGE);
167 char b1[32], b2[32], b3[32];
171 char dt[MAX_TIME_LENGTH];
175 Dmsg0(1000, "Begin status jcr loop.\n");
177 len = Mmsg(msg, _("\nRunning Jobs:\n"));
178 sendit(msg.c_str(), len, sp);
180 const char *vss = "";
182 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
187 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
188 if (njcr->JobId == 0) {
189 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
191 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
192 njcr->JobId, njcr->Job);
193 sendit(msg.c_str(), len, sp);
194 len = Mmsg(msg, _(" %s%s %s Job started: %s\n"),
195 vss, level_to_str(njcr->getJobLevel()),
196 job_type_to_str(njcr->getJobType()), dt);
198 sendit(msg.c_str(), len, sp);
199 if (njcr->JobId == 0) {
202 sec = time(NULL) - njcr->start_time;
206 bps = (int)(njcr->JobBytes / sec);
207 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s Errors=%d\n"),
208 edit_uint64_with_commas(njcr->JobFiles, b1),
209 edit_uint64_with_commas(njcr->JobBytes, b2),
210 edit_uint64_with_commas(bps, b3),
212 sendit(msg.c_str(), len, sp);
213 len = Mmsg(msg, _(" Files Examined=%s\n"),
214 edit_uint64_with_commas(njcr->num_files_examined, b1));
215 sendit(msg.c_str(), len, sp);
216 if (njcr->JobFiles > 0) {
218 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
220 sendit(msg.c_str(), len, sp);
224 if (njcr->store_bsock) {
225 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
226 njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
227 sendit(msg.c_str(), len, sp);
229 len = Mmsg(msg, _(" SDSocket closed.\n"));
230 sendit(msg.c_str(), len, sp);
237 len = Mmsg(msg, _("No Jobs running.\n"));
238 sendit(msg.c_str(), len, sp);
240 sendit(_("====\n"), 5, sp);
245 static void list_terminated_jobs(STATUS_PKT *sp)
247 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
249 struct s_last_job *je;
253 msg = _("\nTerminated Jobs:\n");
254 sendit(msg, strlen(msg), sp);
257 if (last_jobs->size() == 0) {
258 if (!sp->api) sendit(_("====\n"), 5, sp);
261 lock_last_jobs_list();
263 msg = _(" JobId Level Files Bytes Status Finished Name \n");
264 sendit(msg, strlen(msg), sp);
265 msg = _("======================================================================\n");
266 sendit(msg, strlen(msg), sp);
268 foreach_dlist(je, last_jobs) {
269 char JobName[MAX_NAME_LENGTH];
270 const char *termstat;
273 bstrftime_nc(dt, sizeof(dt), je->end_time);
274 switch (je->JobType) {
277 bstrncpy(level, " ", sizeof(level));
280 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
284 switch (je->JobStatus) {
286 termstat = _("Created");
289 case JS_ErrorTerminated:
290 termstat = _("Error");
293 termstat = _("Diffs");
296 termstat = _("Cancel");
302 termstat = _("Other");
305 bstrncpy(JobName, je->Job, sizeof(JobName));
306 /* There are three periods after the Job name */
308 for (int i=0; i<3; i++) {
309 if ((p=strrchr(JobName, '.')) != NULL) {
314 bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
317 edit_uint64_with_commas(je->JobFiles, b1),
318 edit_uint64_with_suffix(je->JobBytes, b2),
322 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
325 edit_uint64_with_commas(je->JobFiles, b1),
326 edit_uint64_with_suffix(je->JobBytes, b2),
330 sendit(buf, strlen(buf), sp);
332 if (!sp->api) sendit(_("====\n"), 5, sp);
333 unlock_last_jobs_list();
338 * Send to bsock (Director or Console)
340 static void sendit(const char *msg, int len, STATUS_PKT *sp)
343 BSOCK *user = sp->bs;
344 user->msg = check_pool_memory_size(user->msg, len+1);
345 memcpy(user->msg, msg, len+1);
346 user->msglen = len+1;
349 sp->callback(msg, len, sp->context);
354 * Status command from Director
356 int status_cmd(JCR *jcr)
358 BSOCK *user = jcr->dir_bsock;
363 sp.api = false; /* no API output */
366 user->signal(BNET_EOD);
371 * .status command from Director
373 int qstatus_cmd(JCR *jcr)
375 BSOCK *dir = jcr->dir_bsock;
382 cmd = get_memory(dir->msglen+1);
384 if (sscanf(dir->msg, qstatus, cmd) != 1) {
385 pm_strcpy(&jcr->errmsg, dir->msg);
386 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
387 dir->fsend(_("2900 Bad .status command, missing argument.\n"));
388 dir->signal(BNET_EOD);
394 if (strcmp(cmd, "current") == 0) {
395 dir->fsend(OKqstatus, cmd);
397 if (njcr->JobId != 0) {
398 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
402 } else if (strcmp(cmd, "last") == 0) {
403 dir->fsend(OKqstatus, cmd);
404 if ((last_jobs) && (last_jobs->size() > 0)) {
405 job = (s_last_job*)last_jobs->last();
406 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
408 } else if (strcasecmp(cmd, "header") == 0) {
410 list_status_header(&sp);
411 } else if (strcasecmp(cmd, "running") == 0) {
413 list_running_jobs(&sp);
414 } else if (strcasecmp(cmd, "terminated") == 0) {
416 list_terminated_jobs(&sp);
418 pm_strcpy(&jcr->errmsg, dir->msg);
419 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
420 dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
421 dir->signal(BNET_EOD);
426 dir->signal(BNET_EOD);
432 * Convert Job Level into a string
434 static const char *level_to_str(int level)
445 str = _("Incremental");
448 str = _("Differential");
453 case L_VERIFY_CATALOG:
454 str = _("Verify Catalog");
457 str = _("Init Catalog");
459 case L_VERIFY_VOLUME_TO_CATALOG:
460 str = _("Volume to Catalog");
462 case L_VERIFY_DISK_TO_CATALOG:
463 str = _("Disk to Catalog");
472 str = _("Unknown Job Level");
479 #if defined(HAVE_WIN32)
483 * Put message in Window List Box
485 char *bac_status(char *buf, int buf_len)
488 const char *termstat = _("Bacula Client: Idle");
489 struct s_last_job *job;
490 int stat = 0; /* Idle */
495 Dmsg0(1000, "Begin bac_status jcr loop.\n");
497 if (njcr->JobId != 0) {
499 termstat = _("Bacula Client: Running");
508 if (last_jobs->size() > 0) {
509 job = (struct s_last_job *)last_jobs->last();
510 stat = job->JobStatus;
511 switch (job->JobStatus) {
513 termstat = _("Bacula Client: Last Job Canceled");
515 case JS_ErrorTerminated:
517 termstat = _("Bacula Client: Last Job Failed");
521 termstat = _("Bacula Client: Last Job had Warnings");
526 Dmsg0(1000, "End bac_status jcr loop.\n");
530 bstrncpy(buf, termstat, buf_len);
535 #endif /* HAVE_WIN32 */