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_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_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);
133 Dmsg0(1000, "Begin status jcr loop.\n");
134 len = Mmsg(msg, _("Running Jobs:\n"));
135 sendit(msg, len, arg);
138 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
143 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
144 if (njcr->JobId == 0) {
145 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
147 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
148 njcr->JobId, njcr->Job);
149 sendit(msg, len, arg);
150 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
151 vss, job_type_to_str(njcr->JobType), dt);
153 sendit(msg, len, arg);
154 if (njcr->JobId == 0) {
157 sec = time(NULL) - njcr->start_time;
161 bps = (int)(njcr->JobBytes / sec);
162 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
163 edit_uint64_with_commas(njcr->JobFiles, b1),
164 edit_uint64_with_commas(njcr->JobBytes, b2),
165 edit_uint64_with_commas(bps, b3));
166 sendit(msg, len, arg);
167 len = Mmsg(msg, _(" Files Examined=%s\n"),
168 edit_uint64_with_commas(njcr->num_files_examined, b1));
169 sendit(msg, len, arg);
170 if (njcr->JobFiles > 0) {
172 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
174 sendit(msg, len, arg);
178 if (njcr->store_bsock) {
179 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
180 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
181 sendit(msg, len, arg);
183 len = Mmsg(msg, _(" SDSocket closed.\n"));
184 sendit(msg, len, arg);
190 len = Mmsg(msg, _("No Jobs running.\n"));
191 sendit(msg, len, arg);
193 len = Mmsg(msg, _("====\n"));
194 sendit(msg, len, arg);
196 list_terminated_jobs(sendit, 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_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_WIN32 */