]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/status.c
Turn off debug code in jobq.c
[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          }
311          sec = time(NULL) - jcr->run_time;
312          if (sec <= 0) {
313             sec = 1;
314          }
315          bps = jcr->JobBytes / sec;
316          bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
317             edit_uint64_with_commas(jcr->JobFiles, b1),
318             edit_uint64_with_commas(jcr->JobBytes, b2),
319             edit_uint64_with_commas(bps, b3));
320          found = true;
321 #ifdef DEBUG
322          if (jcr->file_bsock) {
323             bnet_fsend(user, _("    FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n"),
324                edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1),
325                jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no,
326                jcr->file_bsock->fd);
327          } else {
328             bnet_fsend(user, _("    FDSocket closed\n"));
329          }
330 #endif
331       }
332    }
333    endeach_jcr(jcr);
334
335    if (!found) {
336       bnet_fsend(user, _("No Jobs running.\n"));
337    }
338    bnet_fsend(user, _("====\n"));
339 }
340
341 static void list_jobs_waiting_on_reservation(BSOCK *user)
342
343    JCR *jcr;
344
345    bnet_fsend(user, _("\nJobs waiting to reserve a drive:\n"));
346    foreach_jcr(jcr) {
347       if (!jcr->reserve_msgs) {
348          continue;
349       }
350       send_drive_reserve_messages(jcr, user);
351    }
352    endeach_jcr(jcr);
353
354    bnet_fsend(user, _("====\n"));
355 }
356
357
358 static void list_terminated_jobs(void *arg)
359 {
360    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
361    char level[10];
362    struct s_last_job *je;
363    const char *msg;
364
365    if (last_jobs->size() == 0) {
366       msg = _("No Terminated Jobs.\n");
367       sendit(msg, strlen(msg), arg);
368       return;
369    }
370    lock_last_jobs_list();
371    msg =  _("\nTerminated Jobs:\n");
372    sendit(msg, strlen(msg), arg);
373    msg =  _(" JobId  Level   Files          Bytes Status   Finished        Name \n");
374    sendit(msg, strlen(msg), arg);
375    msg = _("======================================================================\n");
376    sendit(msg, strlen(msg), arg);
377    foreach_dlist(je, last_jobs) {
378       char JobName[MAX_NAME_LENGTH];
379       const char *termstat;
380       char buf[1000];
381
382       bstrftime_nc(dt, sizeof(dt), je->end_time);
383       switch (je->JobType) {
384       case JT_ADMIN:
385       case JT_RESTORE:
386          bstrncpy(level, "    ", sizeof(level));
387          break;
388       default:
389          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
390          level[4] = 0;
391          break;
392       }
393       switch (je->JobStatus) {
394       case JS_Created:
395          termstat = _("Created");
396          break;
397       case JS_FatalError:
398       case JS_ErrorTerminated:
399          termstat = _("Error");
400          break;
401       case JS_Differences:
402          termstat = _("Diffs");
403          break;
404       case JS_Canceled:
405          termstat = _("Cancel");
406          break;
407       case JS_Terminated:
408          termstat = _("OK");
409          break;
410       default:
411          termstat = _("Other");
412          break;
413       }
414       bstrncpy(JobName, je->Job, sizeof(JobName));
415       /* There are three periods after the Job name */
416       char *p;
417       for (int i=0; i<3; i++) {
418          if ((p=strrchr(JobName, '.')) != NULL) {
419             *p = 0;
420          }
421       }
422       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %14s %-7s  %-8s %s\n"),
423          je->JobId,
424          level,
425          edit_uint64_with_commas(je->JobFiles, b1),
426          edit_uint64_with_commas(je->JobBytes, b2),
427          termstat,
428          dt, JobName);
429       sendit(buf, strlen(buf), arg);
430    }
431    sendit(_("====\n"), 5, arg);
432    unlock_last_jobs_list();
433 }
434
435 /*
436  * Convert Job Level into a string
437  */
438 static const char *level_to_str(int level)
439 {
440    const char *str;
441
442    switch (level) {
443    case L_BASE:
444       str = _("Base");
445    case L_FULL:
446       str = _("Full");
447       break;
448    case L_INCREMENTAL:
449       str = _("Incremental");
450       break;
451    case L_DIFFERENTIAL:
452       str = _("Differential");
453       break;
454    case L_SINCE:
455       str = _("Since");
456       break;
457    case L_VERIFY_CATALOG:
458       str = _("Verify Catalog");
459       break;
460    case L_VERIFY_INIT:
461       str = _("Init Catalog");
462       break;
463    case L_VERIFY_VOLUME_TO_CATALOG:
464       str = _("Volume to Catalog");
465       break;
466    case L_VERIFY_DISK_TO_CATALOG:
467       str = _("Disk to Catalog");
468       break;
469    case L_VERIFY_DATA:
470       str = _("Data");
471       break;
472    case L_NONE:
473       str = " ";
474       break;
475    default:
476       str = _("Unknown Job Level");
477       break;
478    }
479    return str;
480 }
481
482 /*
483  * Send to Director
484  */
485 static void sendit(const char *msg, int len, void *arg)
486 {
487    BSOCK *user = (BSOCK *)arg;
488
489    memcpy(user->msg, msg, len+1);
490    user->msglen = len+1;
491    bnet_send(user);
492 }
493
494 /*
495  * .status command from Director
496  */
497 bool qstatus_cmd(JCR *jcr)
498 {
499    BSOCK *dir = jcr->dir_bsock;
500    POOL_MEM time;
501    JCR *njcr;
502    s_last_job* job;
503
504    if (sscanf(dir->msg, qstatus, time.c_str()) != 1) {
505       pm_strcpy(jcr->errmsg, dir->msg);
506       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
507       bnet_fsend(dir, _("3900 Bad .status command, missing argument.\n"));
508       bnet_sig(dir, BNET_EOD);
509       return false;
510    }
511    unbash_spaces(time);
512
513    if (strcmp(time.c_str(), "current") == 0) {
514       bnet_fsend(dir, OKqstatus, time.c_str());
515       foreach_jcr(njcr) {
516          if (njcr->JobId != 0) {
517             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
518          }
519       }
520       endeach_jcr(njcr);
521    } else if (strcmp(time.c_str(), "last") == 0) {
522       bnet_fsend(dir, OKqstatus, time.c_str());
523       if ((last_jobs) && (last_jobs->size() > 0)) {
524          job = (s_last_job*)last_jobs->last();
525          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
526       }
527    } else {
528       pm_strcpy(jcr->errmsg, dir->msg);
529       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
530       bnet_fsend(dir, _("3900 Bad .status command, wrong argument.\n"));
531       bnet_sig(dir, BNET_EOD);
532       return false;
533    }
534    bnet_sig(dir, BNET_EOD);
535    return true;
536 }