]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/status.c
Complete port to Windows
[bacula/bacula] / bacula / src / stored / status.c
1 /*
2  *  This file handles the status command
3  *
4  *     Kern Sibbald, May MMIII
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Copyright (C) 2003-2006 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "stored.h"
26
27 /* Exported variables */
28
29 /* Imported variables */
30 extern BSOCK *filed_chan;
31 extern int r_first, r_last;
32 extern struct s_res resources[];
33
34 /* Static variables */
35 static char qstatus[] = ".status %127s\n";
36
37 static char OKqstatus[]   = "3000 OK .status\n";
38 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
39
40
41 /* Forward referenced functions */
42 static void send_blocked_status(DEVICE *dev, void sendit(const char *msg, int len, void *sarg), void *arg);
43 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
44 static void list_running_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
45 static void list_jobs_waiting_on_reservation(void sendit(const char *msg, int len, void *sarg), void *arg);
46 #if defined(HAVE_WIN32)
47 static void win32_sendit(const char *msg, int len, void *arg);
48 #endif
49
50 static const char *level_to_str(int level);
51
52 /*
53  * Status command from Director
54  */
55 bool do_status(void sendit(const char *msg, int len, void *sarg), void *arg)
56 {
57    DEVRES *device;
58    AUTOCHANGER *changer;
59    DEVICE *dev;
60    char dt[MAX_TIME_LENGTH];
61    char *msg, b1[35], b2[35], b3[35], b4[35];
62    int bpb;
63    int len;
64
65    msg = (char *)get_pool_memory(PM_MESSAGE);
66
67    len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s\n"), 
68               my_name, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
69    sendit(msg, len, arg);
70
71    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
72
73
74    len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
75         dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
76    sendit(msg, len, arg);
77
78    len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
79          edit_uint64_with_commas(sm_bytes, b1),
80          edit_uint64_with_commas(sm_max_bytes, b2),
81          edit_uint64_with_commas(sm_buffers, b3),
82          edit_uint64_with_commas(sm_max_buffers, b4));
83    sendit(msg, len, arg);
84
85    /*
86     * List running jobs
87     */
88    list_running_jobs(sendit, arg);
89
90    /*
91     * List jobs stuck in reservation system
92     */
93    list_jobs_waiting_on_reservation(sendit, arg);
94
95    /*
96     * List terminated jobs
97     */
98    list_terminated_jobs(sendit, arg);
99
100    /*
101     * List devices
102     */
103    len = Mmsg(msg, _("\nDevice status:\n"));
104    sendit(msg, len, arg);
105
106    foreach_res(changer, R_AUTOCHANGER) {
107       len = Mmsg(msg, _("Autochanger \"%s\" with devices:\n"),
108          changer->hdr.name);
109       sendit(msg, len, arg);
110
111       foreach_alist(device, changer->device) {
112          if (device->dev) {
113             len = Mmsg(msg, "   %s\n", device->dev->print_name());
114             sendit(msg, len, arg);
115          } else {
116             len = Mmsg(msg, "   %s\n", device->hdr.name);
117             sendit(msg, len, arg);
118          }
119       }
120    }
121    foreach_res(device, R_DEVICE) {
122       dev = device->dev;
123       if (dev && dev->is_open()) {
124          if (dev->is_labeled()) {
125             len = Mmsg(msg, _("Device %s is mounted with Volume=\"%s\" Pool=\"%s\"\n"),
126                dev->print_name(), dev->VolHdr.VolumeName, 
127                dev->pool_name[0]?dev->pool_name:"*unknown*");
128             sendit(msg, len, arg);
129          } else {
130             len = Mmsg(msg, _("Device %s open but no Bacula volume is mounted.\n"), 
131                dev->print_name());
132             sendit(msg, len, arg);
133          }
134          send_blocked_status(dev, sendit, arg);
135          if (dev->can_append()) {
136             bpb = dev->VolCatInfo.VolCatBlocks;
137             if (bpb <= 0) {
138                bpb = 1;
139             }
140             bpb = dev->VolCatInfo.VolCatBytes / bpb;
141             len = Mmsg(msg, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
142                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
143                edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
144                edit_uint64_with_commas(bpb, b3));
145             sendit(msg, len, arg);
146          } else {  /* reading */
147             bpb = dev->VolCatInfo.VolCatReads;
148             if (bpb <= 0) {
149                bpb = 1;
150             }
151             if (dev->VolCatInfo.VolCatRBytes > 0) {
152                bpb = dev->VolCatInfo.VolCatRBytes / bpb;
153             } else {
154                bpb = 0;
155             }
156             len = Mmsg(msg, _("    Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"),
157                edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1),
158                edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2),
159                edit_uint64_with_commas(bpb, b3));
160             sendit(msg, len, arg);
161          }
162          len = Mmsg(msg, _("    Positioned at File=%s Block=%s\n"),
163             edit_uint64_with_commas(dev->file, b1),
164             edit_uint64_with_commas(dev->block_num, b2));
165          sendit(msg, len, arg);
166
167       } else {
168          if (dev) {
169             len = Mmsg(msg, _("Device %s is not open.\n"), dev->print_name());
170             sendit(msg, len, arg);
171         } else {
172             len = Mmsg(msg, _("Device \"%s\" is not open or does not exist.\n"), device->hdr.name);
173             sendit(msg, len, arg);
174          }
175          send_blocked_status(dev, sendit, arg);
176       }
177    }
178    len = Mmsg(msg, _("====\n\n"));
179    sendit(msg, len, arg);
180    len = Mmsg(msg, _("In Use Volume status:\n"));
181    sendit(msg, len, arg);
182    list_volumes(sendit, arg);
183    len = Mmsg(msg, _("====\n\n"));
184    sendit(msg, len, arg);
185        
186 #ifdef xxx
187    if (debug_level > 10) {
188       bnet_fsend(user, _("====\n\n"));
189       dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
190       bnet_fsend(user, _("====\n\n"));
191    }
192 #endif
193
194    list_spool_stats(sendit, arg);
195
196    free_pool_memory(msg);
197    return true;
198 }
199
200 static void send_blocked_status(DEVICE *dev, void sendit(const char *msg, int len, void *sarg), void *arg)
201 {
202    char *msg;
203    int len;
204
205    msg = (char *)get_pool_memory(PM_MESSAGE);
206
207    if (!dev) {
208       len = Mmsg(msg, _("No DEVICE structure.\n\n"));
209       sendit(msg, len, arg);
210       return;
211    }
212    switch (dev->dev_blocked) {
213    case BST_UNMOUNTED:
214       len = Mmsg(msg, _("    Device is BLOCKED. User unmounted.\n"));
215       sendit(msg, len, arg);
216       break;
217    case BST_UNMOUNTED_WAITING_FOR_SYSOP:
218       len = Mmsg(msg, _("    Device is BLOCKED. User unmounted during wait for media/mount.\n"));
219       sendit(msg, len, arg);
220       break;
221    case BST_WAITING_FOR_SYSOP:
222       {
223          dlist *dcrs = dev->attached_dcrs;
224          bool found_jcr = false;
225
226          if (dcrs != NULL) {
227             DCR *dcr;
228
229             for (dcr = (DCR *)dcrs->first(); dcr != NULL; dcr = (DCR *)dcrs->next(dcr)) {
230                if (dcr->jcr->JobStatus == JS_WaitMount) {
231                   len = Mmsg(msg, _("    Device is BLOCKED waiting for mount of volume \"%s\".\n"),
232                      dcr->VolumeName);
233                   sendit(msg, len, arg);
234                   found_jcr = true;
235                }
236             }
237          }
238
239          if (!found_jcr) {
240             len = Mmsg(msg, _("    Device is BLOCKED waiting for media.\n"));
241             sendit(msg, len, arg);
242          }
243       }
244       break;
245    case BST_DOING_ACQUIRE:
246       len = Mmsg(msg, _("    Device is being initialized.\n"));
247       sendit(msg, len, arg);
248       break;
249    case BST_WRITING_LABEL:
250       len = Mmsg(msg, _("    Device is blocked labeling a Volume.\n"));
251       sendit(msg, len, arg);
252       break;
253    default:
254       break;
255    }
256    /* Send autochanger slot status */
257    if (dev->is_autochanger()) {
258       if (dev->Slot) {
259          len = Mmsg(msg, _("    Slot %d is loaded in drive %d.\n"), 
260             dev->Slot, dev->drive_index);
261          sendit(msg, len, arg);
262       } else {
263          len = Mmsg(msg, _("    Drive %d is not loaded.\n"), dev->drive_index);
264          sendit(msg, len, arg);
265       }
266    }
267    if (debug_level > 1) {
268       len = Mmsg(msg, _("Configured device capabilities:\n"));
269       sendit(msg, len, arg);
270
271       len = Mmsg(msg, "%sEOF %sBSR %sBSF %sFSR %sFSF %sEOM %sREM %sRACCESS %sAUTOMOUNT %sLABEL %sANONVOLS %sALWAYSOPEN\n",
272          dev->capabilities & CAP_EOF ? "" : "!", 
273          dev->capabilities & CAP_BSR ? "" : "!", 
274          dev->capabilities & CAP_BSF ? "" : "!", 
275          dev->capabilities & CAP_FSR ? "" : "!", 
276          dev->capabilities & CAP_FSF ? "" : "!", 
277          dev->capabilities & CAP_EOM ? "" : "!", 
278          dev->capabilities & CAP_REM ? "" : "!", 
279          dev->capabilities & CAP_RACCESS ? "" : "!",
280          dev->capabilities & CAP_AUTOMOUNT ? "" : "!", 
281          dev->capabilities & CAP_LABEL ? "" : "!", 
282          dev->capabilities & CAP_ANONVOLS ? "" : "!", 
283          dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
284       sendit(msg, len, arg);
285
286       len = Mmsg(msg, _("Device state:\n"));
287       sendit(msg, len, arg);
288
289       len = Mmsg(msg, "%sOPENED %sTAPE %sLABEL %sMALLOC %sAPPEND %sREAD %sEOT %sWEOT %sEOF %sNEXTVOL %sSHORT %sMOUNTED\n", 
290          dev->is_open() ? "" : "!", 
291          dev->is_tape() ? "" : "!", 
292          dev->is_labeled() ? "" : "!", 
293          dev->state & ST_MALLOC ? "" : "!", 
294          dev->can_append() ? "" : "!", 
295          dev->can_read() ? "" : "!", 
296          dev->at_eot() ? "" : "!", 
297          dev->state & ST_WEOT ? "" : "!", 
298          dev->at_eof() ? "" : "!", 
299          dev->state & ST_NEXTVOL ? "" : "!", 
300          dev->state & ST_SHORT ? "" : "!", 
301          dev->state & ST_MOUNTED ? "" : "!");
302       sendit(msg, len, arg);
303
304       len = Mmsg(msg, _("num_writers=%d block=%d\n\n"), dev->num_writers, dev->dev_blocked);
305       sendit(msg, len, arg);
306
307       len = Mmsg(msg, _("Device parameters:\n"));
308       sendit(msg, len, arg);
309
310       len = Mmsg(msg, _("Archive name: %s Device name: %s\n"), dev->archive_name(),
311          dev->name());
312       sendit(msg, len, arg);
313
314       len = Mmsg(msg, _("File=%u block=%u\n"), dev->file, dev->block_num);
315       sendit(msg, len, arg);
316
317       len = Mmsg(msg, _("Min block=%u Max block=%u\n"), dev->min_block_size, dev->max_block_size);
318       sendit(msg, len, arg);
319    }
320
321    free_pool_memory(msg);
322 }
323
324 static void list_running_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
325 {
326    bool found = false;
327    int bps, sec;
328    JCR *jcr;
329    DCR *dcr, *rdcr;
330    char JobName[MAX_NAME_LENGTH];
331    char *msg, b1[30], b2[30], b3[30];
332    int len;
333
334    msg = (char *)get_pool_memory(PM_MESSAGE);
335
336    len = Mmsg(msg, _("\nRunning Jobs:\n"));
337    sendit(msg, len, arg);
338
339    foreach_jcr(jcr) {
340       if (jcr->JobStatus == JS_WaitFD) {
341          len = Mmsg(msg, _("%s Job %s waiting for Client connection.\n"),
342             job_type_to_str(jcr->JobType), jcr->Job);
343          sendit(msg, len, arg);
344       }
345       dcr = jcr->dcr;
346       rdcr = jcr->read_dcr;
347       if ((dcr && dcr->device) || rdcr && rdcr->device) {
348          bstrncpy(JobName, jcr->Job, sizeof(JobName));
349          /* There are three periods after the Job name */
350          char *p;
351          for (int i=0; i<3; i++) {
352             if ((p=strrchr(JobName, '.')) != NULL) {
353                *p = 0;
354             }
355          }
356          if (rdcr && rdcr->device) {
357             len = Mmsg(msg, _("Reading: %s %s job %s JobId=%d Volume=\"%s\"\n"
358                             "    pool=\"%s\" device=\"%s\"\n"),
359                    job_level_to_str(jcr->JobLevel),
360                    job_type_to_str(jcr->JobType),
361                    JobName,
362                    jcr->JobId,
363                    rdcr->VolumeName,
364                    rdcr->pool_name,
365                    rdcr->dev?rdcr->dev->print_name(): 
366                             rdcr->device->device_name);
367             sendit(msg, len, arg);
368          }
369          if (dcr && dcr->device) {
370             len = Mmsg(msg, _("Writing: %s %s job %s JobId=%d Volume=\"%s\"\n"
371                             "    pool=\"%s\" device=\"%s\"\n"),
372                    job_level_to_str(jcr->JobLevel),
373                    job_type_to_str(jcr->JobType),
374                    JobName,
375                    jcr->JobId,
376                    dcr->VolumeName,
377                    dcr->pool_name,
378                    dcr->dev?dcr->dev->print_name(): 
379                             dcr->device->device_name);
380             sendit(msg, len, arg);
381          }
382          sec = time(NULL) - jcr->run_time;
383          if (sec <= 0) {
384             sec = 1;
385          }
386          bps = jcr->JobBytes / sec;
387          len = Mmsg(msg, _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
388             edit_uint64_with_commas(jcr->JobFiles, b1),
389             edit_uint64_with_commas(jcr->JobBytes, b2),
390             edit_uint64_with_commas(bps, b3));
391          sendit(msg, len, arg);
392          found = true;
393 #ifdef DEBUG
394          if (jcr->file_bsock) {
395             len = Mmsg(msg, _("    FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n"),
396                edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1),
397                jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no,
398                jcr->file_bsock->fd);
399             sendit(msg, len, arg);
400          } else {
401             len = Mmsg(msg, _("    FDSocket closed\n"));
402             sendit(msg, len, arg);
403          }
404 #endif
405       }
406    }
407    endeach_jcr(jcr);
408
409    if (!found) {
410       len = Mmsg(msg, _("No Jobs running.\n"));
411       sendit(msg, len, arg);
412    }
413    len = Mmsg(msg, _("====\n"));
414    sendit(msg, len, arg);
415
416    free_pool_memory(msg);
417 }
418
419 static void list_jobs_waiting_on_reservation(void sendit(const char *msg, int len, void *sarg), void *arg)
420
421    JCR *jcr;
422    char *msg;
423
424    msg = _("\nJobs waiting to reserve a drive:\n");
425    sendit(msg, strlen(msg), arg);
426
427    foreach_jcr(jcr) {
428       if (!jcr->reserve_msgs) {
429          continue;
430       }
431       send_drive_reserve_messages(jcr, sendit, arg);
432    }
433    endeach_jcr(jcr);
434
435    msg = _("====\n");
436    sendit(msg, strlen(msg), arg);
437 }
438
439
440 static void list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
441 {
442    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
443    char level[10];
444    struct s_last_job *je;
445    const char *msg;
446
447    if (last_jobs->size() == 0) {
448       msg = _("No Terminated Jobs.\n");
449       sendit(msg, strlen(msg), arg);
450       return;
451    }
452    lock_last_jobs_list();
453    msg =  _("\nTerminated Jobs:\n");
454    sendit(msg, strlen(msg), arg);
455    msg =  _(" JobId  Level   Files          Bytes Status   Finished        Name \n");
456    sendit(msg, strlen(msg), arg);
457    msg = _("======================================================================\n");
458    sendit(msg, strlen(msg), arg);
459    foreach_dlist(je, last_jobs) {
460       char JobName[MAX_NAME_LENGTH];
461       const char *termstat;
462       char buf[1000];
463
464       bstrftime_nc(dt, sizeof(dt), je->end_time);
465       switch (je->JobType) {
466       case JT_ADMIN:
467       case JT_RESTORE:
468          bstrncpy(level, "    ", sizeof(level));
469          break;
470       default:
471          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
472          level[4] = 0;
473          break;
474       }
475       switch (je->JobStatus) {
476       case JS_Created:
477          termstat = _("Created");
478          break;
479       case JS_FatalError:
480       case JS_ErrorTerminated:
481          termstat = _("Error");
482          break;
483       case JS_Differences:
484          termstat = _("Diffs");
485          break;
486       case JS_Canceled:
487          termstat = _("Cancel");
488          break;
489       case JS_Terminated:
490          termstat = _("OK");
491          break;
492       default:
493          termstat = _("Other");
494          break;
495       }
496       bstrncpy(JobName, je->Job, sizeof(JobName));
497       /* There are three periods after the Job name */
498       char *p;
499       for (int i=0; i<3; i++) {
500          if ((p=strrchr(JobName, '.')) != NULL) {
501             *p = 0;
502          }
503       }
504       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %14s %-7s  %-8s %s\n"),
505          je->JobId,
506          level,
507          edit_uint64_with_commas(je->JobFiles, b1),
508          edit_uint64_with_commas(je->JobBytes, b2),
509          termstat,
510          dt, JobName);
511       sendit(buf, strlen(buf), arg);
512    }
513    sendit(_("====\n"), 5, arg);
514    unlock_last_jobs_list();
515 }
516
517 /*
518  * Convert Job Level into a string
519  */
520 static const char *level_to_str(int level)
521 {
522    const char *str;
523
524    switch (level) {
525    case L_BASE:
526       str = _("Base");
527    case L_FULL:
528       str = _("Full");
529       break;
530    case L_INCREMENTAL:
531       str = _("Incremental");
532       break;
533    case L_DIFFERENTIAL:
534       str = _("Differential");
535       break;
536    case L_SINCE:
537       str = _("Since");
538       break;
539    case L_VERIFY_CATALOG:
540       str = _("Verify Catalog");
541       break;
542    case L_VERIFY_INIT:
543       str = _("Init Catalog");
544       break;
545    case L_VERIFY_VOLUME_TO_CATALOG:
546       str = _("Volume to Catalog");
547       break;
548    case L_VERIFY_DISK_TO_CATALOG:
549       str = _("Disk to Catalog");
550       break;
551    case L_VERIFY_DATA:
552       str = _("Data");
553       break;
554    case L_NONE:
555       str = " ";
556       break;
557    default:
558       str = _("Unknown Job Level");
559       break;
560    }
561    return str;
562 }
563
564 /*
565  * Send to Director
566  */
567 static void bsock_sendit(const char *msg, int len, void *arg)
568 {
569    BSOCK *user = (BSOCK *)arg;
570
571    memcpy(user->msg, msg, len+1);
572    user->msglen = len+1;
573    bnet_send(user);
574 }
575
576 /*
577  * Status command from Director
578  */
579 bool status_cmd(JCR *jcr)
580 {
581    BSOCK *user = jcr->dir_bsock;
582
583    bnet_fsend(user, "\n");
584    do_status(bsock_sendit, (void *)user);
585
586    bnet_sig(user, BNET_EOD);
587    return 1;
588 }
589
590 /*
591  * .status command from Director
592  */
593 bool qstatus_cmd(JCR *jcr)
594 {
595    BSOCK *dir = jcr->dir_bsock;
596    POOL_MEM time;
597    JCR *njcr;
598    s_last_job* job;
599
600    if (sscanf(dir->msg, qstatus, time.c_str()) != 1) {
601       pm_strcpy(jcr->errmsg, dir->msg);
602       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
603       bnet_fsend(dir, _("3900 Bad .status command, missing argument.\n"));
604       bnet_sig(dir, BNET_EOD);
605       return false;
606    }
607    unbash_spaces(time);
608
609    if (strcmp(time.c_str(), "current") == 0) {
610       bnet_fsend(dir, OKqstatus, time.c_str());
611       foreach_jcr(njcr) {
612          if (njcr->JobId != 0) {
613             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
614          }
615       }
616       endeach_jcr(njcr);
617    } else if (strcmp(time.c_str(), "last") == 0) {
618       bnet_fsend(dir, OKqstatus, time.c_str());
619       if ((last_jobs) && (last_jobs->size() > 0)) {
620          job = (s_last_job*)last_jobs->last();
621          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
622       }
623    } else {
624       pm_strcpy(jcr->errmsg, dir->msg);
625       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
626       bnet_fsend(dir, _("3900 Bad .status command, wrong argument.\n"));
627       bnet_sig(dir, BNET_EOD);
628       return false;
629    }
630    bnet_sig(dir, BNET_EOD);
631    return true;
632 }
633
634 #if defined(HAVE_WIN32)
635 int bacstat = 0;
636
637 struct s_win32_arg {
638    HWND hwnd;
639    int idlist;
640 };
641
642 /*
643  * Put message in Window List Box
644  */
645 static void win32_sendit(const char *msg, int len, void *marg)
646 {
647    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
648
649    if (len > 0 && msg[len-1] == '\n') {
650        // when compiling with visual studio some strings are read-only
651        // and cause access violations.  So we creat a tmp copy.
652        char *_msg = (char *)alloca(len);
653        bstrncpy(_msg, msg, len);
654        msg = _msg;
655    }
656    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
657
658 }
659
660 void FillStatusBox(HWND hwnd, int idlist)
661 {
662    struct s_win32_arg arg;
663
664    arg.hwnd = hwnd;
665    arg.idlist = idlist;
666
667    /* Empty box */
668    for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
669       { }
670    do_status(win32_sendit, (void *)&arg);
671 }
672
673 char *bac_status(char *buf, int buf_len)
674 {
675    JCR *njcr;
676    const char *termstat = _("Bacula Idle");
677    struct s_last_job *job;
678    int stat = 0;                      /* Idle */
679
680    if (!last_jobs) {
681       goto done;
682    }
683    Dmsg0(1000, "Begin bac_status jcr loop.\n");
684    foreach_jcr(njcr) {
685       if (njcr->JobId != 0) {
686          stat = JS_Running;
687          termstat = _("Bacula Running");
688          break;
689       }
690    }
691    endeach_jcr(njcr);
692
693    if (stat != 0) {
694       goto done;
695    }
696    if (last_jobs->size() > 0) {
697       job = (struct s_last_job *)last_jobs->last();
698       stat = job->JobStatus;
699       switch (job->JobStatus) {
700       case JS_Canceled:
701          termstat = _("Last Job Canceled");
702          break;
703       case JS_ErrorTerminated:
704       case JS_FatalError:
705          termstat = _("Last Job Failed");
706          break;
707       default:
708          if (job->Errors) {
709             termstat = _("Last Job had Warnings");
710          }
711          break;
712       }
713    }
714    Dmsg0(1000, "End bac_status jcr loop.\n");
715 done:
716    bacstat = stat;
717    if (buf) {
718       bstrncpy(buf, termstat, buf_len);
719    }
720    return buf;
721 }
722
723 #endif /* HAVE_WIN32 */