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 Job started: %s\n"),
195 vss, job_type_to_str(njcr->get_JobType()), 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 */