2 * Bacula File Daemon Status routines
4 * Kern Sibbald, August MMI
10 Copyright (C) 2001-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
27 /* Forward referenced functions */
28 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
29 static void bsock_sendit(const char *msg, int len, void *arg);
30 static const char *level_to_str(int level);
32 /* Static variables */
33 static char qstatus[] = ".status %s\n";
35 static char OKqstatus[] = "2000 OK .status\n";
36 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
38 #if defined(HAVE_WIN32)
44 extern VSSClient *g_pVSSClient;
50 * General status generator
52 void output_status(void sendit(const char *msg, int len, void *sarg), void *arg)
55 char *msg, b1[32], b2[32], b3[32], b4[32];
59 char dt[MAX_TIME_LENGTH];
61 msg = (char *)get_pool_memory(PM_MESSAGE);
62 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
63 my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
64 sendit(msg, len, arg);
65 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
66 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
67 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
68 sendit(msg, len, arg);
69 #if defined(HAVE_WIN32)
70 if (debug_level > 0) {
72 privs = enable_backup_privileges(NULL, 1);
74 len = Mmsg(msg, "Priv 0x%x\n", privs);
75 sendit(msg, len, arg);
76 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
77 p_OpenProcessToken?"":"!",
78 p_AdjustTokenPrivileges?"":"!",
79 p_LookupPrivilegeValue?"":"!",
81 p_CreateFileW?"":"!");
82 sendit(msg, len, arg);
83 len = Mmsg(msg, " %sWUL,%sWMKD,%sWOP,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
86 p_GetFileAttributesA?"":"!",
87 p_GetFileAttributesW?"":"!",
88 p_GetFileAttributesExA?"":"!",
89 p_GetFileAttributesExW?"":"!",
90 p_SetFileAttributesA?"":"!",
91 p_SetFileAttributesW?"":"!",
94 p_SetProcessShutdownParameters?"":"!");
95 sendit(msg, len, arg);
96 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
97 p_WideCharToMultiByte?"":"!",
98 p_MultiByteToWideChar?"":"!",
99 p_FindFirstFileA?"":"!",
100 p_FindFirstFileW?"":"!",
101 p_FindNextFileA?"":"!",
102 p_FindNextFileW?"":"!",
103 p_SetCurrentDirectoryA?"":"!",
104 p_SetCurrentDirectoryW?"":"!");
105 sendit(msg, len, arg);
106 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",
107 p_GetCurrentDirectoryA?"":"!",
108 p_GetCurrentDirectoryW?"":"!",
109 p_GetVolumePathNameW?"":"!",
110 p_GetVolumeNameForVolumeMountPointW?"":"!");
111 sendit(msg, len, arg);
114 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
115 edit_uint64_with_commas(sm_bytes, b1),
116 edit_uint64_with_commas(sm_max_bytes, b2),
117 edit_uint64_with_commas(sm_buffers, b3),
118 edit_uint64_with_commas(sm_max_buffers, b4));
119 sendit(msg, len, arg);
120 len = Mmsg(msg, _(" Sizeof: boffset_t=%d size_t=%d debug=%d trace=%d\n"),
121 sizeof(boffset_t), sizeof(size_t), debug_level, get_trace());
122 sendit(msg, len, arg);
127 Dmsg0(1000, "Begin status jcr loop.\n");
128 len = Mmsg(msg, _("\nRunning Jobs:\n"));
129 sendit(msg, len, arg);
132 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
137 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
138 if (njcr->JobId == 0) {
139 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
141 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
142 njcr->JobId, njcr->Job);
143 sendit(msg, len, arg);
144 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
145 vss, job_type_to_str(njcr->JobType), dt);
147 sendit(msg, len, arg);
148 if (njcr->JobId == 0) {
151 sec = time(NULL) - njcr->start_time;
155 bps = (int)(njcr->JobBytes / sec);
156 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
157 edit_uint64_with_commas(njcr->JobFiles, b1),
158 edit_uint64_with_commas(njcr->JobBytes, b2),
159 edit_uint64_with_commas(bps, b3));
160 sendit(msg, len, arg);
161 len = Mmsg(msg, _(" Files Examined=%s\n"),
162 edit_uint64_with_commas(njcr->num_files_examined, b1));
163 sendit(msg, len, arg);
164 if (njcr->JobFiles > 0) {
166 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
168 sendit(msg, len, arg);
172 if (njcr->store_bsock) {
173 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
174 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
175 sendit(msg, len, arg);
177 len = Mmsg(msg, _(" SDSocket closed.\n"));
178 sendit(msg, len, arg);
184 len = Mmsg(msg, _("No Jobs running.\n"));
185 sendit(msg, len, arg);
187 sendit(_("====\n"), 5, arg);
189 list_terminated_jobs(sendit, arg);
191 free_pool_memory(msg);
194 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
196 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
198 struct s_last_job *je;
201 msg = _("\nTerminated Jobs:\n");
202 sendit(msg, strlen(msg), arg);
204 if (last_jobs->size() == 0) {
205 sendit(_("====\n"), 5, arg);
208 lock_last_jobs_list();
209 msg = _(" JobId Level Files Bytes Status Finished Name \n");
210 sendit(msg, strlen(msg), arg);
211 msg = _("======================================================================\n");
212 sendit(msg, strlen(msg), arg);
213 foreach_dlist(je, last_jobs) {
214 char JobName[MAX_NAME_LENGTH];
215 const char *termstat;
218 bstrftime_nc(dt, sizeof(dt), je->end_time);
219 switch (je->JobType) {
222 bstrncpy(level, " ", sizeof(level));
225 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
229 switch (je->JobStatus) {
231 termstat = _("Created");
234 case JS_ErrorTerminated:
235 termstat = _("Error");
238 termstat = _("Diffs");
241 termstat = _("Cancel");
247 termstat = _("Other");
250 bstrncpy(JobName, je->Job, sizeof(JobName));
251 /* There are three periods after the Job name */
253 for (int i=0; i<3; i++) {
254 if ((p=strrchr(JobName, '.')) != NULL) {
258 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
261 edit_uint64_with_commas(je->JobFiles, b1),
262 edit_uint64_with_suffix(je->JobBytes, b2),
265 sendit(buf, strlen(buf), arg);
267 sendit(_("====\n"), 5, arg);
268 unlock_last_jobs_list();
273 * Send to bsock (Director or Console)
275 static void bsock_sendit(const char *msg, int len, void *arg)
277 BSOCK *user = (BSOCK *)arg;
279 user->msg = check_pool_memory_size(user->msg, len+1);
280 memcpy(user->msg, msg, len+1);
281 user->msglen = len+1;
286 * Status command from Director
288 int status_cmd(JCR *jcr)
290 BSOCK *user = jcr->dir_bsock;
292 bnet_fsend(user, "\n");
293 output_status(bsock_sendit, (void *)user);
295 bnet_sig(user, BNET_EOD);
300 * .status command from Director
302 int qstatus_cmd(JCR *jcr)
304 BSOCK *dir = jcr->dir_bsock;
309 time = get_memory(dir->msglen+1);
311 if (sscanf(dir->msg, qstatus, time) != 1) {
312 pm_strcpy(&jcr->errmsg, dir->msg);
313 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
314 bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
315 bnet_sig(dir, BNET_EOD);
321 if (strcmp(time, "current") == 0) {
322 bnet_fsend(dir, OKqstatus, time);
324 if (njcr->JobId != 0) {
325 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
329 } else if (strcmp(time, "last") == 0) {
330 bnet_fsend(dir, OKqstatus, time);
331 if ((last_jobs) && (last_jobs->size() > 0)) {
332 job = (s_last_job*)last_jobs->last();
333 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
336 pm_strcpy(&jcr->errmsg, dir->msg);
337 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
338 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
339 bnet_sig(dir, BNET_EOD);
344 bnet_sig(dir, BNET_EOD);
350 * Convert Job Level into a string
352 static const char *level_to_str(int level)
363 str = _("Incremental");
366 str = _("Differential");
371 case L_VERIFY_CATALOG:
372 str = _("Verify Catalog");
375 str = _("Init Catalog");
377 case L_VERIFY_VOLUME_TO_CATALOG:
378 str = _("Volume to Catalog");
380 case L_VERIFY_DISK_TO_CATALOG:
381 str = _("Disk to Catalog");
390 str = _("Unknown Job Level");
397 #if defined(HAVE_WIN32)
401 * Put message in Window List Box
403 char *bac_status(char *buf, int buf_len)
406 const char *termstat = _("Bacula Client: Idle");
407 struct s_last_job *job;
408 int stat = 0; /* Idle */
413 Dmsg0(1000, "Begin bac_status jcr loop.\n");
415 if (njcr->JobId != 0) {
417 termstat = _("Bacula Client: Running");
426 if (last_jobs->size() > 0) {
427 job = (struct s_last_job *)last_jobs->last();
428 stat = job->JobStatus;
429 switch (job->JobStatus) {
431 termstat = _("Bacula Client: Last Job Canceled");
433 case JS_ErrorTerminated:
435 termstat = _("Bacula Client: Last Job Failed");
439 termstat = _("Bacula Client: Last Job had Warnings");
444 Dmsg0(1000, "End bac_status jcr loop.\n");
448 bstrncpy(buf, termstat, buf_len);
453 #endif /* HAVE_WIN32 */