2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2007 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 plus additions
11 that are listed in the file LICENSE.
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);
44 static void bsock_sendit(const char *msg, int len, void *arg);
45 static const char *level_to_str(int level);
47 /* Static variables */
48 static char qstatus[] = ".status %s\n";
50 static char OKqstatus[] = "2000 OK .status\n";
51 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
53 #if defined(HAVE_WIN32)
59 extern VSSClient *g_pVSSClient;
65 * General status generator
67 void output_status(void sendit(const char *msg, int len, void *sarg), void *arg)
70 char *msg, b1[32], b2[32], b3[32], b4[32], b5[5];
74 char dt[MAX_TIME_LENGTH];
76 msg = (char *)get_pool_memory(PM_MESSAGE);
77 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
78 my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
79 sendit(msg, len, arg);
80 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
81 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
82 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
83 sendit(msg, len, arg);
84 #if defined(HAVE_WIN32)
85 if (debug_level > 0) {
87 privs = enable_backup_privileges(NULL, 1);
89 len = Mmsg(msg, "Priv 0x%x\n", privs);
90 sendit(msg, len, arg);
91 len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
92 p_OpenProcessToken?"":"!",
93 p_AdjustTokenPrivileges?"":"!",
94 p_LookupPrivilegeValue?"":"!",
96 p_CreateFileW?"":"!");
97 sendit(msg, len, arg);
98 len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
101 p_GetFileAttributesA?"":"!",
102 p_GetFileAttributesW?"":"!",
103 p_GetFileAttributesExA?"":"!",
104 p_GetFileAttributesExW?"":"!",
105 p_SetFileAttributesA?"":"!",
106 p_SetFileAttributesW?"":"!",
108 p_BackupWrite?"":"!",
109 p_SetProcessShutdownParameters?"":"!");
110 sendit(msg, len, arg);
111 len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
112 p_WideCharToMultiByte?"":"!",
113 p_MultiByteToWideChar?"":"!",
114 p_FindFirstFileA?"":"!",
115 p_FindFirstFileW?"":"!",
116 p_FindNextFileA?"":"!",
117 p_FindNextFileW?"":"!",
118 p_SetCurrentDirectoryA?"":"!",
119 p_SetCurrentDirectoryW?"":"!");
120 sendit(msg, len, arg);
121 len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",
122 p_GetCurrentDirectoryA?"":"!",
123 p_GetCurrentDirectoryW?"":"!",
124 p_GetVolumePathNameW?"":"!",
125 p_GetVolumeNameForVolumeMountPointW?"":"!");
126 sendit(msg, len, arg);
129 len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
130 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
131 edit_uint64_with_commas(sm_bytes, b2),
132 edit_uint64_with_commas(sm_max_bytes, b3),
133 edit_uint64_with_commas(sm_buffers, b4),
134 edit_uint64_with_commas(sm_max_buffers, b5));
135 sendit(msg, len, arg);
136 len = Mmsg(msg, _(" Sizeof: boffset_t=%d size_t=%d debug=%d trace=%d\n"),
137 sizeof(boffset_t), sizeof(size_t), debug_level, get_trace());
138 sendit(msg, len, arg);
143 Dmsg0(1000, "Begin status jcr loop.\n");
144 len = Mmsg(msg, _("\nRunning Jobs:\n"));
145 sendit(msg, len, arg);
148 if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
153 bstrftime_nc(dt, sizeof(dt), njcr->start_time);
154 if (njcr->JobId == 0) {
155 len = Mmsg(msg, _("Director connected at: %s\n"), dt);
157 len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
158 njcr->JobId, njcr->Job);
159 sendit(msg, len, arg);
160 len = Mmsg(msg, _(" %s%s Job started: %s\n"),
161 vss, job_type_to_str(njcr->JobType), dt);
163 sendit(msg, len, arg);
164 if (njcr->JobId == 0) {
167 sec = time(NULL) - njcr->start_time;
171 bps = (int)(njcr->JobBytes / sec);
172 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
173 edit_uint64_with_commas(njcr->JobFiles, b1),
174 edit_uint64_with_commas(njcr->JobBytes, b2),
175 edit_uint64_with_commas(bps, b3));
176 sendit(msg, len, arg);
177 len = Mmsg(msg, _(" Files Examined=%s\n"),
178 edit_uint64_with_commas(njcr->num_files_examined, b1));
179 sendit(msg, len, arg);
180 if (njcr->JobFiles > 0) {
182 len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname);
184 sendit(msg, len, arg);
188 if (njcr->store_bsock) {
189 len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n",
190 njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
191 sendit(msg, len, arg);
193 len = Mmsg(msg, _(" SDSocket closed.\n"));
194 sendit(msg, len, arg);
200 len = Mmsg(msg, _("No Jobs running.\n"));
201 sendit(msg, len, arg);
203 sendit(_("====\n"), 5, arg);
205 list_terminated_jobs(sendit, arg);
207 free_pool_memory(msg);
210 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
212 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
214 struct s_last_job *je;
217 msg = _("\nTerminated Jobs:\n");
218 sendit(msg, strlen(msg), arg);
220 if (last_jobs->size() == 0) {
221 sendit(_("====\n"), 5, arg);
224 lock_last_jobs_list();
225 msg = _(" JobId Level Files Bytes Status Finished Name \n");
226 sendit(msg, strlen(msg), arg);
227 msg = _("======================================================================\n");
228 sendit(msg, strlen(msg), arg);
229 foreach_dlist(je, last_jobs) {
230 char JobName[MAX_NAME_LENGTH];
231 const char *termstat;
234 bstrftime_nc(dt, sizeof(dt), je->end_time);
235 switch (je->JobType) {
238 bstrncpy(level, " ", sizeof(level));
241 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
245 switch (je->JobStatus) {
247 termstat = _("Created");
250 case JS_ErrorTerminated:
251 termstat = _("Error");
254 termstat = _("Diffs");
257 termstat = _("Cancel");
263 termstat = _("Other");
266 bstrncpy(JobName, je->Job, sizeof(JobName));
267 /* There are three periods after the Job name */
269 for (int i=0; i<3; i++) {
270 if ((p=strrchr(JobName, '.')) != NULL) {
274 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
277 edit_uint64_with_commas(je->JobFiles, b1),
278 edit_uint64_with_suffix(je->JobBytes, b2),
281 sendit(buf, strlen(buf), arg);
283 sendit(_("====\n"), 5, arg);
284 unlock_last_jobs_list();
289 * Send to bsock (Director or Console)
291 static void bsock_sendit(const char *msg, int len, void *arg)
293 BSOCK *user = (BSOCK *)arg;
295 user->msg = check_pool_memory_size(user->msg, len+1);
296 memcpy(user->msg, msg, len+1);
297 user->msglen = len+1;
302 * Status command from Director
304 int status_cmd(JCR *jcr)
306 BSOCK *user = jcr->dir_bsock;
308 bnet_fsend(user, "\n");
309 output_status(bsock_sendit, (void *)user);
311 bnet_sig(user, BNET_EOD);
316 * .status command from Director
318 int qstatus_cmd(JCR *jcr)
320 BSOCK *dir = jcr->dir_bsock;
325 time = get_memory(dir->msglen+1);
327 if (sscanf(dir->msg, qstatus, time) != 1) {
328 pm_strcpy(&jcr->errmsg, dir->msg);
329 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
330 bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
331 bnet_sig(dir, BNET_EOD);
337 if (strcmp(time, "current") == 0) {
338 bnet_fsend(dir, OKqstatus, time);
340 if (njcr->JobId != 0) {
341 bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
345 } else if (strcmp(time, "last") == 0) {
346 bnet_fsend(dir, OKqstatus, time);
347 if ((last_jobs) && (last_jobs->size() > 0)) {
348 job = (s_last_job*)last_jobs->last();
349 bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
352 pm_strcpy(&jcr->errmsg, dir->msg);
353 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
354 bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
355 bnet_sig(dir, BNET_EOD);
360 bnet_sig(dir, BNET_EOD);
366 * Convert Job Level into a string
368 static const char *level_to_str(int level)
379 str = _("Incremental");
382 str = _("Differential");
387 case L_VERIFY_CATALOG:
388 str = _("Verify Catalog");
391 str = _("Init Catalog");
393 case L_VERIFY_VOLUME_TO_CATALOG:
394 str = _("Volume to Catalog");
396 case L_VERIFY_DISK_TO_CATALOG:
397 str = _("Disk to Catalog");
406 str = _("Unknown Job Level");
413 #if defined(HAVE_WIN32)
417 * Put message in Window List Box
419 char *bac_status(char *buf, int buf_len)
422 const char *termstat = _("Bacula Client: Idle");
423 struct s_last_job *job;
424 int stat = 0; /* Idle */
429 Dmsg0(1000, "Begin bac_status jcr loop.\n");
431 if (njcr->JobId != 0) {
433 termstat = _("Bacula Client: Running");
442 if (last_jobs->size() > 0) {
443 job = (struct s_last_job *)last_jobs->last();
444 stat = job->JobStatus;
445 switch (job->JobStatus) {
447 termstat = _("Bacula Client: Last Job Canceled");
449 case JS_ErrorTerminated:
451 termstat = _("Bacula Client: Last Job Failed");
455 termstat = _("Bacula Client: Last Job had Warnings");
460 Dmsg0(1000, "End bac_status jcr loop.\n");
464 bstrncpy(buf, termstat, buf_len);
469 #endif /* HAVE_WIN32 */