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 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: %s (%s) %s %s %s %s\n"),
68 my_name, VERSION, BDATE, VSS, 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) {
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,%sGVPNW,%sGVNFVMPW\n",
113 p_GetCurrentDirectoryA?"":"!",
114 p_GetCurrentDirectoryW?"":"!",
115 p_GetVolumePathNameW?"":"!",
116 p_GetVolumeNameForVolumeMountPointW?"":"!");
117 sendit(msg, len, arg);
120 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
121 edit_uint64_with_commas(sm_bytes, b1),
122 edit_uint64_with_commas(sm_max_bytes, b2),
123 edit_uint64_with_commas(sm_buffers, b3),
124 edit_uint64_with_commas(sm_max_buffers, b4));
125 sendit(msg, len, arg);
126 len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
127 sizeof(off_t), sizeof(size_t), debug_level, get_trace());
128 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) {
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);
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:
243 termstat = _("Error");
246 termstat = _("Diffs");
249 termstat = _("Cancel");
255 termstat = _("Other");
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);
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);
344 pm_strcpy(&jcr->errmsg, dir->msg);
345 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
346 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
347 bnet_sig(dir, BNET_EOD);
352 bnet_sig(dir, BNET_EOD);
358 * Convert Job Level into a string
360 static const char *level_to_str(int level)
371 str = _("Incremental");
374 str = _("Differential");
379 case L_VERIFY_CATALOG:
380 str = _("Verify Catalog");
383 str = _("Init Catalog");
385 case L_VERIFY_VOLUME_TO_CATALOG:
386 str = _("Volume to Catalog");
388 case L_VERIFY_DISK_TO_CATALOG:
389 str = _("Disk to Catalog");
398 str = _("Unknown Job Level");
405 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
416 * Put message in Window List Box
418 static void win32_sendit(const char *msg, int len, void *marg)
420 struct s_win32_arg *arg = (struct s_win32_arg *)marg;
422 if (len > 0 && msg[len-1] == '\n') {
423 // when compiling with visual studio some strings are read-only
424 // and cause access violations. So we creat a tmp copy.
425 char *_msg = (char *)alloca(len);
426 bstrncpy(_msg, msg, len);
429 SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
433 void FillStatusBox(HWND hwnd, int idlist)
435 struct s_win32_arg arg;
441 for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
443 do_status(win32_sendit, (void *)&arg);
446 char *bac_status(char *buf, int buf_len)
449 const char *termstat = _("Bacula Idle");
450 struct s_last_job *job;
451 int stat = 0; /* Idle */
456 Dmsg0(1000, "Begin bac_status jcr loop.\n");
458 if (njcr->JobId != 0) {
460 termstat = _("Bacula Running");
469 if (last_jobs->size() > 0) {
470 job = (struct s_last_job *)last_jobs->last();
471 stat = job->JobStatus;
472 switch (job->JobStatus) {
474 termstat = _("Last Job Canceled");
476 case JS_ErrorTerminated:
478 termstat = _("Last Job Failed");
482 termstat = _("Last Job had Warnings");
487 Dmsg0(1000, "End bac_status jcr loop.\n");
491 bstrncpy(buf, termstat, buf_len);
496 #endif /* HAVE_CYGWIN */