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: %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 if (debug_level > 0) {
121 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
122 edit_uint64_with_commas(sm_bytes, b1),
123 edit_uint64_with_commas(sm_max_bytes, b2),
124 edit_uint64_with_commas(sm_buffers, b3),
125 edit_uint64_with_commas(sm_max_buffers, b4));
126 sendit(msg, len, arg);
127 len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
128 sizeof(off_t), sizeof(size_t), debug_level, get_trace());
129 sendit(msg, len, arg);
132 list_terminated_jobs(sendit, arg);
137 Dmsg0(1000, "Begin status jcr loop.\n");
138 len = Mmsg(msg, _("Running Jobs:\n"));
139 sendit(msg, len, arg);
142 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
147 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
148 if (njcr->JobId == 0) {
149 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
151 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
152 njcr->JobId, njcr->Job);
153 sendit(msg, len, arg);
154 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
155 vss, job_type_to_str(njcr->JobType), dt);
157 sendit(msg, len, arg);
158 if (njcr->JobId == 0) {
162 sec = time(NULL) - njcr->start_time;
166 bps = (int)(njcr->JobBytes / sec);
167 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
168 edit_uint64_with_commas(njcr->JobFiles, b1),
169 edit_uint64_with_commas(njcr->JobBytes, b2),
170 edit_uint64_with_commas(bps, b3));
171 sendit(msg, len, arg);
172 len = Mmsg(msg, _(" Files Examined=%s\n"),
173 edit_uint64_with_commas(njcr->num_files_examined, b1));
174 sendit(msg, len, arg);
175 if (njcr->JobFiles > 0) {
177 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
179 sendit(msg, len, arg);
183 if (njcr->store_bsock) {
184 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
185 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
186 sendit(msg, len, arg);
188 len = Mmsg(msg, _(" SDSocket closed.\n"));
189 sendit(msg, len, arg);
193 Dmsg0(1000, "Begin status jcr loop.\n");
195 len = Mmsg(msg, _("No Jobs running.\n"));
196 sendit(msg, len, arg);
198 len = Mmsg(msg, _("====\n"));
199 sendit(msg, len, arg);
200 free_pool_memory(msg);
203 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
205 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
207 struct s_last_job *je;
210 if (last_jobs->size() == 0) {
211 msg = _("No Terminated Jobs.\n");
212 sendit(msg, strlen(msg), arg);
215 lock_last_jobs_list();
216 sendit("\n", 1, arg); /* send separately */
217 msg = _("Terminated Jobs:\n");
218 sendit(msg, strlen(msg), arg);
219 msg = _(" JobId Level Files Bytes Status Finished Name \n");
220 sendit(msg, strlen(msg), arg);
221 msg = _("======================================================================\n");
222 sendit(msg, strlen(msg), arg);
223 foreach_dlist(je, last_jobs) {
224 char JobName[MAX_NAME_LENGTH];
225 const char *termstat;
228 bstrftime_nc(dt, sizeof(dt), je->end_time);
229 switch (je->JobType) {
232 bstrncpy(level, " ", sizeof(level));
235 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
239 switch (je->JobStatus) {
241 termstat = _("Created");
244 case JS_ErrorTerminated:
245 termstat = _("Error");
248 termstat = _("Diffs");
251 termstat = _("Cancel");
257 termstat = _("Other");
260 bstrncpy(JobName, je->Job, sizeof(JobName));
261 /* There are three periods after the Job name */
263 for (int i=0; i<3; i++) {
264 if ((p=strrchr(JobName, '.')) != NULL) {
268 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %14s %-7s %-8s %s\n"),
271 edit_uint64_with_commas(je->JobFiles, b1),
272 edit_uint64_with_commas(je->JobBytes, b2),
275 sendit(buf, strlen(buf), arg);
277 sendit(_("====\n"), 5, arg);
278 unlock_last_jobs_list();
283 * Send to bsock (Director or Console)
285 static void bsock_sendit(const char *msg, int len, void *arg)
287 BSOCK *user = (BSOCK *)arg;
289 user->msg = check_pool_memory_size(user->msg, len+1);
290 memcpy(user->msg, msg, len+1);
291 user->msglen = len+1;
296 * Status command from Director
298 int status_cmd(JCR *jcr)
300 BSOCK *user = jcr->dir_bsock;
302 bnet_fsend(user, "\n");
303 do_status(bsock_sendit, (void *)user);
305 bnet_sig(user, BNET_EOD);
310 * .status command from Director
312 int qstatus_cmd(JCR *jcr)
314 BSOCK *dir = jcr->dir_bsock;
319 time = get_memory(dir->msglen+1);
321 if (sscanf(dir->msg, qstatus, time) != 1) {
322 pm_strcpy(&jcr->errmsg, dir->msg);
323 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
324 bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
325 bnet_sig(dir, BNET_EOD);
331 if (strcmp(time, "current") == 0) {
332 bnet_fsend(dir, OKqstatus, time);
334 if (njcr->JobId != 0) {
335 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
339 } else if (strcmp(time, "last") == 0) {
340 bnet_fsend(dir, OKqstatus, time);
341 if ((last_jobs) && (last_jobs->size() > 0)) {
342 job = (s_last_job*)last_jobs->last();
343 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 */