2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-2012 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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
38 #include "lib/status.h"
40 /* Imported functions */
42 /* Imported variables */
43 extern BSOCK *filed_chan;
44 extern void *start_heap;
46 /* Static variables */
47 static char qstatus[] = ".status %127s\n";
49 static char OKqstatus[] = "3000 OK .status\n";
50 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
53 /* Forward referenced functions */
54 static void sendit(const char *msg, int len, STATUS_PKT *sp);
55 static void sendit(POOL_MEM &msg, int len, STATUS_PKT *sp);
56 static void sendit(const char *msg, int len, void *arg);
58 static void send_blocked_status(DEVICE *dev, STATUS_PKT *sp);
59 static void send_device_status(DEVICE *dev, STATUS_PKT *sp);
60 static void list_terminated_jobs(STATUS_PKT *sp);
61 static void list_running_jobs(STATUS_PKT *sp);
62 static void list_jobs_waiting_on_reservation(STATUS_PKT *sp);
63 static void list_status_header(STATUS_PKT *sp);
64 static void list_devices(STATUS_PKT *sp);
66 static const char *level_to_str(int level);
69 * Status command from Director
71 void output_status(STATUS_PKT *sp)
73 POOL_MEM msg(PM_MESSAGE);
76 list_status_header(sp);
81 list_running_jobs(sp);
84 * List jobs stuck in reservation system
86 list_jobs_waiting_on_reservation(sp);
89 * List terminated jobs
91 list_terminated_jobs(sp);
99 len = Mmsg(msg, _("Used Volume status:\n"));
100 if (!sp->api) sendit(msg, len, sp);
102 list_volumes(sendit, (void *)sp);
103 if (!sp->api) sendit("====\n\n", 6, sp);
106 list_spool_stats(sendit, (void *)sp);
107 if (!sp->api) sendit("====\n\n", 6, sp);
111 static void list_resources(STATUS_PKT *sp)
114 POOL_MEM msg(PM_MESSAGE);
117 len = Mmsg(msg, _("\nSD Resources:\n"));
118 if (!sp->api) sendit(msg, len, sp);
119 dump_resource(R_DEVICE, resources[R_DEVICE-r_first], sp);
120 if (!sp->api) sendit("====\n\n", 6, sp);
125 static find_device(char *devname)
127 foreach_res(device, R_DEVICE) {
128 if (strcasecmp(device->hdr.name, devname) == 0) {
134 foreach_res(changer, R_AUTOCHANGER) {
135 if (strcasecmp(changer->hdr.name, devname) == 0) {
143 static void list_devices(STATUS_PKT *sp)
146 AUTOCHANGER *changer;
148 char b1[35], b2[35], b3[35];
149 POOL_MEM msg(PM_MESSAGE);
153 len = Mmsg(msg, _("\nDevice status:\n"));
154 if (!sp->api) sendit(msg, len, sp);
156 foreach_res(changer, R_AUTOCHANGER) {
157 len = Mmsg(msg, _("Autochanger \"%s\" with devices:\n"),
159 sendit(msg, len, sp);
161 foreach_alist(device, changer->device) {
163 len = Mmsg(msg, " %s\n", device->dev->print_name());
164 sendit(msg, len, sp);
166 len = Mmsg(msg, " %s\n", device->hdr.name);
167 sendit(msg, len, sp);
173 foreach_res(device, R_DEVICE) {
175 if (dev && dev->is_open()) {
176 if (dev->is_labeled()) {
177 len = Mmsg(msg, _("\nDevice %s is %s:\n"
180 " Media type: %s\n"),
182 dev->blocked()?_("waiting for"):_("mounted with"),
183 dev->VolHdr.VolumeName,
184 dev->pool_name[0]?dev->pool_name:_("*unknown*"),
185 dev->device->media_type);
186 sendit(msg, len, sp);
188 len = Mmsg(msg, _("\nDevice %s open but no Bacula volume is currently mounted.\n"),
190 sendit(msg, len, sp);
192 send_blocked_status(dev, sp);
193 if (dev->can_append()) {
194 bpb = dev->VolCatInfo.VolCatBlocks;
198 bpb = dev->VolCatInfo.VolCatBytes / bpb;
199 len = Mmsg(msg, _(" Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
200 edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
201 edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
202 edit_uint64_with_commas(bpb, b3));
203 sendit(msg, len, sp);
204 } else { /* reading */
205 bpb = dev->VolCatInfo.VolCatReads;
209 if (dev->VolCatInfo.VolCatRBytes > 0) {
210 bpb = dev->VolCatInfo.VolCatRBytes / bpb;
214 len = Mmsg(msg, _(" Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"),
215 edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1),
216 edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2),
217 edit_uint64_with_commas(bpb, b3));
218 sendit(msg, len, sp);
220 len = Mmsg(msg, _(" Positioned at File=%s Block=%s\n"),
221 edit_uint64_with_commas(dev->file, b1),
222 edit_uint64_with_commas(dev->block_num, b2));
223 sendit(msg, len, sp);
227 len = Mmsg(msg, _("\nDevice %s is not open.\n"), dev->print_name());
228 sendit(msg, len, sp);
229 send_blocked_status(dev, sp);
231 len = Mmsg(msg, _("\nDevice \"%s\" is not open or does not exist.\n"), device->hdr.name);
232 sendit(msg, len, sp);
236 if (!sp->api) sendit("==\n", 4, sp);
238 if (!sp->api) sendit("====\n\n", 6, sp);
241 static void list_status_header(STATUS_PKT *sp)
243 char dt[MAX_TIME_LENGTH];
244 char b1[35], b2[35], b3[35], b4[35], b5[35];
245 POOL_MEM msg(PM_MESSAGE);
248 len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s\n"),
249 my_name, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
250 sendit(msg, len, sp);
252 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
255 len = Mmsg(msg, _("Daemon started %s. Jobs: run=%d, running=%d.\n"),
256 dt, num_jobs_run, job_count());
257 sendit(msg, len, sp);
258 len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
259 edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
260 edit_uint64_with_commas(sm_bytes, b2),
261 edit_uint64_with_commas(sm_max_bytes, b3),
262 edit_uint64_with_commas(sm_buffers, b4),
263 edit_uint64_with_commas(sm_max_buffers, b5));
264 sendit(msg, len, sp);
265 len = Mmsg(msg, " Sizes: boffset_t=%d size_t=%d int32_t=%d int64_t=%d "
267 (int)sizeof(boffset_t), (int)sizeof(size_t), (int)sizeof(int32_t),
268 (int)sizeof(int64_t), (int)DEVELOPER_MODE, (int)BEEF);
269 sendit(msg, len, sp);
270 if (bplugin_list->size() > 0) {
273 pm_strcpy(msg, " Plugin: ");
274 foreach_alist(plugin, bplugin_list) {
275 len = pm_strcat(msg, plugin->file);
277 pm_strcat(msg, "\n ");
282 len = pm_strcat(msg, "\n");
283 sendit(msg.c_str(), len, sp);
287 static void send_blocked_status(DEVICE *dev, STATUS_PKT *sp)
289 POOL_MEM msg(PM_MESSAGE);
293 len = Mmsg(msg, _("No DEVICE structure.\n\n"));
294 sendit(msg, len, sp);
297 switch (dev->blocked()) {
299 len = Mmsg(msg, _(" Device is BLOCKED. User unmounted.\n"));
300 sendit(msg, len, sp);
302 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
303 len = Mmsg(msg, _(" Device is BLOCKED. User unmounted during wait for media/mount.\n"));
304 sendit(msg, len, sp);
306 case BST_WAITING_FOR_SYSOP:
309 bool found_jcr = false;
311 foreach_dlist(dcr, dev->attached_dcrs) {
312 if (dcr->jcr->JobStatus == JS_WaitMount) {
313 len = Mmsg(msg, _(" Device is BLOCKED waiting for mount of volume \"%s\",\n"
315 " Media type: %s\n"),
319 sendit(msg, len, sp);
321 } else if (dcr->jcr->JobStatus == JS_WaitMedia) {
322 len = Mmsg(msg, _(" Device is BLOCKED waiting to create a volume for:\n"
324 " Media type: %s\n"),
327 sendit(msg, len, sp);
333 len = Mmsg(msg, _(" Device is BLOCKED waiting for media.\n"));
334 sendit(msg, len, sp);
338 case BST_DOING_ACQUIRE:
339 len = Mmsg(msg, _(" Device is being initialized.\n"));
340 sendit(msg, len, sp);
342 case BST_WRITING_LABEL:
343 len = Mmsg(msg, _(" Device is blocked labeling a Volume.\n"));
344 sendit(msg, len, sp);
349 /* Send autochanger slot status */
350 if (dev->is_autochanger()) {
351 if (dev->get_slot() > 0) {
352 len = Mmsg(msg, _(" Slot %d %s loaded in drive %d.\n"),
353 dev->get_slot(), dev->is_open()?"is": "was last", dev->drive_index);
354 sendit(msg, len, sp);
355 } else if (dev->get_slot() <= 0) {
356 len = Mmsg(msg, _(" Drive %d is not loaded.\n"), dev->drive_index);
357 sendit(msg, len, sp);
360 if (debug_level > 1) {
361 send_device_status(dev, sp);
365 static void send_device_status(DEVICE *dev, STATUS_PKT *sp)
367 POOL_MEM msg(PM_MESSAGE);
370 if (debug_level > 5) {
371 len = Mmsg(msg, _("Configured device capabilities:\n"));
372 sendit(msg, len, sp);
373 len = Mmsg(msg, " %sEOF %sBSR %sBSF %sFSR %sFSF %sEOM %sREM %sRACCESS %sAUTOMOUNT %sLABEL %sANONVOLS %sALWAYSOPEN\n",
374 dev->capabilities & CAP_EOF ? "" : "!",
375 dev->capabilities & CAP_BSR ? "" : "!",
376 dev->capabilities & CAP_BSF ? "" : "!",
377 dev->capabilities & CAP_FSR ? "" : "!",
378 dev->capabilities & CAP_FSF ? "" : "!",
379 dev->capabilities & CAP_EOM ? "" : "!",
380 dev->capabilities & CAP_REM ? "" : "!",
381 dev->capabilities & CAP_RACCESS ? "" : "!",
382 dev->capabilities & CAP_AUTOMOUNT ? "" : "!",
383 dev->capabilities & CAP_LABEL ? "" : "!",
384 dev->capabilities & CAP_ANONVOLS ? "" : "!",
385 dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
386 sendit(msg, len, sp);
389 len = Mmsg(msg, _("Device state:\n"));
390 sendit(msg, len, sp);
391 len = Mmsg(msg, " %sOPENED %sTAPE %sLABEL %sMALLOC %sAPPEND %sREAD %sEOT %sWEOT %sEOF %sNEXTVOL %sSHORT %sMOUNTED\n",
392 dev->is_open() ? "" : "!",
393 dev->is_tape() ? "" : "!",
394 dev->is_labeled() ? "" : "!",
395 dev->state & ST_MALLOC ? "" : "!",
396 dev->can_append() ? "" : "!",
397 dev->can_read() ? "" : "!",
398 dev->at_eot() ? "" : "!",
399 dev->state & ST_WEOT ? "" : "!",
400 dev->at_eof() ? "" : "!",
401 dev->state & ST_NEXTVOL ? "" : "!",
402 dev->state & ST_SHORT ? "" : "!",
403 dev->state & ST_MOUNTED ? "" : "!");
404 sendit(msg, len, sp);
405 len = Mmsg(msg, _(" num_writers=%d reserves=%d block=%d\n"), dev->num_writers,
406 dev->num_reserved(), dev->blocked());
407 sendit(msg, len, sp);
409 len = Mmsg(msg, _("Attached Jobs: "));
410 sendit(msg, len, sp);
414 foreach_dlist(dcr, dev->attached_dcrs) {
419 len = Mmsg(msg, "%d", (int)dcr->jcr->JobId);
420 sendit(msg, len, sp);
427 len = Mmsg(msg, _("Device parameters:\n"));
428 sendit(msg, len, sp);
429 len = Mmsg(msg, _(" Archive name: %s Device name: %s\n"), dev->archive_name(),
431 sendit(msg, len, sp);
432 len = Mmsg(msg, _(" File=%u block=%u\n"), dev->file, dev->block_num);
433 sendit(msg, len, sp);
434 len = Mmsg(msg, _(" Min block=%u Max block=%u\n"), dev->min_block_size, dev->max_block_size);
435 sendit(msg, len, sp);
438 static void list_running_jobs(STATUS_PKT *sp)
441 int avebps, bps, sec;
444 char JobName[MAX_NAME_LENGTH];
445 char b1[50], b2[50], b3[50], b4[50];
447 POOL_MEM msg(PM_MESSAGE);
448 time_t now = time(NULL);
450 len = Mmsg(msg, _("\nRunning Jobs:\n"));
451 if (!sp->api) sendit(msg, len, sp);
454 if (jcr->JobStatus == JS_WaitFD) {
455 len = Mmsg(msg, _("%s Job %s waiting for Client connection.\n"),
456 job_type_to_str(jcr->getJobType()), jcr->Job);
457 sendit(msg, len, sp);
460 rdcr = jcr->read_dcr;
461 if ((dcr && dcr->device) || (rdcr && rdcr->device)) {
462 bstrncpy(JobName, jcr->Job, sizeof(JobName));
463 /* There are three periods after the Job name */
465 for (int i=0; i<3; i++) {
466 if ((p=strrchr(JobName, '.')) != NULL) {
470 if (rdcr && rdcr->device) {
471 len = Mmsg(msg, _("Reading: %s %s job %s JobId=%d Volume=\"%s\"\n"
472 " pool=\"%s\" device=%s\n"),
473 job_level_to_str(jcr->getJobLevel()),
474 job_type_to_str(jcr->getJobType()),
479 rdcr->dev?rdcr->dev->print_name():
480 rdcr->device->device_name);
481 sendit(msg, len, sp);
483 if (dcr && dcr->device) {
484 len = Mmsg(msg, _("Writing: %s %s job %s JobId=%d Volume=\"%s\"\n"
485 " pool=\"%s\" device=%s\n"),
486 job_level_to_str(jcr->getJobLevel()),
487 job_type_to_str(jcr->getJobType()),
492 dcr->dev?dcr->dev->print_name():
493 dcr->device->device_name);
494 sendit(msg, len, sp);
495 len= Mmsg(msg, _(" spooling=%d despooling=%d despool_wait=%d\n"),
496 dcr->spooling, dcr->despooling, dcr->despool_wait);
497 sendit(msg, len, sp);
499 if (jcr->last_time == 0) {
500 jcr->last_time = jcr->run_time;
502 sec = now - jcr->last_time;
506 bps = (jcr->JobBytes - jcr->LastJobBytes) / sec;
507 if (jcr->LastRate == 0) {
510 avebps = (jcr->LastRate + bps) / 2;
511 len = Mmsg(msg, _(" Files=%s Bytes=%s AveBytes/sec=%s LastBytes/sec=%s\n"),
512 edit_uint64_with_commas(jcr->JobFiles, b1),
513 edit_uint64_with_commas(jcr->JobBytes, b2),
514 edit_uint64_with_commas(avebps, b3),
515 edit_uint64_with_commas(bps, b4));
516 sendit(msg, len, sp);
517 jcr->LastRate = avebps;
518 jcr->LastJobBytes = jcr->JobBytes;
519 jcr->last_time = now;
522 if (jcr->file_bsock) {
523 len = Mmsg(msg, _(" FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n"),
524 edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1),
525 jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no,
526 jcr->file_bsock->m_fd);
527 sendit(msg, len, sp);
529 len = Mmsg(msg, _(" FDSocket closed\n"));
530 sendit(msg, len, sp);
538 len = Mmsg(msg, _("No Jobs running.\n"));
539 if (!sp->api) sendit(msg, len, sp);
541 if (!sp->api) sendit("====\n", 5, sp);
544 static void list_jobs_waiting_on_reservation(STATUS_PKT *sp)
547 POOL_MEM msg(PM_MESSAGE);
550 len = Mmsg(msg, _("\nJobs waiting to reserve a drive:\n"));
551 if (!sp->api) sendit(msg, len, sp);
554 if (!jcr->reserve_msgs) {
557 send_drive_reserve_messages(jcr, sendit, sp);
561 if (!sp->api) sendit("====\n", 5, sp);
565 static void list_terminated_jobs(STATUS_PKT *sp)
567 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
569 struct s_last_job *je;
572 msg = _("\nTerminated Jobs:\n");
573 if (!sp->api) sendit(msg, strlen(msg), sp);
574 if (last_jobs->size() == 0) {
575 if (!sp->api) sendit("====\n", 5, sp);
578 lock_last_jobs_list();
579 msg = _(" JobId Level Files Bytes Status Finished Name \n");
580 if (!sp->api) sendit(msg, strlen(msg), sp);
581 msg = _("===================================================================\n");
582 if (!sp->api) sendit(msg, strlen(msg), sp);
583 foreach_dlist(je, last_jobs) {
584 char JobName[MAX_NAME_LENGTH];
585 const char *termstat;
588 bstrftime_nc(dt, sizeof(dt), je->end_time);
589 switch (je->JobType) {
592 bstrncpy(level, " ", sizeof(level));
595 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
599 switch (je->JobStatus) {
601 termstat = _("Created");
604 case JS_ErrorTerminated:
605 termstat = _("Error");
608 termstat = _("Diffs");
611 termstat = _("Cancel");
617 termstat = _("OK -- with warnings");
620 termstat = _("Other");
623 bstrncpy(JobName, je->Job, sizeof(JobName));
624 /* There are three periods after the Job name */
626 for (int i=0; i<3; i++) {
627 if ((p=strrchr(JobName, '.')) != NULL) {
632 bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
635 edit_uint64_with_commas(je->JobFiles, b1),
636 edit_uint64_with_suffix(je->JobBytes, b2),
640 bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %10s %-7s %-8s %s\n"),
643 edit_uint64_with_commas(je->JobFiles, b1),
644 edit_uint64_with_suffix(je->JobBytes, b2),
648 sendit(buf, strlen(buf), sp);
650 unlock_last_jobs_list();
651 if (!sp->api) sendit("====\n", 5, sp);
655 * Convert Job Level into a string
657 static const char *level_to_str(int level)
668 str = _("Incremental");
671 str = _("Differential");
676 case L_VERIFY_CATALOG:
677 str = _("Verify Catalog");
680 str = _("Init Catalog");
682 case L_VERIFY_VOLUME_TO_CATALOG:
683 str = _("Volume to Catalog");
685 case L_VERIFY_DISK_TO_CATALOG:
686 str = _("Disk to Catalog");
695 str = _("Unknown Job Level");
704 static void sendit(const char *msg, int len, STATUS_PKT *sp)
708 memcpy(bs->msg, msg, len+1);
712 sp->callback(msg, len, sp->context);
716 static void sendit(const char *msg, int len, void *sp)
718 sendit(msg, len, (STATUS_PKT *)sp);
721 static void sendit(POOL_MEM &msg, int len, STATUS_PKT *sp)
725 memcpy(bs->msg, msg.c_str(), len+1);
729 sp->callback(msg.c_str(), len, sp->context);
735 * Status command from Director
737 bool status_cmd(JCR *jcr)
739 BSOCK *dir = jcr->dir_bsock;
745 dir->signal(BNET_EOD);
750 * .status command from Director
752 bool qstatus_cmd(JCR *jcr)
754 BSOCK *dir = jcr->dir_bsock;
761 if (sscanf(dir->msg, qstatus, cmd.c_str()) != 1) {
762 pm_strcpy(jcr->errmsg, dir->msg);
763 dir->fsend(_("3900 No arg in .status command: %s\n"), jcr->errmsg);
764 dir->signal(BNET_EOD);
769 Dmsg1(200, "cmd=%s\n", cmd.c_str());
771 if (strcasecmp(cmd.c_str(), "current") == 0) {
772 dir->fsend(OKqstatus, cmd.c_str());
774 if (njcr->JobId != 0) {
775 dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
779 } else if (strcasecmp(cmd.c_str(), "last") == 0) {
780 dir->fsend(OKqstatus, cmd.c_str());
781 if ((last_jobs) && (last_jobs->size() > 0)) {
782 job = (s_last_job*)last_jobs->last();
783 dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
785 } else if (strcasecmp(cmd.c_str(), "header") == 0) {
787 list_status_header(&sp);
788 } else if (strcasecmp(cmd.c_str(), "running") == 0) {
790 list_running_jobs(&sp);
791 } else if (strcasecmp(cmd.c_str(), "waitreservation") == 0) {
793 list_jobs_waiting_on_reservation(&sp);
794 } else if (strcasecmp(cmd.c_str(), "devices") == 0) {
797 } else if (strcasecmp(cmd.c_str(), "volumes") == 0) {
799 list_volumes(sendit, &sp);
800 } else if (strcasecmp(cmd.c_str(), "spooling") == 0) {
802 list_spool_stats(sendit, &sp);
803 } else if (strcasecmp(cmd.c_str(), "terminated") == 0) {
805 list_terminated_jobs(&sp);
806 } else if (strcasecmp(cmd.c_str(), "resources") == 0) {
810 pm_strcpy(jcr->errmsg, dir->msg);
811 dir->fsend(_("3900 Unknown arg in .status command: %s\n"), jcr->errmsg);
812 dir->signal(BNET_EOD);
815 dir->signal(BNET_EOD);
819 #if defined(HAVE_WIN32)
822 /* Return a one line status for the tray monitor */
823 char *bac_status(char *buf, int buf_len)
826 const char *termstat = _("Bacula Storage: Idle");
827 struct s_last_job *job;
828 int stat = 0; /* Idle */
833 Dmsg0(1000, "Begin bac_status jcr loop.\n");
835 if (njcr->JobId != 0) {
837 termstat = _("Bacula Storage: Running");
846 if (last_jobs->size() > 0) {
847 job = (struct s_last_job *)last_jobs->last();
848 stat = job->JobStatus;
849 switch (job->JobStatus) {
851 termstat = _("Bacula Storage: Last Job Canceled");
853 case JS_ErrorTerminated:
855 termstat = _("Bacula Storage: Last Job Failed");
859 termstat = _("Bacula Storage: Last Job had Warnings");
864 Dmsg0(1000, "End bac_status jcr loop.\n");
868 bstrncpy(buf, termstat, buf_len);
873 #endif /* HAVE_WIN32 */