]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
07Jan06
[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-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 "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: %s (%s) %s %s %s %s\n"), 
68               my_name, VERSION, BDATE, VSS, 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) {
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,%sGVPNW,%sGVNFVMPW\n",  
113                  p_GetCurrentDirectoryA?"":"!",
114                  p_GetCurrentDirectoryW?"":"!",
115                  p_GetVolumePathNameW?"":"!",
116                  p_GetVolumeNameForVolumeMountPointW?"":"!");
117      sendit(msg, len, arg);
118    }
119 #endif
120    if (debug_level > 0) {
121       len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
122             edit_uint64_with_commas(sm_bytes, b1),
123             edit_uint64_with_commas(sm_max_bytes, b2),
124             edit_uint64_with_commas(sm_buffers, b3),
125             edit_uint64_with_commas(sm_max_buffers, b4));
126       sendit(msg, len, arg);
127       len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
128             sizeof(off_t), sizeof(size_t), debug_level, get_trace());
129       sendit(msg, len, arg);
130    }
131
132    list_terminated_jobs(sendit, arg);
133
134    /*
135     * List running jobs
136     */
137    Dmsg0(1000, "Begin status jcr loop.\n");
138    len = Mmsg(msg, _("Running Jobs:\n"));
139    sendit(msg, len, arg);
140    char *vss = "";
141 #ifdef WIN32_VSS
142    if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
143       vss = "VSS ";
144    }
145 #endif
146    foreach_jcr(njcr) {
147       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
148       if (njcr->JobId == 0) {
149          len = Mmsg(msg, _("Director connected at: %s\n"), dt);
150       } else {
151          len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
152                     njcr->JobId, njcr->Job);
153          sendit(msg, len, arg);
154          len = Mmsg(msg, _("    %s%s Job started: %s\n"),
155                     vss, job_type_to_str(njcr->JobType), dt);
156       }
157       sendit(msg, len, arg);
158       if (njcr->JobId == 0) {
159          continue;
160       }
161       sec = time(NULL) - njcr->start_time;
162       if (sec <= 0) {
163          sec = 1;
164       }
165       bps = (int)(njcr->JobBytes / sec);
166       len = Mmsg(msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
167            edit_uint64_with_commas(njcr->JobFiles, b1),
168            edit_uint64_with_commas(njcr->JobBytes, b2),
169            edit_uint64_with_commas(bps, b3));
170       sendit(msg, len, arg);
171       len = Mmsg(msg, _("    Files Examined=%s\n"),
172            edit_uint64_with_commas(njcr->num_files_examined, b1));
173       sendit(msg, len, arg);
174       if (njcr->JobFiles > 0) {
175          P(njcr->mutex);
176          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
177          V(njcr->mutex);
178          sendit(msg, len, arg);
179       }
180
181       found = 1;
182       if (njcr->store_bsock) {
183          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
184              njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
185          sendit(msg, len, arg);
186       } else {
187          len = Mmsg(msg, _("    SDSocket closed.\n"));
188          sendit(msg, len, arg);
189       }
190    }
191    endeach_jcr(njcr);
192
193    Dmsg0(1000, "Begin status jcr loop.\n");
194    if (!found) {
195       len = Mmsg(msg, _("No Jobs running.\n"));
196       sendit(msg, len, arg);
197    }
198    len = Mmsg(msg, _("====\n"));
199    sendit(msg, len, arg);
200    free_pool_memory(msg);
201 }
202
203 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
204 {
205    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
206    char level[10];
207    struct s_last_job *je;
208    const char *msg;
209
210    if (last_jobs->size() == 0) {
211       msg = _("No Terminated Jobs.\n");
212       sendit(msg, strlen(msg), arg);
213       return;
214    }
215    lock_last_jobs_list();
216    sendit("\n", 1, arg);               /* send separately */
217    msg =  _("Terminated Jobs:\n");
218    sendit(msg, strlen(msg), arg);
219    msg =  _(" JobId  Level     Files         Bytes  Status   Finished        Name \n");
220    sendit(msg, strlen(msg), arg);
221    msg = _("======================================================================\n");
222    sendit(msg, strlen(msg), arg);
223    foreach_dlist(je, last_jobs) {
224       char JobName[MAX_NAME_LENGTH];
225       const char *termstat;
226       char buf[1000];
227
228       bstrftime_nc(dt, sizeof(dt), je->end_time);
229       switch (je->JobType) {
230       case JT_ADMIN:
231       case JT_RESTORE:
232          bstrncpy(level, "    ", sizeof(level));
233          break;
234       default:
235          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
236          level[4] = 0;
237          break;
238       }
239       switch (je->JobStatus) {
240       case JS_Created:
241          termstat = _("Created");
242          break;
243       case JS_FatalError:
244       case JS_ErrorTerminated:
245          termstat = _("Error");
246          break;
247       case JS_Differences:
248          termstat = _("Diffs");
249          break;
250       case JS_Canceled:
251          termstat = _("Cancel");
252          break;
253       case JS_Terminated:
254          termstat = _("OK");
255          break;
256       default:
257          termstat = _("Other");
258          break;
259       }
260       bstrncpy(JobName, je->Job, sizeof(JobName));
261       /* There are three periods after the Job name */
262       char *p;
263       for (int i=0; i<3; i++) {
264          if ((p=strrchr(JobName, '.')) != NULL) {
265             *p = 0;
266          }
267       }
268       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %14s %-7s  %-8s %s\n"),
269          je->JobId,
270          level,
271          edit_uint64_with_commas(je->JobFiles, b1),
272          edit_uint64_with_commas(je->JobBytes, b2),
273          termstat,
274          dt, JobName);
275       sendit(buf, strlen(buf), arg);
276    }
277    sendit(_("====\n"), 5, arg);
278    unlock_last_jobs_list();
279 }
280
281
282 /*
283  * Send to bsock (Director or Console)
284  */
285 static void bsock_sendit(const char *msg, int len, void *arg)
286 {
287    BSOCK *user = (BSOCK *)arg;
288
289    user->msg = check_pool_memory_size(user->msg, len+1);
290    memcpy(user->msg, msg, len+1);
291    user->msglen = len+1;
292    bnet_send(user);
293 }
294
295 /*
296  * Status command from Director
297  */
298 int status_cmd(JCR *jcr)
299 {
300    BSOCK *user = jcr->dir_bsock;
301
302    bnet_fsend(user, "\n");
303    do_status(bsock_sendit, (void *)user);
304
305    bnet_sig(user, BNET_EOD);
306    return 1;
307 }
308
309 /*
310  * .status command from Director
311  */
312 int qstatus_cmd(JCR *jcr)
313 {
314    BSOCK *dir = jcr->dir_bsock;
315    POOLMEM *time;
316    JCR *njcr;
317    s_last_job* job;
318
319    time = get_memory(dir->msglen+1);
320
321    if (sscanf(dir->msg, qstatus, time) != 1) {
322       pm_strcpy(&jcr->errmsg, dir->msg);
323       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
324       bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
325       bnet_sig(dir, BNET_EOD);
326       free_memory(time);
327       return 0;
328    }
329    unbash_spaces(time);
330
331    if (strcmp(time, "current") == 0) {
332       bnet_fsend(dir, OKqstatus, time);
333       foreach_jcr(njcr) {
334          if (njcr->JobId != 0) {
335             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
336          }
337       }
338       endeach_jcr(njcr);
339    } else if (strcmp(time, "last") == 0) {
340       bnet_fsend(dir, OKqstatus, time);
341       if ((last_jobs) && (last_jobs->size() > 0)) {
342          job = (s_last_job*)last_jobs->last();
343          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
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          break;
464       }
465    }
466    endeach_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 */