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