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*/ 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,%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);
340 else if (strcmp(time, "last") == 0) {
341 bnet_fsend(dir, OKqstatus, time);
342 if ((last_jobs) && (last_jobs->size() > 0)) {
343 job = (s_last_job*)last_jobs->last();
344 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
348 pm_strcpy(&jcr->errmsg, dir->msg);
349 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
350 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
351 bnet_sig(dir, BNET_EOD);
356 bnet_sig(dir, BNET_EOD);
362 * Convert Job Level into a string
364 static const char *level_to_str(int level)
375 str = _("Incremental");
378 str = _("Differential");
383 case L_VERIFY_CATALOG:
384 str = _("Verify Catalog");
387 str = _("Init Catalog");
389 case L_VERIFY_VOLUME_TO_CATALOG:
390 str = _("Volume to Catalog");
392 case L_VERIFY_DISK_TO_CATALOG:
393 str = _("Disk to Catalog");
402 str = _("Unknown Job Level");
409 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
420 * Put message in Window List Box
422 static void win32_sendit(const char *msg, int len, void *marg)
424 struct s_win32_arg *arg = (struct s_win32_arg *)marg;
426 if (len > 0 && msg[len-1] == '\n') {
427 // when compiling with visual studio some strings are read-only
428 // and cause access violations. So we creat a tmp copy.
429 char *_msg = (char *)alloca(len);
430 bstrncpy(_msg, msg, len);
433 SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
437 void FillStatusBox(HWND hwnd, int idlist)
439 struct s_win32_arg arg;
445 for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
447 do_status(win32_sendit, (void *)&arg);
450 char *bac_status(char *buf, int buf_len)
453 const char *termstat = _("Bacula Idle");
454 struct s_last_job *job;
455 int stat = 0; /* Idle */
460 Dmsg0(1000, "Begin bac_status jcr loop.\n");
462 if (njcr->JobId != 0) {
464 termstat = _("Bacula Running");
473 if (last_jobs->size() > 0) {
474 job = (struct s_last_job *)last_jobs->last();
475 stat = job->JobStatus;
476 switch (job->JobStatus) {
478 termstat = _("Last Job Canceled");
480 case JS_ErrorTerminated:
482 termstat = _("Last Job Failed");
486 termstat = _("Last Job had Warnings");
491 Dmsg0(1000, "End bac_status jcr loop.\n");
495 bstrncpy(buf, termstat, buf_len);
500 #endif /* HAVE_CYGWIN */