]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
- Add .status [current|last] command to filed and stored
[bacula/bacula] / bacula / src / filed / status.c
1 /*
2  *  Bacula File Daemon Status routines
3  *
4  *    Kern Sibbald, August MMI
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Copyright (C) 2000-2004 Kern Sibbald and John Walker
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 as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
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 GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "filed.h"
31
32 extern char my_name[];
33 extern int num_jobs_run;
34 extern time_t daemon_start_time;
35
36 /* Forward referenced functions */
37 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
38 static void bsock_sendit(const char *msg, int len, void *arg);
39 static const char *level_to_str(int level);
40
41 /* Static variables */
42 static char qstatus[] = ".status %s\n";
43
44 static char OKqstatus[]   = "2000 OK .status\n";
45 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
46
47 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
48 static int privs = 0;
49 #endif
50
51 /*
52  * General status generator
53  */
54 static void do_status(void sendit(const char *msg, int len, void *sarg), void *arg) 
55 {
56    int sec, bps;
57    char *msg, b1[32], b2[32], b3[32], b4[32];
58    int found, len;
59    JCR *njcr;
60    char dt[MAX_TIME_LENGTH];
61
62    msg = (char *)get_pool_memory(PM_MESSAGE);
63    found = 0;
64    len = Mmsg(msg, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
65               HOST_OS, DISTNAME, DISTVER);
66    sendit(msg, len, arg);
67    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
68    len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"), 
69         dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
70    sendit(msg, len, arg);
71 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
72    if (debug_level > 0) {
73       if (!privs) {
74          privs = enable_backup_privileges(NULL, 1);
75       }
76       len = Mmsg(msg, 
77          _(" Priv 0x%x APIs=%sOPT,%sATP,%sLPV,%sGFAE,%sBR,%sBW,%sSPSP\n"), privs,
78          p_OpenProcessToken?"":"!",
79          p_AdjustTokenPrivileges?"":"!",
80          p_LookupPrivilegeValue?"":"!",
81          p_GetFileAttributesEx?"":"!",
82          p_BackupRead?"":"!",
83          p_BackupWrite?"":"!",
84          p_SetProcessShutdownParameters?"":"!");
85       sendit(msg, len, arg);
86    }
87 #endif
88    if (debug_level > 0) {
89       len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
90             edit_uint64_with_commas(sm_bytes, b1),
91             edit_uint64_with_commas(sm_max_bytes, b2),
92             edit_uint64_with_commas(sm_buffers, b3),
93             edit_uint64_with_commas(sm_max_buffers, b4));
94        sendit(msg, len, arg);
95     }
96    if (debug_level > 0) {
97       len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d\n"), sizeof(off_t),
98             sizeof(size_t));
99       sendit(msg, len, arg);
100    }
101
102    list_terminated_jobs(sendit, arg);
103
104    /*
105     * List running jobs  
106     */
107    Dmsg0(1000, "Begin status jcr loop.\n");
108    len = Mmsg(msg, _("Running Jobs:\n"));
109    sendit(msg, len, arg);
110    lock_jcr_chain();
111    foreach_jcr(njcr) {
112       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
113       if (njcr->JobId == 0) {
114          len = Mmsg(msg, _("Director connected at: %s\n"), dt);
115       } else {
116          len = Mmsg(msg, _("JobId %d Job %s is running.\n"), 
117                     njcr->JobId, njcr->Job);
118          sendit(msg, len, arg);
119          len = Mmsg(msg, _("    %s Job started: %s\n"), 
120                     job_type_to_str(njcr->JobType), dt);
121       }
122       sendit(msg, len, arg);
123       if (njcr->JobId == 0) {
124          free_locked_jcr(njcr);
125          continue;
126       }
127       sec = time(NULL) - njcr->start_time;
128       if (sec <= 0) {
129          sec = 1;
130       }
131       bps = (int)(njcr->JobBytes / sec);
132       len = Mmsg(msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"), 
133            edit_uint64_with_commas(njcr->JobFiles, b1),
134            edit_uint64_with_commas(njcr->JobBytes, b2),
135            edit_uint64_with_commas(bps, b3));
136       sendit(msg, len, arg);
137       len = Mmsg(msg, _("    Files Examined=%s\n"), 
138            edit_uint64_with_commas(njcr->num_files_examined, b1));
139       sendit(msg, len, arg);
140       if (njcr->JobFiles > 0) {
141          P(njcr->mutex);
142          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
143          V(njcr->mutex);
144          sendit(msg, len, arg);
145       }
146
147       found = 1;
148       if (njcr->store_bsock) {
149          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
150              njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
151          sendit(msg, len, arg);
152       } else {
153          len = Mmsg(msg, _("    SDSocket closed.\n"));
154          sendit(msg, len, arg);
155       }
156       free_locked_jcr(njcr);
157    }
158    unlock_jcr_chain();
159    Dmsg0(1000, "Begin status jcr loop.\n");
160    if (!found) {
161       len = Mmsg(msg, _("No Jobs running.\n"));
162       sendit(msg, len, arg);
163    }
164    len = Mmsg(msg, _("====\n"));
165    sendit(msg, len, arg);
166    free_pool_memory(msg);
167 }
168
169 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg) 
170 {
171    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
172    char level[10];
173    struct s_last_job *je;
174    const char *msg;
175
176    if (last_jobs->size() == 0) {
177       msg = _("No Terminated Jobs.\n"); 
178       sendit(msg, strlen(msg), arg);
179       return;
180    }
181    lock_last_jobs_list();
182    sendit("\n", 1, arg);               /* send separately */
183    msg =  _("Terminated Jobs:\n"); 
184    sendit(msg, strlen(msg), arg);
185    msg =  _(" JobId  Level     Files         Bytes  Status   Finished        Name \n");
186    sendit(msg, strlen(msg), arg);
187    msg = _("======================================================================\n"); 
188    sendit(msg, strlen(msg), arg);
189    foreach_dlist(je, last_jobs) {
190       char JobName[MAX_NAME_LENGTH];
191       const char *termstat;
192       char buf[1000];
193
194       bstrftime_nc(dt, sizeof(dt), je->end_time);
195       switch (je->JobType) {
196       case JT_ADMIN:
197       case JT_RESTORE:
198          bstrncpy(level, "    ", sizeof(level));
199          break;
200       default:
201          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
202          level[4] = 0;
203          break;
204       }
205       switch (je->JobStatus) {
206       case JS_Created:
207          termstat = "Created";
208          break;
209       case JS_FatalError:
210       case JS_ErrorTerminated:
211          termstat = "Error";
212          break;
213       case JS_Differences:
214          termstat = "Diffs";
215          break;
216       case JS_Canceled:
217          termstat = "Cancel";
218          break;
219       case JS_Terminated:
220          termstat = "OK";
221          break;
222       default:
223          termstat = "Other";
224          break;
225       }
226       bstrncpy(JobName, je->Job, sizeof(JobName));
227       /* There are three periods after the Job name */
228       char *p;
229       for (int i=0; i<3; i++) {
230          if ((p=strrchr(JobName, '.')) != NULL) {
231             *p = 0;
232          }
233       }
234       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %14s %-7s  %-8s %s\n"), 
235          je->JobId,
236          level, 
237          edit_uint64_with_commas(je->JobFiles, b1),
238          edit_uint64_with_commas(je->JobBytes, b2), 
239          termstat,
240          dt, JobName);
241       sendit(buf, strlen(buf), arg);
242    }
243    sendit("====\n", 5, arg);
244    unlock_last_jobs_list();
245 }
246
247
248 /*
249  * Send to bsock (Director or Console)
250  */
251 static void bsock_sendit(const char *msg, int len, void *arg)
252 {
253    BSOCK *user = (BSOCK *)arg;
254
255    user->msg = check_pool_memory_size(user->msg, len+1);
256    memcpy(user->msg, msg, len+1);
257    user->msglen = len+1;
258    bnet_send(user);
259 }
260                                    
261 /*
262  * Status command from Director
263  */
264 int status_cmd(JCR *jcr)
265 {
266    BSOCK *user = jcr->dir_bsock;
267
268    bnet_fsend(user, "\n");
269    do_status(bsock_sendit, (void *)user);
270
271    bnet_sig(user, BNET_EOD);
272    return 1;
273 }
274
275 /*
276  * .status command from Director
277  */
278 int qstatus_cmd(JCR *jcr)
279 {
280    BSOCK *dir = jcr->dir_bsock;
281    char time[dir->msglen+1];
282    JCR *njcr;
283    s_last_job* job;
284       
285    if (sscanf(dir->msg, qstatus, time) != 1) {
286       pm_strcpy(&jcr->errmsg, dir->msg);
287       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
288       bnet_fsend(dir, "2900 Bad .status command, missing argument.\n");
289       bnet_sig(dir, BNET_EOD);
290       return 0;
291    }
292    unbash_spaces(time);
293    
294    if (strcmp(time, "current") == 0) {
295       bnet_fsend(dir, OKqstatus, time);
296       lock_jcr_chain();
297       foreach_jcr(njcr) {
298          if (njcr->JobId != 0) {
299             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
300          }
301          free_locked_jcr(njcr);
302       }
303       unlock_jcr_chain();
304    }
305    else if (strcmp(time, "last") == 0) {
306       bnet_fsend(dir, OKqstatus, time);
307       if ((last_jobs) && (last_jobs->size() > 0)) {
308          job = (s_last_job*)last_jobs->last();
309          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
310       }
311    }
312    else {
313       pm_strcpy(&jcr->errmsg, dir->msg);
314       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
315       bnet_fsend(dir, "2900 Bad .status command, wrong argument.\n");
316       bnet_sig(dir, BNET_EOD);
317       return 0;
318    }
319    
320    bnet_sig(dir, BNET_EOD);
321    return 1;
322 }
323
324 /*
325  * Convert Job Level into a string
326  */
327 static const char *level_to_str(int level) 
328 {
329    const char *str;
330
331    switch (level) {
332    case L_BASE:
333       str = _("Base");
334    case L_FULL:
335       str = _("Full");
336       break;
337    case L_INCREMENTAL:
338       str = _("Incremental");
339       break;
340    case L_DIFFERENTIAL:
341       str = _("Differential");
342       break;
343    case L_SINCE:
344       str = _("Since");
345       break;
346    case L_VERIFY_CATALOG:
347       str = _("Verify Catalog");
348       break;
349    case L_VERIFY_INIT:
350       str = _("Init Catalog");
351       break;
352    case L_VERIFY_VOLUME_TO_CATALOG:
353       str = _("Volume to Catalog");
354       break;
355    case L_VERIFY_DISK_TO_CATALOG:
356       str = _("Disk to Catalog");
357       break;
358    case L_VERIFY_DATA:
359       str = _("Data");
360       break;
361    case L_NONE:
362       str = " ";
363       break;
364    default:
365       str = _("Unknown Job Level");
366       break;
367    }
368    return str;
369 }
370
371
372 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
373 #include <windows.h>
374
375 int bacstat = 0;
376
377 struct s_win32_arg {
378    HWND hwnd;
379    int idlist;
380 };
381
382 /*
383  * Put message in Window List Box
384  */
385 static void win32_sendit(const char *msg, int len, void *marg)
386 {
387    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
388
389    if (len > 0 && msg[len-1] == '\n') {
390        // when compiling with visual studio some strings are read-only 
391        // and cause access violations.  So we creat a tmp copy.
392        char *_msg = (char *)alloca(len);
393        bstrncpy(_msg, msg, len);
394        msg = _msg;
395    }
396    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
397    
398 }
399
400 void FillStatusBox(HWND hwnd, int idlist)
401 {
402    struct s_win32_arg arg;
403
404    arg.hwnd = hwnd;
405    arg.idlist = idlist;
406
407    /* Empty box */
408    for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
409       { }
410    do_status(win32_sendit, (void *)&arg);
411 }
412
413 char *bac_status(char *buf, int buf_len)
414 {
415    JCR *njcr;
416    const char *termstat = _("Bacula Idle");
417    struct s_last_job *job;
418    int stat = 0;                      /* Idle */
419
420    if (!last_jobs) {
421       goto done;
422    }
423    Dmsg0(1000, "Begin bac_status jcr loop.\n");
424    lock_jcr_chain();
425    foreach_jcr(njcr) {
426       if (njcr->JobId != 0) {
427          stat = JS_Running;
428          termstat = _("Bacula Running");
429          free_locked_jcr(njcr);
430          break;
431       }
432       free_locked_jcr(njcr);
433    }
434    unlock_jcr_chain();
435    if (stat != 0) {
436       goto done;
437    }
438    if (last_jobs->size() > 0) {
439       job = (struct s_last_job *)last_jobs->last();
440       stat = job->JobStatus;
441       switch (job->JobStatus) {
442       case JS_Canceled:
443          termstat = _("Last Job Canceled");
444          break;
445       case JS_ErrorTerminated:
446       case JS_FatalError:  
447          termstat = _("Last Job Failed");
448          break;
449       default:
450          if (job->Errors) {
451             termstat = _("Last Job had Warnings");
452          }
453          break;
454       }
455    }
456    Dmsg0(1000, "End bac_status jcr loop.\n");
457 done:
458    bacstat = stat;
459    if (buf) {
460       bstrncpy(buf, termstat, buf_len);
461    }
462    return buf;
463 }
464
465 #endif /* HAVE_CYGWIN */