2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many 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 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula File Daemon Status routines
22 * Kern Sibbald, August MMI
28 #include "lib/status.h"
30 extern void *start_heap;
32 extern bool GetWindowsVersionString(char *buf, int maxsiz);
35 /* Forward referenced functions */
36 static void list_running_jobs(STATUS_PKT *sp);
37 static void list_status_header(STATUS_PKT *sp);
39 /* Static variables */
40 static char qstatus1[] = ".status %127s\n";
41 static char qstatus2[] = ".status %127s api=%d api_opts=%127s";
43 static char OKqstatus[] = "2000 OK .status\n";
44 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
49 * General status generator
51 void output_status(STATUS_PKT *sp)
53 list_status_header(sp);
54 list_running_jobs(sp);
55 list_terminated_jobs(sp); /* defined in lib/status.h */
59 static const bool have_lzo = true;
61 static const bool have_lzo = false;
65 static void list_status_header(STATUS_PKT *sp)
67 POOL_MEM msg(PM_MESSAGE);
68 char b1[32], b2[32], b3[32], b4[32], b5[35];
70 char dt[MAX_TIME_LENGTH];
72 len = Mmsg(msg, _("%s %sVersion: %s (%s) %s %s %s %s\n"),
73 my_name, "", VERSION, BDATE, VSS, HOST_OS,
75 sendit(msg.c_str(), len, sp);
76 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
77 len = Mmsg(msg, _("Daemon started %s. Jobs: run=%d running=%d.\n"),
78 dt, num_jobs_run, job_count());
79 sendit(msg.c_str(), len, sp);
80 len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
81 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
82 edit_uint64_with_commas(sm_bytes, b2),
83 edit_uint64_with_commas(sm_max_bytes, b3),
84 edit_uint64_with_commas(sm_buffers, b4),
85 edit_uint64_with_commas(sm_max_buffers, b5));
86 sendit(msg.c_str(), len, sp);
87 len = Mmsg(msg, _(" Sizes: boffset_t=%d size_t=%d debug=%s trace=%d "
88 "mode=%d bwlimit=%skB/s\n"),
89 sizeof(boffset_t), sizeof(size_t),
90 edit_uint64(debug_level, b2), get_trace(), (int)DEVELOPER_MODE,
91 edit_uint64_with_commas(me->max_bandwidth_per_job/1024, b1));
92 sendit(msg.c_str(), len, sp);
93 if (b_plugin_list && b_plugin_list->size() > 0) {
96 pm_strcpy(msg, " Plugin: ");
97 foreach_alist(plugin, b_plugin_list) {
98 len = pm_strcat(msg, plugin->file);
99 /* Print plugin version when debug activated */
100 if (debug_level > 0 && plugin->pinfo) {
101 pInfo *info = (pInfo *)plugin->pinfo;
103 pm_strcat(msg, NPRT(info->plugin_version));
104 len = pm_strcat(msg, ")");
107 pm_strcat(msg, "\n ");
112 len = pm_strcat(msg, "\n");
113 sendit(msg.c_str(), len, sp);
118 * List running jobs in for humans.
120 static void list_running_jobs_plain(STATUS_PKT *sp)
122 int total_sec, inst_sec;
123 uint64_t total_bps, inst_bps;
124 POOL_MEM msg(PM_MESSAGE);
125 char b1[50], b2[50], b3[50], b4[50], b5[50], b6[50];
129 time_t now = time(NULL);
130 char dt[MAX_TIME_LENGTH];
132 Dmsg0(1000, "Begin status jcr loop.\n");
133 len = Mmsg(msg, _("\nRunning Jobs:\n"));
134 sendit(msg.c_str(), len, sp);
135 const char *vss = "";
137 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
138 if (njcr->JobId == 0) {
139 len = Mmsg(msg, _("Director connected %sat: %s\n"),
140 (njcr->dir_bsock && njcr->dir_bsock->tls)?_("using TLS "):"",
143 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
144 njcr->JobId, njcr->Job);
145 sendit(msg.c_str(), len, sp);
146 len = Mmsg(msg, _(" %s%s %s Job started: %s\n"),
147 vss, job_level_to_str(njcr->getJobLevel()),
148 job_type_to_str(njcr->getJobType()), dt);
150 sendit(msg.c_str(), len, sp);
151 if (njcr->JobId == 0) {
154 if (njcr->last_time == 0) {
155 njcr->last_time = njcr->start_time;
157 total_sec = now - njcr->start_time;
158 inst_sec = now - njcr->last_time;
159 if (total_sec <= 0) {
165 /* Instanteous bps not smoothed */
166 inst_bps = (njcr->JobBytes - njcr->LastJobBytes) / inst_sec;
167 if (njcr->LastRate <= 0) {
168 njcr->LastRate = inst_bps;
170 /* Smooth the instantaneous bps a bit */
171 inst_bps = (2 * njcr->LastRate + inst_bps) / 3;
172 /* total bps (AveBytes/sec) since start of job */
173 total_bps = njcr->JobBytes / total_sec;
174 len = Mmsg(msg, _(" Files=%s Bytes=%s AveBytes/sec=%s LastBytes/sec=%s Errors=%d\n"
175 " Bwlimit=%s ReadBytes=%s\n"),
176 edit_uint64_with_commas(njcr->JobFiles, b1),
177 edit_uint64_with_commas(njcr->JobBytes, b2),
178 edit_uint64_with_commas(total_bps, b3),
179 edit_uint64_with_commas(inst_bps, b4),
180 njcr->JobErrors, edit_uint64_with_commas(njcr->max_bandwidth, b5),
181 edit_uint64_with_commas(njcr->ReadBytes, b6));
182 sendit(msg.c_str(), len, sp);
184 if (njcr->is_JobType(JT_RESTORE) && njcr->ExpectedFiles > 0) {
185 len = Mmsg(msg, _(" Files: Restored=%s Expected=%s Completed=%d%%\n"),
186 edit_uint64_with_commas(njcr->num_files_examined, b1),
187 edit_uint64_with_commas(njcr->ExpectedFiles, b2),
188 (100*njcr->num_files_examined)/njcr->ExpectedFiles);
190 len = Mmsg(msg, _(" Files: Examined=%s Backed up=%s\n"),
191 edit_uint64_with_commas(njcr->num_files_examined, b1),
192 edit_uint64_with_commas(njcr->JobFiles, b2));
194 /* Update only every 10 seconds */
195 if (now - njcr->last_time > 10) {
196 njcr->LastRate = inst_bps;
197 njcr->LastJobBytes = njcr->JobBytes;
198 njcr->last_time = now;
200 sendit(msg.c_str(), len, sp);
201 if (njcr->JobFiles > 0) {
203 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
205 sendit(msg.c_str(), len, sp);
209 if (njcr->store_bsock) {
210 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d SDtls=%d\n",
211 njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd,
212 (njcr->store_bsock->tls)?1:0);
213 sendit(msg.c_str(), len, sp);
215 len = Mmsg(msg, _(" SDSocket closed.\n"));
216 sendit(msg.c_str(), len, sp);
222 len = Mmsg(msg, _("No Jobs running.\n"));
223 sendit(msg.c_str(), len, sp);
225 sendit(_("====\n"), 5, sp);
228 static void list_running_jobs(STATUS_PKT *sp)
230 list_running_jobs_plain(sp);
234 * Status command from Director
236 int status_cmd(JCR *jcr)
238 BSOCK *user = jcr->dir_bsock;
243 sp.api = false; /* no API output */
246 user->signal(BNET_EOD);
251 * .status command from Director
253 int qstatus_cmd(JCR *jcr)
255 BSOCK *dir = jcr->dir_bsock;
262 cmd = get_memory(dir->msglen+1);
264 if (sscanf(dir->msg, qstatus2, cmd, &sp.api, sp.api_opts) != 3) {
265 if (sscanf(dir->msg, qstatus1, cmd) != 1) {
266 pm_strcpy(&jcr->errmsg, dir->msg);
267 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
268 dir->fsend(_("2900 Bad .status command, missing argument.\n"));
269 dir->signal(BNET_EOD);
276 if (strcasecmp(cmd, "current") == 0) {
277 dir->fsend(OKqstatus, cmd);
279 if (njcr->JobId != 0) {
280 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
284 } else if (strcasecmp(cmd, "last") == 0) {
285 dir->fsend(OKqstatus, cmd);
286 if ((last_jobs) && (last_jobs->size() > 0)) {
287 job = (s_last_job*)last_jobs->last();
288 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
290 } else if (strcasecmp(cmd, "header") == 0) {
292 list_status_header(&sp);
293 } else if (strcasecmp(cmd, "running") == 0) {
295 list_running_jobs(&sp);
296 } else if (strcasecmp(cmd, "terminated") == 0) {
297 sp.api = MAX(sp.api, 1);
298 list_terminated_jobs(&sp); /* defined in lib/status.h */
300 pm_strcpy(&jcr->errmsg, dir->msg);
301 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
302 dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
303 dir->signal(BNET_EOD);
308 dir->signal(BNET_EOD);