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)
49 extern VSSClient *g_pVSSClient;
55 * General status generator
57 static void do_status(void sendit(const char *msg, int len, void *sarg), void *arg)
60 char *msg, b1[32], b2[32], b3[32], b4[32];
63 char dt[MAX_TIME_LENGTH];
65 msg = (char *)get_pool_memory(PM_MESSAGE);
67 len = Mmsg(msg, "%s Version: " VERSION " (" BDATE ")" VSS " %s %s %s\n",
68 my_name, HOST_OS, DISTNAME, DISTVER);
69 sendit(msg, len, arg);
70 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
71 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
72 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
73 sendit(msg, len, arg);
74 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
75 if (/*debug_level > 0*/ true) {
77 privs = enable_backup_privileges(NULL, 1);
79 len = Mmsg(msg, "Priv 0x%x\n", privs);
80 sendit(msg, len, arg);
81 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
82 p_OpenProcessToken?"":"!",
83 p_AdjustTokenPrivileges?"":"!",
84 p_LookupPrivilegeValue?"":"!",
86 p_CreateFileW?"":"!");
87 sendit(msg, len, arg);
88 len = Mmsg(msg, " %sWUL,%sWMKD,%sWOP,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
92 p_GetFileAttributesA?"":"!",
93 p_GetFileAttributesW?"":"!",
94 p_GetFileAttributesExA?"":"!",
95 p_GetFileAttributesExW?"":"!",
96 p_SetFileAttributesA?"":"!",
97 p_SetFileAttributesW?"":"!",
100 p_SetProcessShutdownParameters?"":"!");
101 sendit(msg, len, arg);
102 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
103 p_WideCharToMultiByte?"":"!",
104 p_MultiByteToWideChar?"":"!",
105 p_FindFirstFileA?"":"!",
106 p_FindFirstFileW?"":"!",
107 p_FindNextFileA?"":"!",
108 p_FindNextFileW?"":"!",
109 p_SetCurrentDirectoryA?"":"!",
110 p_SetCurrentDirectoryW?"":"!");
111 sendit(msg, len, arg);
112 len = Mmsg(msg, " %sGCDA,%sGCDW\n",
113 p_GetCurrentDirectoryA?"":"!",
114 p_GetCurrentDirectoryW?"":"!");
115 sendit(msg, len, arg);
118 if (debug_level > 0) {
119 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
120 edit_uint64_with_commas(sm_bytes, b1),
121 edit_uint64_with_commas(sm_max_bytes, b2),
122 edit_uint64_with_commas(sm_buffers, b3),
123 edit_uint64_with_commas(sm_max_buffers, b4));
124 sendit(msg, len, arg);
125 len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
126 sizeof(off_t), sizeof(size_t), debug_level, get_trace());
127 sendit(msg, len, arg);
130 list_terminated_jobs(sendit, arg);
135 Dmsg0(1000, "Begin status jcr loop.\n");
136 len = Mmsg(msg, _("Running Jobs:\n"));
137 sendit(msg, len, arg);
140 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
145 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
146 if (njcr->JobId == 0) {
147 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
149 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
150 njcr->JobId, njcr->Job);
151 sendit(msg, len, arg);
152 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
153 vss, job_type_to_str(njcr->JobType), dt);
155 sendit(msg, len, arg);
156 if (njcr->JobId == 0) {
160 sec = time(NULL) - njcr->start_time;
164 bps = (int)(njcr->JobBytes / sec);
165 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
166 edit_uint64_with_commas(njcr->JobFiles, b1),
167 edit_uint64_with_commas(njcr->JobBytes, b2),
168 edit_uint64_with_commas(bps, b3));
169 sendit(msg, len, arg);
170 len = Mmsg(msg, _(" Files Examined=%s\n"),
171 edit_uint64_with_commas(njcr->num_files_examined, b1));
172 sendit(msg, len, arg);
173 if (njcr->JobFiles > 0) {
175 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
177 sendit(msg, len, arg);
181 if (njcr->store_bsock) {
182 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
183 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
184 sendit(msg, len, arg);
186 len = Mmsg(msg, _(" SDSocket closed.\n"));
187 sendit(msg, len, arg);
191 Dmsg0(1000, "Begin status jcr loop.\n");
193 len = Mmsg(msg, _("No Jobs running.\n"));
194 sendit(msg, len, arg);
196 len = Mmsg(msg, _("====\n"));
197 sendit(msg, len, arg);
198 free_pool_memory(msg);
201 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
203 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
205 struct s_last_job *je;
208 if (last_jobs->size() == 0) {
209 msg = _("No Terminated Jobs.\n");
210 sendit(msg, strlen(msg), arg);
213 lock_last_jobs_list();
214 sendit("\n", 1, arg); /* send separately */
215 msg = _("Terminated Jobs:\n");
216 sendit(msg, strlen(msg), arg);
217 msg = _(" JobId Level Files Bytes Status Finished Name \n");
218 sendit(msg, strlen(msg), arg);
219 msg = _("======================================================================\n");
220 sendit(msg, strlen(msg), arg);
221 foreach_dlist(je, last_jobs) {
222 char JobName[MAX_NAME_LENGTH];
223 const char *termstat;
226 bstrftime_nc(dt, sizeof(dt), je->end_time);
227 switch (je->JobType) {
230 bstrncpy(level, " ", sizeof(level));
233 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
237 switch (je->JobStatus) {
239 termstat = "Created";
242 case JS_ErrorTerminated:
258 bstrncpy(JobName, je->Job, sizeof(JobName));
259 /* There are three periods after the Job name */
261 for (int i=0; i<3; i++) {
262 if ((p=strrchr(JobName, '.')) != NULL) {
266 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %14s %-7s %-8s %s\n"),
269 edit_uint64_with_commas(je->JobFiles, b1),
270 edit_uint64_with_commas(je->JobBytes, b2),
273 sendit(buf, strlen(buf), arg);
275 sendit("====\n", 5, arg);
276 unlock_last_jobs_list();
281 * Send to bsock (Director or Console)
283 static void bsock_sendit(const char *msg, int len, void *arg)
285 BSOCK *user = (BSOCK *)arg;
287 user->msg = check_pool_memory_size(user->msg, len+1);
288 memcpy(user->msg, msg, len+1);
289 user->msglen = len+1;
294 * Status command from Director
296 int status_cmd(JCR *jcr)
298 BSOCK *user = jcr->dir_bsock;
300 bnet_fsend(user, "\n");
301 do_status(bsock_sendit, (void *)user);
303 bnet_sig(user, BNET_EOD);
308 * .status command from Director
310 int qstatus_cmd(JCR *jcr)
312 BSOCK *dir = jcr->dir_bsock;
317 time = get_memory(dir->msglen+1);
319 if (sscanf(dir->msg, qstatus, time) != 1) {
320 pm_strcpy(&jcr->errmsg, dir->msg);
321 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
322 bnet_fsend(dir, "2900 Bad .status command, missing argument.\n");
323 bnet_sig(dir, BNET_EOD);
329 if (strcmp(time, "current") == 0) {
330 bnet_fsend(dir, OKqstatus, time);
332 if (njcr->JobId != 0) {
333 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
338 else if (strcmp(time, "last") == 0) {
339 bnet_fsend(dir, OKqstatus, time);
340 if ((last_jobs) && (last_jobs->size() > 0)) {
341 job = (s_last_job*)last_jobs->last();
342 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
346 pm_strcpy(&jcr->errmsg, dir->msg);
347 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
348 bnet_fsend(dir, "2900 Bad .status command, wrong argument.\n");
349 bnet_sig(dir, BNET_EOD);
354 bnet_sig(dir, BNET_EOD);
360 * Convert Job Level into a string
362 static const char *level_to_str(int level)
373 str = _("Incremental");
376 str = _("Differential");
381 case L_VERIFY_CATALOG:
382 str = _("Verify Catalog");
385 str = _("Init Catalog");
387 case L_VERIFY_VOLUME_TO_CATALOG:
388 str = _("Volume to Catalog");
390 case L_VERIFY_DISK_TO_CATALOG:
391 str = _("Disk to Catalog");
400 str = _("Unknown Job Level");
407 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
418 * Put message in Window List Box
420 static void win32_sendit(const char *msg, int len, void *marg)
422 struct s_win32_arg *arg = (struct s_win32_arg *)marg;
424 if (len > 0 && msg[len-1] == '\n') {
425 // when compiling with visual studio some strings are read-only
426 // and cause access violations. So we creat a tmp copy.
427 char *_msg = (char *)alloca(len);
428 bstrncpy(_msg, msg, len);
431 SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
435 void FillStatusBox(HWND hwnd, int idlist)
437 struct s_win32_arg arg;
443 for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
445 do_status(win32_sendit, (void *)&arg);
448 char *bac_status(char *buf, int buf_len)
451 const char *termstat = _("Bacula Idle");
452 struct s_last_job *job;
453 int stat = 0; /* Idle */
458 Dmsg0(1000, "Begin bac_status jcr loop.\n");
460 if (njcr->JobId != 0) {
462 termstat = _("Bacula Running");
471 if (last_jobs->size() > 0) {
472 job = (struct s_last_job *)last_jobs->last();
473 stat = job->JobStatus;
474 switch (job->JobStatus) {
476 termstat = _("Last Job Canceled");
478 case JS_ErrorTerminated:
480 termstat = _("Last Job Failed");
484 termstat = _("Last Job had Warnings");
489 Dmsg0(1000, "End bac_status jcr loop.\n");
493 bstrncpy(buf, termstat, buf_len);
498 #endif /* HAVE_CYGWIN */