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\n"),
142 sizeof(boffset_t), sizeof(size_t), debug_level, get_trace());
143 sendit(msg.c_str(), len, sp);
144 if (debug_level > 0 && plugin_list->size() > 0) {
147 pm_strcpy(msg, "Plugin: ");
148 foreach_alist(plugin, plugin_list) {
149 len = pm_strcat(msg, plugin->file);
151 pm_strcat(msg, "\n ");
156 len = pm_strcat(msg, "\n");
157 sendit(msg.c_str(), len, sp);
161 static void list_running_jobs(STATUS_PKT *sp)
164 POOL_MEM msg(PM_MESSAGE);
165 char b1[32], b2[32], b3[32];
169 char dt[MAX_TIME_LENGTH];
173 Dmsg0(1000, "Begin status jcr loop.\n");
175 len = Mmsg(msg, _("\nRunning Jobs:\n"));
176 sendit(msg.c_str(), len, sp);
178 const char *vss = "";
180 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
185 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
186 if (njcr->JobId == 0) {
187 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
189 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
190 njcr->JobId, njcr->Job);
191 sendit(msg.c_str(), len, sp);
192 len = Mmsg(msg, _(" %s%s %s Job started: %s\n"),
193 vss, level_to_str(njcr->getJobLevel()),
194 job_type_to_str(njcr->getJobType()), dt);
196 sendit(msg.c_str(), len, sp);
197 if (njcr->JobId == 0) {
200 sec = time(NULL) - njcr->start_time;
204 bps = (int)(njcr->JobBytes / sec);
205 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s Errors=%d\n"),
206 edit_uint64_with_commas(njcr->JobFiles, b1),
207 edit_uint64_with_commas(njcr->JobBytes, b2),
208 edit_uint64_with_commas(bps, b3),
210 sendit(msg.c_str(), len, sp);
211 len = Mmsg(msg, _(" Files Examined=%s\n"),
212 edit_uint64_with_commas(njcr->num_files_examined, b1));
213 sendit(msg.c_str(), len, sp);
214 if (njcr->JobFiles > 0) {
216 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
218 sendit(msg.c_str(), len, sp);
222 if (njcr->store_bsock) {
223 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
224 njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
225 sendit(msg.c_str(), len, sp);
227 len = Mmsg(msg, _(" SDSocket closed.\n"));
228 sendit(msg.c_str(), len, sp);
235 len = Mmsg(msg, _("No Jobs running.\n"));
236 sendit(msg.c_str(), len, sp);
238 sendit(_("====\n"), 5, sp);
243 static void list_terminated_jobs(STATUS_PKT *sp)
245 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
247 struct s_last_job *je;
251 msg = _("\nTerminated Jobs:\n");
252 sendit(msg, strlen(msg), sp);
255 if (last_jobs->size() == 0) {
256 if (!sp->api) sendit(_("====\n"), 5, sp);
259 lock_last_jobs_list();
261 msg = _(" JobId Level Files Bytes Status Finished Name \n");
262 sendit(msg, strlen(msg), sp);
263 msg = _("======================================================================\n");
264 sendit(msg, strlen(msg), sp);
266 foreach_dlist(je, last_jobs) {
267 char JobName[MAX_NAME_LENGTH];
268 const char *termstat;
271 bstrftime_nc(dt, sizeof(dt), je->end_time);
272 switch (je->JobType) {
275 bstrncpy(level, " ", sizeof(level));
278 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
282 switch (je->JobStatus) {
284 termstat = _("Created");
287 case JS_ErrorTerminated:
288 termstat = _("Error");
291 termstat = _("Diffs");
294 termstat = _("Cancel");
300 termstat = _("Other");
303 bstrncpy(JobName, je->Job, sizeof(JobName));
304 /* There are three periods after the Job name */
306 for (int i=0; i<3; i++) {
307 if ((p=strrchr(JobName, '.')) != NULL) {
312 bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
315 edit_uint64_with_commas(je->JobFiles, b1),
316 edit_uint64_with_suffix(je->JobBytes, b2),
320 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
323 edit_uint64_with_commas(je->JobFiles, b1),
324 edit_uint64_with_suffix(je->JobBytes, b2),
328 sendit(buf, strlen(buf), sp);
330 if (!sp->api) sendit(_("====\n"), 5, sp);
331 unlock_last_jobs_list();
336 * Send to bsock (Director or Console)
338 static void sendit(const char *msg, int len, STATUS_PKT *sp)
341 BSOCK *user = sp->bs;
342 user->msg = check_pool_memory_size(user->msg, len+1);
343 memcpy(user->msg, msg, len+1);
344 user->msglen = len+1;
347 sp->callback(msg, len, sp->context);
352 * Status command from Director
354 int status_cmd(JCR *jcr)
356 BSOCK *user = jcr->dir_bsock;
361 sp.api = false; /* no API output */
364 user->signal(BNET_EOD);
369 * .status command from Director
371 int qstatus_cmd(JCR *jcr)
373 BSOCK *dir = jcr->dir_bsock;
380 cmd = get_memory(dir->msglen+1);
382 if (sscanf(dir->msg, qstatus, cmd) != 1) {
383 pm_strcpy(&jcr->errmsg, dir->msg);
384 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
385 dir->fsend(_("2900 Bad .status command, missing argument.\n"));
386 dir->signal(BNET_EOD);
392 if (strcmp(cmd, "current") == 0) {
393 dir->fsend(OKqstatus, cmd);
395 if (njcr->JobId != 0) {
396 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
400 } else if (strcmp(cmd, "last") == 0) {
401 dir->fsend(OKqstatus, cmd);
402 if ((last_jobs) && (last_jobs->size() > 0)) {
403 job = (s_last_job*)last_jobs->last();
404 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
406 } else if (strcasecmp(cmd, "header") == 0) {
408 list_status_header(&sp);
409 } else if (strcasecmp(cmd, "running") == 0) {
411 list_running_jobs(&sp);
412 } else if (strcasecmp(cmd, "terminated") == 0) {
414 list_terminated_jobs(&sp);
416 pm_strcpy(&jcr->errmsg, dir->msg);
417 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
418 dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
419 dir->signal(BNET_EOD);
424 dir->signal(BNET_EOD);
430 * Convert Job Level into a string
432 static const char *level_to_str(int level)
443 str = _("Incremental");
446 str = _("Differential");
451 case L_VERIFY_CATALOG:
452 str = _("Verify Catalog");
455 str = _("Init Catalog");
457 case L_VERIFY_VOLUME_TO_CATALOG:
458 str = _("Volume to Catalog");
460 case L_VERIFY_DISK_TO_CATALOG:
461 str = _("Disk to Catalog");
470 str = _("Unknown Job Level");
477 #if defined(HAVE_WIN32)
481 * Put message in Window List Box
483 char *bac_status(char *buf, int buf_len)
486 const char *termstat = _("Bacula Client: Idle");
487 struct s_last_job *job;
488 int stat = 0; /* Idle */
493 Dmsg0(1000, "Begin bac_status jcr loop.\n");
495 if (njcr->JobId != 0) {
497 termstat = _("Bacula Client: Running");
506 if (last_jobs->size() > 0) {
507 job = (struct s_last_job *)last_jobs->last();
508 stat = job->JobStatus;
509 switch (job->JobStatus) {
511 termstat = _("Bacula Client: Last Job Canceled");
513 case JS_ErrorTerminated:
515 termstat = _("Bacula Client: Last Job Failed");
519 termstat = _("Bacula Client: Last Job had Warnings");
524 Dmsg0(1000, "End bac_status jcr loop.\n");
528 bstrncpy(buf, termstat, buf_len);
533 #endif /* HAVE_WIN32 */