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);
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);
148 static void list_running_jobs(STATUS_PKT *sp)
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)
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 (!sp->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 (!sp->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;
347 sp.api = false; /* no API output */
350 user->signal(BNET_EOD);
355 * .status command from Director
357 int qstatus_cmd(JCR *jcr)
359 BSOCK *dir = jcr->dir_bsock;
366 cmd = get_memory(dir->msglen+1);
368 if (sscanf(dir->msg, qstatus, cmd) != 1) {
369 pm_strcpy(&jcr->errmsg, dir->msg);
370 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
371 dir->fsend(_("2900 Bad .status command, missing argument.\n"));
372 dir->signal(BNET_EOD);
378 if (strcmp(cmd, "current") == 0) {
379 dir->fsend(OKqstatus, cmd);
381 if (njcr->JobId != 0) {
382 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
386 } else if (strcmp(cmd, "last") == 0) {
387 dir->fsend(OKqstatus, cmd);
388 if ((last_jobs) && (last_jobs->size() > 0)) {
389 job = (s_last_job*)last_jobs->last();
390 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
392 } else if (strcasecmp(cmd, "header") == 0) {
394 list_status_header(&sp);
395 } else if (strcasecmp(cmd, "running") == 0) {
397 list_running_jobs(&sp);
398 } else if (strcasecmp(cmd, "terminated") == 0) {
400 list_terminated_jobs(&sp);
402 pm_strcpy(&jcr->errmsg, dir->msg);
403 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
404 dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
405 dir->signal(BNET_EOD);
410 dir->signal(BNET_EOD);
416 * Convert Job Level into a string
418 static const char *level_to_str(int level)
429 str = _("Incremental");
432 str = _("Differential");
437 case L_VERIFY_CATALOG:
438 str = _("Verify Catalog");
441 str = _("Init Catalog");
443 case L_VERIFY_VOLUME_TO_CATALOG:
444 str = _("Volume to Catalog");
446 case L_VERIFY_DISK_TO_CATALOG:
447 str = _("Disk to Catalog");
456 str = _("Unknown Job Level");
463 #if defined(HAVE_WIN32)
467 * Put message in Window List Box
469 char *bac_status(char *buf, int buf_len)
472 const char *termstat = _("Bacula Client: Idle");
473 struct s_last_job *job;
474 int stat = 0; /* Idle */
479 Dmsg0(1000, "Begin bac_status jcr loop.\n");
481 if (njcr->JobId != 0) {
483 termstat = _("Bacula Client: Running");
492 if (last_jobs->size() > 0) {
493 job = (struct s_last_job *)last_jobs->last();
494 stat = job->JobStatus;
495 switch (job->JobStatus) {
497 termstat = _("Bacula Client: Last Job Canceled");
499 case JS_ErrorTerminated:
501 termstat = _("Bacula Client: Last Job Failed");
505 termstat = _("Bacula Client: Last Job had Warnings");
510 Dmsg0(1000, "End bac_status jcr loop.\n");
514 bstrncpy(buf, termstat, buf_len);
519 #endif /* HAVE_WIN32 */