2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula File Daemon Status routines
31 * Kern Sibbald, August MMI
40 extern void *start_heap;
42 /* Forward referenced functions */
43 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg, bool api);
44 static void list_running_jobs(void sendit(const char *msg, int len, void *sarg), void *arg, bool api);
45 static void list_status_header(void sendit(const char *msg, int len, void *sarg), void *arg, bool api);
46 static void bsock_sendit(const char *msg, int len, void *arg);
47 static const char *level_to_str(int level);
49 /* Static variables */
50 static char qstatus[] = ".status %s\n";
52 static char OKqstatus[] = "2000 OK .status\n";
53 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
55 #if defined(HAVE_WIN32)
61 extern VSSClient *g_pVSSClient;
67 * General status generator
69 void output_status(void sendit(const char *msg, int len, void *sarg), void *arg)
71 list_status_header(sendit, arg, false /*no api*/);
72 list_running_jobs(sendit, arg, false /*no api*/);
73 list_terminated_jobs(sendit, arg, false /*no api*/);
76 static void list_status_header(void sendit(const char *msg, int len, void *sarg), void *arg, bool api)
78 POOL_MEM msg(PM_MESSAGE);
79 char b1[32], b2[32], b3[32], b4[32], b5[35];
81 char dt[MAX_TIME_LENGTH];
83 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
84 my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
85 sendit(msg.c_str(), len, arg);
86 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
87 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
88 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
89 sendit(msg.c_str(), len, arg);
90 #if defined(HAVE_WIN32)
91 if (debug_level > 0) {
93 privs = enable_backup_privileges(NULL, 1);
95 len = Mmsg(msg, "VSS %s, Priv 0x%x\n", g_pVSSClient?"enabled":"disabled", privs);
96 sendit(msg.c_str(), len, arg);
97 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
98 p_OpenProcessToken?"":"!",
99 p_AdjustTokenPrivileges?"":"!",
100 p_LookupPrivilegeValue?"":"!",
101 p_CreateFileA?"":"!",
102 p_CreateFileW?"":"!");
103 sendit(msg.c_str(), len, arg);
104 len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
107 p_GetFileAttributesA?"":"!",
108 p_GetFileAttributesW?"":"!",
109 p_GetFileAttributesExA?"":"!",
110 p_GetFileAttributesExW?"":"!",
111 p_SetFileAttributesA?"":"!",
112 p_SetFileAttributesW?"":"!",
114 p_BackupWrite?"":"!",
115 p_SetProcessShutdownParameters?"":"!");
116 sendit(msg.c_str(), len, arg);
117 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
118 p_WideCharToMultiByte?"":"!",
119 p_MultiByteToWideChar?"":"!",
120 p_FindFirstFileA?"":"!",
121 p_FindFirstFileW?"":"!",
122 p_FindNextFileA?"":"!",
123 p_FindNextFileW?"":"!",
124 p_SetCurrentDirectoryA?"":"!",
125 p_SetCurrentDirectoryW?"":"!");
126 sendit(msg.c_str(), len, arg);
127 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",
128 p_GetCurrentDirectoryA?"":"!",
129 p_GetCurrentDirectoryW?"":"!",
130 p_GetVolumePathNameW?"":"!",
131 p_GetVolumeNameForVolumeMountPointW?"":"!");
132 sendit(msg.c_str(), len, arg);
135 len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
136 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
137 edit_uint64_with_commas(sm_bytes, b2),
138 edit_uint64_with_commas(sm_max_bytes, b3),
139 edit_uint64_with_commas(sm_buffers, b4),
140 edit_uint64_with_commas(sm_max_buffers, b5));
141 sendit(msg.c_str(), len, arg);
142 len = Mmsg(msg, _(" Sizeof: boffset_t=%d size_t=%d debug=%d trace=%d\n"),
143 sizeof(boffset_t), sizeof(size_t), debug_level, get_trace());
144 sendit(msg.c_str(), len, arg);
147 static void list_running_jobs(void sendit(const char *msg, int len, void *sarg), void *arg, bool api)
150 POOL_MEM msg(PM_MESSAGE);
151 char b1[32], b2[32], b3[32];
155 char dt[MAX_TIME_LENGTH];
159 Dmsg0(1000, "Begin status jcr loop.\n");
161 len = Mmsg(msg, _("\nRunning Jobs:\n"));
162 sendit(msg.c_str(), len, arg);
164 const char *vss = "";
166 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
171 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
172 if (njcr->JobId == 0) {
173 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
175 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
176 njcr->JobId, njcr->Job);
177 sendit(msg.c_str(), len, arg);
178 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
179 vss, job_type_to_str(njcr->JobType), dt);
181 sendit(msg.c_str(), len, arg);
182 if (njcr->JobId == 0) {
185 sec = time(NULL) - njcr->start_time;
189 bps = (int)(njcr->JobBytes / sec);
190 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s Errors=%d\n"),
191 edit_uint64_with_commas(njcr->JobFiles, b1),
192 edit_uint64_with_commas(njcr->JobBytes, b2),
193 edit_uint64_with_commas(bps, b3),
195 sendit(msg.c_str(), len, arg);
196 len = Mmsg(msg, _(" Files Examined=%s\n"),
197 edit_uint64_with_commas(njcr->num_files_examined, b1));
198 sendit(msg.c_str(), len, arg);
199 if (njcr->JobFiles > 0) {
201 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
203 sendit(msg.c_str(), len, arg);
207 if (njcr->store_bsock) {
208 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
209 njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
210 sendit(msg.c_str(), len, arg);
212 len = Mmsg(msg, _(" SDSocket closed.\n"));
213 sendit(msg.c_str(), len, arg);
220 len = Mmsg(msg, _("No Jobs running.\n"));
221 sendit(msg.c_str(), len, arg);
223 sendit(_("====\n"), 5, arg);
228 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg, bool api)
230 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
232 struct s_last_job *je;
236 msg = _("\nTerminated Jobs:\n");
237 sendit(msg, strlen(msg), arg);
240 if (last_jobs->size() == 0) {
241 if (!api) sendit(_("====\n"), 5, arg);
244 lock_last_jobs_list();
246 msg = _(" JobId Level Files Bytes Status Finished Name \n");
247 sendit(msg, strlen(msg), arg);
248 msg = _("======================================================================\n");
249 sendit(msg, strlen(msg), arg);
251 foreach_dlist(je, last_jobs) {
252 char JobName[MAX_NAME_LENGTH];
253 const char *termstat;
256 bstrftime_nc(dt, sizeof(dt), je->end_time);
257 switch (je->JobType) {
260 bstrncpy(level, " ", sizeof(level));
263 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
267 switch (je->JobStatus) {
269 termstat = _("Created");
272 case JS_ErrorTerminated:
273 termstat = _("Error");
276 termstat = _("Diffs");
279 termstat = _("Cancel");
285 termstat = _("Other");
288 bstrncpy(JobName, je->Job, sizeof(JobName));
289 /* There are three periods after the Job name */
291 for (int i=0; i<3; i++) {
292 if ((p=strrchr(JobName, '.')) != NULL) {
297 bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
300 edit_uint64_with_commas(je->JobFiles, b1),
301 edit_uint64_with_suffix(je->JobBytes, b2),
305 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
308 edit_uint64_with_commas(je->JobFiles, b1),
309 edit_uint64_with_suffix(je->JobBytes, b2),
313 sendit(buf, strlen(buf), arg);
315 if (!api) sendit(_("====\n"), 5, arg);
316 unlock_last_jobs_list();
321 * Send to bsock (Director or Console)
323 static void bsock_sendit(const char *msg, int len, void *arg)
325 BSOCK *user = (BSOCK *)arg;
327 user->msg = check_pool_memory_size(user->msg, len+1);
328 memcpy(user->msg, msg, len+1);
329 user->msglen = len+1;
334 * Status command from Director
336 int status_cmd(JCR *jcr)
338 BSOCK *user = jcr->dir_bsock;
341 output_status(bsock_sendit, (void *)user);
343 user->signal(BNET_EOD);
348 * .status command from Director
350 int qstatus_cmd(JCR *jcr)
352 BSOCK *dir = jcr->dir_bsock;
357 cmd = get_memory(dir->msglen+1);
359 if (sscanf(dir->msg, qstatus, cmd) != 1) {
360 pm_strcpy(&jcr->errmsg, dir->msg);
361 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
362 dir->fsend(_("2900 Bad .status command, missing argument.\n"));
363 dir->signal(BNET_EOD);
369 if (strcmp(cmd, "current") == 0) {
370 dir->fsend(OKqstatus, cmd);
372 if (njcr->JobId != 0) {
373 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
377 } else if (strcmp(cmd, "last") == 0) {
378 dir->fsend(OKqstatus, cmd);
379 if ((last_jobs) && (last_jobs->size() > 0)) {
380 job = (s_last_job*)last_jobs->last();
381 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
383 } else if (strcasecmp(cmd, "header") == 0) {
384 list_status_header(bsock_sendit, (void *)dir, true/*api*/);
385 } else if (strcasecmp(cmd, "running") == 0) {
386 list_running_jobs(bsock_sendit, (void *)dir, true/*api*/);
387 } else if (strcasecmp(cmd, "terminated") == 0) {
388 list_terminated_jobs(bsock_sendit, (void *)dir, true/*api*/);
390 pm_strcpy(&jcr->errmsg, dir->msg);
391 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
392 dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
393 bnet_sig(dir, BNET_EOD);
398 bnet_sig(dir, BNET_EOD);
404 * Convert Job Level into a string
406 static const char *level_to_str(int level)
417 str = _("Incremental");
420 str = _("Differential");
425 case L_VERIFY_CATALOG:
426 str = _("Verify Catalog");
429 str = _("Init Catalog");
431 case L_VERIFY_VOLUME_TO_CATALOG:
432 str = _("Volume to Catalog");
434 case L_VERIFY_DISK_TO_CATALOG:
435 str = _("Disk to Catalog");
444 str = _("Unknown Job Level");
451 #if defined(HAVE_WIN32)
455 * Put message in Window List Box
457 char *bac_status(char *buf, int buf_len)
460 const char *termstat = _("Bacula Client: Idle");
461 struct s_last_job *job;
462 int stat = 0; /* Idle */
467 Dmsg0(1000, "Begin bac_status jcr loop.\n");
469 if (njcr->JobId != 0) {
471 termstat = _("Bacula Client: Running");
480 if (last_jobs->size() > 0) {
481 job = (struct s_last_job *)last_jobs->last();
482 stat = job->JobStatus;
483 switch (job->JobStatus) {
485 termstat = _("Bacula Client: Last Job Canceled");
487 case JS_ErrorTerminated:
489 termstat = _("Bacula Client: Last Job Failed");
493 termstat = _("Bacula Client: Last Job had Warnings");
498 Dmsg0(1000, "End bac_status jcr loop.\n");
502 bstrncpy(buf, termstat, buf_len);
507 #endif /* HAVE_WIN32 */