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