]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/status.c
- Add VolumePurged method to Python JobEvents class. Fixes
[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-2005 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 extern char my_name[];
34 extern time_t daemon_start_time;
35 extern int num_jobs_run;
36
37
38 /* Static variables */
39 static char qstatus[] = ".status %127s\n";
40
41 static char OKqstatus[]   = "3000 OK .status\n";
42 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
43
44
45 /* Forward referenced functions */
46 static void send_blocked_status(JCR *jcr, DEVICE *dev);
47 static void list_terminated_jobs(void *arg);
48 static void list_running_jobs(BSOCK *user);
49 static void sendit(const char *msg, int len, void *arg);
50 static const char *level_to_str(int level);
51
52
53 /*
54  * Status command from Director
55  */
56 bool status_cmd(JCR *jcr)
57 {
58    DEVRES *device;
59    AUTOCHANGER *changer;
60    DEVICE *dev;
61    BSOCK *user = jcr->dir_bsock;
62    char dt[MAX_TIME_LENGTH];
63    char b1[30], b2[30], b3[30];
64    int bpb;
65
66    bnet_fsend(user, _("\n%s Version: %s (%s) %s %s %s\n"), my_name,
67               VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
68    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
69    if (num_jobs_run == 1) {
70       bnet_fsend(user, _("Daemon started %s, 1 Job run since started.\n"), dt);
71    }
72    else {
73       bnet_fsend(user, _("Daemon started %s, %d Jobs run since started.\n"), dt, num_jobs_run);
74    }
75    if (debug_level > 0) {
76       char b1[35], b2[35], b3[35], b4[35];
77       bnet_fsend(user, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
78             edit_uint64_with_commas(sm_bytes, b1),
79             edit_uint64_with_commas(sm_max_bytes, b2),
80             edit_uint64_with_commas(sm_buffers, b3),
81             edit_uint64_with_commas(sm_max_buffers, b4));
82    }
83
84    /*
85     * List running jobs
86     */
87    list_running_jobs(user);
88
89    /*
90     * List terminated jobs
91     */
92    list_terminated_jobs(user);
93
94    /*
95     * List devices
96     */
97    bnet_fsend(user, _("\nDevice status:\n"));
98    foreach_res(changer, R_AUTOCHANGER) {
99       bnet_fsend(user, _("Autochanger \"%s\" with devices:\n"),
100          changer->hdr.name);
101       foreach_alist(device, changer->device) {
102          if (device->dev) {
103             bnet_fsend(user, "   %s\n", device->dev->print_name());
104          } else {
105             bnet_fsend(user, "   %s\n", device->hdr.name);
106          }
107       }
108    }
109    foreach_res(device, R_DEVICE) {
110       dev = device->dev;
111       if (dev && dev->is_open()) {
112          if (dev->is_labeled()) {
113             bnet_fsend(user, _("Device %s is mounted with Volume \"%s\"\n"),
114                dev->print_name(), dev->VolHdr.VolumeName);
115          } else {
116             bnet_fsend(user, _("Device %s open but no Bacula volume is mounted.\n"), 
117                dev->print_name());
118          }
119          send_blocked_status(jcr, dev);
120          if (dev->can_append()) {
121             bpb = dev->VolCatInfo.VolCatBlocks;
122             if (bpb <= 0) {
123                bpb = 1;
124             }
125             bpb = dev->VolCatInfo.VolCatBytes / bpb;
126             bnet_fsend(user, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
127                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
128                edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
129                edit_uint64_with_commas(bpb, b3));
130          } else {  /* reading */
131             bpb = dev->VolCatInfo.VolCatReads;
132             if (bpb <= 0) {
133                bpb = 1;
134             }
135             if (dev->VolCatInfo.VolCatRBytes > 0) {
136                bpb = dev->VolCatInfo.VolCatRBytes / bpb;
137             } else {
138                bpb = 0;
139             }
140             bnet_fsend(user, _("    Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"),
141                edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1),
142                edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2),
143                edit_uint64_with_commas(bpb, b3));
144          }
145          bnet_fsend(user, _("    Positioned at File=%s Block=%s\n"),
146             edit_uint64_with_commas(dev->file, b1),
147             edit_uint64_with_commas(dev->block_num, b2));
148
149       } else {
150          if (dev) {
151             bnet_fsend(user, _("Device %s is not open or does not exist.\n"), dev->print_name());
152          } else {
153             bnet_fsend(user, _("Device \"%s\" is not open or does not exist.\n"), device->hdr.name);
154          }
155          send_blocked_status(jcr, dev);
156       }
157    }
158    bnet_fsend(user, _("====\n\n"));
159    bnet_fsend(user, _("In Use Volume status:\n"));
160    list_volumes(user);
161    bnet_fsend(user, _("====\n\n"));
162        
163
164 #ifdef xxx
165    if (debug_level > 0) {
166       bnet_fsend(user, _("====\n\n"));
167       dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
168    }
169    bnet_fsend(user, _("====\n\n"));
170 #endif
171
172    list_spool_stats(user);
173
174    bnet_sig(user, BNET_EOD);
175    return true;
176 }
177
178 static void send_blocked_status(JCR *jcr, DEVICE *dev)
179 {
180    BSOCK *user = jcr->dir_bsock;
181    DCR *dcr = jcr->dcr;
182
183    if (!dev) {
184       bnet_fsend(user, _("No DEVICE structure.\n\n"));
185       return;
186    }
187    switch (dev->dev_blocked) {
188    case BST_UNMOUNTED:
189       bnet_fsend(user, _("    Device is BLOCKED. User unmounted.\n"));
190       break;
191    case BST_UNMOUNTED_WAITING_FOR_SYSOP:
192       bnet_fsend(user, _("    Device is BLOCKED. User unmounted during wait for media/mount.\n"));
193       break;
194    case BST_WAITING_FOR_SYSOP:
195       if (jcr->JobStatus == JS_WaitMount) {
196          bnet_fsend(user, _("    Device is BLOCKED waiting for mount of volume \"%s\".\n"),
197             dcr->VolumeName);
198       } else {
199          bnet_fsend(user, _("    Device is BLOCKED waiting for media.\n"));
200       }
201       break;
202    case BST_DOING_ACQUIRE:
203       bnet_fsend(user, _("    Device is being initialized.\n"));
204       break;
205    case BST_WRITING_LABEL:
206       bnet_fsend(user, _("    Device is blocked labeling a Volume.\n"));
207       break;
208    default:
209       break;
210    }
211    /* Send autochanger slot status */
212    if (dev->is_autochanger()) {
213       if (dev->Slot) {
214          bnet_fsend(user, _("    Slot %d is loaded in drive %d.\n"), 
215             dev->Slot, dev->drive_index);
216       } else {
217          bnet_fsend(user, _("    Drive %d is not loaded.\n"), dev->drive_index);
218       }
219    }
220    if (debug_level > 1) {
221       bnet_fsend(user, _("Configured device capabilities:\n"));
222       bnet_fsend(user, "%sEOF ", dev->capabilities & CAP_EOF ? "" : "!");
223       bnet_fsend(user, "%sBSR ", dev->capabilities & CAP_BSR ? "" : "!");
224       bnet_fsend(user, "%sBSF ", dev->capabilities & CAP_BSF ? "" : "!");
225       bnet_fsend(user, "%sFSR ", dev->capabilities & CAP_FSR ? "" : "!");
226       bnet_fsend(user, "%sFSF ", dev->capabilities & CAP_FSF ? "" : "!");
227       bnet_fsend(user, "%sEOM ", dev->capabilities & CAP_EOM ? "" : "!");
228       bnet_fsend(user, "%sREM ", dev->capabilities & CAP_REM ? "" : "!");
229       bnet_fsend(user, "%sRACCESS ", dev->capabilities & CAP_RACCESS ? "" : "!");
230       bnet_fsend(user, "%sAUTOMOUNT ", dev->capabilities & CAP_AUTOMOUNT ? "" : "!");
231       bnet_fsend(user, "%sLABEL ", dev->capabilities & CAP_LABEL ? "" : "!");
232       bnet_fsend(user, "%sANONVOLS ", dev->capabilities & CAP_ANONVOLS ? "" : "!");
233       bnet_fsend(user, "%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
234       bnet_fsend(user, "\n");
235
236       bnet_fsend(user, _("Device state:\n"));
237       bnet_fsend(user, "%sOPENED ", dev->is_open() ? "" : "!");
238       bnet_fsend(user, "%sTAPE ", dev->is_tape() ? "" : "!");
239       bnet_fsend(user, "%sLABEL ", dev->is_labeled() ? "" : "!");
240       bnet_fsend(user, "%sMALLOC ", dev->state & ST_MALLOC ? "" : "!");
241       bnet_fsend(user, "%sAPPEND ", dev->can_append() ? "" : "!");
242       bnet_fsend(user, "%sREAD ", dev->can_read() ? "" : "!");
243       bnet_fsend(user, "%sEOT ", dev->at_eot() ? "" : "!");
244       bnet_fsend(user, "%sWEOT ", dev->state & ST_WEOT ? "" : "!");
245       bnet_fsend(user, "%sEOF ", dev->at_eof() ? "" : "!");
246       bnet_fsend(user, "%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!");
247       bnet_fsend(user, "%sSHORT ", dev->state & ST_SHORT ? "" : "!");
248       bnet_fsend(user, "%sMOUNTED ", dev->state & ST_MOUNTED ? "" : "!");
249       bnet_fsend(user, "\n");
250       bnet_fsend(user, _("num_writers=%d JobStatus=%c block=%d\n\n"), dev->num_writers,
251          jcr->JobStatus, dev->dev_blocked);
252
253       bnet_fsend(user, _("Device parameters:\n"));
254       bnet_fsend(user, _("Archive name: %s Device name: %s\n"), dev->archive_name(),
255          dev->name());
256       bnet_fsend(user, _("File=%u block=%u\n"), dev->file, dev->block_num);
257       bnet_fsend(user, _("Min block=%u Max block=%u\n"), dev->min_block_size, dev->max_block_size);
258    }
259
260 }
261
262 static void list_running_jobs(BSOCK *user)
263 {
264    bool found = false;
265    int bps, sec;
266    JCR *jcr;
267    char JobName[MAX_NAME_LENGTH];
268    char b1[30], b2[30], b3[30];
269
270    bnet_fsend(user, _("\nRunning Jobs:\n"));
271    foreach_jcr(jcr) {
272       if (jcr->JobStatus == JS_WaitFD) {
273          bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"),
274             job_type_to_str(jcr->JobType), jcr->Job);
275       }
276       if (jcr->dcr && jcr->dcr->device) {
277          bstrncpy(JobName, jcr->Job, sizeof(JobName));
278          /* There are three periods after the Job name */
279          char *p;
280          for (int i=0; i<3; i++) {
281             if ((p=strrchr(JobName, '.')) != NULL) {
282                *p = 0;
283             }
284          }
285          bnet_fsend(user, _("%s %s job %s JobId=%d Volume=\"%s\" device=\"%s\"\n"),
286                    job_level_to_str(jcr->JobLevel),
287                    job_type_to_str(jcr->JobType),
288                    JobName,
289                    jcr->JobId,
290                    jcr->dcr->VolumeName,
291                    jcr->dcr->device->device_name);
292          sec = time(NULL) - jcr->run_time;
293          if (sec <= 0) {
294             sec = 1;
295          }
296          bps = jcr->JobBytes / sec;
297          bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
298             edit_uint64_with_commas(jcr->JobFiles, b1),
299             edit_uint64_with_commas(jcr->JobBytes, b2),
300             edit_uint64_with_commas(bps, b3));
301          found = true;
302 #ifdef DEBUG
303          if (jcr->file_bsock) {
304             bnet_fsend(user, _("    FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n"),
305                edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1),
306                jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no,
307                jcr->file_bsock->fd);
308          } else {
309             bnet_fsend(user, _("    FDSocket closed\n"));
310          }
311 #endif
312       }
313       free_jcr(jcr);
314    }
315    if (!found) {
316       bnet_fsend(user, _("No Jobs running.\n"));
317    }
318    bnet_fsend(user, _("====\n"));
319 }
320
321 static void list_terminated_jobs(void *arg)
322 {
323    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
324    char level[10];
325    struct s_last_job *je;
326    const char *msg;
327
328    if (last_jobs->size() == 0) {
329       msg = _("No Terminated Jobs.\n");
330       sendit(msg, strlen(msg), arg);
331       return;
332    }
333    lock_last_jobs_list();
334    msg =  _("\nTerminated Jobs:\n");
335    sendit(msg, strlen(msg), arg);
336    msg =  _(" JobId  Level   Files          Bytes Status   Finished        Name \n");
337    sendit(msg, strlen(msg), arg);
338    msg = _("======================================================================\n");
339    sendit(msg, strlen(msg), arg);
340    foreach_dlist(je, last_jobs) {
341       char JobName[MAX_NAME_LENGTH];
342       const char *termstat;
343       char buf[1000];
344
345       bstrftime_nc(dt, sizeof(dt), je->end_time);
346       switch (je->JobType) {
347       case JT_ADMIN:
348       case JT_RESTORE:
349          bstrncpy(level, "    ", sizeof(level));
350          break;
351       default:
352          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
353          level[4] = 0;
354          break;
355       }
356       switch (je->JobStatus) {
357       case JS_Created:
358          termstat = _("Created");
359          break;
360       case JS_FatalError:
361       case JS_ErrorTerminated:
362          termstat = _("Error");
363          break;
364       case JS_Differences:
365          termstat = _("Diffs");
366          break;
367       case JS_Canceled:
368          termstat = _("Cancel");
369          break;
370       case JS_Terminated:
371          termstat = _("OK");
372          break;
373       default:
374          termstat = _("Other");
375          break;
376       }
377       bstrncpy(JobName, je->Job, sizeof(JobName));
378       /* There are three periods after the Job name */
379       char *p;
380       for (int i=0; i<3; i++) {
381          if ((p=strrchr(JobName, '.')) != NULL) {
382             *p = 0;
383          }
384       }
385       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %14s %-7s  %-8s %s\n"),
386          je->JobId,
387          level,
388          edit_uint64_with_commas(je->JobFiles, b1),
389          edit_uint64_with_commas(je->JobBytes, b2),
390          termstat,
391          dt, JobName);
392       sendit(buf, strlen(buf), arg);
393    }
394    sendit(_("====\n"), 5, arg);
395    unlock_last_jobs_list();
396 }
397
398 /*
399  * Convert Job Level into a string
400  */
401 static const char *level_to_str(int level)
402 {
403    const char *str;
404
405    switch (level) {
406    case L_BASE:
407       str = _("Base");
408    case L_FULL:
409       str = _("Full");
410       break;
411    case L_INCREMENTAL:
412       str = _("Incremental");
413       break;
414    case L_DIFFERENTIAL:
415       str = _("Differential");
416       break;
417    case L_SINCE:
418       str = _("Since");
419       break;
420    case L_VERIFY_CATALOG:
421       str = _("Verify Catalog");
422       break;
423    case L_VERIFY_INIT:
424       str = _("Init Catalog");
425       break;
426    case L_VERIFY_VOLUME_TO_CATALOG:
427       str = _("Volume to Catalog");
428       break;
429    case L_VERIFY_DISK_TO_CATALOG:
430       str = _("Disk to Catalog");
431       break;
432    case L_VERIFY_DATA:
433       str = _("Data");
434       break;
435    case L_NONE:
436       str = " ";
437       break;
438    default:
439       str = _("Unknown Job Level");
440       break;
441    }
442    return str;
443 }
444
445 /*
446  * Send to Director
447  */
448 static void sendit(const char *msg, int len, void *arg)
449 {
450    BSOCK *user = (BSOCK *)arg;
451
452    memcpy(user->msg, msg, len+1);
453    user->msglen = len+1;
454    bnet_send(user);
455 }
456
457 /*
458  * .status command from Director
459  */
460 bool qstatus_cmd(JCR *jcr)
461 {
462    BSOCK *dir = jcr->dir_bsock;
463    POOL_MEM time;
464    JCR *njcr;
465    s_last_job* job;
466
467    if (sscanf(dir->msg, qstatus, time.c_str()) != 1) {
468       pm_strcpy(jcr->errmsg, dir->msg);
469       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
470       bnet_fsend(dir, _("3900 Bad .status command, missing argument.\n"));
471       bnet_sig(dir, BNET_EOD);
472       return false;
473    }
474    unbash_spaces(time);
475
476    if (strcmp(time.c_str(), "current") == 0) {
477       bnet_fsend(dir, OKqstatus, time.c_str());
478       foreach_jcr(njcr) {
479          if (njcr->JobId != 0) {
480             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
481          }
482          free_jcr(njcr);
483       }
484    } else if (strcmp(time.c_str(), "last") == 0) {
485       bnet_fsend(dir, OKqstatus, time.c_str());
486       if ((last_jobs) && (last_jobs->size() > 0)) {
487          job = (s_last_job*)last_jobs->last();
488          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
489       }
490    } else {
491       pm_strcpy(jcr->errmsg, dir->msg);
492       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
493       bnet_fsend(dir, _("3900 Bad .status command, wrong argument.\n"));
494       bnet_sig(dir, BNET_EOD);
495       return false;
496    }
497    bnet_sig(dir, BNET_EOD);
498    return true;
499 }