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 /* Forward referenced functions */
28 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
29 static void bsock_sendit(const char *msg, int len, void *arg);
30 static const char *level_to_str(int level);
32 /* Static variables */
33 static char qstatus[] = ".status %s\n";
35 static char OKqstatus[] = "2000 OK .status\n";
36 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
38 #if defined(HAVE_WIN32)
44 extern VSSClient *g_pVSSClient;
50 * General status generator
52 void output_status(void sendit(const char *msg, int len, void *sarg), void *arg)
55 char *msg, b1[32], b2[32], b3[32], b4[32];
58 char dt[MAX_TIME_LENGTH];
60 msg = (char *)get_pool_memory(PM_MESSAGE);
62 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
63 my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
64 sendit(msg, len, arg);
65 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
66 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
67 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
68 sendit(msg, len, arg);
69 #if defined(HAVE_WIN32)
70 if (debug_level > 0) {
72 privs = enable_backup_privileges(NULL, 1);
74 len = Mmsg(msg, "Priv 0x%x\n", privs);
75 sendit(msg, len, arg);
76 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
77 p_OpenProcessToken?"":"!",
78 p_AdjustTokenPrivileges?"":"!",
79 p_LookupPrivilegeValue?"":"!",
81 p_CreateFileW?"":"!");
82 sendit(msg, len, arg);
83 len = Mmsg(msg, " %sWUL,%sWMKD,%sWOP,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
86 p_GetFileAttributesA?"":"!",
87 p_GetFileAttributesW?"":"!",
88 p_GetFileAttributesExA?"":"!",
89 p_GetFileAttributesExW?"":"!",
90 p_SetFileAttributesA?"":"!",
91 p_SetFileAttributesW?"":"!",
94 p_SetProcessShutdownParameters?"":"!");
95 sendit(msg, len, arg);
96 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
97 p_WideCharToMultiByte?"":"!",
98 p_MultiByteToWideChar?"":"!",
99 p_FindFirstFileA?"":"!",
100 p_FindFirstFileW?"":"!",
101 p_FindNextFileA?"":"!",
102 p_FindNextFileW?"":"!",
103 p_SetCurrentDirectoryA?"":"!",
104 p_SetCurrentDirectoryW?"":"!");
105 sendit(msg, len, arg);
106 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",
107 p_GetCurrentDirectoryA?"":"!",
108 p_GetCurrentDirectoryW?"":"!",
109 p_GetVolumePathNameW?"":"!",
110 p_GetVolumeNameForVolumeMountPointW?"":"!");
111 sendit(msg, len, arg);
114 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
115 edit_uint64_with_commas(sm_bytes, b1),
116 edit_uint64_with_commas(sm_max_bytes, b2),
117 edit_uint64_with_commas(sm_buffers, b3),
118 edit_uint64_with_commas(sm_max_buffers, b4));
119 sendit(msg, len, arg);
120 len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
121 sizeof(off_t), sizeof(size_t), debug_level, get_trace());
122 sendit(msg, len, arg);
127 Dmsg0(1000, "Begin status jcr loop.\n");
128 len = Mmsg(msg, _("\nRunning Jobs:\n"));
129 sendit(msg, len, arg);
132 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
137 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
138 if (njcr->JobId == 0) {
139 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
141 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
142 njcr->JobId, njcr->Job);
143 sendit(msg, len, arg);
144 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
145 vss, job_type_to_str(njcr->JobType), dt);
147 sendit(msg, len, arg);
148 if (njcr->JobId == 0) {
151 sec = time(NULL) - njcr->start_time;
155 bps = (int)(njcr->JobBytes / sec);
156 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
157 edit_uint64_with_commas(njcr->JobFiles, b1),
158 edit_uint64_with_commas(njcr->JobBytes, b2),
159 edit_uint64_with_commas(bps, b3));
160 sendit(msg, len, arg);
161 len = Mmsg(msg, _(" Files Examined=%s\n"),
162 edit_uint64_with_commas(njcr->num_files_examined, b1));
163 sendit(msg, len, arg);
164 if (njcr->JobFiles > 0) {
166 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
168 sendit(msg, len, arg);
172 if (njcr->store_bsock) {
173 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
174 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
175 sendit(msg, len, arg);
177 len = Mmsg(msg, _(" SDSocket closed.\n"));
178 sendit(msg, len, arg);
183 sendit(_("====\n"), 5, arg);
185 list_terminated_jobs(sendit, arg);
187 free_pool_memory(msg);
190 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
192 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
194 struct s_last_job *je;
197 msg = _("\nTerminated Jobs:\n");
198 sendit(msg, strlen(msg), arg);
200 if (last_jobs->size() == 0) {
201 sendit(_("====\n"), 5, arg);
204 lock_last_jobs_list();
205 msg = _(" JobId Level Files Bytes Status Finished Name \n");
206 sendit(msg, strlen(msg), arg);
207 msg = _("======================================================================\n");
208 sendit(msg, strlen(msg), arg);
209 foreach_dlist(je, last_jobs) {
210 char JobName[MAX_NAME_LENGTH];
211 const char *termstat;
214 bstrftime_nc(dt, sizeof(dt), je->end_time);
215 switch (je->JobType) {
218 bstrncpy(level, " ", sizeof(level));
221 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
225 switch (je->JobStatus) {
227 termstat = _("Created");
230 case JS_ErrorTerminated:
231 termstat = _("Error");
234 termstat = _("Diffs");
237 termstat = _("Cancel");
243 termstat = _("Other");
246 bstrncpy(JobName, je->Job, sizeof(JobName));
247 /* There are three periods after the Job name */
249 for (int i=0; i<3; i++) {
250 if ((p=strrchr(JobName, '.')) != NULL) {
254 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
257 edit_uint64_with_commas(je->JobFiles, b1),
258 edit_uint64_with_suffix(je->JobBytes, b2),
261 sendit(buf, strlen(buf), arg);
263 sendit(_("====\n"), 5, arg);
264 unlock_last_jobs_list();
269 * Send to bsock (Director or Console)
271 static void bsock_sendit(const char *msg, int len, void *arg)
273 BSOCK *user = (BSOCK *)arg;
275 user->msg = check_pool_memory_size(user->msg, len+1);
276 memcpy(user->msg, msg, len+1);
277 user->msglen = len+1;
282 * Status command from Director
284 int status_cmd(JCR *jcr)
286 BSOCK *user = jcr->dir_bsock;
288 bnet_fsend(user, "\n");
289 output_status(bsock_sendit, (void *)user);
291 bnet_sig(user, BNET_EOD);
296 * .status command from Director
298 int qstatus_cmd(JCR *jcr)
300 BSOCK *dir = jcr->dir_bsock;
305 time = get_memory(dir->msglen+1);
307 if (sscanf(dir->msg, qstatus, time) != 1) {
308 pm_strcpy(&jcr->errmsg, dir->msg);
309 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
310 bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
311 bnet_sig(dir, BNET_EOD);
317 if (strcmp(time, "current") == 0) {
318 bnet_fsend(dir, OKqstatus, time);
320 if (njcr->JobId != 0) {
321 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
325 } else if (strcmp(time, "last") == 0) {
326 bnet_fsend(dir, OKqstatus, time);
327 if ((last_jobs) && (last_jobs->size() > 0)) {
328 job = (s_last_job*)last_jobs->last();
329 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
332 pm_strcpy(&jcr->errmsg, dir->msg);
333 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
334 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
335 bnet_sig(dir, BNET_EOD);
340 bnet_sig(dir, BNET_EOD);
346 * Convert Job Level into a string
348 static const char *level_to_str(int level)
359 str = _("Incremental");
362 str = _("Differential");
367 case L_VERIFY_CATALOG:
368 str = _("Verify Catalog");
371 str = _("Init Catalog");
373 case L_VERIFY_VOLUME_TO_CATALOG:
374 str = _("Volume to Catalog");
376 case L_VERIFY_DISK_TO_CATALOG:
377 str = _("Disk to Catalog");
386 str = _("Unknown Job Level");
393 #if defined(HAVE_WIN32)
397 * Put message in Window List Box
399 char *bac_status(char *buf, int buf_len)
402 const char *termstat = _("Bacula Client: Idle");
403 struct s_last_job *job;
404 int stat = 0; /* Idle */
409 Dmsg0(1000, "Begin bac_status jcr loop.\n");
411 if (njcr->JobId != 0) {
413 termstat = _("Bacula Client: Running");
422 if (last_jobs->size() > 0) {
423 job = (struct s_last_job *)last_jobs->last();
424 stat = job->JobStatus;
425 switch (job->JobStatus) {
427 termstat = _("Bacula Client: Last Job Canceled");
429 case JS_ErrorTerminated:
431 termstat = _("Bacula Client: Last Job Failed");
435 termstat = _("Bacula Client: Last Job had Warnings");
440 Dmsg0(1000, "End bac_status jcr loop.\n");
444 bstrncpy(buf, termstat, buf_len);
449 #endif /* HAVE_WIN32 */