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