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 static void do_status(void sendit(const char *msg, int len, void *sarg), void *arg)
55 char *msg, b1[32], b2[32], b3[32], b4[32];
58 char dt[MAX_TIME_LENGTH];
60 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",
87 p_GetFileAttributesA?"":"!",
88 p_GetFileAttributesW?"":"!",
89 p_GetFileAttributesExA?"":"!",
90 p_GetFileAttributesExW?"":"!",
91 p_SetFileAttributesA?"":"!",
92 p_SetFileAttributesW?"":"!",
95 p_SetProcessShutdownParameters?"":"!");
96 sendit(msg, len, arg);
97 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
98 p_WideCharToMultiByte?"":"!",
99 p_MultiByteToWideChar?"":"!",
100 p_FindFirstFileA?"":"!",
101 p_FindFirstFileW?"":"!",
102 p_FindNextFileA?"":"!",
103 p_FindNextFileW?"":"!",
104 p_SetCurrentDirectoryA?"":"!",
105 p_SetCurrentDirectoryW?"":"!");
106 sendit(msg, len, arg);
107 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",
108 p_GetCurrentDirectoryA?"":"!",
109 p_GetCurrentDirectoryW?"":"!",
110 p_GetVolumePathNameW?"":"!",
111 p_GetVolumeNameForVolumeMountPointW?"":"!");
112 sendit(msg, len, arg);
115 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
116 edit_uint64_with_commas(sm_bytes, b1),
117 edit_uint64_with_commas(sm_max_bytes, b2),
118 edit_uint64_with_commas(sm_buffers, b3),
119 edit_uint64_with_commas(sm_max_buffers, b4));
120 sendit(msg, len, arg);
121 len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
122 sizeof(off_t), sizeof(size_t), debug_level, get_trace());
123 sendit(msg, len, arg);
128 Dmsg0(1000, "Begin status jcr loop.\n");
129 len = Mmsg(msg, _("Running Jobs:\n"));
130 sendit(msg, len, arg);
133 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
138 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
139 if (njcr->JobId == 0) {
140 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
142 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
143 njcr->JobId, njcr->Job);
144 sendit(msg, len, arg);
145 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
146 vss, job_type_to_str(njcr->JobType), dt);
148 sendit(msg, len, arg);
149 if (njcr->JobId == 0) {
152 sec = time(NULL) - njcr->start_time;
156 bps = (int)(njcr->JobBytes / sec);
157 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
158 edit_uint64_with_commas(njcr->JobFiles, b1),
159 edit_uint64_with_commas(njcr->JobBytes, b2),
160 edit_uint64_with_commas(bps, b3));
161 sendit(msg, len, arg);
162 len = Mmsg(msg, _(" Files Examined=%s\n"),
163 edit_uint64_with_commas(njcr->num_files_examined, b1));
164 sendit(msg, len, arg);
165 if (njcr->JobFiles > 0) {
167 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
169 sendit(msg, len, arg);
173 if (njcr->store_bsock) {
174 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
175 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
176 sendit(msg, len, arg);
178 len = Mmsg(msg, _(" SDSocket closed.\n"));
179 sendit(msg, len, arg);
185 len = Mmsg(msg, _("No Jobs running.\n"));
186 sendit(msg, len, arg);
188 len = Mmsg(msg, _("====\n"));
189 sendit(msg, len, arg);
191 list_terminated_jobs(sendit, arg);
193 free_pool_memory(msg);
196 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
198 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
200 struct s_last_job *je;
203 if (last_jobs->size() == 0) {
204 msg = _("No Terminated Jobs.\n");
205 sendit(msg, strlen(msg), arg);
208 lock_last_jobs_list();
209 sendit("\n", 1, arg); /* send separately */
210 msg = _("Terminated Jobs:\n");
211 sendit(msg, strlen(msg), arg);
212 msg = _(" JobId Level Files Bytes Status Finished Name \n");
213 sendit(msg, strlen(msg), arg);
214 msg = _("======================================================================\n");
215 sendit(msg, strlen(msg), arg);
216 foreach_dlist(je, last_jobs) {
217 char JobName[MAX_NAME_LENGTH];
218 const char *termstat;
221 bstrftime_nc(dt, sizeof(dt), je->end_time);
222 switch (je->JobType) {
225 bstrncpy(level, " ", sizeof(level));
228 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
232 switch (je->JobStatus) {
234 termstat = _("Created");
237 case JS_ErrorTerminated:
238 termstat = _("Error");
241 termstat = _("Diffs");
244 termstat = _("Cancel");
250 termstat = _("Other");
253 bstrncpy(JobName, je->Job, sizeof(JobName));
254 /* There are three periods after the Job name */
256 for (int i=0; i<3; i++) {
257 if ((p=strrchr(JobName, '.')) != NULL) {
261 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %14s %-7s %-8s %s\n"),
264 edit_uint64_with_commas(je->JobFiles, b1),
265 edit_uint64_with_commas(je->JobBytes, b2),
268 sendit(buf, strlen(buf), arg);
270 sendit(_("====\n"), 5, arg);
271 unlock_last_jobs_list();
276 * Send to bsock (Director or Console)
278 static void bsock_sendit(const char *msg, int len, void *arg)
280 BSOCK *user = (BSOCK *)arg;
282 user->msg = check_pool_memory_size(user->msg, len+1);
283 memcpy(user->msg, msg, len+1);
284 user->msglen = len+1;
289 * Status command from Director
291 int status_cmd(JCR *jcr)
293 BSOCK *user = jcr->dir_bsock;
295 bnet_fsend(user, "\n");
296 do_status(bsock_sendit, (void *)user);
298 bnet_sig(user, BNET_EOD);
303 * .status command from Director
305 int qstatus_cmd(JCR *jcr)
307 BSOCK *dir = jcr->dir_bsock;
312 time = get_memory(dir->msglen+1);
314 if (sscanf(dir->msg, qstatus, time) != 1) {
315 pm_strcpy(&jcr->errmsg, dir->msg);
316 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
317 bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
318 bnet_sig(dir, BNET_EOD);
324 if (strcmp(time, "current") == 0) {
325 bnet_fsend(dir, OKqstatus, time);
327 if (njcr->JobId != 0) {
328 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
332 } else if (strcmp(time, "last") == 0) {
333 bnet_fsend(dir, OKqstatus, time);
334 if ((last_jobs) && (last_jobs->size() > 0)) {
335 job = (s_last_job*)last_jobs->last();
336 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
339 pm_strcpy(&jcr->errmsg, dir->msg);
340 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
341 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
342 bnet_sig(dir, BNET_EOD);
347 bnet_sig(dir, BNET_EOD);
353 * Convert Job Level into a string
355 static const char *level_to_str(int level)
366 str = _("Incremental");
369 str = _("Differential");
374 case L_VERIFY_CATALOG:
375 str = _("Verify Catalog");
378 str = _("Init Catalog");
380 case L_VERIFY_VOLUME_TO_CATALOG:
381 str = _("Volume to Catalog");
383 case L_VERIFY_DISK_TO_CATALOG:
384 str = _("Disk to Catalog");
393 str = _("Unknown Job Level");
400 #if defined(HAVE_WIN32)
409 * Put message in Window List Box
411 static void win32_sendit(const char *msg, int len, void *marg)
413 struct s_win32_arg *arg = (struct s_win32_arg *)marg;
415 if (len > 0 && msg[len-1] == '\n') {
416 // when compiling with visual studio some strings are read-only
417 // and cause access violations. So we creat a tmp copy.
418 char *_msg = (char *)alloca(len);
419 bstrncpy(_msg, msg, len);
422 SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
426 void FillStatusBox(HWND hwnd, int idlist)
428 struct s_win32_arg arg;
434 for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
436 do_status(win32_sendit, (void *)&arg);
439 char *bac_status(char *buf, int buf_len)
442 const char *termstat = _("Bacula Idle");
443 struct s_last_job *job;
444 int stat = 0; /* Idle */
449 Dmsg0(1000, "Begin bac_status jcr loop.\n");
451 if (njcr->JobId != 0) {
453 termstat = _("Bacula Running");
462 if (last_jobs->size() > 0) {
463 job = (struct s_last_job *)last_jobs->last();
464 stat = job->JobStatus;
465 switch (job->JobStatus) {
467 termstat = _("Last Job Canceled");
469 case JS_ErrorTerminated:
471 termstat = _("Last Job Failed");
475 termstat = _("Last Job had Warnings");
480 Dmsg0(1000, "End bac_status jcr loop.\n");
484 bstrncpy(buf, termstat, buf_len);
489 #endif /* HAVE_WIN32 */