2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-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 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 * This file handles the status command
31 * Kern Sibbald, May MMIII
40 /* Exported variables */
42 /* Imported variables */
43 extern BSOCK *filed_chan;
44 extern int r_first, r_last;
45 extern struct s_res resources[];
46 extern void *start_heap;
48 /* Static variables */
49 static char qstatus[] = ".status %127s\n";
51 static char OKqstatus[] = "3000 OK .status\n";
52 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
55 /* Forward referenced functions */
56 static void send_blocked_status(DEVICE *dev, void sendit(const char *msg, int len, void *sarg), void *arg);
57 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
58 static void list_running_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
59 static void list_jobs_waiting_on_reservation(void sendit(const char *msg, int len, void *sarg), void *arg);
61 static const char *level_to_str(int level);
64 * Status command from Director
66 void output_status(void sendit(const char *msg, int len, void *sarg), void *arg)
71 char dt[MAX_TIME_LENGTH];
72 char b1[35], b2[35], b3[35], b4[35], b5[35];
77 msg = get_pool_memory(PM_MESSAGE);
79 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s\n"),
80 my_name, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
81 sendit(msg, len, arg);
83 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
86 len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
87 dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
88 sendit(msg, len, arg);
90 len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
91 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
92 edit_uint64_with_commas(sm_bytes, b2),
93 edit_uint64_with_commas(sm_max_bytes, b3),
94 edit_uint64_with_commas(sm_buffers, b4),
95 edit_uint64_with_commas(sm_max_buffers, b5));
96 sendit(msg, len, arg);
97 len = Mmsg(msg, "Sizes: boffset_t=%d size_t=%d int32_t=%d int64_t=%d\n",
98 (int)sizeof(boffset_t), (int)sizeof(size_t), (int)sizeof(int32_t),
99 (int)sizeof(int64_t));
100 sendit(msg, len, arg);
105 list_running_jobs(sendit, arg);
108 * List jobs stuck in reservation system
110 list_jobs_waiting_on_reservation(sendit, arg);
113 * List terminated jobs
115 list_terminated_jobs(sendit, arg);
120 len = Mmsg(msg, _("\nDevice status:\n"));
121 sendit(msg, len, arg);
123 foreach_res(changer, R_AUTOCHANGER) {
124 len = Mmsg(msg, _("Autochanger \"%s\" with devices:\n"),
126 sendit(msg, len, arg);
128 foreach_alist(device, changer->device) {
130 len = Mmsg(msg, " %s\n", device->dev->print_name());
131 sendit(msg, len, arg);
133 len = Mmsg(msg, " %s\n", device->hdr.name);
134 sendit(msg, len, arg);
138 foreach_res(device, R_DEVICE) {
140 if (dev && dev->is_open()) {
141 if (dev->is_labeled()) {
142 len = Mmsg(msg, _("Device %s is mounted with:\n"
145 " Media type: %s\n"),
147 dev->VolHdr.VolumeName,
148 dev->pool_name[0]?dev->pool_name:"*unknown*",
149 dev->device->media_type);
150 sendit(msg, len, arg);
152 len = Mmsg(msg, _("Device %s open but no Bacula volume is currently mounted.\n"),
154 sendit(msg, len, arg);
156 send_blocked_status(dev, sendit, arg);
157 if (dev->can_append()) {
158 bpb = dev->VolCatInfo.VolCatBlocks;
162 bpb = dev->VolCatInfo.VolCatBytes / bpb;
163 len = Mmsg(msg, _(" Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
164 edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
165 edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
166 edit_uint64_with_commas(bpb, b3));
167 sendit(msg, len, arg);
168 } else { /* reading */
169 bpb = dev->VolCatInfo.VolCatReads;
173 if (dev->VolCatInfo.VolCatRBytes > 0) {
174 bpb = dev->VolCatInfo.VolCatRBytes / bpb;
178 len = Mmsg(msg, _(" Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"),
179 edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1),
180 edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2),
181 edit_uint64_with_commas(bpb, b3));
182 sendit(msg, len, arg);
184 len = Mmsg(msg, _(" Positioned at File=%s Block=%s\n"),
185 edit_uint64_with_commas(dev->file, b1),
186 edit_uint64_with_commas(dev->block_num, b2));
187 sendit(msg, len, arg);
191 len = Mmsg(msg, _("Device %s is not open.\n"), dev->print_name());
192 sendit(msg, len, arg);
193 send_blocked_status(dev, sendit, arg);
195 len = Mmsg(msg, _("Device \"%s\" is not open or does not exist.\n"), device->hdr.name);
196 sendit(msg, len, arg);
200 sendit("====\n\n", 6, arg);
201 len = Mmsg(msg, _("In Use Volume status:\n"));
202 sendit(msg, len, arg);
203 list_volumes(sendit, arg);
204 sendit("====\n\n", 6, arg);
207 if (debug_level > 10) {
208 user->fsend(_("====\n\n"));
209 dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
210 user->fsend(_("====\n\n"));
214 list_spool_stats(sendit, arg);
216 free_pool_memory(msg);
219 static void send_blocked_status(DEVICE *dev, void sendit(const char *msg, int len, void *sarg), void *arg)
224 msg = (char *)get_pool_memory(PM_MESSAGE);
227 len = Mmsg(msg, _("No DEVICE structure.\n\n"));
228 sendit(msg, len, arg);
229 free_pool_memory(msg);
232 switch (dev->blocked()) {
234 len = Mmsg(msg, _(" Device is BLOCKED. User unmounted.\n"));
235 sendit(msg, len, arg);
237 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
238 len = Mmsg(msg, _(" Device is BLOCKED. User unmounted during wait for media/mount.\n"));
239 sendit(msg, len, arg);
241 case BST_WAITING_FOR_SYSOP:
243 dlist *dcrs = dev->attached_dcrs;
244 bool found_jcr = false;
248 for (dcr = (DCR *)dcrs->first(); dcr != NULL; dcr = (DCR *)dcrs->next(dcr)) {
249 if (dcr->jcr->JobStatus == JS_WaitMount) {
250 len = Mmsg(msg, _(" Device is BLOCKED waiting for mount of volume \"%s\",\n"
252 " Media type: %s\n"),
256 sendit(msg, len, arg);
258 } else if (dcr->jcr->JobStatus == JS_WaitMedia) {
259 len = Mmsg(msg, _(" Device is BLOCKED waiting to create a volume for:\n"
261 " Media type: %s\n"),
264 sendit(msg, len, arg);
271 len = Mmsg(msg, _(" Device is BLOCKED waiting for media.\n"));
272 sendit(msg, len, arg);
276 case BST_DOING_ACQUIRE:
277 len = Mmsg(msg, _(" Device is being initialized.\n"));
278 sendit(msg, len, arg);
280 case BST_WRITING_LABEL:
281 len = Mmsg(msg, _(" Device is blocked labeling a Volume.\n"));
282 sendit(msg, len, arg);
287 /* Send autochanger slot status */
288 if (dev->is_autochanger()) {
290 len = Mmsg(msg, _(" Slot %d is loaded in drive %d.\n"),
291 dev->Slot, dev->drive_index);
292 sendit(msg, len, arg);
293 } else if (dev->Slot == 0) {
294 len = Mmsg(msg, _(" Drive %d is not loaded.\n"), dev->drive_index);
295 sendit(msg, len, arg);
297 len = Mmsg(msg, _(" Drive %d status unknown.\n"), dev->drive_index);
298 sendit(msg, len, arg);
301 if (debug_level > 1) {
302 len = Mmsg(msg, _("Configured device capabilities:\n"));
303 sendit(msg, len, arg);
305 len = Mmsg(msg, "%sEOF %sBSR %sBSF %sFSR %sFSF %sEOM %sREM %sRACCESS %sAUTOMOUNT %sLABEL %sANONVOLS %sALWAYSOPEN\n",
306 dev->capabilities & CAP_EOF ? "" : "!",
307 dev->capabilities & CAP_BSR ? "" : "!",
308 dev->capabilities & CAP_BSF ? "" : "!",
309 dev->capabilities & CAP_FSR ? "" : "!",
310 dev->capabilities & CAP_FSF ? "" : "!",
311 dev->capabilities & CAP_EOM ? "" : "!",
312 dev->capabilities & CAP_REM ? "" : "!",
313 dev->capabilities & CAP_RACCESS ? "" : "!",
314 dev->capabilities & CAP_AUTOMOUNT ? "" : "!",
315 dev->capabilities & CAP_LABEL ? "" : "!",
316 dev->capabilities & CAP_ANONVOLS ? "" : "!",
317 dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
318 sendit(msg, len, arg);
320 len = Mmsg(msg, _("Device state:\n"));
321 sendit(msg, len, arg);
323 len = Mmsg(msg, "%sOPENED %sTAPE %sLABEL %sMALLOC %sAPPEND %sREAD %sEOT %sWEOT %sEOF %sNEXTVOL %sSHORT %sMOUNTED\n",
324 dev->is_open() ? "" : "!",
325 dev->is_tape() ? "" : "!",
326 dev->is_labeled() ? "" : "!",
327 dev->state & ST_MALLOC ? "" : "!",
328 dev->can_append() ? "" : "!",
329 dev->can_read() ? "" : "!",
330 dev->at_eot() ? "" : "!",
331 dev->state & ST_WEOT ? "" : "!",
332 dev->at_eof() ? "" : "!",
333 dev->state & ST_NEXTVOL ? "" : "!",
334 dev->state & ST_SHORT ? "" : "!",
335 dev->state & ST_MOUNTED ? "" : "!");
336 sendit(msg, len, arg);
338 len = Mmsg(msg, _("num_writers=%d block=%d\n\n"), dev->num_writers, dev->blocked());
339 sendit(msg, len, arg);
341 len = Mmsg(msg, _("Device parameters:\n"));
342 sendit(msg, len, arg);
344 len = Mmsg(msg, _("Archive name: %s Device name: %s\n"), dev->archive_name(),
346 sendit(msg, len, arg);
348 len = Mmsg(msg, _("File=%u block=%u\n"), dev->file, dev->block_num);
349 sendit(msg, len, arg);
351 len = Mmsg(msg, _("Min block=%u Max block=%u\n"), dev->min_block_size, dev->max_block_size);
352 sendit(msg, len, arg);
355 free_pool_memory(msg);
358 static void list_running_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
364 char JobName[MAX_NAME_LENGTH];
365 char *msg, b1[30], b2[30], b3[30];
368 msg = (char *)get_pool_memory(PM_MESSAGE);
370 len = Mmsg(msg, _("\nRunning Jobs:\n"));
371 sendit(msg, len, arg);
374 if (jcr->JobStatus == JS_WaitFD) {
375 len = Mmsg(msg, _("%s Job %s waiting for Client connection.\n"),
376 job_type_to_str(jcr->JobType), jcr->Job);
377 sendit(msg, len, arg);
380 rdcr = jcr->read_dcr;
381 if ((dcr && dcr->device) || rdcr && rdcr->device) {
382 bstrncpy(JobName, jcr->Job, sizeof(JobName));
383 /* There are three periods after the Job name */
385 for (int i=0; i<3; i++) {
386 if ((p=strrchr(JobName, '.')) != NULL) {
390 if (rdcr && rdcr->device) {
391 len = Mmsg(msg, _("Reading: %s %s job %s JobId=%d Volume=\"%s\"\n"
392 " pool=\"%s\" device=%s\n"),
393 job_level_to_str(jcr->JobLevel),
394 job_type_to_str(jcr->JobType),
399 rdcr->dev?rdcr->dev->print_name():
400 rdcr->device->device_name);
401 sendit(msg, len, arg);
403 if (dcr && dcr->device) {
404 len = Mmsg(msg, _("Writing: %s %s job %s JobId=%d Volume=\"%s\"\n"
405 " pool=\"%s\" device=%s\n"),
406 job_level_to_str(jcr->JobLevel),
407 job_type_to_str(jcr->JobType),
412 dcr->dev?dcr->dev->print_name():
413 dcr->device->device_name);
414 sendit(msg, len, arg);
415 len= Mmsg(msg, _(" spooling=%d despooling=%d despool_wait=%d\n"),
416 dcr->spooling, dcr->despooling, dcr->despool_wait);
417 sendit(msg, len, arg);
419 sec = time(NULL) - jcr->run_time;
423 bps = jcr->JobBytes / sec;
424 len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"),
425 edit_uint64_with_commas(jcr->JobFiles, b1),
426 edit_uint64_with_commas(jcr->JobBytes, b2),
427 edit_uint64_with_commas(bps, b3));
428 sendit(msg, len, arg);
431 if (jcr->file_bsock) {
432 len = Mmsg(msg, _(" FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n"),
433 edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1),
434 jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no,
435 jcr->file_bsock->m_fd);
436 sendit(msg, len, arg);
438 len = Mmsg(msg, _(" FDSocket closed\n"));
439 sendit(msg, len, arg);
447 len = Mmsg(msg, _("No Jobs running.\n"));
448 sendit(msg, len, arg);
450 sendit("====\n", 5, arg);
452 free_pool_memory(msg);
455 static void list_jobs_waiting_on_reservation(void sendit(const char *msg, int len, void *sarg), void *arg)
460 msg = _("\nJobs waiting to reserve a drive:\n");
461 sendit(msg, strlen(msg), arg);
464 if (!jcr->reserve_msgs) {
467 send_drive_reserve_messages(jcr, sendit, arg);
471 sendit("====\n", 5, arg);
475 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
477 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
479 struct s_last_job *je;
482 msg = _("\nTerminated Jobs:\n");
483 sendit(msg, strlen(msg), arg);
484 if (last_jobs->size() == 0) {
485 sendit("====\n", 5, arg);
488 lock_last_jobs_list();
489 msg = _(" JobId Level Files Bytes Status Finished Name \n");
490 sendit(msg, strlen(msg), arg);
491 msg = _("===================================================================\n");
492 sendit(msg, strlen(msg), arg);
493 foreach_dlist(je, last_jobs) {
494 char JobName[MAX_NAME_LENGTH];
495 const char *termstat;
498 bstrftime_nc(dt, sizeof(dt), je->end_time);
499 switch (je->JobType) {
502 bstrncpy(level, " ", sizeof(level));
505 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
509 switch (je->JobStatus) {
511 termstat = _("Created");
514 case JS_ErrorTerminated:
515 termstat = _("Error");
518 termstat = _("Diffs");
521 termstat = _("Cancel");
527 termstat = _("Other");
530 bstrncpy(JobName, je->Job, sizeof(JobName));
531 /* There are three periods after the Job name */
533 for (int i=0; i<3; i++) {
534 if ((p=strrchr(JobName, '.')) != NULL) {
538 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
541 edit_uint64_with_commas(je->JobFiles, b1),
542 edit_uint64_with_suffix(je->JobBytes, b2),
545 sendit(buf, strlen(buf), arg);
547 unlock_last_jobs_list();
548 sendit("====\n", 5, arg);
552 * Convert Job Level into a string
554 static const char *level_to_str(int level)
565 str = _("Incremental");
568 str = _("Differential");
573 case L_VERIFY_CATALOG:
574 str = _("Verify Catalog");
577 str = _("Init Catalog");
579 case L_VERIFY_VOLUME_TO_CATALOG:
580 str = _("Volume to Catalog");
582 case L_VERIFY_DISK_TO_CATALOG:
583 str = _("Disk to Catalog");
592 str = _("Unknown Job Level");
601 static void dir_sendit(const char *msg, int len, void *arg)
603 BSOCK *user = (BSOCK *)arg;
605 memcpy(user->msg, msg, len+1);
606 user->msglen = len+1;
611 * Status command from Director
613 bool status_cmd(JCR *jcr)
615 BSOCK *user = jcr->dir_bsock;
618 output_status(dir_sendit, (void *)user);
620 user->signal(BNET_EOD);
625 * .status command from Director
627 bool qstatus_cmd(JCR *jcr)
629 BSOCK *dir = jcr->dir_bsock;
634 if (sscanf(dir->msg, qstatus, time.c_str()) != 1) {
635 pm_strcpy(jcr->errmsg, dir->msg);
636 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
637 dir->fsend(_("3900 Bad .status command, missing argument.\n"));
638 dir->signal(BNET_EOD);
643 if (strcmp(time.c_str(), "current") == 0) {
644 dir->fsend(OKqstatus, time.c_str());
646 if (njcr->JobId != 0) {
647 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
651 } else if (strcmp(time.c_str(), "last") == 0) {
652 dir->fsend(OKqstatus, time.c_str());
653 if ((last_jobs) && (last_jobs->size() > 0)) {
654 job = (s_last_job*)last_jobs->last();
655 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
658 pm_strcpy(jcr->errmsg, dir->msg);
659 Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
660 dir->fsend(_("3900 Bad .status command, wrong argument.\n"));
661 dir->signal(BNET_EOD);
664 dir->signal(BNET_EOD);
668 #if defined(HAVE_WIN32)
671 char *bac_status(char *buf, int buf_len)
674 const char *termstat = _("Bacula Storage: Idle");
675 struct s_last_job *job;
676 int stat = 0; /* Idle */
681 Dmsg0(1000, "Begin bac_status jcr loop.\n");
683 if (njcr->JobId != 0) {
685 termstat = _("Bacula Storage: Running");
694 if (last_jobs->size() > 0) {
695 job = (struct s_last_job *)last_jobs->last();
696 stat = job->JobStatus;
697 switch (job->JobStatus) {
699 termstat = _("Bacula Storage: Last Job Canceled");
701 case JS_ErrorTerminated:
703 termstat = _("Bacula Storage: Last Job Failed");
707 termstat = _("Bacula Storage: Last Job had Warnings");
712 Dmsg0(1000, "End bac_status jcr loop.\n");
716 bstrncpy(buf, termstat, buf_len);
721 #endif /* HAVE_WIN32 */