]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/status.c
1b6843ab5a4852907229a29a6128baa0bc12d0d7
[bacula/bacula] / bacula / src / stored / status.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2003-2010 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *  This file handles the status command
30  *
31  *     Kern Sibbald, May MMIII
32  *
33  *
34  */
35
36 #include "bacula.h"
37 #include "stored.h"
38 #include "lib/status.h"
39
40 /* Exported variables */
41
42 /* Imported variables */
43 extern BSOCK *filed_chan;
44 extern void *start_heap;
45
46 /* Static variables */
47 static char qstatus[] = ".status %127s\n";
48
49 static char OKqstatus[]   = "3000 OK .status\n";
50 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
51
52
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);
57
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);
65
66 static const char *level_to_str(int level);
67
68 /*
69  * Status command from Director
70  */
71 void output_status(STATUS_PKT *sp)
72 {
73    POOL_MEM msg(PM_MESSAGE);
74    int len;
75
76    list_status_header(sp);
77
78    /*
79     * List running jobs
80     */
81    list_running_jobs(sp);
82
83    /*
84     * List jobs stuck in reservation system
85     */
86    list_jobs_waiting_on_reservation(sp);
87
88    /*
89     * List terminated jobs
90     */
91    list_terminated_jobs(sp);
92
93    /*
94     * List devices
95     */
96    list_devices(sp);
97
98
99    len = Mmsg(msg, _("Used Volume status:\n"));
100    if (!sp->api) sendit(msg, len, sp);
101
102    list_volumes(sendit, (void *)sp);
103    if (!sp->api) sendit("====\n\n", 6, sp);
104
105 #ifdef xxx
106    if (debug_level > 10) {
107       bs->fsend(_("====\n\n"));
108       dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
109       bs->fsend(_("====\n\n"));
110    }
111 #endif
112
113    list_spool_stats(sendit, (void *)sp);
114    if (!sp->api) sendit("====\n\n", 6, sp);
115 }
116
117
118 static void list_devices(STATUS_PKT *sp)
119 {
120    DEVRES *device;
121    AUTOCHANGER *changer;
122    DEVICE *dev;
123    char b1[35], b2[35], b3[35];
124    POOL_MEM msg(PM_MESSAGE);
125    int len;
126    int bpb;
127
128    len = Mmsg(msg, _("\nDevice status:\n"));
129    if (!sp->api) sendit(msg, len, sp);
130
131    foreach_res(changer, R_AUTOCHANGER) {
132       len = Mmsg(msg, _("Autochanger \"%s\" with devices:\n"),
133          changer->hdr.name);
134       sendit(msg, len, sp);
135
136       foreach_alist(device, changer->device) {
137          if (device->dev) {
138             len = Mmsg(msg, "   %s\n", device->dev->print_name());
139             sendit(msg, len, sp);
140          } else {
141             len = Mmsg(msg, "   %s\n", device->hdr.name);
142             sendit(msg, len, sp);
143          }
144       }
145    }
146    foreach_res(device, R_DEVICE) {
147       dev = device->dev;
148       if (dev && dev->is_open()) {
149          if (dev->is_labeled()) {
150             len = Mmsg(msg, _("Device %s is mounted with:\n"
151                               "    Volume:      %s\n"
152                               "    Pool:        %s\n"
153                               "    Media type:  %s\n"),
154                dev->print_name(), 
155                dev->VolHdr.VolumeName, 
156                dev->pool_name[0]?dev->pool_name:"*unknown*",
157                dev->device->media_type);
158             sendit(msg, len, sp);
159          } else {
160             len = Mmsg(msg, _("Device %s open but no Bacula volume is currently mounted.\n"), 
161                dev->print_name());
162             sendit(msg, len, sp);
163          }
164          send_blocked_status(dev, sp);
165          if (dev->can_append()) {
166             bpb = dev->VolCatInfo.VolCatBlocks;
167             if (bpb <= 0) {
168                bpb = 1;
169             }
170             bpb = dev->VolCatInfo.VolCatBytes / bpb;
171             len = Mmsg(msg, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
172                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
173                edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
174                edit_uint64_with_commas(bpb, b3));
175             sendit(msg, len, sp);
176          } else {  /* reading */
177             bpb = dev->VolCatInfo.VolCatReads;
178             if (bpb <= 0) {
179                bpb = 1;
180             }
181             if (dev->VolCatInfo.VolCatRBytes > 0) {
182                bpb = dev->VolCatInfo.VolCatRBytes / bpb;
183             } else {
184                bpb = 0;
185             }
186             len = Mmsg(msg, _("    Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"),
187                edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1),
188                edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2),
189                edit_uint64_with_commas(bpb, b3));
190             sendit(msg, len, sp);
191          }
192          len = Mmsg(msg, _("    Positioned at File=%s Block=%s\n"),
193             edit_uint64_with_commas(dev->file, b1),
194             edit_uint64_with_commas(dev->block_num, b2));
195          sendit(msg, len, sp);
196
197       } else {
198          if (dev) {
199             len = Mmsg(msg, _("Device %s is not open.\n"), dev->print_name());
200             sendit(msg, len, sp);
201             send_blocked_status(dev, sp);
202         } else {
203             len = Mmsg(msg, _("Device \"%s\" is not open or does not exist.\n"), device->hdr.name);
204             sendit(msg, len, sp);
205          }
206       }
207    }
208    if (!sp->api) sendit("====\n\n", 6, sp);
209 }
210
211 static void list_status_header(STATUS_PKT *sp)
212 {
213    char dt[MAX_TIME_LENGTH];
214    char b1[35], b2[35], b3[35], b4[35], b5[35];
215    POOL_MEM msg(PM_MESSAGE);
216    int len;
217
218    len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s\n"), 
219               my_name, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
220    sendit(msg, len, sp);
221
222    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
223
224
225    len = Mmsg(msg, _("Daemon started %s. Jobs: run=%d, running=%d.\n"),
226         dt, num_jobs_run, job_count());
227    sendit(msg, len, sp);
228    len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
229          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
230          edit_uint64_with_commas(sm_bytes, b2),
231          edit_uint64_with_commas(sm_max_bytes, b3),
232          edit_uint64_with_commas(sm_buffers, b4),
233          edit_uint64_with_commas(sm_max_buffers, b5));
234    sendit(msg, len, sp);
235    len = Mmsg(msg, " Sizes: boffset_t=%d size_t=%d int32_t=%d int64_t=%d "
236               "mode=%d,%d\n", 
237               (int)sizeof(boffset_t), (int)sizeof(size_t), (int)sizeof(int32_t),
238               (int)sizeof(int64_t), (int)DEVELOPER_MODE, (int)BEEF);
239    sendit(msg, len, sp);
240 }
241
242 static void send_blocked_status(DEVICE *dev, STATUS_PKT *sp)
243 {
244    POOL_MEM msg(PM_MESSAGE);
245    int len;
246
247    if (!dev) {
248       len = Mmsg(msg, _("No DEVICE structure.\n\n"));
249       sendit(msg, len, sp);
250       return;
251    }
252    switch (dev->blocked()) {
253    case BST_UNMOUNTED:
254       len = Mmsg(msg, _("    Device is BLOCKED. User unmounted.\n"));
255       sendit(msg, len, sp);
256       break;
257    case BST_UNMOUNTED_WAITING_FOR_SYSOP:
258       len = Mmsg(msg, _("    Device is BLOCKED. User unmounted during wait for media/mount.\n"));
259       sendit(msg, len, sp);
260       break;
261    case BST_WAITING_FOR_SYSOP:
262       {
263          dlist *dcrs = dev->attached_dcrs;
264          bool found_jcr = false;
265
266          if (dcrs != NULL) {
267             DCR *dcr;
268             for (dcr = (DCR *)dcrs->first(); dcr != NULL; dcr = (DCR *)dcrs->next(dcr)) {
269                if (dcr->jcr->JobStatus == JS_WaitMount) {
270                   len = Mmsg(msg, _("    Device is BLOCKED waiting for mount of volume \"%s\",\n"
271                                     "       Pool:        %s\n"
272                                     "       Media type:  %s\n"),
273                              dcr->VolumeName,
274                              dcr->pool_name,
275                              dcr->media_type);
276                   sendit(msg, len, sp);
277                   found_jcr = true;
278                } else if (dcr->jcr->JobStatus == JS_WaitMedia) {
279                   len = Mmsg(msg, _("    Device is BLOCKED waiting to create a volume for:\n"
280                                     "       Pool:        %s\n"
281                                     "       Media type:  %s\n"),
282                              dcr->pool_name,
283                              dcr->media_type);
284                   sendit(msg, len, sp);
285                   found_jcr = true;
286                }
287             }
288          }
289
290          if (!found_jcr) {
291             len = Mmsg(msg, _("    Device is BLOCKED waiting for media.\n"));
292             sendit(msg, len, sp);
293          }
294       }
295       break;
296    case BST_DOING_ACQUIRE:
297       len = Mmsg(msg, _("    Device is being initialized.\n"));
298       sendit(msg, len, sp);
299       break;
300    case BST_WRITING_LABEL:
301       len = Mmsg(msg, _("    Device is blocked labeling a Volume.\n"));
302       sendit(msg, len, sp);
303       break;
304    default:
305       break;
306    }
307    /* Send autochanger slot status */
308    if (dev->is_autochanger()) {
309       if (dev->get_slot() > 0) {
310          len = Mmsg(msg, _("    Slot %d is loaded in drive %d.\n"), 
311             dev->get_slot(), dev->drive_index);
312          sendit(msg, len, sp);
313       } else if (dev->get_slot() == 0) {
314          len = Mmsg(msg, _("    Drive %d is not loaded.\n"), dev->drive_index);
315          sendit(msg, len, sp);
316       } else {
317          len = Mmsg(msg, _("    Drive %d status unknown.\n"), dev->drive_index);
318          sendit(msg, len, sp);
319       }
320    }
321    if (debug_level > 1) {
322       send_device_status(dev, sp);
323    }
324 }
325
326 static void send_device_status(DEVICE *dev, STATUS_PKT *sp)
327 {
328    POOL_MEM msg(PM_MESSAGE);
329    int len;
330
331    len = Mmsg(msg, _("Configured device capabilities:\n"));
332    sendit(msg, len, sp);
333
334    len = Mmsg(msg, "%sEOF %sBSR %sBSF %sFSR %sFSF %sEOM %sREM %sRACCESS %sAUTOMOUNT %sLABEL %sANONVOLS %sALWAYSOPEN\n",
335       dev->capabilities & CAP_EOF ? "" : "!", 
336       dev->capabilities & CAP_BSR ? "" : "!", 
337       dev->capabilities & CAP_BSF ? "" : "!", 
338       dev->capabilities & CAP_FSR ? "" : "!", 
339       dev->capabilities & CAP_FSF ? "" : "!", 
340       dev->capabilities & CAP_EOM ? "" : "!", 
341       dev->capabilities & CAP_REM ? "" : "!", 
342       dev->capabilities & CAP_RACCESS ? "" : "!",
343       dev->capabilities & CAP_AUTOMOUNT ? "" : "!", 
344       dev->capabilities & CAP_LABEL ? "" : "!", 
345       dev->capabilities & CAP_ANONVOLS ? "" : "!", 
346       dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
347    sendit(msg, len, sp);
348
349    len = Mmsg(msg, _("Device state:\n"));
350    sendit(msg, len, sp);
351
352    len = Mmsg(msg, "%sOPENED %sTAPE %sLABEL %sMALLOC %sAPPEND %sREAD %sEOT %sWEOT %sEOF %sNEXTVOL %sSHORT %sMOUNTED\n", 
353       dev->is_open() ? "" : "!", 
354       dev->is_tape() ? "" : "!", 
355       dev->is_labeled() ? "" : "!", 
356       dev->state & ST_MALLOC ? "" : "!", 
357       dev->can_append() ? "" : "!", 
358       dev->can_read() ? "" : "!", 
359       dev->at_eot() ? "" : "!", 
360       dev->state & ST_WEOT ? "" : "!", 
361       dev->at_eof() ? "" : "!", 
362       dev->state & ST_NEXTVOL ? "" : "!", 
363       dev->state & ST_SHORT ? "" : "!", 
364       dev->state & ST_MOUNTED ? "" : "!");
365    sendit(msg, len, sp);
366
367    len = Mmsg(msg, _("num_writers=%d reserved=%d block=%d\n\n"), dev->num_writers, 
368               dev->num_reserved(), dev->blocked());
369    sendit(msg, len, sp);
370
371    len = Mmsg(msg, _("Device parameters:\n"));
372    sendit(msg, len, sp);
373
374    len = Mmsg(msg, _("Archive name: %s Device name: %s\n"), dev->archive_name(),
375       dev->name());
376    sendit(msg, len, sp);
377
378    len = Mmsg(msg, _("File=%u block=%u\n"), dev->file, dev->block_num);
379    sendit(msg, len, sp);
380
381    len = Mmsg(msg, _("Min block=%u Max block=%u\n"), dev->min_block_size, dev->max_block_size);
382    sendit(msg, len, sp);
383 }
384
385 static void list_running_jobs(STATUS_PKT *sp)
386 {
387    bool found = false;
388    int bps, sec;
389    JCR *jcr;
390    DCR *dcr, *rdcr;
391    char JobName[MAX_NAME_LENGTH];
392    char b1[30], b2[30], b3[30];
393    int len;
394    POOL_MEM msg(PM_MESSAGE);
395
396    len = Mmsg(msg, _("\nRunning Jobs:\n"));
397    if (!sp->api) sendit(msg, len, sp);
398
399    foreach_jcr(jcr) {
400       if (jcr->JobStatus == JS_WaitFD) {
401          len = Mmsg(msg, _("%s Job %s waiting for Client connection.\n"),
402             job_type_to_str(jcr->getJobType()), jcr->Job);
403          sendit(msg, len, sp);
404       }
405       dcr = jcr->dcr;
406       rdcr = jcr->read_dcr;
407       if ((dcr && dcr->device) || (rdcr && rdcr->device)) {
408          bstrncpy(JobName, jcr->Job, sizeof(JobName));
409          /* There are three periods after the Job name */
410          char *p;
411          for (int i=0; i<3; i++) {
412             if ((p=strrchr(JobName, '.')) != NULL) {
413                *p = 0;
414             }
415          }
416          if (rdcr && rdcr->device) {
417             len = Mmsg(msg, _("Reading: %s %s job %s JobId=%d Volume=\"%s\"\n"
418                             "    pool=\"%s\" device=%s\n"),
419                    job_level_to_str(jcr->getJobLevel()),
420                    job_type_to_str(jcr->getJobType()),
421                    JobName,
422                    jcr->JobId,
423                    rdcr->VolumeName,
424                    rdcr->pool_name,
425                    rdcr->dev?rdcr->dev->print_name(): 
426                             rdcr->device->device_name);
427             sendit(msg, len, sp);
428          }
429          if (dcr && dcr->device) {
430             len = Mmsg(msg, _("Writing: %s %s job %s JobId=%d Volume=\"%s\"\n"
431                             "    pool=\"%s\" device=%s\n"),
432                    job_level_to_str(jcr->getJobLevel()),
433                    job_type_to_str(jcr->getJobType()),
434                    JobName,
435                    jcr->JobId,
436                    dcr->VolumeName,
437                    dcr->pool_name,
438                    dcr->dev?dcr->dev->print_name(): 
439                             dcr->device->device_name);
440             sendit(msg, len, sp);
441             len= Mmsg(msg, _("    spooling=%d despooling=%d despool_wait=%d\n"),
442                    dcr->spooling, dcr->despooling, dcr->despool_wait);
443             sendit(msg, len, sp);
444          }
445          sec = time(NULL) - jcr->run_time;
446          if (sec <= 0) {
447             sec = 1;
448          }
449          bps = jcr->JobBytes / sec;
450          len = Mmsg(msg, _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
451             edit_uint64_with_commas(jcr->JobFiles, b1),
452             edit_uint64_with_commas(jcr->JobBytes, b2),
453             edit_uint64_with_commas(bps, b3));
454          sendit(msg, len, sp);
455          found = true;
456 #ifdef DEBUG
457          if (jcr->file_bsock) {
458             len = Mmsg(msg, _("    FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n"),
459                edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1),
460                jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no,
461                jcr->file_bsock->m_fd);
462             sendit(msg, len, sp);
463          } else {
464             len = Mmsg(msg, _("    FDSocket closed\n"));
465             sendit(msg, len, sp);
466          }
467 #endif
468       }
469    }
470    endeach_jcr(jcr);
471
472    if (!found) {
473       len = Mmsg(msg, _("No Jobs running.\n"));
474       if (!sp->api) sendit(msg, len, sp);
475    }
476    if (!sp->api) sendit("====\n", 5, sp);
477 }
478
479 static void list_jobs_waiting_on_reservation(STATUS_PKT *sp)
480
481    JCR *jcr;
482    POOL_MEM msg(PM_MESSAGE);
483    int len;
484
485    len = Mmsg(msg, _("\nJobs waiting to reserve a drive:\n"));
486    if (!sp->api) sendit(msg, len, sp);
487
488    foreach_jcr(jcr) {
489       if (!jcr->reserve_msgs) {
490          continue;
491       }
492       send_drive_reserve_messages(jcr, sendit, sp);
493    }
494    endeach_jcr(jcr);
495
496    if (!sp->api) sendit("====\n", 5, sp);
497 }
498
499
500 static void list_terminated_jobs(STATUS_PKT *sp)
501 {
502    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
503    char level[10];
504    struct s_last_job *je;
505    const char *msg;
506
507    msg =  _("\nTerminated Jobs:\n");
508    if (!sp->api) sendit(msg, strlen(msg), sp);
509    if (last_jobs->size() == 0) {
510       if (!sp->api) sendit("====\n", 5, sp);
511       return;
512    }
513    lock_last_jobs_list();
514    msg =  _(" JobId  Level    Files      Bytes   Status   Finished        Name \n");
515    if (!sp->api) sendit(msg, strlen(msg), sp);
516    msg =  _("===================================================================\n");
517    if (!sp->api) sendit(msg, strlen(msg), sp);
518    foreach_dlist(je, last_jobs) {
519       char JobName[MAX_NAME_LENGTH];
520       const char *termstat;
521       char buf[1000];
522
523       bstrftime_nc(dt, sizeof(dt), je->end_time);
524       switch (je->JobType) {
525       case JT_ADMIN:
526       case JT_RESTORE:
527          bstrncpy(level, "    ", sizeof(level));
528          break;
529       default:
530          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
531          level[4] = 0;
532          break;
533       }
534       switch (je->JobStatus) {
535       case JS_Created:
536          termstat = _("Created");
537          break;
538       case JS_FatalError:
539       case JS_ErrorTerminated:
540          termstat = _("Error");
541          break;
542       case JS_Differences:
543          termstat = _("Diffs");
544          break;
545       case JS_Canceled:
546          termstat = _("Cancel");
547          break;
548       case JS_Terminated:
549          termstat = _("OK");
550          break;
551       case JS_Warnings:
552          termstat = _("OK -- with warnings");
553          break;
554       default:
555          termstat = _("Other");
556          break;
557       }
558       bstrncpy(JobName, je->Job, sizeof(JobName));
559       /* There are three periods after the Job name */
560       char *p;
561       for (int i=0; i<3; i++) {
562          if ((p=strrchr(JobName, '.')) != NULL) {
563             *p = 0;
564          }
565       }
566       if (sp->api) {
567          bsnprintf(buf, sizeof(buf), _("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
568             je->JobId,
569             level,
570             edit_uint64_with_commas(je->JobFiles, b1),
571             edit_uint64_with_suffix(je->JobBytes, b2),
572             termstat,
573             dt, JobName);
574       } else {
575          bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %10s  %-7s  %-8s %s\n"),
576             je->JobId,
577             level,
578             edit_uint64_with_commas(je->JobFiles, b1),
579             edit_uint64_with_suffix(je->JobBytes, b2),
580             termstat,
581             dt, JobName);
582       }  
583       sendit(buf, strlen(buf), sp);
584    }
585    unlock_last_jobs_list();
586    if (!sp->api) sendit("====\n", 5, sp);
587 }
588
589 /*
590  * Convert Job Level into a string
591  */
592 static const char *level_to_str(int level)
593 {
594    const char *str;
595
596    switch (level) {
597    case L_BASE:
598       str = _("Base");
599    case L_FULL:
600       str = _("Full");
601       break;
602    case L_INCREMENTAL:
603       str = _("Incremental");
604       break;
605    case L_DIFFERENTIAL:
606       str = _("Differential");
607       break;
608    case L_SINCE:
609       str = _("Since");
610       break;
611    case L_VERIFY_CATALOG:
612       str = _("Verify Catalog");
613       break;
614    case L_VERIFY_INIT:
615       str = _("Init Catalog");
616       break;
617    case L_VERIFY_VOLUME_TO_CATALOG:
618       str = _("Volume to Catalog");
619       break;
620    case L_VERIFY_DISK_TO_CATALOG:
621       str = _("Disk to Catalog");
622       break;
623    case L_VERIFY_DATA:
624       str = _("Data");
625       break;
626    case L_NONE:
627       str = " ";
628       break;
629    default:
630       str = _("Unknown Job Level");
631       break;
632    }
633    return str;
634 }
635
636 /*
637  * Send to Director
638  */
639 static void sendit(const char *msg, int len, STATUS_PKT *sp)
640 {
641    BSOCK *bs = sp->bs;
642    if (bs) {
643       memcpy(bs->msg, msg, len+1);
644       bs->msglen = len+1;
645       bs->send();
646    } else {
647       sp->callback(msg, len, sp->context);
648    }
649 }
650
651 static void sendit(const char *msg, int len, void *sp)
652 {
653    sendit(msg, len, (STATUS_PKT *)sp);
654 }
655
656 static void sendit(POOL_MEM &msg, int len, STATUS_PKT *sp)
657 {
658    BSOCK *bs = sp->bs;
659    if (bs) {
660       memcpy(bs->msg, msg.c_str(), len+1);
661       bs->msglen = len+1;
662       bs->send();
663    } else {
664       sp->callback(msg.c_str(), len, sp->context);
665    }
666 }
667
668
669 /*
670  * Status command from Director
671  */
672 bool status_cmd(JCR *jcr)
673 {
674    BSOCK *dir = jcr->dir_bsock;
675    STATUS_PKT sp;
676
677    dir->fsend("\n");
678    sp.bs = dir;
679    output_status(&sp);
680    dir->signal(BNET_EOD);
681    return true;
682 }
683
684 /*
685  * .status command from Director
686  */
687 bool qstatus_cmd(JCR *jcr)
688 {
689    BSOCK *dir = jcr->dir_bsock;
690    POOL_MEM cmd;
691    JCR *njcr;
692    s_last_job* job;
693    STATUS_PKT sp;
694
695    sp.bs = dir;
696    if (sscanf(dir->msg, qstatus, cmd.c_str()) != 1) {
697       pm_strcpy(jcr->errmsg, dir->msg);
698       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
699       dir->fsend(_("3900 Bad .status command, missing argument.\n"));
700       dir->signal(BNET_EOD);
701       return false;
702    }
703    unbash_spaces(cmd);
704
705    Dmsg1(200, "cmd=%s\n", cmd.c_str());
706
707    if (strcmp(cmd.c_str(), "current") == 0) {
708       dir->fsend(OKqstatus, cmd.c_str());
709       foreach_jcr(njcr) {
710          if (njcr->JobId != 0) {
711             dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
712          }
713       }
714       endeach_jcr(njcr);
715    } else if (strcmp(cmd.c_str(), "last") == 0) {
716       dir->fsend(OKqstatus, cmd.c_str());
717       if ((last_jobs) && (last_jobs->size() > 0)) {
718          job = (s_last_job*)last_jobs->last();
719          dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
720       }
721    } else if (strcasecmp(cmd.c_str(), "header") == 0) {
722        sp.api = true;
723        list_status_header(&sp);
724    } else if (strcasecmp(cmd.c_str(), "running") == 0) {
725        sp.api = true;
726        list_running_jobs(&sp);
727    } else if (strcasecmp(cmd.c_str(), "waitreservation") == 0) {
728        sp.api = true;
729        list_jobs_waiting_on_reservation(&sp);
730    } else if (strcasecmp(cmd.c_str(), "devices") == 0) {
731        sp.api = true;
732        list_devices(&sp);
733    } else if (strcasecmp(cmd.c_str(), "volumes") == 0) {
734        sp.api = true;
735        list_volumes(sendit, &sp);
736    } else if (strcasecmp(cmd.c_str(), "spooling") == 0) {
737        sp.api = true;
738        list_spool_stats(sendit, &sp);
739    } else if (strcasecmp(cmd.c_str(), "terminated") == 0) {
740        sp.api = true;
741        list_terminated_jobs(&sp);
742    } else {
743       pm_strcpy(jcr->errmsg, dir->msg);
744       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
745       dir->fsend(_("3900 Bad .status command, wrong argument.\n"));
746       dir->signal(BNET_EOD);
747       return false;
748    }
749    dir->signal(BNET_EOD);
750    return true;
751 }
752
753 #if defined(HAVE_WIN32)
754 int bacstat = 0;
755
756 /* Return a one line status for the tray monitor */
757 char *bac_status(char *buf, int buf_len)
758 {
759    JCR *njcr;
760    const char *termstat = _("Bacula Storage: Idle");
761    struct s_last_job *job;
762    int stat = 0;                      /* Idle */
763
764    if (!last_jobs) {
765       goto done;
766    }
767    Dmsg0(1000, "Begin bac_status jcr loop.\n");
768    foreach_jcr(njcr) {
769       if (njcr->JobId != 0) {
770          stat = JS_Running;
771          termstat = _("Bacula Storage: Running");
772          break;
773       }
774    }
775    endeach_jcr(njcr);
776
777    if (stat != 0) {
778       goto done;
779    }
780    if (last_jobs->size() > 0) {
781       job = (struct s_last_job *)last_jobs->last();
782       stat = job->JobStatus;
783       switch (job->JobStatus) {
784       case JS_Canceled:
785          termstat = _("Bacula Storage: Last Job Canceled");
786          break;
787       case JS_ErrorTerminated:
788       case JS_FatalError:
789          termstat = _("Bacula Storage: Last Job Failed");
790          break;
791       default:
792          if (job->Errors) {
793             termstat = _("Bacula Storage: Last Job had Warnings");
794          }
795          break;
796       }
797    }
798    Dmsg0(1000, "End bac_status jcr loop.\n");
799 done:
800    bacstat = stat;
801    if (buf) {
802       bstrncpy(buf, termstat, buf_len);
803    }
804    return buf;
805 }
806
807 #endif /* HAVE_WIN32 */