2 * Bacula File Daemon Status routines
4 * Kern Sibbald, August MMI
10 Copyright (C) 2001-2005 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 extern char my_name[];
28 extern int num_jobs_run;
29 extern time_t daemon_start_time;
30 extern bool get_trace(void);
32 /* Forward referenced functions */
33 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
34 static void bsock_sendit(const char *msg, int len, void *arg);
35 static const char *level_to_str(int level);
37 /* Static variables */
38 static char qstatus[] = ".status %s\n";
40 static char OKqstatus[] = "2000 OK .status\n";
41 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
43 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
53 * General status generator
55 static void do_status(void sendit(const char *msg, int len, void *sarg), void *arg)
58 char *msg, b1[32], b2[32], b3[32], b4[32];
61 char dt[MAX_TIME_LENGTH];
63 msg = (char *)get_pool_memory(PM_MESSAGE);
65 len = Mmsg(msg, "%s Version: " VERSION " (" BDATE ")" VSS " %s %s %s\n",
66 my_name, HOST_OS, DISTNAME, DISTVER);
67 sendit(msg, len, arg);
68 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
69 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
70 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
71 sendit(msg, len, arg);
72 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
73 if (/*debug_level > 0*/ true) {
75 privs = enable_backup_privileges(NULL, 1);
78 _(" Priv 0x%x\n APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n"
79 " %sWUL,%sWMKD,%sWOP,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n"
80 " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n"
83 p_OpenProcessToken?"":"!",
84 p_AdjustTokenPrivileges?"":"!",
85 p_LookupPrivilegeValue?"":"!",
94 p_GetFileAttributesA?"":"!",
95 p_GetFileAttributesW?"":"!",
97 p_GetFileAttributesExA?"":"!",
98 p_GetFileAttributesExW?"":"!",
100 p_SetFileAttributesA?"":"!",
101 p_SetFileAttributesW?"":"!",
103 p_BackupWrite?"":"!",
104 p_SetProcessShutdownParameters?"":"!",
106 p_WideCharToMultiByte?"":"!",
107 p_MultiByteToWideChar?"":"!",
109 p_FindFirstFileA?"":"!",
110 p_FindFirstFileW?"":"!",
112 p_FindNextFileA?"":"!",
113 p_FindNextFileW?"":"!",
115 p_SetCurrentDirectoryA?"":"!",
116 p_SetCurrentDirectoryW?"":"!",
118 p_GetCurrentDirectoryA?"":"!",
119 p_GetCurrentDirectoryW?"":"!");
120 sendit(msg, len, arg);
123 if (debug_level > 0) {
124 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
125 edit_uint64_with_commas(sm_bytes, b1),
126 edit_uint64_with_commas(sm_max_bytes, b2),
127 edit_uint64_with_commas(sm_buffers, b3),
128 edit_uint64_with_commas(sm_max_buffers, b4));
129 sendit(msg, len, arg);
130 len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
131 sizeof(off_t), sizeof(size_t), debug_level, get_trace());
132 sendit(msg, len, arg);
135 list_terminated_jobs(sendit, arg);
140 Dmsg0(1000, "Begin status jcr loop.\n");
141 len = Mmsg(msg, _("Running Jobs:\n"));
142 sendit(msg, len, arg);
144 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
145 if (njcr->JobId == 0) {
146 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
148 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
149 njcr->JobId, njcr->Job);
150 sendit(msg, len, arg);
151 len = Mmsg(msg, _(" %s Job started: %s\n"),
152 job_type_to_str(njcr->JobType), dt);
154 sendit(msg, len, arg);
155 if (njcr->JobId == 0) {
159 sec = time(NULL) - njcr->start_time;
163 bps = (int)(njcr->JobBytes / sec);
164 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
165 edit_uint64_with_commas(njcr->JobFiles, b1),
166 edit_uint64_with_commas(njcr->JobBytes, b2),
167 edit_uint64_with_commas(bps, b3));
168 sendit(msg, len, arg);
169 len = Mmsg(msg, _(" Files Examined=%s\n"),
170 edit_uint64_with_commas(njcr->num_files_examined, b1));
171 sendit(msg, len, arg);
172 if (njcr->JobFiles > 0) {
174 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
176 sendit(msg, len, arg);
180 if (njcr->store_bsock) {
181 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
182 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
183 sendit(msg, len, arg);
185 len = Mmsg(msg, _(" SDSocket closed.\n"));
186 sendit(msg, len, arg);
190 Dmsg0(1000, "Begin status jcr loop.\n");
192 len = Mmsg(msg, _("No Jobs running.\n"));
193 sendit(msg, len, arg);
195 len = Mmsg(msg, _("====\n"));
196 sendit(msg, len, arg);
197 free_pool_memory(msg);
200 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
202 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
204 struct s_last_job *je;
207 if (last_jobs->size() == 0) {
208 msg = _("No Terminated Jobs.\n");
209 sendit(msg, strlen(msg), arg);
212 lock_last_jobs_list();
213 sendit("\n", 1, arg); /* send separately */
214 msg = _("Terminated Jobs:\n");
215 sendit(msg, strlen(msg), arg);
216 msg = _(" JobId Level Files Bytes Status Finished Name \n");
217 sendit(msg, strlen(msg), arg);
218 msg = _("======================================================================\n");
219 sendit(msg, strlen(msg), arg);
220 foreach_dlist(je, last_jobs) {
221 char JobName[MAX_NAME_LENGTH];
222 const char *termstat;
225 bstrftime_nc(dt, sizeof(dt), je->end_time);
226 switch (je->JobType) {
229 bstrncpy(level, " ", sizeof(level));
232 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
236 switch (je->JobStatus) {
238 termstat = "Created";
241 case JS_ErrorTerminated:
257 bstrncpy(JobName, je->Job, sizeof(JobName));
258 /* There are three periods after the Job name */
260 for (int i=0; i<3; i++) {
261 if ((p=strrchr(JobName, '.')) != NULL) {
265 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %14s %-7s %-8s %s\n"),
268 edit_uint64_with_commas(je->JobFiles, b1),
269 edit_uint64_with_commas(je->JobBytes, b2),
272 sendit(buf, strlen(buf), arg);
274 sendit("====\n", 5, arg);
275 unlock_last_jobs_list();
280 * Send to bsock (Director or Console)
282 static void bsock_sendit(const char *msg, int len, void *arg)
284 BSOCK *user = (BSOCK *)arg;
286 user->msg = check_pool_memory_size(user->msg, len+1);
287 memcpy(user->msg, msg, len+1);
288 user->msglen = len+1;
293 * Status command from Director
295 int status_cmd(JCR *jcr)
297 BSOCK *user = jcr->dir_bsock;
299 bnet_fsend(user, "\n");
300 do_status(bsock_sendit, (void *)user);
302 bnet_sig(user, BNET_EOD);
307 * .status command from Director
309 int qstatus_cmd(JCR *jcr)
311 BSOCK *dir = jcr->dir_bsock;
316 time = get_memory(dir->msglen+1);
318 if (sscanf(dir->msg, qstatus, time) != 1) {
319 pm_strcpy(&jcr->errmsg, dir->msg);
320 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
321 bnet_fsend(dir, "2900 Bad .status command, missing argument.\n");
322 bnet_sig(dir, BNET_EOD);
328 if (strcmp(time, "current") == 0) {
329 bnet_fsend(dir, OKqstatus, time);
331 if (njcr->JobId != 0) {
332 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
337 else if (strcmp(time, "last") == 0) {
338 bnet_fsend(dir, OKqstatus, time);
339 if ((last_jobs) && (last_jobs->size() > 0)) {
340 job = (s_last_job*)last_jobs->last();
341 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
345 pm_strcpy(&jcr->errmsg, dir->msg);
346 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
347 bnet_fsend(dir, "2900 Bad .status command, wrong argument.\n");
348 bnet_sig(dir, BNET_EOD);
353 bnet_sig(dir, BNET_EOD);
359 * Convert Job Level into a string
361 static const char *level_to_str(int level)
372 str = _("Incremental");
375 str = _("Differential");
380 case L_VERIFY_CATALOG:
381 str = _("Verify Catalog");
384 str = _("Init Catalog");
386 case L_VERIFY_VOLUME_TO_CATALOG:
387 str = _("Volume to Catalog");
389 case L_VERIFY_DISK_TO_CATALOG:
390 str = _("Disk to Catalog");
399 str = _("Unknown Job Level");
406 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
417 * Put message in Window List Box
419 static void win32_sendit(const char *msg, int len, void *marg)
421 struct s_win32_arg *arg = (struct s_win32_arg *)marg;
423 if (len > 0 && msg[len-1] == '\n') {
424 // when compiling with visual studio some strings are read-only
425 // and cause access violations. So we creat a tmp copy.
426 char *_msg = (char *)alloca(len);
427 bstrncpy(_msg, msg, len);
430 SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
434 void FillStatusBox(HWND hwnd, int idlist)
436 struct s_win32_arg arg;
442 for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
444 do_status(win32_sendit, (void *)&arg);
447 char *bac_status(char *buf, int buf_len)
450 const char *termstat = _("Bacula Idle");
451 struct s_last_job *job;
452 int stat = 0; /* Idle */
457 Dmsg0(1000, "Begin bac_status jcr loop.\n");
459 if (njcr->JobId != 0) {
461 termstat = _("Bacula Running");
470 if (last_jobs->size() > 0) {
471 job = (struct s_last_job *)last_jobs->last();
472 stat = job->JobStatus;
473 switch (job->JobStatus) {
475 termstat = _("Last Job Canceled");
477 case JS_ErrorTerminated:
479 termstat = _("Last Job Failed");
483 termstat = _("Last Job had Warnings");
488 Dmsg0(1000, "End bac_status jcr loop.\n");
492 bstrncpy(buf, termstat, buf_len);
497 #endif /* HAVE_CYGWIN */