2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
17 * Bacula File Daemon Status routines
19 * Kern Sibbald, August MMI
25 #include "lib/status.h"
27 extern void *start_heap;
29 extern bool GetWindowsVersionString(char *buf, int maxsiz);
32 /* Forward referenced functions */
33 static void list_running_jobs(STATUS_PKT *sp);
34 static void list_status_header(STATUS_PKT *sp);
36 /* Static variables */
37 static char qstatus1[] = ".status %127s\n";
38 static char qstatus2[] = ".status %127s api=%d api_opts=%127s";
40 static char OKqstatus[] = "2000 OK .status\n";
41 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
43 #if defined(HAVE_WIN32)
49 extern VSSClient *g_pVSSClient;
55 * General status generator
57 void output_status(STATUS_PKT *sp)
59 list_status_header(sp);
60 list_running_jobs(sp);
61 list_terminated_jobs(sp); /* defined in lib/status.h */
65 static const bool have_lzo = true;
67 static const bool have_lzo = false;
70 static void list_status_header(STATUS_PKT *sp)
72 POOL_MEM msg(PM_MESSAGE);
73 char b1[32], b2[32], b3[32], b4[32], b5[35];
75 char dt[MAX_TIME_LENGTH];
77 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
78 my_name, VERSION, BDATE, VSS, HOST_OS,
80 sendit(msg.c_str(), len, sp);
81 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
82 len = Mmsg(msg, _("Daemon started %s. Jobs: run=%d running=%d.\n"),
83 dt, num_jobs_run, job_count());
84 sendit(msg.c_str(), len, sp);
85 #if defined(HAVE_WIN32)
87 if (GetWindowsVersionString(buf, sizeof(buf))) {
88 len = Mmsg(msg, "%s\n", buf);
89 sendit(msg.c_str(), len, sp);
91 if (debug_level > 0) {
93 privs = enable_backup_privileges(NULL, 1);
95 len = Mmsg(msg, "VSS %s, Priv 0x%x\n", g_pVSSClient?"enabled":"disabled", privs);
96 sendit(msg.c_str(), len, sp);
97 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
98 p_OpenProcessToken?"":"!",
99 p_AdjustTokenPrivileges?"":"!",
100 p_LookupPrivilegeValue?"":"!",
101 p_CreateFileA?"":"!",
102 p_CreateFileW?"":"!");
103 sendit(msg.c_str(), len, sp);
104 len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
107 p_GetFileAttributesA?"":"!",
108 p_GetFileAttributesW?"":"!",
109 p_GetFileAttributesExA?"":"!",
110 p_GetFileAttributesExW?"":"!",
111 p_SetFileAttributesA?"":"!",
112 p_SetFileAttributesW?"":"!",
114 p_BackupWrite?"":"!",
115 p_SetProcessShutdownParameters?"":"!");
116 sendit(msg.c_str(), len, sp);
117 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
118 p_WideCharToMultiByte?"":"!",
119 p_MultiByteToWideChar?"":"!",
120 p_FindFirstFileA?"":"!",
121 p_FindFirstFileW?"":"!",
122 p_FindNextFileA?"":"!",
123 p_FindNextFileW?"":"!",
124 p_SetCurrentDirectoryA?"":"!",
125 p_SetCurrentDirectoryW?"":"!");
126 sendit(msg.c_str(), len, sp);
127 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW,%sLZO\n",
128 p_GetCurrentDirectoryA?"":"!",
129 p_GetCurrentDirectoryW?"":"!",
130 p_GetVolumePathNameW?"":"!",
131 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, _(" Sizes: boffset_t=%d size_t=%d debug=%s trace=%d "
144 "mode=%d,%d bwlimit=%skB/s\n"),
145 sizeof(boffset_t), sizeof(size_t),
146 edit_uint64(debug_level, b2), get_trace(), (int)DEVELOPER_MODE, (int)BEEF,
147 edit_uint64_with_commas(me->max_bandwidth_per_job/1024, b1));
148 sendit(msg.c_str(), len, sp);
149 if (bplugin_list->size() > 0) {
152 pm_strcpy(msg, " Plugin: ");
153 foreach_alist(plugin, bplugin_list) {
154 len = pm_strcat(msg, plugin->file);
155 /* Print plugin version when debug activated */
156 if (debug_level > 0 && plugin->pinfo) {
157 pInfo *info = (pInfo *)plugin->pinfo;
159 pm_strcat(msg, NPRT(info->plugin_version));
160 len = pm_strcat(msg, ")");
163 pm_strcat(msg, "\n ");
168 len = pm_strcat(msg, "\n");
169 sendit(msg.c_str(), len, sp);
174 * List running jobs in for humans.
176 static void list_running_jobs_plain(STATUS_PKT *sp)
178 int total_sec, inst_sec, total_bps, inst_bps;
179 POOL_MEM msg(PM_MESSAGE);
180 char b1[50], b2[50], b3[50], b4[50], b5[50];
184 time_t now = time(NULL);
185 char dt[MAX_TIME_LENGTH];
187 Dmsg0(1000, "Begin status jcr loop.\n");
188 len = Mmsg(msg, _("\nRunning Jobs:\n"));
189 sendit(msg.c_str(), len, sp);
190 const char *vss = "";
192 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
197 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
198 if (njcr->JobId == 0) {
199 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
201 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
202 njcr->JobId, njcr->Job);
203 sendit(msg.c_str(), len, sp);
204 len = Mmsg(msg, _(" %s%s %s Job started: %s\n"),
205 vss, job_level_to_str(njcr->getJobLevel()),
206 job_type_to_str(njcr->getJobType()), dt);
208 sendit(msg.c_str(), len, sp);
209 if (njcr->JobId == 0) {
212 if (njcr->last_time == 0) {
213 njcr->last_time = njcr->start_time;
215 total_sec = now - njcr->start_time;
216 inst_sec = now - njcr->last_time;
217 if (total_sec <= 0) {
223 /* Instanteous bps not smoothed */
224 inst_bps = (njcr->JobBytes - njcr->LastJobBytes) / inst_sec;
225 if (njcr->LastRate <= 0) {
226 njcr->LastRate = inst_bps;
228 /* Smooth the instantaneous bps a bit */
229 inst_bps = (2 * njcr->LastRate + inst_bps) / 3;
230 /* total bps (AveBytes/sec) since start of job */
231 total_bps = njcr->JobBytes / total_sec;
232 len = Mmsg(msg, _(" Files=%s Bytes=%s AveBytes/sec=%s LastBytes/sec=%s Errors=%d\n"
234 edit_uint64_with_commas(njcr->JobFiles, b1),
235 edit_uint64_with_commas(njcr->JobBytes, b2),
236 edit_uint64_with_commas(total_bps, b3),
237 edit_uint64_with_commas(inst_bps, b4),
238 njcr->JobErrors, edit_uint64_with_commas(njcr->max_bandwidth, b5));
239 sendit(msg.c_str(), len, sp);
241 if (njcr->is_JobType(JT_RESTORE) && njcr->ExpectedFiles > 0) {
242 len = Mmsg(msg, _(" Files: Restored=%s Expected=%s Completed=%d%%\n"),
243 edit_uint64_with_commas(njcr->num_files_examined, b1),
244 edit_uint64_with_commas(njcr->ExpectedFiles, b2),
245 (100*njcr->num_files_examined)/njcr->ExpectedFiles);
247 len = Mmsg(msg, _(" Files: Examined=%s Backed up=%s\n"),
248 edit_uint64_with_commas(njcr->num_files_examined, b1),
249 edit_uint64_with_commas(njcr->JobFiles, b2));
251 /* Update only every 10 seconds */
252 if (now - njcr->last_time > 10) {
253 njcr->LastRate = inst_bps;
254 njcr->LastJobBytes = njcr->JobBytes;
255 njcr->last_time = now;
257 sendit(msg.c_str(), len, sp);
258 if (njcr->JobFiles > 0) {
260 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
262 sendit(msg.c_str(), len, sp);
266 if (njcr->store_bsock) {
267 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
268 njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
269 sendit(msg.c_str(), len, sp);
271 len = Mmsg(msg, _(" SDSocket closed.\n"));
272 sendit(msg.c_str(), len, sp);
278 len = Mmsg(msg, _("No Jobs running.\n"));
279 sendit(msg.c_str(), len, sp);
281 sendit(_("====\n"), 5, sp);
284 static void list_running_jobs_api(STATUS_PKT *sp)
287 POOL_MEM msg(PM_MESSAGE);
288 char b1[32], b2[32], b3[32];
291 char dt[MAX_TIME_LENGTH];
293 * List running jobs for Bat/Bweb (simple to parse)
297 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
302 bstrutime(dt, sizeof(dt), njcr->start_time);
303 if (njcr->JobId == 0) {
304 len = Mmsg(msg, "DirectorConnected=%s\n", dt);
306 len = Mmsg(msg, "JobId=%d\n Job=%s\n",
307 njcr->JobId, njcr->Job);
308 sendit(msg.c_str(), len, sp);
309 len = Mmsg(msg," VSS=%d\n Level=%c\n JobType=%c\n JobStarted=%s\n",
310 vss, njcr->getJobLevel(),
311 njcr->getJobType(), dt);
313 sendit(msg.c_str(), len, sp);
314 if (njcr->JobId == 0) {
317 sec = time(NULL) - njcr->start_time;
321 bps = (int)(njcr->JobBytes / sec);
322 len = Mmsg(msg, " Files=%s\n Bytes=%s\n Bytes/sec=%s\n Errors=%d\n",
323 edit_uint64(njcr->JobFiles, b1),
324 edit_uint64(njcr->JobBytes, b2),
325 edit_uint64(bps, b3),
327 sendit(msg.c_str(), len, sp);
328 len = Mmsg(msg, " Files Examined=%s\n",
329 edit_uint64(njcr->num_files_examined, b1));
330 sendit(msg.c_str(), len, sp);
331 if (njcr->JobFiles > 0) {
333 len = Mmsg(msg, " Processing file=%s\n", njcr->last_fname);
335 sendit(msg.c_str(), len, sp);
338 if (njcr->store_bsock) {
339 len = Mmsg(msg, " SDReadSeqNo=%" lld "\n fd=%d\n",
340 njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
341 sendit(msg.c_str(), len, sp);
343 len = Mmsg(msg, _(" SDSocket=closed\n"));
344 sendit(msg.c_str(), len, sp);
350 static void list_running_jobs(STATUS_PKT *sp)
353 list_running_jobs_api(sp);
355 list_running_jobs_plain(sp);
360 * Status command from Director
362 int status_cmd(JCR *jcr)
364 BSOCK *user = jcr->dir_bsock;
369 sp.api = false; /* no API output */
372 user->signal(BNET_EOD);
377 * .status command from Director
379 int qstatus_cmd(JCR *jcr)
381 BSOCK *dir = jcr->dir_bsock;
388 cmd = get_memory(dir->msglen+1);
390 if (sscanf(dir->msg, qstatus2, cmd, &sp.api, sp.api_opts) != 3) {
391 if (sscanf(dir->msg, qstatus1, cmd) != 1) {
392 pm_strcpy(&jcr->errmsg, dir->msg);
393 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
394 dir->fsend(_("2900 Bad .status command, missing argument.\n"));
395 dir->signal(BNET_EOD);
402 if (strcasecmp(cmd, "current") == 0) {
403 dir->fsend(OKqstatus, cmd);
405 if (njcr->JobId != 0) {
406 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
410 } else if (strcasecmp(cmd, "last") == 0) {
411 dir->fsend(OKqstatus, cmd);
412 if ((last_jobs) && (last_jobs->size() > 0)) {
413 job = (s_last_job*)last_jobs->last();
414 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
416 } else if (strcasecmp(cmd, "header") == 0) {
418 list_status_header(&sp);
419 } else if (strcasecmp(cmd, "running") == 0) {
421 list_running_jobs(&sp);
422 } else if (strcasecmp(cmd, "terminated") == 0) {
423 sp.api = MAX(sp.api, 1);
424 list_terminated_jobs(&sp); /* defined in lib/status.h */
426 pm_strcpy(&jcr->errmsg, dir->msg);
427 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
428 dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
429 dir->signal(BNET_EOD);
434 dir->signal(BNET_EOD);