2 * Bacula File Daemon Status routines
4 * Kern Sibbald, August MMI
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
40 /* Forward referenced functions */
41 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
42 static void bsock_sendit(const char *msg, int len, void *arg);
43 static const char *level_to_str(int level);
45 /* Static variables */
46 static char qstatus[] = ".status %s\n";
48 static char OKqstatus[] = "2000 OK .status\n";
49 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
51 #if defined(HAVE_WIN32)
57 extern VSSClient *g_pVSSClient;
63 * General status generator
65 void output_status(void sendit(const char *msg, int len, void *sarg), void *arg)
68 char *msg, b1[32], b2[32], b3[32], b4[32];
72 char dt[MAX_TIME_LENGTH];
74 msg = (char *)get_pool_memory(PM_MESSAGE);
75 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
76 my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
77 sendit(msg, len, arg);
78 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
79 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
80 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
81 sendit(msg, len, arg);
82 #if defined(HAVE_WIN32)
83 if (debug_level > 0) {
85 privs = enable_backup_privileges(NULL, 1);
87 len = Mmsg(msg, "Priv 0x%x\n", privs);
88 sendit(msg, len, arg);
89 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
90 p_OpenProcessToken?"":"!",
91 p_AdjustTokenPrivileges?"":"!",
92 p_LookupPrivilegeValue?"":"!",
94 p_CreateFileW?"":"!");
95 sendit(msg, len, arg);
96 len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
99 p_GetFileAttributesA?"":"!",
100 p_GetFileAttributesW?"":"!",
101 p_GetFileAttributesExA?"":"!",
102 p_GetFileAttributesExW?"":"!",
103 p_SetFileAttributesA?"":"!",
104 p_SetFileAttributesW?"":"!",
106 p_BackupWrite?"":"!",
107 p_SetProcessShutdownParameters?"":"!");
108 sendit(msg, len, arg);
109 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
110 p_WideCharToMultiByte?"":"!",
111 p_MultiByteToWideChar?"":"!",
112 p_FindFirstFileA?"":"!",
113 p_FindFirstFileW?"":"!",
114 p_FindNextFileA?"":"!",
115 p_FindNextFileW?"":"!",
116 p_SetCurrentDirectoryA?"":"!",
117 p_SetCurrentDirectoryW?"":"!");
118 sendit(msg, len, arg);
119 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",
120 p_GetCurrentDirectoryA?"":"!",
121 p_GetCurrentDirectoryW?"":"!",
122 p_GetVolumePathNameW?"":"!",
123 p_GetVolumeNameForVolumeMountPointW?"":"!");
124 sendit(msg, len, arg);
127 len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
128 edit_uint64_with_commas(sm_bytes, b1),
129 edit_uint64_with_commas(sm_max_bytes, b2),
130 edit_uint64_with_commas(sm_buffers, b3),
131 edit_uint64_with_commas(sm_max_buffers, b4));
132 sendit(msg, len, arg);
133 len = Mmsg(msg, _(" Sizeof: boffset_t=%d size_t=%d debug=%d trace=%d\n"),
134 sizeof(boffset_t), sizeof(size_t), debug_level, get_trace());
135 sendit(msg, len, arg);
140 Dmsg0(1000, "Begin status jcr loop.\n");
141 len = Mmsg(msg, _("\nRunning Jobs:\n"));
142 sendit(msg, len, arg);
145 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
150 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
151 if (njcr->JobId == 0) {
152 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
154 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
155 njcr->JobId, njcr->Job);
156 sendit(msg, len, arg);
157 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
158 vss, job_type_to_str(njcr->JobType), dt);
160 sendit(msg, len, arg);
161 if (njcr->JobId == 0) {
164 sec = time(NULL) - njcr->start_time;
168 bps = (int)(njcr->JobBytes / sec);
169 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
170 edit_uint64_with_commas(njcr->JobFiles, b1),
171 edit_uint64_with_commas(njcr->JobBytes, b2),
172 edit_uint64_with_commas(bps, b3));
173 sendit(msg, len, arg);
174 len = Mmsg(msg, _(" Files Examined=%s\n"),
175 edit_uint64_with_commas(njcr->num_files_examined, b1));
176 sendit(msg, len, arg);
177 if (njcr->JobFiles > 0) {
179 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
181 sendit(msg, len, arg);
185 if (njcr->store_bsock) {
186 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
187 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
188 sendit(msg, len, arg);
190 len = Mmsg(msg, _(" SDSocket closed.\n"));
191 sendit(msg, len, arg);
197 len = Mmsg(msg, _("No Jobs running.\n"));
198 sendit(msg, len, arg);
200 sendit(_("====\n"), 5, arg);
202 list_terminated_jobs(sendit, arg);
204 free_pool_memory(msg);
207 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
209 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
211 struct s_last_job *je;
214 msg = _("\nTerminated Jobs:\n");
215 sendit(msg, strlen(msg), arg);
217 if (last_jobs->size() == 0) {
218 sendit(_("====\n"), 5, arg);
221 lock_last_jobs_list();
222 msg = _(" JobId Level Files Bytes Status Finished Name \n");
223 sendit(msg, strlen(msg), arg);
224 msg = _("======================================================================\n");
225 sendit(msg, strlen(msg), arg);
226 foreach_dlist(je, last_jobs) {
227 char JobName[MAX_NAME_LENGTH];
228 const char *termstat;
231 bstrftime_nc(dt, sizeof(dt), je->end_time);
232 switch (je->JobType) {
235 bstrncpy(level, " ", sizeof(level));
238 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
242 switch (je->JobStatus) {
244 termstat = _("Created");
247 case JS_ErrorTerminated:
248 termstat = _("Error");
251 termstat = _("Diffs");
254 termstat = _("Cancel");
260 termstat = _("Other");
263 bstrncpy(JobName, je->Job, sizeof(JobName));
264 /* There are three periods after the Job name */
266 for (int i=0; i<3; i++) {
267 if ((p=strrchr(JobName, '.')) != NULL) {
271 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
274 edit_uint64_with_commas(je->JobFiles, b1),
275 edit_uint64_with_suffix(je->JobBytes, b2),
278 sendit(buf, strlen(buf), arg);
280 sendit(_("====\n"), 5, arg);
281 unlock_last_jobs_list();
286 * Send to bsock (Director or Console)
288 static void bsock_sendit(const char *msg, int len, void *arg)
290 BSOCK *user = (BSOCK *)arg;
292 user->msg = check_pool_memory_size(user->msg, len+1);
293 memcpy(user->msg, msg, len+1);
294 user->msglen = len+1;
299 * Status command from Director
301 int status_cmd(JCR *jcr)
303 BSOCK *user = jcr->dir_bsock;
305 bnet_fsend(user, "\n");
306 output_status(bsock_sendit, (void *)user);
308 bnet_sig(user, BNET_EOD);
313 * .status command from Director
315 int qstatus_cmd(JCR *jcr)
317 BSOCK *dir = jcr->dir_bsock;
322 time = get_memory(dir->msglen+1);
324 if (sscanf(dir->msg, qstatus, time) != 1) {
325 pm_strcpy(&jcr->errmsg, dir->msg);
326 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
327 bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
328 bnet_sig(dir, BNET_EOD);
334 if (strcmp(time, "current") == 0) {
335 bnet_fsend(dir, OKqstatus, time);
337 if (njcr->JobId != 0) {
338 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
342 } else if (strcmp(time, "last") == 0) {
343 bnet_fsend(dir, OKqstatus, time);
344 if ((last_jobs) && (last_jobs->size() > 0)) {
345 job = (s_last_job*)last_jobs->last();
346 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
349 pm_strcpy(&jcr->errmsg, dir->msg);
350 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
351 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
352 bnet_sig(dir, BNET_EOD);
357 bnet_sig(dir, BNET_EOD);
363 * Convert Job Level into a string
365 static const char *level_to_str(int level)
376 str = _("Incremental");
379 str = _("Differential");
384 case L_VERIFY_CATALOG:
385 str = _("Verify Catalog");
388 str = _("Init Catalog");
390 case L_VERIFY_VOLUME_TO_CATALOG:
391 str = _("Volume to Catalog");
393 case L_VERIFY_DISK_TO_CATALOG:
394 str = _("Disk to Catalog");
403 str = _("Unknown Job Level");
410 #if defined(HAVE_WIN32)
414 * Put message in Window List Box
416 char *bac_status(char *buf, int buf_len)
419 const char *termstat = _("Bacula Client: Idle");
420 struct s_last_job *job;
421 int stat = 0; /* Idle */
426 Dmsg0(1000, "Begin bac_status jcr loop.\n");
428 if (njcr->JobId != 0) {
430 termstat = _("Bacula Client: Running");
439 if (last_jobs->size() > 0) {
440 job = (struct s_last_job *)last_jobs->last();
441 stat = job->JobStatus;
442 switch (job->JobStatus) {
444 termstat = _("Bacula Client: Last Job Canceled");
446 case JS_ErrorTerminated:
448 termstat = _("Bacula Client: Last Job Failed");
452 termstat = _("Bacula Client: Last Job had Warnings");
457 Dmsg0(1000, "End bac_status jcr loop.\n");
461 bstrncpy(buf, termstat, buf_len);
466 #endif /* HAVE_WIN32 */