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",
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: off_t=%d size_t=%d debug=%d trace=%d\n"),
121 sizeof(off_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, _("Running 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 len = Mmsg(msg, _("====\n"));
188 sendit(msg, len, arg);
190 list_terminated_jobs(sendit, arg);
192 free_pool_memory(msg);
195 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
197 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
199 struct s_last_job *je;
202 if (last_jobs->size() == 0) {
203 msg = _("No Terminated Jobs.\n");
204 sendit(msg, strlen(msg), arg);
207 lock_last_jobs_list();
208 sendit("\n", 1, arg); /* send separately */
209 msg = _("Terminated Jobs:\n");
210 sendit(msg, strlen(msg), arg);
211 msg = _(" JobId Level Files Bytes Status Finished Name \n");
212 sendit(msg, strlen(msg), arg);
213 msg = _("======================================================================\n");
214 sendit(msg, strlen(msg), arg);
215 foreach_dlist(je, last_jobs) {
216 char JobName[MAX_NAME_LENGTH];
217 const char *termstat;
220 bstrftime_nc(dt, sizeof(dt), je->end_time);
221 switch (je->JobType) {
224 bstrncpy(level, " ", sizeof(level));
227 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
231 switch (je->JobStatus) {
233 termstat = _("Created");
236 case JS_ErrorTerminated:
237 termstat = _("Error");
240 termstat = _("Diffs");
243 termstat = _("Cancel");
249 termstat = _("Other");
252 bstrncpy(JobName, je->Job, sizeof(JobName));
253 /* There are three periods after the Job name */
255 for (int i=0; i<3; i++) {
256 if ((p=strrchr(JobName, '.')) != NULL) {
260 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %14s %-7s %-8s %s\n"),
263 edit_uint64_with_commas(je->JobFiles, b1),
264 edit_uint64_with_commas(je->JobBytes, b2),
267 sendit(buf, strlen(buf), arg);
269 sendit(_("====\n"), 5, arg);
270 unlock_last_jobs_list();
275 * Send to bsock (Director or Console)
277 static void bsock_sendit(const char *msg, int len, void *arg)
279 BSOCK *user = (BSOCK *)arg;
281 user->msg = check_pool_memory_size(user->msg, len+1);
282 memcpy(user->msg, msg, len+1);
283 user->msglen = len+1;
288 * Status command from Director
290 int status_cmd(JCR *jcr)
292 BSOCK *user = jcr->dir_bsock;
294 bnet_fsend(user, "\n");
295 do_status(bsock_sendit, (void *)user);
297 bnet_sig(user, BNET_EOD);
302 * .status command from Director
304 int qstatus_cmd(JCR *jcr)
306 BSOCK *dir = jcr->dir_bsock;
311 time = get_memory(dir->msglen+1);
313 if (sscanf(dir->msg, qstatus, time) != 1) {
314 pm_strcpy(&jcr->errmsg, dir->msg);
315 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
316 bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
317 bnet_sig(dir, BNET_EOD);
323 if (strcmp(time, "current") == 0) {
324 bnet_fsend(dir, OKqstatus, time);
326 if (njcr->JobId != 0) {
327 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
331 } else if (strcmp(time, "last") == 0) {
332 bnet_fsend(dir, OKqstatus, time);
333 if ((last_jobs) && (last_jobs->size() > 0)) {
334 job = (s_last_job*)last_jobs->last();
335 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
338 pm_strcpy(&jcr->errmsg, dir->msg);
339 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
340 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
341 bnet_sig(dir, BNET_EOD);
346 bnet_sig(dir, BNET_EOD);
352 * Convert Job Level into a string
354 static const char *level_to_str(int level)
365 str = _("Incremental");
368 str = _("Differential");
373 case L_VERIFY_CATALOG:
374 str = _("Verify Catalog");
377 str = _("Init Catalog");
379 case L_VERIFY_VOLUME_TO_CATALOG:
380 str = _("Volume to Catalog");
382 case L_VERIFY_DISK_TO_CATALOG:
383 str = _("Disk to Catalog");
392 str = _("Unknown Job Level");
399 #if defined(HAVE_WIN32)
408 * Put message in Window List Box
410 static void win32_sendit(const char *msg, int len, void *marg)
412 struct s_win32_arg *arg = (struct s_win32_arg *)marg;
414 if (len > 0 && msg[len-1] == '\n') {
415 // when compiling with visual studio some strings are read-only
416 // and cause access violations. So we creat a tmp copy.
417 char *_msg = (char *)alloca(len);
418 bstrncpy(_msg, msg, len);
421 SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
425 void FillStatusBox(HWND hwnd, int idlist)
427 struct s_win32_arg arg;
433 for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
435 do_status(win32_sendit, (void *)&arg);
438 char *bac_status(char *buf, int buf_len)
441 const char *termstat = _("Bacula Idle");
442 struct s_last_job *job;
443 int stat = 0; /* Idle */
448 Dmsg0(1000, "Begin bac_status jcr loop.\n");
450 if (njcr->JobId != 0) {
452 termstat = _("Bacula Running");
461 if (last_jobs->size() > 0) {
462 job = (struct s_last_job *)last_jobs->last();
463 stat = job->JobStatus;
464 switch (job->JobStatus) {
466 termstat = _("Last Job Canceled");
468 case JS_ErrorTerminated:
470 termstat = _("Last Job Failed");
474 termstat = _("Last Job had Warnings");
479 Dmsg0(1000, "End bac_status jcr loop.\n");
483 bstrncpy(buf, termstat, buf_len);
488 #endif /* HAVE_WIN32 */